]> git.lyx.org Git - lyx.git/blobdiff - src/BufferView.cpp
Introduce new helpers ParagraphMetrics::top/bottom
[lyx.git] / src / BufferView.cpp
index 913c4598d37937ad00e8d82cc1d312a320522b6a..dd312739b519bd8e2c3be69ad0b9a8fec48fed00 100644 (file)
@@ -283,11 +283,11 @@ struct BufferView::Private
        ///
        map<string, Inset *> edited_insets_;
 
-       /// When the row where the cursor lies is scrolled, this
-       /// contains the scroll offset
        // cache for id of the paragraph which was edited the last time
        int bookmark_edit_position_;
 
+       /// When the row where the cursor lies is scrolled, this
+       /// contains the scroll offset
        int horiz_scroll_offset_;
        /// a slice pointing to the start of the row where the cursor
        /// is (at last draw time)
@@ -337,6 +337,14 @@ BufferView::~BufferView()
 }
 
 
+void BufferView::copySettingsFrom(BufferView const & bv)
+{
+       setCursor(bv.cursor());
+       d->anchor_pit_ = bv.d->anchor_pit_;
+       d->anchor_ypos_ = bv.d->anchor_ypos_;
+}
+
+
 int BufferView::defaultMargin() const
 {
        // The value used to be hardcoded to 10
@@ -435,6 +443,12 @@ CoordCache const & BufferView::coordCache() const
 }
 
 
+bool BufferView::hasMathRow(MathData const * cell) const
+{
+       return d->math_rows_.find(cell) != d->math_rows_.end();
+}
+
+
 MathRow const & BufferView::mathRow(MathData const * cell) const
 {
        auto it = d->math_rows_.find(cell);
@@ -605,7 +619,7 @@ void BufferView::updateScrollbarParameters()
        Text & t = buffer_.text();
        TextMetrics & tm = d->text_metrics_[&t];
 
-       LYXERR(Debug::GUI, " Updating scrollbar: height: "
+       LYXERR(Debug::SCROLLING, " Updating scrollbar: height: "
                << t.paragraphs().size()
                << " curr par: " << d->cursor_.bottom().pit()
                << " default height " << defaultRowHeight());
@@ -627,8 +641,8 @@ void BufferView::updateScrollbarParameters()
                        << d->par_height_[pit]);
        }
 
-       int top_pos = first.second->position() - first.second->ascent();
-       int bottom_pos = last.second->position() + last.second->descent();
+       int top_pos = first.second->top();
+       int bottom_pos = last.second->bottom();
        bool first_visible = first.first == 0 && top_pos >= 0;
        bool last_visible = last.first + 1 == int(parsize) && bottom_pos <= height_;
        if (first_visible && last_visible) {
@@ -1077,6 +1091,13 @@ bool BufferView::scrollToCursor(DocIterator const & dit, ScrollType how)
        d->anchor_ypos_ = - offset + row_dim.ascent();
        if (how == SCROLL_CENTER)
                d->anchor_ypos_ += height_/2 - row_dim.height() / 2;
+       else if (!lyxrc.scroll_below_document && d->anchor_pit_ == max_pit)
+               d->anchor_ypos_ = height_ - offset - row_dim.descent();
+       else if (offset > height_)
+               d->anchor_ypos_ = height_ - offset - defaultRowHeight();
+       else
+               d->anchor_ypos_ = defaultRowHeight() * 2;
+
        return d->anchor_ypos_ != old_ypos || d->anchor_pit_ != old_pit;
 }
 
