mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-12 16:50:39 +00:00
Insert a real empty row before display math at start of paragraph
In LaTeX, when a displayed equation is at the start of a paragraph, there is an empty row in front of it. Up to now, this was mimicked in LyX by increasing the metrics on top of the inset. This commit creates a real empty row, accessible by the cursor. To make this work, many small unrelated changes are needed. * Introduce new AlwaysBreakBefore inset row flag that means "I want a break before myself, even if that means creating an empty row". * Let InsetMathHull use that for display math. * Remove the workaround that was added for InsetMathHull metrics. This means that MetricsInfo::vmode is not used anymore. I decided to keep it, since it may prove useful later. * Handle the flag in TextMetrics::breakParagraph. This requires to add a new flag 'ignore_contents' to TextMetrics::leftMargin, because we want the empty row to have a normal left indentation, not the one of display math (which is also at pos==0). * In the initial empty row, do not inherit from the centered alignment of the math inset, although both are at position 0. * Concerning cursor positioning with mouse, two methods need fixing: For the vertical part, handle in TextMetrics::getRowIndex the cursor boundary at position 0 when it is set. Basically, with cursor boundary true, the cursor will be in the empty row, whereas it will be in font of the math inset otherwise. For the horizontal part, handle empty row in TextMetrics::getPosNearX. Fixes bugs 11593 and 11093.
This commit is contained in:
parent
6727022b05
commit
33442b17ee
@ -105,6 +105,7 @@ public:
|
|||||||
/// The context to resolve macros
|
/// The context to resolve macros
|
||||||
MacroContext const & macrocontext;
|
MacroContext const & macrocontext;
|
||||||
/// Are we at the start of a paragraph (vertical mode)?
|
/// Are we at the start of a paragraph (vertical mode)?
|
||||||
|
/// This is not used anymore, but could be useful
|
||||||
bool vmode;
|
bool vmode;
|
||||||
/// if true, do not expand insets to max width artificially
|
/// if true, do not expand insets to max width artificially
|
||||||
bool tight_insets;
|
bool tight_insets;
|
||||||
|
@ -95,6 +95,10 @@ size_t ParagraphMetrics::getRowIndex(pos_type pos, bool boundary) const
|
|||||||
{
|
{
|
||||||
LBUFERR(!rows().empty());
|
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
|
// If boundary is set we should return the row on which
|
||||||
// the character before is inside.
|
// the character before is inside.
|
||||||
if (pos > 0 && boundary)
|
if (pos > 0 && boundary)
|
||||||
|
@ -27,30 +27,32 @@ enum RowFlags {
|
|||||||
// Do not break before or after this element, except if really
|
// Do not break before or after this element, except if really
|
||||||
// needed (between NoBreak* and CanBreak*).
|
// needed (between NoBreak* and CanBreak*).
|
||||||
Inline = 0,
|
Inline = 0,
|
||||||
|
// force (maybe empty) row before this element
|
||||||
|
AlwaysBreakBefore = 1 << 0,
|
||||||
// break row before this element if the row is not empty
|
// break row before this element if the row is not empty
|
||||||
BreakBefore = 1 << 0,
|
BreakBefore = 1 << 1,
|
||||||
// break row whenever needed before this element
|
// break row whenever needed before this element
|
||||||
CanBreakBefore = 1 << 1,
|
CanBreakBefore = 1 << 2,
|
||||||
// Avoid breaking row before this element
|
// Avoid breaking row before this element
|
||||||
NoBreakBefore = 1 << 2,
|
NoBreakBefore = 1 << 3,
|
||||||
// flush the row before this element (useful with BreakBefore)
|
// flush the row before this element (useful with BreakBefore)
|
||||||
FlushBefore = 1 << 3,
|
FlushBefore = 1 << 4,
|
||||||
// force new (maybe empty) row after this element
|
// force new (maybe empty) row after this element
|
||||||
AlwaysBreakAfter = 1 << 4,
|
AlwaysBreakAfter = 1 << 5,
|
||||||
// break row after this element if there are more elements
|
// break row after this element if there are more elements
|
||||||
BreakAfter = 1 << 5,
|
BreakAfter = 1 << 6,
|
||||||
// break row whenever needed after this element
|
// break row whenever needed after this element
|
||||||
CanBreakAfter = 1 << 6,
|
CanBreakAfter = 1 << 7,
|
||||||
// Avoid breaking row after this element
|
// 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)
|
// 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 the row that ends with this element
|
||||||
Flush = 1 << 9,
|
Flush = 1 << 10,
|
||||||
// specify an alignment (left, right) for a display element
|
// specify an alignment (left, right) for a display element
|
||||||
// (default is center)
|
// (default is center)
|
||||||
AlignLeft = 1 << 10,
|
AlignLeft = 1 << 11,
|
||||||
AlignRight = 1 << 11,
|
AlignRight = 1 << 12,
|
||||||
// A display element breaks row at both ends
|
// A display element breaks row at both ends
|
||||||
Display = FlushBefore | BreakBefore | BreakAfter,
|
Display = FlushBefore | BreakBefore | BreakAfter,
|
||||||
// Flags that concern breaking after element
|
// Flags that concern breaking after element
|
||||||
|
@ -706,7 +706,8 @@ LyXAlignment TextMetrics::getAlign(Paragraph const & par, Row const & row) const
|
|||||||
|
|
||||||
// Display-style insets should always be on a centered row
|
// Display-style insets should always be on a centered row
|
||||||
if (Inset const * inset = par.getInset(row.pos())) {
|
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)
|
if (inset->rowFlags() & AlignLeft)
|
||||||
align = LYX_ALIGN_LEFT;
|
align = LYX_ALIGN_LEFT;
|
||||||
else if (inset->rowFlags() & AlignRight)
|
else if (inset->rowFlags() & AlignRight)
|
||||||
@ -1155,7 +1156,7 @@ void cleanupRow(Row & row, bool at_end)
|
|||||||
// Implement the priorities described in RowFlags.h.
|
// Implement the priorities described in RowFlags.h.
|
||||||
bool needsRowBreak(int f1, int f2)
|
bool needsRowBreak(int f1, int f2)
|
||||||
{
|
{
|
||||||
if (f1 & AlwaysBreakAfter /*|| f2 & AlwaysBreakBefore*/)
|
if (f1 & AlwaysBreakAfter || f2 & AlwaysBreakBefore)
|
||||||
return true;
|
return true;
|
||||||
if (f1 & NoBreakAfter || f2 & NoBreakBefore)
|
if (f1 & NoBreakAfter || f2 & NoBreakBefore)
|
||||||
return false;
|
return false;
|
||||||
@ -1183,13 +1184,21 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const
|
|||||||
bool const row_empty = rows.empty() || rows.back().empty();
|
bool const row_empty = rows.empty() || rows.back().empty();
|
||||||
// The row flags of previous element, if there is one.
|
// The row flags of previous element, if there is one.
|
||||||
// Otherwise we use NoBreakAfter to avoid an empty row before
|
// 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;
|
int const f1 = row_empty ? NoBreakAfter : rows.back().back().row_flags;
|
||||||
// The row flags of next element, if there is one.
|
// The row flags of next element, if there is one.
|
||||||
// Otherwise we use NoBreakBefore (see above), unless the
|
// Otherwise we use NoBreakBefore (see above), unless the
|
||||||
// paragraph has an end label (for which an empty row is OK).
|
// paragraph has an end label (for which an empty row is OK).
|
||||||
int const f2 = (fcit == end) ? (end_label ? Inline : NoBreakBefore)
|
int const f2 = (fcit == end) ? (end_label ? Inline : NoBreakBefore)
|
||||||
: fcit->row_flags;
|
: 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() || needsRowBreak(f1, f2)) {
|
||||||
if (!rows.empty()) {
|
if (!rows.empty()) {
|
||||||
// Flush row as requested by row flags
|
// Flush row as requested by row flags
|
||||||
@ -1468,14 +1477,15 @@ pos_type TextMetrics::getPosNearX(Row const & row, int & x,
|
|||||||
boundary = true;
|
boundary = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (row.empty())
|
||||||
|
boundary = row.end_boundary();
|
||||||
/** This tests for the case where the cursor is set at the end
|
/** 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
|
* of a row which has been broken due something else than a
|
||||||
* separator (a display inset or a forced breaking of the
|
* separator (a display inset or a forced breaking of the
|
||||||
* row). We know that there is a separator when the end 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.
|
* row is larger than the end of its last element.
|
||||||
*/
|
*/
|
||||||
if (!row.empty() && pos == row.back().endpos
|
else if (pos == row.back().endpos && row.back().endpos == row.endpos()) {
|
||||||
&& row.back().endpos == row.endpos()) {
|
|
||||||
Inset const * inset = row.back().inset;
|
Inset const * inset = row.back().inset;
|
||||||
if (inset && (inset->lyxCode() == NEWLINE_CODE
|
if (inset && (inset->lyxCode() == NEWLINE_CODE
|
||||||
|| inset->lyxCode() == SEPARATOR_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();
|
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
|
// in some insets, paragraphs are never indented
|
||||||
&& !text_->inset().neverIndent()
|
&& !text_->inset().neverIndent()
|
||||||
// display style insets do not need indentation
|
// display style insets do not need indentation
|
||||||
&& !(!par.empty()
|
&& !(!ignore_contents
|
||||||
|
&& !par.empty()
|
||||||
&& par.isInset(0)
|
&& par.isInset(0)
|
||||||
&& par.getInset(0)->rowFlags() & Display)
|
&& par.getInset(0)->rowFlags() & Display)
|
||||||
&& (!(tclass.isDefaultLayout(par.layout())
|
&& (!(tclass.isDefaultLayout(par.layout())
|
||||||
|
@ -138,8 +138,10 @@ public:
|
|||||||
* This information cannot be taken from the layout object, because
|
* This information cannot be taken from the layout object, because
|
||||||
* in LaTeX the beginning of the text fits in some cases
|
* in LaTeX the beginning of the text fits in some cases
|
||||||
* (for example sections) exactly the label-width.
|
* (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.
|
/// Return the left beginning of a row which is not the first one.
|
||||||
/// This is the left margin when there is no indentation.
|
/// This is the left margin when there is no indentation.
|
||||||
int leftMargin(pit_type pit) const;
|
int leftMargin(pit_type pit) const;
|
||||||
|
@ -525,9 +525,6 @@ void InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const
|
|||||||
*/
|
*/
|
||||||
int const bottom_display_margin = mi.base.bv->zoomedPixels(6);
|
int const bottom_display_margin = mi.base.bv->zoomedPixels(6);
|
||||||
int top_display_margin = bottom_display_margin;
|
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);
|
int const ind = indent(*mi.base.bv);
|
||||||
mi.extrawidth = ind;
|
mi.extrawidth = ind;
|
||||||
@ -1029,9 +1026,9 @@ int InsetMathHull::rowFlags() const
|
|||||||
case hullMultline:
|
case hullMultline:
|
||||||
case hullGather:
|
case hullGather:
|
||||||
if (buffer().params().is_math_indent)
|
if (buffer().params().is_math_indent)
|
||||||
return Display | AlignLeft;
|
return AlwaysBreakBefore | Display | AlignLeft;
|
||||||
else
|
else
|
||||||
return Display;
|
return AlwaysBreakBefore | Display;
|
||||||
}
|
}
|
||||||
// avoid warning
|
// avoid warning
|
||||||
return Display;
|
return Display;
|
||||||
|
Loading…
Reference in New Issue
Block a user