X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FTextMetrics.cpp;h=f4241181c295e15f440d78a48f05dbf6d7621d5f;hb=4ed0312c51704780af1c452d3a82a84171b3725a;hp=d681a633560d8454f479b75c4dc34e45ae6e4953;hpb=4b69f5efa7825c3aa5464686f4ecaea212f73422;p=lyx.git diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index d681a63356..f4241181c2 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -35,6 +35,7 @@ #include "TextClass.h" #include "VSpace.h" +#include "insets/InsetSeparator.h" #include "insets/InsetText.h" #include "mathed/MacroTable.h" @@ -621,7 +622,7 @@ LyXAlignment TextMetrics::getAlign(Paragraph const & par, Row const & row) const if (Inset const * inset = par.getInset(row.pos())) { if (inset->rowFlags() & Display) { if (inset->rowFlags() & AlignLeft) - align = LYX_ALIGN_BLOCK; + align = LYX_ALIGN_LEFT; else if (inset->rowFlags() & AlignRight) align = LYX_ALIGN_RIGHT; else @@ -786,15 +787,6 @@ int TextMetrics::labelFill(Row const & row) const } -int TextMetrics::labelEnd(pit_type const pit) const -{ - // labelEnd is only needed if the layout fills a flushleft label. - if (text_->getPar(pit).layout().margintype != MARGIN_MANUAL) - return 0; - // return the beginning of the body - return leftMargin(pit); -} - namespace { /** @@ -901,16 +893,12 @@ Row TextMetrics::tokenizeParagraph(pit_type const pit) const Dimension dim = bv_->coordCache().insets().dim(ins); row.add(i, ins, dim, *fi, par.lookupChange(i)); } else if (c == ' ' && i + 1 == body_pos) { - // There is a space at i, but it should not be - // added as a separator, because it is just - // before body_pos. Instead, insert some spacing to - // align text + // This space is an \item separator. Represent it with a + // special space element, which dimension will be computed + // in breakRow. FontMetrics const & fm = theFontMetrics(text_->labelFont(par)); - // this is needed to make sure that the row width is correct - row.finalizeLast(); - int const add = max(fm.width(par.layout().labelsep), - labelEnd(pit) - row.width()); - row.addSpace(i, add, *fi, par.lookupChange(i)); + int const wid = fm.width(par.layout().labelsep); + row.addMarginSpace(i, wid, *fi, par.lookupChange(i)); } else if (c == '\t') row.addSpace(i, theFontMetrics(*fi).width(from_ascii(" ")), *fi, par.lookupChange(i)); @@ -920,7 +908,7 @@ Row TextMetrics::tokenizeParagraph(pit_type const pit) const * U+2029 PARAGRAPH SEPARATOR * These are special unicode characters that break - * lines/pragraphs. Not handling them lead to trouble wrt + * lines/pragraphs. Not handling them leads to trouble wrt * Qt QTextLayout formatting. We add a visible character * on screen so that the user can see that something is * happening. @@ -929,10 +917,10 @@ Row TextMetrics::tokenizeParagraph(pit_type const pit) const // ⤶ U+2936 ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS // ¶ U+00B6 PILCROW SIGN char_type const screen_char = (c == 0x2028) ? 0x2936 : 0x00B6; - row.add(i, screen_char, *fi, par.lookupChange(i), i >= body_pos); + row.add(i, screen_char, *fi, par.lookupChange(i)); } else // row elements before body are unbreakable - row.add(i, c, *fi, par.lookupChange(i), i >= body_pos); + row.add(i, c, *fi, par.lookupChange(i)); // add inline completion width // draw logically behind the previous character @@ -992,7 +980,7 @@ class flexible_const_iterator { public: // - flexible_const_iterator operator++() { + flexible_const_iterator & operator++() { if (pile_.empty()) ++cit_; else @@ -1050,6 +1038,7 @@ Row newRow(TextMetrics const & tm, pit_type pit, pos_type pos, bool is_rtl) nrow.pos(pos); nrow.left_margin = tm.leftMargin(pit, pos); nrow.right_margin = tm.rightMargin(pit); + nrow.setRTL(is_rtl); if (is_rtl) swap(nrow.left_margin, nrow.right_margin); // Remember that the row width takes into account the left_margin @@ -1059,21 +1048,21 @@ Row newRow(TextMetrics const & tm, pit_type pit, pos_type pos, bool is_rtl) } -void cleanupRow(Row & row, pos_type real_endpos, bool is_rtl) +void cleanupRow(Row & row, bool at_end) { if (row.empty()) { - row.endpos(0); + row.endpos(row.pos()); return; } row.endpos(row.back().endpos); // remove trailing spaces on row break - if (row.endpos() < real_endpos) + if (!at_end && !row.flushed()) row.back().rtrim(); // boundary exists when there was no space at the end of row - row.right_boundary(row.endpos() < real_endpos && row.back().endpos == row.endpos()); + row.end_boundary(!at_end && row.back().endpos == row.endpos()); // make sure that the RTL elements are in reverse ordering - row.reverseRTL(is_rtl); + row.reverseRTL(); } @@ -1098,6 +1087,8 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const RowList rows; bool const is_rtl = text_->isRTL(bigrow.pit()); bool const end_label = text_->getEndLabel(bigrow.pit()) != END_LABEL_NO_LABEL; + int const next_width = max_width_ - leftMargin(bigrow.pit(), bigrow.endpos()) + - rightMargin(bigrow.pit()); int width = 0; flexible_const_iterator fcit = flexible_begin(bigrow); @@ -1114,8 +1105,11 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const int const f2 = (fcit == end) ? (end_label ? Inline : NoBreakBefore) : fcit->row_flags; if (rows.empty() || needsRowBreak(f1, f2)) { - if (!rows.empty()) - cleanupRow(rows.back(), bigrow.endpos(), is_rtl); + if (!rows.empty()) { + // Flush row as requested by row flags + rows.back().flushed((f1 & Flush) || (f2 & FlushBefore)); + cleanupRow(rows.back(), false); + } pos_type pos = rows.empty() ? 0 : rows.back().endpos(); rows.push_back(newRow(*this, bigrow.pit(), pos, is_rtl)); // the width available for the row. @@ -1130,47 +1124,32 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const // Next element to consider is either the top of the temporary // pile, or the place when we were in main row Row::Element elt = *fcit; - Row::Element next_elt = elt.splitAt(width - rows.back().width(), - !elt.font.language()->wordWrap()); - if (elt.dim.wid > width - rows.back().width()) { - Row & rb = rows.back(); - rb.push_back(*fcit); - // if the row is too large, try to cut at last separator. In case - // of success, reset indication that the row was broken abruptly. - int const next_width = max_width_ - leftMargin(rb.pit(), rb.endpos()) - - rightMargin(rb.pit()); - - Row::Elements next_elts = rb.shortenIfNeeded(width, next_width); - - // Go to next element - ++fcit; - - // Handle later the elements returned by shortenIfNeeded. - if (!next_elts.empty()) { - rb.flushed(false); - fcit.put(next_elts); - } - } else { - // a new element in the row - rows.back().push_back(elt); - rows.back().finalizeLast(); - - // Go to next element - ++fcit; - - // Add a new next element on the pile - if (next_elt.isValid()) { - // do as if we inserted this element in the original row - if (!next_elt.str.empty()) - fcit.put(next_elt); - } + Row::Elements tail; + elt.splitAt(width - rows.back().width(), next_width, false, tail); + Row & rb = rows.back(); + if (elt.type == Row::MARGINSPACE) + elt.dim.wid = max(elt.dim.wid, leftMargin(bigrow.pit()) - rb.width()); + rb.push_back(elt); + rb.finalizeLast(); + if (rb.width() > width) { + // Keep the tail for later; this ought to be rare, but play safe. + if (!tail.empty()) + fcit.put(tail); + // if the row is too large, try to cut at last separator. + tail = rb.shortenIfNeeded(width, next_width); } + + // Go to next element + ++fcit; + + // Handle later the elements returned by splitAt or shortenIfNeeded. + fcit.put(tail); } if (!rows.empty()) { - cleanupRow(rows.back(), bigrow.endpos(), is_rtl); // Last row in paragraph is flushed rows.back().flushed(true); + cleanupRow(rows.back(), true); } return rows; @@ -1226,7 +1205,10 @@ int TextMetrics::parTopSpacing(pit_type const pit) const && prevpar.getLabelWidthString() == par.getLabelWidthString()) { layoutasc = layout.itemsep * dh; } else if (pit != 0 && layout.topsep > 0) - layoutasc = layout.topsep * dh; + // combine the separation between different layouts (with same depth) + layoutasc = max(0.0, + prevpar.getDepth() != par.getDepth() ? layout.topsep + : layout.topsep - prevpar.layout().bottomsep) * dh; asc += int(layoutasc * 2 / (2 + pars[pit].getDepth())); @@ -1389,7 +1371,7 @@ pos_type TextMetrics::getPosNearX(Row const & row, int & x, || inset->lyxCode() == SEPARATOR_CODE)) pos = row.back().pos; else - boundary = row.right_boundary(); + boundary = row.end_boundary(); } x += xo - offset; @@ -1811,11 +1793,13 @@ int TextMetrics::leftMargin(pit_type const pit, pos_type const pos) const } } - // This happens after sections or environments in standard classes. - // We have to check the previous layout at same depth. + // Check for reasons to remove indentation. + // First, at document level. if (buffer.params().paragraph_separation == BufferParams::ParagraphSkipSeparation) parindent.erase(); + // This happens after sections or environments in standard classes. + // We have to check the previous layout at same depth. else if (pit > 0 && pars[pit - 1].getDepth() >= par.getDepth()) { pit_type prev = text_->depthHook(pit, par.getDepth()); if (par.layout() == pars[prev].layout()) { @@ -1825,6 +1809,15 @@ int TextMetrics::leftMargin(pit_type const pit, pos_type const pos) const } else if (pars[prev].layout().nextnoindent) parindent.erase(); } + // The previous paragraph may have ended with a separator inset. + if (pit > 0) { + Paragraph const & ppar = pars[pit - 1]; + if (ppar.size() > 0) { + auto * in = dynamic_cast(ppar.getInset(ppar.size() - 1)); + if (in != nullptr && in->nextnoindent()) + parindent.erase(); + } + } FontInfo const labelfont = text_->labelFont(par); FontMetrics const & lfm = theFontMetrics(labelfont); @@ -2005,7 +1998,7 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const swap(pi.leftx, pi.rightx); BookmarksSection::BookmarkPosList bpl = - theSession().bookmarks().bookmarksInPar(bv_->buffer().fileName(), pm.par().id()); + theSession().bookmarks().bookmarksInPar(bv_->buffer().fileName(), pm.id()); for (size_t i = 0; i != nrows; ++i) { @@ -2063,9 +2056,9 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const // already cleared because of a full repaint. if (!pi.full_repaint && row.changed()) { LYXERR(Debug::PAINTING, "Clear rect@(" - << max(row_x, 0) << ", " << y - row.ascent() << ")=" + << x << ", " << y - row.ascent() << ")=" << width() << " x " << row.height()); - pi.pain.fillRectangle(row_x, y - row.ascent(), + pi.pain.fillRectangle(x, y - row.ascent(), width(), row.height(), pi.background_color); }