@@ -1759,6 +1780,10 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
        }
 
        case LFUN_INDEX_TAG_ALL: {
+               if (cur.pos() == 0)
+                       // nothing precedes
+                       break;
+
                Inset * ins = cur.nextInset();
                if (!ins || ins->lyxCode() != INDEX_CODE)
                        // not at index inset
@@ -1795,6 +1820,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                // Get word or selection
                cur.text()->selectWord(cur, WHOLE_WORD);
                docstring const searched_string = cur.selectionAsString(false);
+               if (searched_string.empty())
+                       break;
                // Start from the beginning
                lyx::dispatch(FuncRequest(LFUN_BUFFER_BEGIN));
                while (findOne(this, searched_string,
@@ -2638,7 +2665,7 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
        // Put anchor at the same position.
        cur.resetAnchor();
 
-       cur.beginUndoGroup();
+       old.beginUndoGroup();
 
        // Try to dispatch to an non-editable inset near this position
        // via the temp cursor. If the inset wishes to change the real
@@ -2660,7 +2687,7 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
                        cursor().fixIfBroken();
        }
 
-       cur.endUndoGroup();
+       old.endUndoGroup();
 
        // Do we have a selection?
        theSelection().haveSelection(cursor().selection());
@@ -2699,7 +2726,7 @@ int BufferView::scrollDown(int pixels)
        int const ymax = height_ + pixels;
        while (true) {
                pair<pit_type, ParagraphMetrics const *> last = tm.last();
-               int bottom_pos = last.second->position() + last.second->descent();
+               int bottom_pos = last.second->bottom();
                if (lyxrc.scroll_below_document)
                        bottom_pos += height_ - minVisiblePart();
                if (last.first + 1 == int(text->paragraphs().size())) {
@@ -2724,7 +2751,7 @@ int BufferView::scrollUp(int pixels)
        int ymin = - pixels;
        while (true) {
                pair<pit_type, ParagraphMetrics const *> first = tm.first();
-               int top_pos = first.second->position() - first.second->ascent();
+               int top_pos = first.second->top();
                if (first.first == 0) {
                        if (top_pos >= 0)
                                return 0;
@@ -2966,6 +2993,25 @@ void BufferView::putSelectionAt(DocIterator const & cur,
 }
 
 
+void BufferView::setSelection(DocIterator const & from,
+                             DocIterator const & to)
+{
+       if (from.pit() != to.pit()) {
+               // there are multiple paragraphs in selection
+               cursor().setCursor(from);
+               cursor().clearSelection();
+               cursor().selection(true);
+               cursor().setCursor(to);
+               cursor().selection(true);
+       } else {
+               // only single paragraph
+               int const size = to.pos() - from.pos();
+               putSelectionAt(from, size, false);
+       }
+       processUpdateFlags(Update::Force | Update::FitCursor);
+}
+
+
 bool BufferView::selectIfEmpty(DocIterator & cur)
 {
        if ((cur.inTexted() && !cur.paragraph().empty())
@@ -3017,24 +3063,36 @@ Cursor const & BufferView::cursor() const
 
 bool BufferView::singleParUpdate()
 {
-       Text & buftext = buffer_.text();
-       pit_type const bottom_pit = d->cursor_.bottom().pit();
-       TextMetrics & tm = textMetrics(&buftext);
-       Dimension const old_dim = tm.parMetrics(bottom_pit).dim();
+       CursorSlice const & its = d->cursor_.innerTextSlice();
+       pit_type const pit = its.pit();
+       TextMetrics & tm = textMetrics(its.text());
+       Dimension const old_dim = tm.parMetrics(pit).dim();
 
        // make sure inline completion pointer is ok
        if (d->inlineCompletionPos_.fixIfBroken())
                d->inlineCompletionPos_ = DocIterator();
 
-       // In Single Paragraph mode, rebreak only
-       // the (main text, not inset!) paragraph containing the cursor.
-       // (if this paragraph contains insets etc., rebreaking will
-       // recursively descend)
-       tm.redoParagraph(bottom_pit);
-       ParagraphMetrics & pm = tm.parMetrics(bottom_pit);
-       if (pm.height() != old_dim.height()) {
-               // Paragraph height has changed so we cannot proceed to
-               // the singlePar optimisation.
+       /* Try to rebreak only the paragraph containing the cursor (if
+        * this paragraph contains insets etc., rebreaking will
+        * recursively descend). We need a full redraw if either
+        * 1/ the height has changed
+        * or
+        * 2/ the width has changed and it was equal to the textmetrics
+        *    width; the goal is to catch the case of a one-row inset that
+        *    grows with its contents, but optimize the case of typing at
+        *    the end of a mmultiple-row paragraph.
+        *
+        * NOTE: if only the height has changed, then it should be
+        *   possible to update all metrics at minimal cost. However,
+        *   since this is risky, we do not try that right now.
+        */
+       tm.redoParagraph(pit);
+       ParagraphMetrics & pm = tm.parMetrics(pit);
+       if (pm.height() != old_dim.height()
+               || (pm.width() != old_dim.width() && old_dim.width() == tm.width())) {
+               // Paragraph height or width has changed so we cannot proceed
+               // to the singlePar optimisation.
+               LYXERR(Debug::PAINTING, "SinglePar optimization failed.");
                return false;
        }
        // Since position() points to the baseline of the first row, we
@@ -3042,12 +3100,10 @@ bool BufferView::singleParUpdate()
        // the height does not change but the ascent does.
        pm.setPosition(pm.position() - old_dim.ascent() + pm.ascent());
 
-       tm.updatePosCache(bottom_pit);
+       tm.updatePosCache(pit);
 
-       LYXERR(Debug::PAINTING, "\ny1: " << pm.position() - pm.ascent()
-               << " y2: " << pm.position() + pm.descent()
-               << " pit: " << bottom_pit
-               << " singlepar: 1");
+       LYXERR(Debug::PAINTING, "\ny1: " << pm.top() << " y2: " << pm.bottom()
+               << " pit: " << pit << " singlepar: 1");
        return true;
 }
 
@@ -3103,7 +3159,6 @@ void BufferView::updateMetrics(Update::flags & update_flags)
                }
        }
        anchor_pm.setPosition(d->anchor_ypos_);
-       tm.updatePosCache(d->anchor_pit_);
 
        LYXERR(Debug::PAINTING, "metrics: "
                << " anchor pit = " << d->anchor_pit_
@@ -3119,7 +3174,6 @@ void BufferView::updateMetrics(Update::flags & update_flags)
                y1 -= pm.descent();
                // Save the paragraph position in the cache.
                pm.setPosition(y1);
-               tm.updatePosCache(pit1);
                y1 -= pm.ascent();
        }
 
@@ -3133,7 +3187,6 @@ void BufferView::updateMetrics(Update::flags & update_flags)
                y2 += pm.ascent();
                // Save the paragraph position in the cache.
                pm.setPosition(y2);
-               tm.updatePosCache(pit2);
                y2 += pm.descent();
        }
 
@@ -3310,7 +3363,7 @@ bool BufferView::paragraphVisible(DocIterator const & dit) const
 void BufferView::caretPosAndDim(Point & p, Dimension & dim) const
 {
        Cursor const & cur = cursor();
-       if (cur.inMathed()) {
+       if (cur.inMathed() && hasMathRow(&cur.cell())) {
                MathRow const & mrow = mathRow(&cur.cell());
                dim = mrow.caret_dim;
        } else {
@@ -3598,7 +3651,7 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret)
 
                // and possibly grey out below
                pair<pit_type, ParagraphMetrics const *> lastpm = tm.last();
-               int const y2 = lastpm.second->position() + lastpm.second->descent();
+               int const y2 = lastpm.second->bottom();
 
                if (y2 < height_) {
                        Color color = buffer().isInternal()
@@ -3619,7 +3672,7 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret)
        pair<pit_type, ParagraphMetrics const *> lastpm = tm.last();
        for (pit_type pit = firstpm.first; pit <= lastpm.first; ++pit) {
                ParagraphMetrics const & pm = tm.parMetrics(pit);
-               if (pm.position() + pm.descent() > 0) {
+               if (pm.bottom() > 0) {
                        if (d->anchor_pit_ != pit
                            || d->anchor_ypos_ != pm.position())
                                LYXERR(Debug::PAINTING, "Found new anchor pit = " << d->anchor_pit_