X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FTextMetrics.cpp;h=0b3bfc1d16a79ce057eb979d2231dda30cfd9974;hb=dd1a85a2baf0aeb867a634ade47275b952d38354;hp=89e8699077734a3f66a7da24428354290b55b302;hpb=824d1c993a138d051c79149fc4b27e1c002736a4;p=lyx.git diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 89e8699077..0b3bfc1d16 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -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" @@ -557,28 +558,53 @@ bool TextMetrics::redoParagraph(pit_type const pit, bool const align_rows) if (row_index < pm.rows().size()) pm.rows().resize(row_index); - // The space above and below the paragraph. - int const top = parTopSpacing(pit); - pm.rows().front().dim().asc += top; - int const bottom = parBottomSpacing(pit); - pm.rows().back().dim().des += bottom; - pm.dim().des += top + bottom; + // This type of margin can only be handled at the global paragraph level + if (par.layout().margintype == MARGIN_RIGHT_ADDRESS_BOX) { + int offset = 0; + if (par.isRTL(buffer.params())) { + // globally align the paragraph to the left. + int minleft = max_width_; + for (Row const & row : pm.rows()) + minleft = min(minleft, row.left_margin); + offset = right_margin - minleft; + } else { + // globally align the paragraph to the right. + int maxwid = 0; + for (Row const & row : pm.rows()) + maxwid = max(maxwid, row.width()); + offset = max_width_ - right_margin - maxwid; + } - pm.dim().asc += pm.rows()[0].ascent(); - pm.dim().des -= pm.rows()[0].ascent(); + for (Row & row : pm.rows()) { + row.left_margin += offset; + row.dim().wid += offset; + } + } + + // The space above and below the paragraph. + int top = parTopSpacing(pit); + int bottom = parBottomSpacing(pit); // Top and bottom margin of the document (only at top-level) // FIXME: It might be better to move this in another method // specially tailored for the main text. if (text_->isMainText()) { if (pit == 0) - pm.dim().asc += bv_->topMargin(); - ParagraphList const & pars = text_->paragraphs(); - if (pit + 1 == pit_type(pars.size())) { - pm.dim().des += bv_->bottomMargin(); + top += bv_->topMargin(); + if (pit + 1 == pit_type(text_->paragraphs().size())) { + bottom += bv_->bottomMargin(); } } + // Add the top/bottom space to rows and paragraph metrics + pm.rows().front().dim().asc += top; + pm.rows().back().dim().des += bottom; + pm.dim().des += top + bottom; + + // Move the pm ascent to be the same as the first row ascent + pm.dim().asc += pm.rows().front().ascent(); + pm.dim().des -= pm.rows().front().ascent(); + changed |= old_dim.height() != pm.dim().height(); return changed; @@ -779,22 +805,6 @@ int TextMetrics::labelFill(Row const & row) const } -#if 0 -// Not used, see TextMetrics::breakRow -// this needs special handling - only newlines count as a break point -static pos_type addressBreakPoint(pos_type i, Paragraph const & par) -{ - pos_type const end = par.size(); - - for (; i < end; ++i) - if (par.isNewline(i)) - return i + 1; - - return end; -} -#endif - - int TextMetrics::labelEnd(pit_type const pit) const { // labelEnd is only needed if the layout fills a flushleft label. @@ -870,6 +880,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(); @@ -886,14 +900,6 @@ bool TextMetrics::breakRow(Row & row, int const right_margin) const // the width available for the row. int const width = max_width_ - row.right_margin; -#if 0 - //FIXME: As long as leftMargin() is not correctly implemented for - // MARGIN_RIGHT_ADDRESS_BOX, we should also not do this here. - // Otherwise, long rows will be painted off the screen. - if (par.layout().margintype == MARGIN_RIGHT_ADDRESS_BOX) - return addressBreakPoint(pos, par); -#endif - // check for possible inline completion DocIterator const & ic_it = bv_->inlineCompletionPos(); pos_type ic_pos = -1; @@ -904,7 +910,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)) { @@ -998,9 +1021,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); } @@ -1165,6 +1186,9 @@ void TextMetrics::setRowHeight(Row & row) const row.dim().asc = maxasc; row.dim().des = maxdes; + + // This is useful for selections + row.contents_dim() = row.dim(); } @@ -1331,7 +1355,7 @@ Row const & TextMetrics::getPitAndRowNearY(int & y, pit_type & pit, { ParagraphMetrics const & pm = par_metrics_[pit]; - int yy = pm.position() - pm.rows().front().ascent(); + int yy = pm.position() - pm.ascent(); LBUFERR(!pm.rows().empty()); RowList::const_iterator rit = pm.rows().begin(); RowList::const_iterator rlast = pm.rows().end(); @@ -1598,8 +1622,9 @@ void TextMetrics::deleteLineForward(Cursor & cur) int TextMetrics::leftMargin(pit_type pit) const { - // the + 1 is useful when the paragraph is empty - return leftMargin(pit, text_->paragraphs()[pit].size() + 1); + // FIXME: what is the semantics? It depends on whether the + // paragraph is empty! + return leftMargin(pit, text_->paragraphs()[pit].size()); } @@ -1612,7 +1637,7 @@ int TextMetrics::leftMargin(pit_type const pit, pos_type const pos) const Paragraph const & par = pars[pit]; LASSERT(pos >= 0, return 0); // We do not really care whether pos > par.size(), since we do not - // access the data. It can be actially useful, when querying the + // access the data. It can be actually useful, when querying the // margin without indentation (see leftMargin(pit_type). Buffer const & buffer = bv_->buffer(); @@ -1729,25 +1754,10 @@ int TextMetrics::leftMargin(pit_type const pit, pos_type const pos) const } break; - case MARGIN_RIGHT_ADDRESS_BOX: { -#if 0 - // The left margin depends on the widest row in this paragraph. - // This code is wrong because it depends on the rows, but at the - // same time this function is used in redoParagraph to construct - // the rows. - ParagraphMetrics const & pm = par_metrics_[pit]; - int minfill = max_width_; - for (row : pm.rows()) - if (row.fill() < minfill) - minfill = row.fill(); - l_margin += bfm.signedWidth(layout.leftmargin); - l_margin += minfill; -#endif - // also wrong, but much shorter. - l_margin += max_width_ / 2; + case MARGIN_RIGHT_ADDRESS_BOX: + // This is handled globally in redoParagraph(). break; } - } if (!par.params().leftIndent().zero()) l_margin += par.params().leftIndent().inPixels(max_width_, lfm.em()); @@ -1867,6 +1877,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]; @@ -1911,6 +1924,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; @@ -1953,8 +1969,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