]> git.lyx.org Git - lyx.git/blobdiff - src/BufferView.cpp
Center correctly top labels like Abstract.
[lyx.git] / src / BufferView.cpp
index 3c7940a049d9065eb1bf9a2f6fd28c71f2700250..e316aab02e2d38319d2d5dd6df5d7cabb106a90d 100644 (file)
@@ -35,7 +35,6 @@
 #include "Language.h"
 #include "LaTeXFeatures.h"
 #include "LayoutFile.h"
-#include "Length.h"
 #include "Lexer.h"
 #include "LyX.h"
 #include "LyXAction.h"
@@ -81,6 +80,7 @@
 #include "support/filetools.h"
 #include "support/gettext.h"
 #include "support/lassert.h"
+#include "support/Length.h"
 #include "support/lstrings.h"
 #include "support/lyxlib.h"
 #include "support/Package.h"
@@ -596,25 +596,29 @@ void BufferView::updateScrollbar()
        }
 
        // Look at paragraph heights on-screen
-       for (pit_type pit = tm.firstPit(); pit <= tm.lastPit(); ++pit) {
+       pair<pit_type, ParagraphMetrics const *> first = tm.first();
+       pair<pit_type, ParagraphMetrics const *> last = tm.last();
+       for (pit_type pit = first.first; pit <= last.first; ++pit) {
                d->par_height_[pit] = tm.parMetrics(pit).height();
                LYXERR(Debug::SCROLLING, "storing height for pit " << pit << " : "
                        << d->par_height_[pit]);
        }
 
-       bool first_visible = tm.firstPit() == 0 && tm.topPosition() >= 0;
-       bool last_visible = tm.lastPit() + 1 == int(parsize) && tm.bottomPosition() <= height_;
+       int top_pos = first.second->position() - first.second->ascent();
+       int bottom_pos = last.second->position() + last.second->descent();
+       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) {
                d->scrollbarParameters_.min = 0;
                d->scrollbarParameters_.max = 0;
                return;
        }
 
-       d->scrollbarParameters_.min = tm.topPosition();
-       for (size_t i = 0; i != size_t(tm.firstPit()); ++i)
+       d->scrollbarParameters_.min = top_pos;
+       for (size_t i = 0; i != size_t(first.first); ++i)
                d->scrollbarParameters_.min -= d->par_height_[i];
-       d->scrollbarParameters_.max = tm.bottomPosition();
-       for (size_t i = tm.lastPit() + 1; i != parsize; ++i)
+       d->scrollbarParameters_.max = bottom_pos;
+       for (size_t i = last.first + 1; i != parsize; ++i)
                d->scrollbarParameters_.max += d->par_height_[i];
 
        // The reference is the top position so we remove one page.
@@ -951,9 +955,9 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter)
                bot_pit = max_pit;
        }
 
-       if (bot_pit == tm.firstPit() - 1)
+       if (bot_pit == tm.first().first - 1)
                tm.newParMetricsUp();
-       else if (bot_pit == tm.lastPit() + 1)
+       else if (bot_pit == tm.last().first + 1)
                tm.newParMetricsDown();
 
        if (tm.contains(bot_pit)) {
@@ -963,7 +967,8 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter)
                CursorSlice const & cs = dit.innerTextSlice();
                int offset = coordOffset(dit).y_;
                int ypos = pm.position() + offset;
-               Row const & row = pm.getRow(cs.pos(), dit.boundary());
+               Dimension const & row_dim =
+                       pm.getRow(cs.pos(), dit.boundary()).dim();
                int scrolled = 0;
                if (recenter)
                        scrolled = scroll(ypos - height_/2);
@@ -972,7 +977,7 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter)
                // the screen height, we scroll to a heuristic value of height_ / 4.
                // FIXME: This heuristic value should be replaced by a recursive search
                // for a row in the inset that can be visualized completely.
