diff --git a/src/MetricsInfo.h b/src/MetricsInfo.h index 48d313ba71..3732e17481 100644 --- a/src/MetricsInfo.h +++ b/src/MetricsInfo.h @@ -105,6 +105,7 @@ public: /// The context to resolve macros MacroContext const & macrocontext; /// Are we at the start of a paragraph (vertical mode)? + /// This is not used anymore, but could be useful bool vmode; /// if true, do not expand insets to max width artificially bool tight_insets; diff --git a/src/ParagraphMetrics.cpp b/src/ParagraphMetrics.cpp index 470c765350..b6058a897e 100644 --- a/src/ParagraphMetrics.cpp +++ b/src/ParagraphMetrics.cpp @@ -95,6 +95,10 @@ size_t ParagraphMetrics::getRowIndex(pos_type pos, bool boundary) const { LBUFERR(!rows().empty()); + // This makes a difference when the first row is empty (e.g. before display math) + if (pos == 0 && boundary) + return 0; + // If boundary is set we should return the row on which // the character before is inside. if (pos > 0 && boundary) diff --git a/src/RowFlags.h b/src/RowFlags.h index 953d7f92ee..ccc7f5b46c 100644 --- a/src/RowFlags.h +++ b/src/RowFlags.h @@ -27,30 +27,32 @@ enum RowFlags { // Do not break before or after this element, except if really // needed (between NoBreak* and CanBreak*). Inline = 0, + // force (maybe empty) row before this element + AlwaysBreakBefore = 1 << 0, // break row before this element if the row is not empty - BreakBefore = 1 << 0, + BreakBefore = 1 << 1, // break row whenever needed before this element - CanBreakBefore = 1 << 1, + CanBreakBefore = 1 << 2, // Avoid breaking row before this element - NoBreakBefore = 1 << 2, + NoBreakBefore = 1 << 3, // flush the row before this element (useful with BreakBefore) - FlushBefore = 1 << 3, + FlushBefore = 1 << 4, // force new (maybe empty) row after this element - AlwaysBreakAfter = 1 << 4, + AlwaysBreakAfter = 1 << 5, // break row after this element if there are more elements - BreakAfter = 1 << 5, + BreakAfter = 1 << 6, // break row whenever needed after this element - CanBreakAfter = 1 << 6, + CanBreakAfter = 1 << 7, // Avoid breaking row after this element - NoBreakAfter = 1 << 7, + NoBreakAfter = 1 << 8, // The contents of the row may be broken in two (e.g. string) - CanBreakInside = 1 << 8, + CanBreakInside = 1 << 9, // Flush the row that ends with this element - Flush = 1 << 9, + Flush = 1 << 10, // specify an alignment (left, right) for a display element // (default is center) - AlignLeft = 1 << 10, - AlignRight = 1 << 11, + AlignLeft = 1 << 11, + AlignRight = 1 << 12, // A display element breaks row at both ends Display = FlushBefore | BreakBefore | BreakAfter, // Flags that concern breaking after element diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index c5f2bf498a..84e43c1d7d 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -706,7 +706,8 @@ 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())) { - if (inset->rowFlags() & Display) { + // If we are in empty row, alignment of inset does not apply (it is in next row) + if (!row.empty() && inset->rowFlags() & Display) { if (inset->rowFlags() & AlignLeft) align = LYX_ALIGN_LEFT; else if (inset->rowFlags() & AlignRight) @@ -1155,7 +1156,7 @@ void cleanupRow(Row & row, bool at_end) // Implement the priorities described in RowFlags.h. bool needsRowBreak(int f1, int f2) { - if (f1 & AlwaysBreakAfter /*|| f2 & AlwaysBreakBefore*/) + if (f1 & AlwaysBreakAfter || f2 & AlwaysBreakBefore) return true; if (f1 & NoBreakAfter || f2 & NoBreakBefore) return false; @@ -1183,13 +1184,21 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const bool const row_empty = rows.empty() || rows.back().empty(); // The row flags of previous element, if there is one. // Otherwise we use NoBreakAfter to avoid an empty row before - // e.g. a displayed equation. + // e.g. a displayed inset. int const f1 = row_empty ? NoBreakAfter : rows.back().back().row_flags; // The row flags of next element, if there is one. // Otherwise we use NoBreakBefore (see above), unless the // paragraph has an end label (for which an empty row is OK). int const f2 = (fcit == end) ? (end_label ? Inline : NoBreakBefore) : fcit->row_flags; + if (rows.empty() && needsRowBreak(f1, f2)) { + // Create an empty row before element + rows.push_back(newRow(*this, bigrow.pit(), 0, is_rtl)); + Row & newrow = rows.back(); + cleanupRow(newrow, false); + newrow.end_boundary(true); + newrow.left_margin = leftMargin(newrow.pit(), 0, true); + } if (rows.empty() || needsRowBreak(f1, f2)) { if (!rows.empty()) { // Flush row as requested by row flags @@ -1468,14 +1477,15 @@ pos_type TextMetrics::getPosNearX(Row const & row, int & x, boundary = true; } + if (row.empty()) + boundary = row.end_boundary(); /** This tests for the case where the cursor is set at the end * of a row which has been broken due something else than a * separator (a display inset or a forced breaking of the * row). We know that there is a separator when the end of the * row is larger than the end of its last element. */ - if (!row.empty() && pos == row.back().endpos - && row.back().endpos == row.endpos()) { + else if (pos == row.back().endpos && row.back().endpos == row.endpos()) { Inset const * inset = row.back().inset; if (inset && (inset->lyxCode() == NEWLINE_CODE || inset->lyxCode() == SEPARATOR_CODE)) @@ -1838,7 +1848,7 @@ int TextMetrics::leftMargin(pit_type pit) const } -int TextMetrics::leftMargin(pit_type const pit, pos_type const pos) const +int TextMetrics::leftMargin(pit_type const pit, pos_type const pos, bool ignore_contents) const { ParagraphList const & pars = text_->paragraphs(); @@ -1998,7 +2008,8 @@ int TextMetrics::leftMargin(pit_type const pit, pos_type const pos) const // in some insets, paragraphs are never indented && !text_->inset().neverIndent() // display style insets do not need indentation - && !(!par.empty() + && !(!ignore_contents + && !par.empty() && par.isInset(0) && par.getInset(0)->rowFlags() & Display) && (!(tclass.isDefaultLayout(par.layout()) diff --git a/src/TextMetrics.h b/src/TextMetrics.h index d5606b610a..02b27cf067 100644 --- a/src/TextMetrics.h +++ b/src/TextMetrics.h @@ -138,8 +138,10 @@ public: * This information cannot be taken from the layout object, because * in LaTeX the beginning of the text fits in some cases * (for example sections) exactly the label-width. + * When \c ignore_contents is true, alignment properties related + * to insets in paragraph are not taken into account. */ - int leftMargin(pit_type pit, pos_type pos) const; + int leftMargin(pit_type pit, pos_type pos, bool ignore_contents = false) const; /// Return the left beginning of a row which is not the first one. /// This is the left margin when there is no indentation. int leftMargin(pit_type pit) const; diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp index de20771e38..32a0d81bf0 100644 --- a/src/mathed/InsetMathHull.cpp +++ b/src/mathed/InsetMathHull.cpp @@ -525,9 +525,6 @@ void InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const */ int const bottom_display_margin = mi.base.bv->zoomedPixels(6); int top_display_margin = bottom_display_margin; - // at start of paragraph, add an empty line - if (mi.vmode) - top_display_margin += theFontMetrics(mi.base.font).maxHeight() + 2; int const ind = indent(*mi.base.bv); mi.extrawidth = ind; @@ -1029,9 +1026,9 @@ int InsetMathHull::rowFlags() const case hullMultline: case hullGather: if (buffer().params().is_math_indent) - return Display | AlignLeft; + return AlwaysBreakBefore | Display | AlignLeft; else - return Display; + return AlwaysBreakBefore | Display; } // avoid warning return Display;