* Clean-up of drawing code
-The goal is to make painting with drawing disable fast enough that it
-can be used after every metrics computation. Then we can separate real
-drawing from metrics.
-
-Other changes are only clean-ups.
-
** When a paragraph ends with a newline, compute correctly the height of the extra row.
** Merging bv::updateMetrics and tm::metrics
+ transfer all the logic of bv::updateMetrics to tm.
+ Main InsetText should not be special.
-The difficuly for a tall table cell for example, is that it may be
+The difficulty for a tall table cell for example, is that it may be
necessary to break the whole contents to know the width of the cell.
existing metrics. Note that the Update::SinglePar flag is *never*
taken into account.
+If a computation of metrics has taken place, Force is removed from the
+flags and ForceDraw is added instead.
+
+It is OK to call processUptateFlags several times before an update. In
+this case, the effects are cumulative.processUpdateFlags execute the
+metrics-related actions, but defers the actual drawing to the next
+paint event.
+
The screen is drawn (with appropriate update strategy), except when
update flag is Update::None.
-** Metrics computation
+** Metrics computation (and nodraw drawing phase)
This is triggered by bv::updateMetrics, which calls tm::redoParagraph for
all visible paragraphs. Some Paragraphs above or below the screen (needed
of text insets, this will invoke recursively tm::metrics, which redoes
all the paragraphs of the inset.
+At the end of the function, bv::updatePosCache is called. It triggers
+a repaint of the document with a NullPainter (a painter that does
+nothing). This has the effect of caching all insets positions.
** Drawing the work area.
struct BufferView::Private
{
- Private(BufferView & bv) : update_strategy_(NoScreenUpdate),
+ Private(BufferView & bv) : update_strategy_(FullScreenUpdate),
+ update_flags_(Update::Force),
wh_(0), cursor_(bv),
anchor_pit_(0), anchor_ypos_(0),
inlineCompletionUniqueChars_(0),
///
ScreenUpdateStrategy update_strategy_;
///
+ Update::flags update_flags_;
+ ///
CoordCache coord_cache_;
/// Estimated average par height for scrollbar.
void BufferView::processUpdateFlags(Update::flags flags)
{
- // This is close to a hot-path.
- LYXERR(Debug::PAINTING, "BufferView::processUpdateFlags()"
- << "[fitcursor = " << (flags & Update::FitCursor)
- << ", forceupdate = " << (flags & Update::Force)
- << ", singlepar = " << (flags & Update::SinglePar)
- << "] buffer: " << &buffer_);
+ // The update flags are reset to None after the redraw is actually done
+ d->update_flags_ = d->update_flags_ | flags;
- // FIXME Does this really need doing here? It's done in updateBuffer, and
- // if the Buffer doesn't need updating, then do the macros?
- buffer_.updateMacros();
+ // This is close to a hot-path.
+ LYXERR(Debug::PAINTING, "BufferView::processUpdateFlags( "
+ << ((d->update_flags_ & Update::FitCursor) ? "fitcursor " : "")
+ << ((d->update_flags_ & Update::Force) ? "forceupdate " : "")
+ << ((d->update_flags_ & Update::ForceDraw) ? "forcedraw " : "")
+ << ((d->update_flags_ & Update::SinglePar) ? "singlepar " : "")
+ << ") buffer: " << &buffer_);
// Now do the first drawing step if needed. This consists on updating
// the CoordCache in updateMetrics().
// FIXME: is this still true now that Buffer::changed() is used all over?
// Case when no explicit update is requested.
- if (!flags) {
+ if (!d->update_flags_) {
// no need to redraw anything.
d->update_strategy_ = NoScreenUpdate;
return;
}
- if (flags == Update::Decoration) {
+ if (d->update_flags_ == Update::Decoration) {
d->update_strategy_ = DecorationUpdate;
buffer_.changed(false);
return;
}
- if (flags == Update::FitCursor
- || flags == (Update::Decoration | Update::FitCursor)) {
+ if (d->update_flags_ == Update::FitCursor
+ || d->update_flags_ == (Update::Decoration | Update::FitCursor)) {
// tell the frontend to update the screen if needed.
if (needsFitCursor()) {
showCursor();
return;
}
- if (flags & Update::Decoration) {
+ if (d->update_flags_ & Update::Decoration) {
d->update_strategy_ = DecorationUpdate;
buffer_.changed(false);
return;
return;
}
+ // We test against the flags parameter here to honor explicit metrics requests
bool const full_metrics = flags & Update::Force || !singleParUpdate();
if (full_metrics)
// We have to update the full screen metrics.
updateMetrics();
+ if (d->update_flags_ & Update::ForceDraw)
+ d->update_strategy_ = FullScreenUpdate;
- if (!(flags & Update::FitCursor)) {
- // Nothing to do anymore. Trigger a redraw and return
+ if (!(d->update_flags_ & Update::FitCursor)) {
+ // Nothing to do anymore. Trigger a redraw and return.
buffer_.changed(false);
return;
}
- // updateMetrics() does not update paragraph position
- // This is done at draw() time. So we need a redraw!
- buffer_.changed(false);
-
if (needsFitCursor()) {
// The cursor is off screen so ensure it is visible.
// refresh it:
}
updateHoveredInset();
+
+ // Trigger a redraw.
+ buffer_.changed(false);
}
<< " pit1 = " << pit1
<< " pit2 = " << pit2);
- d->update_strategy_ = FullScreenUpdate;
+ // It is not necessary anymore to compute metrics, but a redraw is needed
+ d->update_flags_ = (d->update_flags_ & ~Update::Force) | Update::ForceDraw;
// Now update the positions of insets in the cache.
updatePosCache();
LYXERR(Debug::PAINTING, "Found new anchor pit = " << d->anchor_pit_
<< " anchor ypos = " << d->anchor_ypos_);
+ if (!pain.isNull()) {
+ // reset the update flags, everything has been done
+ d->update_flags_ = Update::None;
+ }
+
// Remember what has just been done for the next draw() step
if (paint_caret)
d->caret_slice_ = d->cursor_.top();