}
+bool const BufferView::repaintAll() const
+{
+ return pimpl_->repaintAll();
+}
+
+
+void const BufferView::repaintAll(bool r) const
+{
+ pimpl_->repaintAll(r);
+}
+
+
LCursor & BufferView::cursor()
{
return pimpl_->cursor_;
enum flags {
FitCursor = 1,
Force = 2,
- SinglePar = 4
+ SinglePar = 4,
+ MultiParSel = 8
};
inline flags operator|(flags const f, flags const g)
*/
void putSelectionAt(DocIterator const & cur,
int length, bool backwards);
-
+ ///
+ bool const repaintAll() const;
+ ///
+ void const repaintAll(bool r) const;
private:
///
}
+bool BufferView::Pimpl::multiParSel()
+{
+ if (!cursor_.selection())
+ return false;
+ bool ret = multiparsel_cache_;
+ multiparsel_cache_ = cursor_.selBegin().pit() != cursor_.selEnd().pit();
+ // Either this, or previous selection spans paragraphs
+ return ret || multiparsel_cache_;
+}
+
+
void BufferView::Pimpl::update(Update::flags flags)
{
lyxerr[Debug::DEBUG]
// First drawing step
ViewMetricsInfo vi = metrics(flags & Update::SinglePar);
- bool forceupdate(flags & Update::Force);
+ bool forceupdate(flags & (Update::Force | Update::SinglePar));
if ((flags & Update::FitCursor) && fitCursor()) {
forceupdate = true;
vi = metrics();
}
+ if ((flags & Update::MultiParSel) && multiParSel()) {
+ forceupdate = true;
+ vi = metrics();
+ }
if (forceupdate) {
// Second drawing step
screen().redraw(*bv_, vi);
if (cur.result().update())
update(Update::FitCursor | Update::Force);
else
- update();
+ update(Update::FitCursor | Update::MultiParSel);
}
// See workAreaKeyPress
void resizeCurrentBuffer();
//
bool fitCursor();
+ //
+ bool multiParSel();
///
void update(Update::flags flags = Update::Force);
///
FuncStatus getStatus(FuncRequest const & cmd);
/// a function should be executed
bool dispatch(FuncRequest const & ev);
+ /// Flag: do a full redraw of inside text of inset
+ bool repaintAll() { return refresh_inside_; }
+ ///
+ void repaintAll(bool r) {refresh_inside_ = r; }
private:
/// An error list (replaces the error insets)
ErrorList errorlist_;
///
LCursor cursor_;
///
+ bool multiparsel_cache_;
///
lyx::pit_type anchor_ref_;
///
int offset_ref_;
///
ViewMetricsInfo metrics(bool singlepar = false);
-
-
+ /// Working variable indicating a full screen refresh
+ mutable bool refresh_inside_;
+
};
#endif // BUFFERVIEW_PIMPL_H
+2006-03-10 Martin Vermeer <martin.vermeer@hut.fi>
+
+ * BufferView.[Ch]:
+ * BufferView_pimpl.[Ch]:
+ * LyXAction.C:
+ * debug.[Ch]:
+ * rowpainter.C:
+ * text3.C: Inside-inset speedup, esp. for the Mac (bug 2195)
+
2006-03-07 Georg Baum <Georg.Baum@post.rwth-aachen.de>
* pch.h: fix nullstream.hpp location for boost 1.33.0
{ LFUN_UNDERBAR, "accent-underbar", Noop },
{ LFUN_UNDERDOT, "accent-underdot", Noop },
{ LFUN_APPENDIX, "appendix", Noop },
- { LFUN_LEFTSEL, "backward-select", ReadOnly },
+ { LFUN_LEFTSEL, "backward-select", ReadOnly | SingleParUpdate },
{ LFUN_BOOKMARK_GOTO, "bookmark-goto", ReadOnly },
{ LFUN_BOOKMARK_SAVE, "bookmark-save", ReadOnly },
{ LFUN_BREAKLINE, "break-line", Noop },
{ LFUN_DEPTH_MIN, "depth-decrement", Noop },
{ LFUN_DEPTH_PLUS, "depth-increment", Noop },
{ LFUN_LDOTS, "dots-insert", Noop },
- { LFUN_DOWN, "down", ReadOnly | NoUpdate},
- { LFUN_DOWNSEL, "down-select", ReadOnly },
+ { LFUN_DOWN, "down", ReadOnly | NoUpdate },
+ { LFUN_DOWNSEL, "down-select", ReadOnly | SingleParUpdate },
{ LFUN_DROP_LAYOUTS_CHOICE, "drop-layouts-choice", ReadOnly },
{ LFUN_END_OF_SENTENCE, "end-of-sentence-period-insert", Noop },
{ LFUN_ENVIRONMENT_INSERT, "environment-insert", Noop },
{ LFUN_FONT_STATE, "font-state", ReadOnly },
{ LFUN_UNDERLINE, "font-underline", Noop },
{ LFUN_INSET_FOOTNOTE, "footnote-insert", Noop },
- { LFUN_RIGHTSEL, "forward-select", ReadOnly },
+ { LFUN_RIGHTSEL, "forward-select", ReadOnly | SingleParUpdate },
{ LFUN_HFILL, "hfill-insert", Noop },
{ LFUN_HELP_OPEN, "help-open", NoBuffer | Argument},
{ LFUN_HTMLURL, "html-insert", Noop },
{ LFUN_LAYOUT_PARAGRAPH, "layout-paragraph", ReadOnly },
{ LFUN_LAYOUT_TABULAR, "layout-tabular", Noop },
{ LFUN_HOME, "line-begin", ReadOnly | NoUpdate},
- { LFUN_HOMESEL, "line-begin-select", ReadOnly },
+ { LFUN_HOMESEL, "line-begin-select", ReadOnly | SingleParUpdate },
{ LFUN_DELETE_LINE_FORWARD, "line-delete-forward", Noop },
{ LFUN_END, "line-end", ReadOnly | NoUpdate},
- { LFUN_ENDSEL, "line-end-select", ReadOnly },
+ { LFUN_ENDSEL, "line-end-select", ReadOnly | SingleParUpdate },
#if 0
{ LFUN_INSET_LIST, "list-insert", Noop },
#endif
{ LFUN_TOGGLECURSORFOLLOW, "toggle-cursor-follows-scrollbar", ReadOnly },
{ LFUN_UNDO, "undo", Noop },
{ LFUN_UP, "up", ReadOnly | NoUpdate},
- { LFUN_UPSEL, "up-select", ReadOnly },
+ { LFUN_UPSEL, "up-select", ReadOnly | SingleParUpdate },
{ LFUN_URL, "url-insert", Noop },
{ LFUN_VC_CHECKIN, "vc-check-in", ReadOnly },
{ LFUN_VC_CHECKOUT, "vc-check-out", ReadOnly },
{ LFUN_VC_REVERT, "vc-revert", ReadOnly },
{ LFUN_VC_UNDO, "vc-undo-last", ReadOnly },
{ LFUN_WORDLEFT, "word-backward", ReadOnly | NoUpdate},
- { LFUN_WORDLEFTSEL, "word-backward-select", ReadOnly },
+ { LFUN_WORDLEFTSEL, "word-backward-select", ReadOnly | SingleParUpdate },
{ LFUN_CAPITALIZE_WORD, "word-capitalize", Noop },
{ LFUN_DELETE_WORD_BACKWARD, "word-delete-backward", Noop },
{ LFUN_DELETE_WORD_FORWARD, "word-delete-forward", Noop },
{ LFUN_WORDFINDBACKWARD, "word-find-backward", ReadOnly },
{ LFUN_WORDFINDFORWARD, "word-find-forward", ReadOnly },
{ LFUN_WORDRIGHT, "word-forward", ReadOnly | NoUpdate},
- { LFUN_WORDRIGHTSEL, "word-forward-select", ReadOnly },
+ { LFUN_WORDRIGHTSEL, "word-forward-select", ReadOnly | SingleParUpdate },
{ LFUN_LOWCASE_WORD, "word-lowcase", Noop },
{ LFUN_WORDSEL, "word-select", ReadOnly },
{ LFUN_UPCASE_WORD, "word-upcase", Noop },
{ LFUN_FINISHED_UP, "", ReadOnly },
{ LFUN_FINISHED_DOWN, "", ReadOnly },
{ LFUN_MOUSE_PRESS, "", ReadOnly },
- { LFUN_MOUSE_MOTION, "", ReadOnly },
+ { LFUN_MOUSE_MOTION, "", ReadOnly | SingleParUpdate },
{ LFUN_MOUSE_RELEASE, "", ReadOnly },
{ LFUN_MOUSE_DOUBLE, "", ReadOnly },
{ LFUN_MOUSE_TRIPLE, "", ReadOnly },
{ Debug::GRAPHICS, "graphics", N_("Graphics conversion and loading")},
{ Debug::CHANGES, "changes", N_("Change tracking")},
{ Debug::EXTERNAL, "external", N_("External template/inset messages")},
+ { Debug::PAINTING, "painting", N_("RowPainter profiling")},
{ Debug::DEBUG, "debug", N_("Developers' general debug messages")},
{ Debug::ANY, "any", N_("All debugging messages")}
};
///
EXTERNAL = (1 << 23),
///
+ PAINTING = (1 << 24),
+ ///
DEBUG = (1 << 31),
///
ANY = 0xffffffff
-2005-02-25 Martin Vermeer <martin.vermeer@hut.fi>
+2005-03-10 Martin Vermeer <martin.vermeer@hut.fi>
+
+ * insetcollapsable.C:
+ * insettext.[Ch]: Inside-inset speedup, esp. for the Mac (bug 2195)
+
2006-02-25 Georg Baum <Georg.Baum@post.rwth-aachen.de>
* insetert.[Ch] (read): new, force all paragraphs to latex_language
dim = dimensionCollapsed();
if (status() == Open) {
InsetText::metrics(mi, textdim_);
- openinlined_ = (textdim_.wid + dim.wid <= mi.base.textwidth);
+ openinlined_ = textdim_.wid + 2 * dim.wid <= mi.base.textwidth;
if (openinlined_) {
dim.wid += textdim_.wid;
dim.des = max(dim.des - textdim_.asc + dim.asc, textdim_.des);
button_dim.y2 = top + dimc.height();
pi.pain.buttonText(xx, top + dimc.asc, label, labelfont_);
+
if (status() == Open) {
int textx, texty;
if (openinlined_) {
// update our idea of where we are
setPosCache(pi, x, y);
+ text_.background_color_ = backgroundColor();
text_.draw(pi, x + border_, y);
if (drawFrame_) {
int const a = text_.ascent() + border_;
int const h = a + text_.descent() + border_;
int const ww = pi.base.bv->workWidth();
- if (w > ww - 40) {
+ if (w > ww - 40 || Wide()) {
pi.pain.line(0, y - a, ww, y - a, frameColor());
pi.pain.line(0, y - a + h, ww, y - a + h, frameColor());
} else {
void InsetText::drawSelection(PainterInfo & pi, int x, int y) const
{
- if (backgroundColor() != LColor::background) {
- // repaint the background if needed
- int const w = text_.width() + 2 * border_;
- int const a = text_.ascent() + border_;
- int const h = a + text_.descent() + border_;
- pi.pain.fillRectangle(x, y - a, w, h, backgroundColor());
- }
+ int const w = text_.width() + 2 * border_;
+ int const a = text_.ascent() + border_;
+ int const h = a + text_.descent() + border_;
+ int const ww = pi.base.bv->workWidth();
+ if (Wide())
+ pi.pain.fillRectangle(0, y - a, ww, h,
+ backgroundColor());
+ else
+ pi.pain.fillRectangle(x, y - a, w, h,
+ backgroundColor());
text_.drawSelection(pi, x, y);
}
bool neverIndent() const;
///
InsetText(InsetText const &);
-
+ ///
+ bool & Wide() const { return wide_inset_; }
+
protected:
///
virtual void doDispatch(LCursor & cur, FuncRequest & cmd);
mutable lyx::pit_type old_pit;
///
static int border_;
+ ///
+ mutable bool wide_inset_;
public:
///
mutable LyXText text_;
}
+bool isTrueTextInset(InsetBase * in)
+{
+ // Math and tabular insets have isTextInset = true, though they are
+ // not derived from InsetText. Paint them fully
+ return (in && in->isTextInset() && in->asMathInset() == 0
+ && in->lyxCode() != InsetBase::TABULAR_CODE);
+}
+
+
void RowPainter::paintInset(pos_type const pos, LyXFont const & font)
{
InsetBase const * inset = par_.getInset(pos);
pi.ltr_pos = (text_.bidi.level(pos) % 2 == 0);
pi.erased_ = erased_ || isDeletedText(par_, pos);
theCoords.insets().add(inset, int(x_), yo_);
- inset->drawSelection(pi, int(x_), yo_);
+ InsetBase * in = const_cast<InsetBase *>(inset);
+ // non-wide insets are painted completely. Recursive
+ bool tmp = bv_.repaintAll();
+ if (!isTrueTextInset(in) || !static_cast<InsetText*>(in)->Wide())
+ bv_.repaintAll(true);
+ if (bv_.repaintAll())
+ inset->drawSelection(pi, int(x_), yo_);
inset->draw(pi, int(x_), yo_);
+ bv_.repaintAll(tmp);
x_ += inset->width();
}
}
-lyx::size_type calculateRowSignature(Row const & row, Paragraph const & par)
+lyx::size_type calculateRowSignature(Row const & row, Paragraph const & par,
+ int x, int y)
{
boost::crc_32_type crc;
for (lyx::pos_type i = row.pos(); i < row.endpos(); ++i) {
const unsigned char b[] = { par.getChar(i) };
crc.process_bytes(b, 1);
}
+ const unsigned char b[] = { x, y, row.width() };
+ crc.process_bytes(b, 3);
return crc.checksum();
}
-bool isCursorOnRow(PainterInfo & pi, pit_type pit, RowList::const_iterator rit)
+bool CursorOnRow(PainterInfo & pi, pit_type const pit,
+ RowList::const_iterator rit, LyXText const & text)
{
+ // Is there a cursor on this row (or inside inset on row)
LCursor & cur = pi.base.bv->cursor();
- for (lyx::size_type d = 0; d < cur.depth(); d++)
- if (cur[d].pit() == pit
- && cur[d].pos() >= rit->pos()
- && cur[d].pos() <= rit->endpos())
+ for (lyx::size_type d = 0; d < cur.depth(); d++) {
+ CursorSlice const & sl = cur[d];
+ if (sl.text() == &text
+ && sl.pit() == pit
+ && sl.pos() >= rit->pos()
+ && sl.pos() < rit->endpos())
return true;
+ }
+ return false;
+}
+
+
+bool innerCursorOnRow(PainterInfo & pi, pit_type pit,
+ RowList::const_iterator rit, LyXText const & text)
+{
+ // Is there a cursor inside an inset on this row, and is this inset
+ // the only "character" on this row
+ LCursor & cur = pi.base.bv->cursor();
+ if (rit->pos() + 1 != rit->endpos())
+ return false;
+ for (lyx::size_type d = 0; d < cur.depth(); d++) {
+ CursorSlice const & sl = cur[d];
+ if (sl.text() == &text
+ && sl.pit() == pit
+ && sl.pos() == rit->pos())
+ return d < cur.depth() - 1;
+ }
return false;
}
lyx::size_type rowno(0);
for (RowList::const_iterator rit = rb; rit != re; ++rit, ++rowno) {
y += rit->ascent();
+ // Allow setting of bv->repaintAll() for nested insets in
+ // this row only
+ bool tmp = pi.base.bv->repaintAll();
// Row signature; has row changed since last paint?
- lyx::size_type const row_sig = calculateRowSignature(*rit, par);
-
- bool cursor_on_row = isCursorOnRow(pi, pit, rit);
+ lyx::size_type const row_sig = calculateRowSignature(*rit, par, x, y);
+ bool row_has_changed = par.rowSignature()[rowno] != row_sig;
- // If selection is on, the current row signature differs from
+ bool cursor_on_row = CursorOnRow(pi, pit, rit, text);
+ bool in_inset_alone_on_row = innerCursorOnRow(pi, pit, rit,
+ text);
+
+ // If this is the only object on the row, we can make it wide
+ for (pos_type i = rit->pos() ; i != rit->endpos(); ++i) {
+ InsetBase* in
+ = const_cast<InsetBase*>(par.getInset(i));
+ if (isTrueTextInset(in))
+ static_cast<InsetText*>(in)->Wide()
+ = in_inset_alone_on_row;
+ }
+
+ // If selection is on, the current row signature differs
// from cache, or cursor is inside an inset _on this row_,
// then paint the row
- if (repaintAll || par.rowSignature()[rowno] != row_sig
- || cursor_on_row) {
+ if (repaintAll || row_has_changed || cursor_on_row) {
// Add to row signature cache
par.rowSignature()[rowno] = row_sig;
RowPainter rp(inside ? pi : nullpi, text, pit, *rit, x, y);
// Clear background of this row
// (if paragraph background was not cleared)
- if (!repaintAll) {
- pi.pain.fillRectangle(x, y - rit->ascent(),
+ if (!repaintAll &&
+ (!in_inset_alone_on_row || row_has_changed)) {
+ pi.pain.fillRectangle(( rowno ? 0 : x - 10 ), y - rit->ascent(),
pi.base.bv->workWidth(), rit->height(),
text.backgroundColor());
+ // If outer row has changed, force nested
+ // insets to repaint completely
+ if (row_has_changed)
+ pi.base.bv->repaintAll(true);
}
// Instrumentation for testing row cache (see also
// 12 lines lower):
- //lyxerr << "#";
+ if (text.isMainText())
+ lyxerr[Debug::PAINTING] << "#";
+ else
+ lyxerr[Debug::PAINTING] << "[" <<
+ repaintAll << row_has_changed <<
+ cursor_on_row << "]";
rp.paintAppendix();
rp.paintDepthBar();
rp.paintChangeBar();
rp.paintText();
}
y += rit->descent();
+ // Restore, see above
+ pi.base.bv->repaintAll(tmp);
}
- //lyxerr << "." << endl;
+ lyxerr[Debug::PAINTING] << "." << endl;
}
} // namespace anon
bool const select = bv.cursor().selection();
PainterInfo pi(const_cast<BufferView *>(&bv), pain);
- if (select || !vi.singlepar) {
- // Clear background (Delegated to rows if no selection)
+ // Should the whole screen, including insets, be refreshed?
+ bool repaintAll(select || !vi.singlepar);
+
+ if (repaintAll) {
+ // Clear background (if not delegated to rows)
pain.fillRectangle(0, vi.y1, bv.workWidth(), vi.y2 - vi.y1,
text->backgroundColor());
}
int yy = vi.y1;
// draw contents
for (pit_type pit = vi.p1; pit <= vi.p2; ++pit) {
+ bv.repaintAll(repaintAll);
Paragraph const & par = text->getPar(pit);
yy += par.ascent();
- paintPar(pi, *bv.text(), pit, 0, yy, select || !vi.singlepar);
+ paintPar(pi, *bv.text(), pit, 0, yy, repaintAll);
yy += par.descent();
}
// lyxerr << " paintTextInset: y: " << y << endl;
y -= text.getPar(0).ascent();
+ // This flag can not be set from within same inset:
+ bool repaintAll = pi.base.bv->repaintAll();
for (int pit = 0; pit < int(text.paragraphs().size()); ++pit) {
y += text.getPar(pit).ascent();
- paintPar(pi, text, pit, x, y, true);
+ paintPar(pi, text, pit, x, y, repaintAll);
y += text.getPar(pit).descent();
}
}
case LFUN_DELETE:
if (!cur.selection()) {
+ if (cur.pos() == cur.paragraph().size())
+ // Par boundary, force full-screen update
+ singleParUpdate = false;
needsUpdate = Delete(cur);
cur.resetAnchor();
// It is possible to make it a lot faster still
// just comment out the line below...
} else {
cutSelection(cur, true, false);
+ singleParUpdate = false;
}
moveCursor(cur, false);
break;
case LFUN_BACKSPACE:
if (!cur.selection()) {
if (bv->owner()->getIntl().getTransManager().backspace()) {
+ // Par boundary, full-screen update
+ if (cur.pos() == 0)
+ singleParUpdate = false;
needsUpdate = backspace(cur);
cur.resetAnchor();
// It is possible to make it a lot faster still
}
} else {
cutSelection(cur, true, false);
+ singleParUpdate = false;
}
bv->switchKeyMap();
break;
if (singleParUpdate)
// Inserting characters does not change par height
- if (cur.bottom().paragraph().dim().height()
+ if (cur.bottom().paragraph().dim().height()
== olddim.height()) {
// if so, update _only_ this paragraph
- cur.bv().update(Update::SinglePar | Update::Force);
+ cur.bv().update(Update::SinglePar |
+ Update::FitCursor |
+ Update::MultiParSel);
+ cur.noUpdate();
+ return;
} else
needsUpdate = true;
if (!needsUpdate