]> git.lyx.org Git - lyx.git/blobdiff - src/TextMetrics.cpp
Maintain plain layout for separating paragraphs when switching layouts (#11936)
[lyx.git] / src / TextMetrics.cpp
index d908ef30aa2609e79905804535ec09d6c3e4d86b..88ea65541f044b596ff33fc63aa44020f4b7fd42 100644 (file)
@@ -185,6 +185,12 @@ ParagraphMetrics const & TextMetrics::parMetrics(pit_type pit) const
 }
 
 
+ParagraphMetrics & TextMetrics::parMetrics(pit_type pit)
+{
+       return parMetrics(pit, true);
+}
+
+
 void TextMetrics::newParMetricsDown()
 {
        pair<pit_type, ParagraphMetrics> const & last = *par_metrics_.rbegin();
@@ -557,28 +563,6 @@ bool TextMetrics::redoParagraph(pit_type const pit, bool const align_rows)
        if (row_index < pm.rows().size())
                pm.rows().resize(row_index);
 
-       // FIXME: It might be better to move this in another method
-       // specially tailored for the main text.
-       // Top and bottom margin of the document (only at top-level)
-       if (text_->isMainText()) {
-               // original value was 20px, which is 0.2in at 100dpi
-               int const margin = bv_->zoomedPixels(20);
-               if (pit == 0) {
-                       pm.rows().front().dim().asc += margin;
-                       /* coverity thinks that we should update pm.dim().asc
-                        * below, but all the rows heights are actually counted as
-                        * part of the paragraph metric descent see loop above).
-                        */
-                       // coverity[copy_paste_error]
-                       pm.dim().des += margin;
-               }
-               ParagraphList const & pars = text_->paragraphs();
-               if (pit + 1 == pit_type(pars.size())) {
-                       pm.rows().back().dim().des += margin;
-                       pm.dim().des += margin;
-               }
-       }
-
        // The space above and below the paragraph.
        int const top = parTopSpacing(pit);
        pm.rows().front().dim().asc += top;
@@ -589,6 +573,18 @@ bool TextMetrics::redoParagraph(pit_type const pit, bool const align_rows)
        pm.dim().asc += pm.rows()[0].ascent();
        pm.dim().des -= pm.rows()[0].ascent();
 
+       // 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();
+               }
+       }
+
        changed |= old_dim.height() != pm.dim().height();
 
        return changed;
@@ -622,19 +618,13 @@ LyXAlignment TextMetrics::getAlign(Paragraph const & par, Row const & row) const
 
        // Display-style insets should always be on a centered row
        if (Inset const * inset = par.getInset(row.pos())) {
-               switch (inset->display()) {
-               case Inset::AlignLeft:
-                       align = LYX_ALIGN_BLOCK;
-                       break;
-               case Inset::AlignCenter:
-                       align = LYX_ALIGN_CENTER;
-                       break;
-               case Inset::Inline:
-                       // unchanged (use align)
-                       break;
-               case Inset::AlignRight:
-                       align = LYX_ALIGN_RIGHT;
-                       break;
+               if (inset->rowFlags() & Inset::Display) {
+                       if (inset->rowFlags() & Inset::AlignLeft)
+                               align = LYX_ALIGN_BLOCK;
+                       else if (inset->rowFlags() & Inset::AlignRight)
+                               align = LYX_ALIGN_RIGHT;
+                       else
+                               align = LYX_ALIGN_CENTER;
                }
        }
 
@@ -976,23 +966,22 @@ bool TextMetrics::breakRow(Row & row, int const right_margin) const
                }
 
                // Handle some situations that abruptly terminate the row
-               // - A newline inset
-               // - Before a display inset
-               // - After a display inset
-               Inset const * inset = 0;
-               if (par.isNewline(i) || par.isEnvSeparator(i)
-                   || (i + 1 < end && (inset = par.getInset(i + 1))
-                       && inset->display())
-                   || (!row.empty() && row.back().inset
-                       && row.back().inset->display())) {
+               // - Before an inset with BreakBefore
+               // - After an inset with BreakAfter
+               Inset const * prevInset = !row.empty() ? row.back().inset : 0;
+               Inset const * nextInset = (i + 1 < end) ? par.getInset(i + 1) : 0;
+               if ((nextInset && nextInset->rowFlags() & Inset::BreakBefore)
+                   || (prevInset && prevInset->rowFlags() & Inset::BreakAfter)) {
                        row.flushed(true);
-                       // We will force a row creation after either
-                       // - a newline;
-                       // - a display inset followed by a end label.
-                       need_new_row =
-                               par.isNewline(i)
-                               || (inset && inset->display() && i + 1 == end
-                                   && text_->getEndLabel(row.pit()) != END_LABEL_NO_LABEL);
+                       // Force a row creation after this one if it is ended by
+                       // an inset that either
+                       // - has row flag RowAfter that enforces that;
+                       // - or (1) did force the row breaking, (2) is at end of
+                       //   paragraph and (3) the said paragraph has an end label.
+                       need_new_row = prevInset &&
+                               (prevInset->rowFlags() & Inset::RowAfter
+                                || (prevInset->rowFlags() & Inset::BreakAfter && i + 1 == end
+                                    && text_->getEndLabel(row.pit()) != END_LABEL_NO_LABEL));
                        ++i;
                        break;
                }
@@ -1156,6 +1145,14 @@ void TextMetrics::setRowHeight(Row & row) const
        int maxasc = int(fm.maxAscent() * spacing_val);
        int maxdes = int(fm.maxDescent() * spacing_val);
 
+       // Take label string into account (useful if labelfont is large)
+       if (row.pos() == 0 && layout.labelIsInline()) {
+               FontInfo const labelfont = text_->labelFont(par);
+               FontMetrics const & lfm = theFontMetrics(labelfont);
+               maxasc = max(maxasc, int(lfm.maxAscent() * spacing_val));
+               maxdes = max(maxdes, int(lfm.maxDescent() * spacing_val));
+       }
+
        // Find the ascent/descent of the row contents
        for (Row::Element const & e : row) {
                if (e.inset) {
@@ -1340,7 +1337,7 @@ Row const & TextMetrics::getPitAndRowNearY(int & y, pit_type & pit,
 {
        ParagraphMetrics const & pm = par_metrics_[pit];
 
-       int yy = pm.position() - pm.ascent();
+       int yy = pm.position() - pm.rows().front().ascent();
        LBUFERR(!pm.rows().empty());
        RowList::const_iterator rit = pm.rows().begin();
        RowList::const_iterator rlast = pm.rows().end();
@@ -1771,10 +1768,10 @@ int TextMetrics::leftMargin(pit_type const pit, pos_type const pos) const
            && !par.params().noindent()
            // in some insets, paragraphs are never indented
            && !text_->inset().neverIndent()
-           // display style insets are always centered, omit indentation
+           // display style insets do not need indentation
            && !(!par.empty()
                 && par.isInset(pos)
-                && par.getInset(pos)->display())
+                && par.getInset(pos)->rowFlags() & Inset::Display)
            && (!(tclass.isDefaultLayout(par.layout())
                || tclass.isPlainLayout(par.layout()))
                || buffer.params().paragraph_separation