]> git.lyx.org Git - features.git/blobdiff - src/TextMetrics.cpp
Fix for bug #11974
[features.git] / src / TextMetrics.cpp
index 6616956f4f58bac5493e780d01932b5dc89610c7..a2a3e4b4271e6afaa593f1d6cebc14a04769e1ec 100644 (file)
@@ -30,6 +30,7 @@
 #include "MetricsInfo.h"
 #include "ParagraphParameters.h"
 #include "RowPainter.h"
+#include "Session.h"
 #include "Text.h"
 #include "TextClass.h"
 #include "VSpace.h"
@@ -105,14 +106,9 @@ int numberOfHfills(Row const & row, ParagraphMetrics const & pm,
 
 
 TextMetrics::TextMetrics(BufferView * bv, Text * text)
-       : bv_(bv), text_(text)
-{
-       LBUFERR(bv_);
-       max_width_ = bv_->workWidth();
-       dim_.wid = max_width_;
-       dim_.asc = 10;
-       dim_.des = 10;
-}
+       : bv_(bv), text_(text), dim_(bv_->workWidth(), 10, 10),
+         max_width_(dim_.wid), tight_(false)
+{}
 
 
 bool TextMetrics::contains(pit_type pit) const
@@ -215,18 +211,18 @@ void TextMetrics::newParMetricsUp()
 }
 
 