-               else if (row.height() > height_) {
+               else if (row_dim.height() > height_) {
                        if (ypos < defaultRowHeight())
                                scrolled = scroll(ypos - height_ / 4);
                        else if (ypos > height_ - defaultRowHeight())
@@ -981,14 +986,14 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter)
 
                // If the top part of the row falls of the screen, we scroll
                // up to align the top of the row with the top of the screen.
-               else if (ypos - row.totalAscent() < 0 && ypos < height_) {
-                       int ynew = row.totalAscent();
+               else if (ypos - row_dim.ascent() < 0 && ypos < height_) {
+                       int ynew = row_dim.ascent();
                        scrolled = scrollUp(ynew - ypos);
                }
 
                // If the bottom of the row falls of the screen, we scroll down.
-               else if (ypos + row.totalDescent() > height_ && ypos > 0) {
-                       int ynew = height_ - row.totalDescent();
+               else if (ypos + row_dim.descent() > height_ && ypos > 0) {
+                       int ynew = height_ - row_dim.descent();
                        scrolled = scrollDown(ypos - ynew);
                }
 
@@ -1006,14 +1011,15 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter)
 
        d->anchor_pit_ = bot_pit;
        CursorSlice const & cs = dit.innerTextSlice();
-       Row const & row = pm.getRow(cs.pos(), dit.boundary());
+       Dimension const & row_dim =
+               pm.getRow(cs.pos(), dit.boundary()).dim();
 
        if (recenter)
                d->anchor_ypos_ = height_/2;
        else if (d->anchor_pit_ == 0)
                d->anchor_ypos_ = offset + pm.ascent();
        else if (d->anchor_pit_ == max_pit)
-               d->anchor_ypos_ = height_ - offset - row.totalDescent();
+               d->anchor_ypos_ = height_ - offset - row_dim.descent();
        else if (offset > height_)
                d->anchor_ypos_ = height_ - offset - defaultRowHeight();
        else
@@ -2449,10 +2455,11 @@ int BufferView::scrollDown(int offset)
        TextMetrics & tm = d->text_metrics_[text];
        int const ymax = height_ + offset;
        while (true) {
-               int bottom_pos = tm.bottomPosition();
+               pair<pit_type, ParagraphMetrics const *> last = tm.last();
+               int bottom_pos = last.second->position() + last.second->descent();
                if (lyxrc.scroll_below_document)
                        bottom_pos += height_ - minVisiblePart();
-               if (tm.lastPit() + 1 == int(text->paragraphs().size())) {
+               if (last.first + 1 == int(text->paragraphs().size())) {
                        if (bottom_pos <= height_)
                                return 0;
                        offset = min(offset, bottom_pos - height_);
@@ -2473,8 +2480,9 @@ int BufferView::scrollUp(int offset)
        TextMetrics & tm = d->text_metrics_[text];
        int ymin = - offset;
        while (true) {
-               int const top_pos = tm.topPosition();
-               if (tm.firstPit() == 0) {
+               pair<pit_type, ParagraphMetrics const *> first = tm.first();
+               int top_pos = first.second->position() - first.second->ascent();
+               if (first.first == 0) {
                        if (top_pos >= 0)
                                return 0;
                        offset = min(offset, - top_pos);
@@ -2769,7 +2777,7 @@ bool BufferView::singleParUpdate()
        Text & buftext = buffer_.text();
        pit_type const bottom_pit = d->cursor_.bottom().pit();
        TextMetrics & tm = textMetrics(&buftext);
-       int old_height = tm.parMetrics(bottom_pit).height();
+       Dimension const old_dim = tm.parMetrics(bottom_pit).dim();
 
        // make sure inline completion pointer is ok
        if (d->inlineCompletionPos_.fixIfBroken())
@@ -2780,11 +2788,16 @@ bool BufferView::singleParUpdate()
        // (if this paragraph contains insets etc., rebreaking will
        // recursively descend)
        tm.redoParagraph(bottom_pit);
-       ParagraphMetrics const & pm = tm.parMetrics(bottom_pit);
-       if (pm.height() != old_height)
+       ParagraphMetrics & pm = tm.parMetrics(bottom_pit);
+       if (pm.height() != old_dim.height()) {
                // Paragraph height has changed so we cannot proceed to
                // the singlePar optimisation.
                return false;
+       }
+       // Since position() points to the baseline of the first row, we
+       // may have to update it. See ticket #11601 for an example where
+       // the height does not change but the ascent does.
+       pm.setPosition(pm.position() - old_dim.ascent() + pm.ascent());
 
        tm.updatePosCache(bottom_pit);
 
@@ -2832,7 +2845,7 @@ void BufferView::updateMetrics(Update::flags & update_flags)
 
        // Rebreak anchor paragraph.
        tm.redoParagraph(d->anchor_pit_);
-       ParagraphMetrics & anchor_pm = tm.par_metrics_[d->anchor_pit_];
+       ParagraphMetrics & anchor_pm = tm.parMetrics(d->anchor_pit_);
 
        // position anchor
        if (d->anchor_pit_ == 0) {
@@ -2859,7 +2872,7 @@ void BufferView::updateMetrics(Update::flags & update_flags)
        pit_type pit1 = d->anchor_pit_ - 1;
        for (; pit1 >= 0 && y1 >= 0; --pit1) {
                tm.redoParagraph(pit1);
-               ParagraphMetrics & pm = tm.par_metrics_[pit1];
+               ParagraphMetrics & pm = tm.parMetrics(pit1);
                y1 -= pm.descent();
                // Save the paragraph position in the cache.
                pm.setPosition(y1);
@@ -2873,7 +2886,7 @@ void BufferView::updateMetrics(Update::flags & update_flags)
        pit_type pit2 = d->anchor_pit_ + 1;
        for (; pit2 < npit && y2 <= height_; ++pit2) {
                tm.redoParagraph(pit2);
-               ParagraphMetrics & pm = tm.par_metrics_[pit2];
+               ParagraphMetrics & pm = tm.parMetrics(pit2);
                y2 += pm.ascent();
                // Save the paragraph position in the cache.
                pm.setPosition(y2);
@@ -2989,7 +3002,7 @@ Point BufferView::coordOffset(DocIterator const & dit) const
        ParagraphMetrics const & pm = tm.parMetrics(sl.pit());
 
        LBUFERR(!pm.rows().empty());
-       y -= pm.rows()[0].totalAscent();
+       y -= pm.rows()[0].ascent();
 #if 1
        // FIXME: document this mess
        size_t rend;
@@ -3006,7 +3019,7 @@ Point BufferView::coordOffset(DocIterator const & dit) const
 #endif
        for (size_t rit = 0; rit != rend; ++rit)
                y += pm.rows()[rit].height();
-       y += pm.rows()[rend].totalAscent();
+       y += pm.rows()[rend].ascent();
 
        TextMetrics const & bottom_tm = textMetrics(dit.bottom().text());
 
@@ -3195,7 +3208,7 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret)
                                 : "\t\t*** START DRAWING ***"));
        Text & text = buffer_.text();
        TextMetrics const & tm = d->text_metrics_[&text];
-       int const y = tm.parMetrics(tm.firstPit()).position();
+       int const y = tm.first().second->position();
        PainterInfo pi(this, pain);
 
        // Check whether the row where the cursor lives needs to be scrolled.
@@ -3250,7 +3263,8 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret)
                tm.draw(pi, 0, y);
 
                // and possibly grey out below
-               int const y2 = tm.bottomPosition();
+               pair<pit_type, ParagraphMetrics const *> lastpm = tm.last();
+               int const y2 = lastpm.second->position() + lastpm.second->descent();
 
                if (y2 < height_) {
                        Color color = buffer().isInternal()
@@ -3266,7 +3280,9 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret)
        updateScrollbar();
 
        // Normalize anchor for next time
-       for (pit_type pit = tm.firstPit(); pit <= tm.lastPit(); ++pit) {
+       pair<pit_type, ParagraphMetrics const *> firstpm = tm.first();
+       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 (d->anchor_pit_ != pit