]> git.lyx.org Git - lyx.git/blobdiff - src/BufferView.cpp
Russian layouttranslations reviewed by Yuriy, Dec 13 2017.
[lyx.git] / src / BufferView.cpp
index 70548ed391ff1bbb9bf52f79b38edbb74c209126..29bb53b8f7e71708a8c54211fda8b4f665256b77 100644 (file)
@@ -228,7 +228,8 @@ enum ScreenUpdateStrategy {
 
 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),
@@ -245,6 +246,8 @@ struct BufferView::Private
        ///
        ScreenUpdateStrategy update_strategy_;
        ///
+       Update::flags update_flags_;
+       ///
        CoordCache coord_cache_;
 
        /// Estimated average par height for scrollbar.
@@ -445,79 +448,85 @@ bool BufferView::needsFitCursor() const
 }
 
 
-void BufferView::processUpdateFlags(Update::flags flags)
+namespace {
+
+// this is for debugging only.
+string flagsAsString(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_);
+       if (flags == Update::None)
+               return "None ";
+       return string((flags & Update::FitCursor) ? "FitCursor " : "")
+               + ((flags & Update::Force) ? "Force " : "")
+               + ((flags & Update::ForceDraw) ? "ForceDraw " : "")
+               + ((flags & Update::SinglePar) ? "SinglePar " : "");
+}
 
-       // 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();
+}
 