-bool TextMetrics::metrics(MetricsInfo const & mi, Dimension & dim, int min_width,
-                         bool const expand_on_multipars)
+bool TextMetrics::metrics(MetricsInfo const & mi, Dimension & dim, int min_width)
 {
        LBUFERR(mi.base.textwidth > 0);
        max_width_ = mi.base.textwidth;
+       tight_ = mi.tight_insets;
        // backup old dimension.
        Dimension const old_dim = dim_;
        // reset dimension.
        dim_ = Dimension();
        dim_.wid = min_width;
        pit_type const npar = text_->paragraphs().size();
-       if (npar > 1 && expand_on_multipars)
+       if (npar > 1 && !tight_)
                // If there is more than one row, expand the text to
                // the full allowable width.
                dim_.wid = max_width_;
@@ -438,7 +434,7 @@ bool TextMetrics::redoParagraph(pit_type const pit, bool const align_rows)
        // environment? I think the answer is: when paragraphs are merged;
        // when layout is set; when material is pasted.
        if (par.brokenBiblio()) {
-               Cursor & cur = const_cast<Cursor &>(bv_->cursor());
+               Cursor & cur = bv_->cursor();
                // In some cases, we do not know how to record undo
                if (&cur.inset() == &text_->inset())
                        cur.recordUndo(pit, pit);
@@ -497,8 +493,9 @@ bool TextMetrics::redoParagraph(pit_type const pit, bool const align_rows)
                // substracted to the available width. The logic here is
                // almost the same as in breakRow, remember keep them in sync.
                int eop = 0;
-               if (lyxrc.paragraph_markers && e.pos + 1 == par.size()
-                   && size_type(pit + 1) < text_->paragraphs().size()) {
+               if (e.pos + 1 == par.size()
+                     && (lyxrc.paragraph_markers || par.lookupChange(par.size()).changed())
+                     && size_type(pit + 1) < text_->paragraphs().size()) {
                        Font f(text_->layoutFont(pit));
                        // ¶ U+00B6 PILCROW SIGN
                        eop = theFontMetrics(f).width(char_type(0x00B6));
@@ -511,7 +508,7 @@ bool TextMetrics::redoParagraph(pit_type const pit, bool const align_rows)
                Font const & font = e.inset->inheritFont() ?
                        displayFont(pit, e.pos) : bufferfont;
                MacroContext mc(&buffer, parPos);
-               MetricsInfo mi(bv_, font.fontInfo(), w, mc, e.pos == 0);
+               MetricsInfo mi(bv_, font.fontInfo(), w, mc, e.pos == 0, tight_);
                e.inset->metrics(mi, dim);
                if (!insetCache.has(e.inset) || insetCache.dim(e.inset) != dim) {
                        insetCache.add(e.inset, dim);
@@ -535,12 +532,12 @@ bool TextMetrics::redoParagraph(pit_type const pit, bool const align_rows)
                setRowHeight(row);
                row.changed(true);
                if ((row_index || row.endpos() < par.size() || row.right_boundary())
-                   && par.inInset().lyxCode() != CELL_CODE) {
+                   && !tight_) {
                        /* If there is more than one row or the row has been
                         * broken by a display inset or a newline, expand the text
                         * to the full allowable width. This setting here is
                         * needed for the setRowAlignment() below.
-                        * We do nothing when inside a table cell.
+                        * We do nothing when tight insets are requested.
                         */
                        if (dim_.wid < max_width_)
                                dim_.wid = max_width_;
@@ -703,7 +700,7 @@ void TextMetrics::setRowAlignment(Row & row, int width) const
        // We don't have to look at the alignment if the row is already
        // larger then the permitted width as then we force the
        // LEFT_ALIGN'edness!
-       if (int(row.width()) >= max_width_)
+       if (row.width() >= max_width_)
                return;
 
        if (nh == 0) {
@@ -879,6 +876,10 @@ bool TextMetrics::breakRow(Row & row, int const right_margin) const
 {
        LATTEST(row.empty());
        Paragraph const & par = text_->getPar(row.pit());
+       Buffer const & buf = text_->inset().buffer();
+       BookmarksSection::BookmarkPosList bpl =
+               theSession().bookmarks().bookmarksInPar(buf.fileName(), par.id());
+
        pos_type const end = par.size();
        pos_type const pos = row.pos();
        pos_type const body_pos = par.beginOfBody();
@@ -905,7 +906,24 @@ bool TextMetrics::breakRow(Row & row, int const right_margin) const
        // or the end of the par, then build a representation of the row.
        pos_type i = pos;
        FontIterator fi = FontIterator(*this, par, row.pit(), pos);
-       while (i < end && (i == pos || row.width() <= width)) {
+       // The real stopping condition is a few lines below.
+       while (true) {
+               // Firstly, check whether there is a bookmark here.
+               if (lyxrc.bookmarks_visibility == LyXRC::BMK_INLINE)
+                       for (auto const & bp_p : bpl)
+                               if (bp_p.second == i) {
+                                       Font f = *fi;
+                                       f.fontInfo().setColor(Color_bookmark);
+                                       // ❶ U+2776 DINGBAT NEGATIVE CIRCLED DIGIT ONE
+                                       char_type const ch = 0x2775 + bp_p.first;
+                                       row.addVirtual(i, docstring(1, ch), f, Change());
+                               }
+
+               // The stopping condition is here so that the display of a
+               // bookmark can take place at paragraph start too.
+               if (i >= end || (i != pos && row.width() > width))
+                       break;
+
                char_type c = par.getChar(i);
                // The most special cases are handled first.
                if (par.isInset(i)) {
@@ -999,9 +1017,7 @@ bool TextMetrics::breakRow(Row & row, int const right_margin) const
                // in the paragraph.
                Font f(text_->layoutFont(row.pit()));
                f.fontInfo().setColor(Color_paragraphmarker);
-               BufferParams const & bparams
-                       = text_->inset().buffer().params();
-               f.setLanguage(par.getParLanguage(bparams));
+               f.setLanguage(par.getParLanguage(buf.params()));
                // ¶ U+00B6 PILCROW SIGN
                row.addVirtual(end, docstring(1, char_type(0x00B6)), f, change);
        }
@@ -1284,7 +1300,7 @@ pit_type TextMetrics::getPitNearY(int y)
 
        ParagraphMetrics const & pm = it->second;
 
-       if (y < it->second.position() - int(pm.ascent())) {
+       if (y < it->second.position() - pm.ascent()) {
                // We are looking for a position that is before the first paragraph in
                // the cache (which is in priciple off-screen, that is before the
                // visible part.
@@ -1299,7 +1315,7 @@ pit_type TextMetrics::getPitNearY(int y)
 
        ParagraphMetrics const & pm_last = par_metrics_[last->first];
 
-       if (y >= last->second.position() + int(pm_last.descent())) {
+       if (y >= last->second.position() + pm_last.descent()) {
                // We are looking for a position that is after the last paragraph in
                // the cache (which is in priciple off-screen), that is before the
                // visible part.
@@ -1318,7 +1334,7 @@ pit_type TextMetrics::getPitNearY(int y)
 
                ParagraphMetrics const & pm2 = par_metrics_[it->first];
 
-               if (it->first >= pit && int(it->second.position()) - int(pm2.ascent()) <= y) {
+               if (it->first >= pit && it->second.position() - pm2.ascent() <= y) {
                        pit = it->first;
                        yy = it->second.position();
                }
@@ -1445,7 +1461,7 @@ void TextMetrics::setCursorFromCoordinates(Cursor & cur, int const x, int const
        LBUFERR(pm.rows().size());
        for (; r < int(pm.rows().size()) - 1; ++r) {
                Row const & row = pm.rows()[r];
-               if (int(yy + row.height()) > y)
+               if (yy + row.height() > y)
                        break;
                yy += row.height();
        }
@@ -1857,6 +1873,9 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
        if (text_->isRTL(pit))
                swap(pi.leftx, pi.rightx);
 
+       BookmarksSection::BookmarkPosList bpl =
+               theSession().bookmarks().bookmarksInPar(bv_->buffer().fileName(), pm.par().id());
+
        for (size_t i = 0; i != nrows; ++i) {
 
                Row const & row = pm.rows()[i];
@@ -1901,6 +1920,9 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
                        // Paint only the insets if the text itself is
                        // unchanged.
                        rp.paintOnlyInsets();
+                       rp.paintTooLargeMarks(
+                               row_x + row.left_x() < bv_->leftMargin(),
+                               row_x + row.right_x() > bv_->workWidth() - bv_->rightMargin());
                        row.changed(false);
                        y += row.descent();
                        continue;
@@ -1943,8 +1965,15 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
                if (i == nrows - 1)
                        rp.paintLast();
                rp.paintText();
-               rp.paintTooLargeMarks(row_x + row.left_x() < 0,
-                                     row_x + row.right_x() > bv_->workWidth());
+               rp.paintTooLargeMarks(
+                       row_x + row.left_x() < bv_->leftMargin(),
+                       row_x + row.right_x() > bv_->workWidth() - bv_->rightMargin());
+               // indicate bookmarks presence in margin
+               if (lyxrc.bookmarks_visibility == LyXRC::BMK_MARGIN)
+                       for (auto const & bp_p : bpl)
+                               if (bp_p.second >= row.pos() && bp_p.second < row.endpos())
+                                       rp.paintBookmark(bp_p.first);
+
                y += row.descent();
 
 #if 0