-       // Now do the first drawing step if needed. This consists on updating
-       // the CoordCache in updateMetrics().
-       // The second drawing step is done in WorkArea::redraw() if needed.
-       // FIXME: is this still true now that Buffer::changed() is used all over?
+void BufferView::processUpdateFlags(Update::flags flags)
+{
+       LYXERR(Debug::PAINTING, "BufferView::processUpdateFlags( "
+                  << flagsAsString(flags) << ")  buffer: " << &buffer_);
 
        // Case when no explicit update is requested.
-       if (!flags) {
-               // no need to redraw anything.
-               d->update_strategy_ = NoScreenUpdate;
+       if (flags == Update::None)
                return;
-       }
 
-       if (flags == Update::Decoration) {
-               d->update_strategy_ = DecorationUpdate;
-               buffer_.changed(false);
-               return;
+       // SinglePar is ignored for now (this should probably change). We
+       // set it ourselves below, at the price of always rebreaking the
+       // paragraph at cursor. This can be expensive for large tables.
+       flags = flags & ~Update::SinglePar;
+
+       // First check whether the metrics and inset positions should be updated
+       if (flags & Update::Force) {
+               // This will update the CoordCache items and replace Force
+               // with ForceDraw in flags.
+               updateMetrics(flags);
        }
 
-       if (flags == Update::FitCursor
-               || flags == (Update::Decoration | Update::FitCursor)) {
-               // tell the frontend to update the screen if needed.
+       // Then make sure that the screen contains the cursor if needed
+       if (flags & Update::FitCursor) {
                if (needsFitCursor()) {
-                       showCursor();
-                       return;
-               }
-               if (flags & Update::Decoration) {
-                       d->update_strategy_ = DecorationUpdate;
-                       buffer_.changed(false);
-                       return;
+                       scrollToCursor(d->cursor_, false);
+                       // Metrics have to be recomputed (maybe again)
+                       updateMetrics(flags);
                }
-               // no screen update is needed in principle, but this
-               // could change if cursor row needs horizontal scrolling.
-               d->update_strategy_ = NoScreenUpdate;
-               buffer_.changed(false);
-               return;
+               flags = flags & ~Update::FitCursor;
        }
 
-       bool const full_metrics = flags & Update::Force || !singleParUpdate();
-
-       if (full_metrics)
-               // We have to update the full screen metrics.
-               updateMetrics();
-
-       if (!(flags & Update::FitCursor)) {
-               // Nothing to do anymore. Trigger a redraw and return
-               buffer_.changed(false);
-               return;
+       // Finally detect whether we can only repaint a single paragraph
+       if (!(flags & Update::ForceDraw)) {
+               if (singleParUpdate())
+                       flags = flags | Update::SinglePar;
+               else
+                       updateMetrics(flags);
        }
 
-       // updateMetrics() does not update paragraph position
-       // This is done at draw() time. So we need a redraw!
-       buffer_.changed(false);
+       // Add flags to the the update flags. These will be reset to None
+       // after the redraw is actually done
+       d->update_flags_ = d->update_flags_ | flags;
+       LYXERR(Debug::PAINTING, "Cumulative flags: " << flagsAsString(flags));
 
-       if (needsFitCursor()) {
-               // The cursor is off screen so ensure it is visible.
-               // refresh it:
-               showCursor();
+       // Now compute the update strategy
+       // Possibly values in flag are None, Decoration, ForceDraw
+       LATTEST((d->update_flags_ & ~(Update::None | Update::SinglePar
+                                     | Update::Decoration | Update::ForceDraw)) == 0);
+
+       if (d->update_flags_ & Update::ForceDraw)
+               d->update_strategy_ = FullScreenUpdate;
+       else if (d->update_flags_ & Update::Decoration)
+               d->update_strategy_ = DecorationUpdate;
+       else if (d->update_flags_ & Update::SinglePar)
+               d->update_strategy_ = SingleParUpdate;
+       else {
+               // no need to redraw anything.
+               d->update_strategy_ = NoScreenUpdate;
        }
 
        updateHoveredInset();
+
+       // Trigger a redraw.
+       buffer_.changed(false);
 }
 
 
@@ -632,8 +641,7 @@ void BufferView::scrollDocView(int const value, bool update)
        // If the offset is less than 2 screen height, prefer to scroll instead.
        if (abs(value) <= 2 * height_) {
                d->anchor_ypos_ -= value;
-               buffer_.changed(true);
-               updateHoveredInset();
+               processUpdateFlags(Update::Force);
                return;
        }
 
@@ -794,7 +802,7 @@ bool BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos,
                if (!dit.atEnd()) {
                        dit.pos() = min(dit.paragraph().size(), top_pos);
                        // Some slices of the iterator may not be
-                       // reachable (e.g. closed collapsable inset)
+                       // reachable (e.g. closed collapsible inset)
                        // so the dociterator may need to be
                        // shortened. Otherwise, setCursor may crash
                        // lyx when the cursor can not be set to these
@@ -830,12 +838,7 @@ bool BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos,
                d->cursor_.setCurrentFont();
                // Do not forget to reset the anchor (see #9912)
                d->cursor_.resetAnchor();
-               // To center the screen on this new position we need the
-               // paragraph position which is computed at draw() time.
-               // So we need a redraw!
-               buffer_.changed(false);
-               if (needsFitCursor())
-                       showCursor();
+               processUpdateFlags(Update::FitCursor);
        }
 
        return success;
@@ -877,19 +880,15 @@ void BufferView::showCursor()
 void BufferView::showCursor(DocIterator const & dit,
        bool recenter, bool update)
 {
-       if (scrollToCursor(dit, recenter) && update) {
-               buffer_.changed(true);
-               updateHoveredInset();
-       }
+       if (scrollToCursor(dit, recenter) && update)
+               processUpdateFlags(Update::Force);
 }
 
 
 void BufferView::scrollToCursor()
 {
-       if (scrollToCursor(d->cursor_, false)) {
-               buffer_.changed(true);
-               updateHoveredInset();
-       }
+       if (scrollToCursor(d->cursor_, false))
+               processUpdateFlags(Update::Force);
 }
 
 
@@ -1372,16 +1371,6 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                else
                        dr.screenUpdate(Update::Force | Update::FitCursor);
                dr.forceBufferUpdate();
-               // we only need to do this if we have deleted or restored a
-               // BiBTeX inset. but there is no other place to do it. one
-               // obvious idea is to try to do it in a copy constructor for
-               // InsetBibTeX, but when that is invoked, the buffer_ member
-               // is not yet set. another idea is to look at the InsetLists
-               // of the various paragraphs. but we'd have to recurse through
-               // the contained insets to make that work. it doesn't seem to
-               // be worth it, as this will not happen that often.
-               buffer().invalidateBibfileCache();
-               buffer().removeBiblioTempFiles();
                break;
 
        case LFUN_REDO:
@@ -1392,9 +1381,6 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                else
                        dr.screenUpdate(Update::Force | Update::FitCursor);
                dr.forceBufferUpdate();
-               // see above
-               buffer().invalidateBibfileCache();
-               buffer().removeBiblioTempFiles();
                break;
 
        case LFUN_FONT_STATE:
@@ -1647,10 +1633,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                InsetBibtex * inset = getInsetByCode<InsetBibtex>(tmpcur,
                                                BIBTEX_CODE);
                if (inset) {
-                       if (inset->addDatabase(cmd.argument())) {
-                               buffer_.invalidateBibfileCache();
+                       if (inset->addDatabase(cmd.argument()))
                                dr.forceBufferUpdate();
-                       }
                }
                break;
        }
@@ -1661,10 +1645,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                InsetBibtex * inset = getInsetByCode<InsetBibtex>(tmpcur,
                                                BIBTEX_CODE);
                if (inset) {
-                       if (inset->delDatabase(cmd.argument())) {
-                               buffer_.invalidateBibfileCache();
+                       if (inset->delDatabase(cmd.argument()))
                                dr.forceBufferUpdate();
-                       }
                }
                break;
        }
@@ -1728,8 +1710,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                bool const in_texted = cur.inTexted();
                cur.setCursor(doc_iterator_begin(cur.buffer()));
                cur.selHandle(false);
-               buffer_.changed(true);
-               updateHoveredInset();
+               // Force an immediate computation of metrics because we need it below
+               processUpdateFlags(Update::Force);
 
                d->text_metrics_[&buffer_.text()].editXY(cur, p.x_, p.y_,
                        true, act == LFUN_SCREEN_UP);
@@ -1763,8 +1745,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        if (scroll_value)
                                scroll(scroll_step * scroll_value);
                }
-               buffer_.changed(true);
-               updateHoveredInset();
+               dr.screenUpdate(Update::ForceDraw);
                dr.forceBufferUpdate();
                break;
        }
@@ -2630,12 +2611,6 @@ Cursor const & BufferView::cursor() const
 }
 
 
-pit_type BufferView::anchor_ref() const
-{
-       return d->anchor_pit_;
-}
-
-
 bool BufferView::singleParUpdate()
 {
        Text & buftext = buffer_.text();
@@ -2659,7 +2634,6 @@ bool BufferView::singleParUpdate()
                return false;
 
        tm.updatePosCache(bottom_pit);
-       d->update_strategy_ = SingleParUpdate;
 
        LYXERR(Debug::PAINTING, "\ny1: " << pm.position() - pm.ascent()
                << " y2: " << pm.position() + pm.descent()
@@ -2670,6 +2644,13 @@ bool BufferView::singleParUpdate()
 
 
 void BufferView::updateMetrics()
+{
+       updateMetrics(d->update_flags_);
+       d->update_strategy_ = FullScreenUpdate;
+}
+
+
+void BufferView::updateMetrics(Update::flags & update_flags)
 {
        if (height_ == 0 || width_ == 0)
                return;
@@ -2754,7 +2735,8 @@ void BufferView::updateMetrics()
                << " pit1 = " << pit1
                << " pit2 = " << pit2);
 
-       d->update_strategy_ = FullScreenUpdate;
+       // metrics is done, full drawing is necessary now
+       update_flags = (update_flags & ~Update::Force) | Update::ForceDraw;
 
        // Now update the positions of insets in the cache.
        updatePosCache();
@@ -2987,7 +2969,7 @@ namespace {
 bool sliceInRow(CursorSlice const & cs, Text const * text, Row const & row)
 {
        return !cs.empty() && cs.text() == text && cs.pit() == row.pit()
-               && row.pos() <= cs.pos() && cs.pos() <= row.endpos();
+               && row.pos() <= cs.pos() && cs.pos() < row.endpos();
 }
 
 }
@@ -3063,8 +3045,8 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret)
 {
        if (height_ == 0 || width_ == 0)
                return;
-       LYXERR(Debug::PAINTING, "\t\t*** START DRAWING ***");
-
+       LYXERR(Debug::PAINTING, (pain.isNull() ? "\t\t--- START NODRAW ---"
+                                : "\t\t*** START DRAWING ***"));
        Text & text = buffer_.text();
        TextMetrics const & tm = d->text_metrics_[&text];
        int const y = tm.first().second->position();
@@ -3143,7 +3125,8 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret)
                }
                break;
        }
-       LYXERR(Debug::PAINTING, "\n\t\t*** END DRAWING  ***");
+       LYXERR(Debug::PAINTING, (pain.isNull() ? "\t\t --- END NODRAW ---"
+                               : "\t\t *** END DRAWING ***"));
 
        // The scrollbar needs an update.
        updateScrollbar();
@@ -3154,18 +3137,27 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret)
        for (pit_type pit = firstpm.first; pit <= lastpm.first; ++pit) {
                ParagraphMetrics const & pm = tm.parMetrics(pit);
                if (pm.position() + pm.descent() > 0) {
+                       if (d->anchor_pit_ != pit
+                           || d->anchor_ypos_ != pm.position())
+                               LYXERR(Debug::PAINTING, "Found new anchor pit = " << d->anchor_pit_
+                                      << "  anchor ypos = " << d->anchor_ypos_);
                        d->anchor_pit_ = pit;
                        d->anchor_ypos_ = pm.position();
                        break;
                }
        }
-       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)
+       if (paint_caret) {
                d->caret_slice_ = d->cursor_.top();
-       else
+               if (d->cursor_.boundary()
+                   || d->cursor_.top().pos() == d->cursor_.top().lastpos())
+                       --d->caret_slice_.pos();
+       } else
                d->caret_slice_ = CursorSlice();
 }