From 361bd53bc36da61c6abfc2e0b7b7c7294800bbd9 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Mon, 30 May 2016 10:33:35 +0200 Subject: [PATCH 1/7] Introduce the notion of math class This done according to the TeXbook. This class replaces the individual isMathXXX() methods. The mathClass() method (currently unused) is provided for the following insets: * InsetMathChar (with a revised list of affected characters) * InsetMathSymbol: the class is given by the `extra' field Operators defined in lib/symbols (e.g. \log) are MC_OP * InsetMathFrac is MC_INNER (except nicefrac and units) * InsetDelimiters is MC_INNER * InsetStackrel is MC_REL * The class of InsetScript is the class of the last element of its nucleus (yes, it is a hack, but doing it right is more work). Remove the explicit spacing that was done in the different insets. The spacing will be reintroduced properly in a forthcoming commit. --- src/Makefile.am | 4 +- src/mathed/InsetMath.cpp | 6 +++ src/mathed/InsetMath.h | 11 ++--- src/mathed/InsetMathChar.cpp | 29 +++++------ src/mathed/InsetMathChar.h | 6 +-- src/mathed/InsetMathDelim.cpp | 9 ++-- src/mathed/InsetMathDelim.h | 2 + src/mathed/InsetMathFrac.cpp | 25 ++++++++++ src/mathed/InsetMathFrac.h | 4 ++ src/mathed/InsetMathHull.cpp | 2 +- src/mathed/InsetMathScript.cpp | 13 +++++ src/mathed/InsetMathScript.h | 2 + src/mathed/InsetMathStackrel.cpp | 7 +++ src/mathed/InsetMathStackrel.h | 4 +- src/mathed/InsetMathSymbol.cpp | 29 ++++------- src/mathed/InsetMathSymbol.h | 6 +-- src/mathed/MathClass.cpp | 82 ++++++++++++++++++++++++++++++++ src/mathed/MathClass.h | 64 +++++++++++++++++++++++++ src/mathed/MathSupport.cpp | 11 ----- 19 files changed, 245 insertions(+), 71 deletions(-) create mode 100644 src/mathed/MathClass.cpp create mode 100644 src/mathed/MathClass.h diff --git a/src/Makefile.am b/src/Makefile.am index f3dd870077..fc135af00e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -447,14 +447,15 @@ SOURCEFILESMATHED = \ mathed/InsetMathXArrow.cpp \ mathed/InsetMathXYMatrix.cpp \ mathed/InsetMathDiagram.cpp \ + mathed/MacroTable.cpp \ mathed/MathAtom.cpp \ mathed/MathAutoCorrect.cpp \ + mathed/MathClass.cpp \ mathed/MathData.cpp \ mathed/MathExtern.cpp \ mathed/MathFactory.cpp \ mathed/MathMacro.cpp \ mathed/MathMacroArgument.cpp \ - mathed/MacroTable.cpp \ mathed/MathMacroTemplate.cpp \ mathed/MathParser.cpp \ mathed/MathStream.cpp \ @@ -518,6 +519,7 @@ HEADERFILESMATHED = \ mathed/InsetMathDiagram.h \ mathed/MathAtom.h \ mathed/MathAutoCorrect.h \ + mathed/MathClass.h \ mathed/MathData.h \ mathed/MathCompletionList.h \ mathed/MathExtern.h \ diff --git a/src/mathed/InsetMath.cpp b/src/mathed/InsetMath.cpp index 2fb1ff5a55..aec53d0518 100644 --- a/src/mathed/InsetMath.cpp +++ b/src/mathed/InsetMath.cpp @@ -49,6 +49,12 @@ MathData const & InsetMath::cell(idx_type) const } +MathClass InsetMath::mathClass() const +{ + return MC_ORD; +} + + void InsetMath::dump() const { lyxerr << "---------------------------------------------" << endl; diff --git a/src/mathed/InsetMath.h b/src/mathed/InsetMath.h index da84af1010..e791099b72 100644 --- a/src/mathed/InsetMath.h +++ b/src/mathed/InsetMath.h @@ -13,6 +13,8 @@ #ifndef MATH_INSET_H #define MATH_INSET_H +#include "MathClass.h" + #include "insets/Inset.h" @@ -160,14 +162,11 @@ public: virtual InsetMathRef * asRefInset() { return 0; } virtual InsetMathSpecialChar const * asSpecialCharInset() const { return 0; } + /// The class of the math object (used primarily for spacing) + virtual MathClass mathClass() const; + /// identifies things that can get scripts virtual bool isScriptable() const { return false; } - /// identifies a binary operators (used for spacing) - virtual bool isMathBin() const { return false; } - /// identifies relational operators (used for spacing and splitting equations) - virtual bool isMathRel() const { return false; } - /// identifies punctuation (used for spacing) - virtual bool isMathPunct() const { return false; } /// will this get written as a single block in {..} virtual bool extraBraces() const { return false; } diff --git a/src/mathed/InsetMathChar.cpp b/src/mathed/InsetMathChar.cpp index ae843bf00d..1669515b66 100644 --- a/src/mathed/InsetMathChar.cpp +++ b/src/mathed/InsetMathChar.cpp @@ -121,8 +121,6 @@ void InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const dim = fm.dimension(char_); kerning_ = fm.rbearing(char_) - dim.wid; } - if (mathfont && isMathPunct()) - dim.wid += mathed_thinmuskip(mi.base.font); } @@ -266,22 +264,19 @@ void InsetMathChar::htmlize(HtmlStream & ms) const } -bool InsetMathChar::isMathBin() const +MathClass InsetMathChar::mathClass() const { - return subst_ && subst_->extra == "mathbin"; -} - - -bool InsetMathChar::isMathRel() const -{ - return subst_ && subst_->extra == "mathrel"; -} - - -bool InsetMathChar::isMathPunct() const -{ - return support::contains(",;", static_cast(char_)) - || (subst_ && subst_->extra == "mathpunct"); + // this information comes from fontmath.ltx in LaTeX source. + char const ch = static_cast(char_); + if (subst_) + return string_to_class(subst_->extra); + else if (support::contains(",;", ch)) + return MC_PUNCT; + else if (support::contains("([", ch)) + return MC_OPEN; + else if (support::contains(")]!?", ch)) + return MC_CLOSE; + else return MC_ORD; } diff --git a/src/mathed/InsetMathChar.h b/src/mathed/InsetMathChar.h index ea190211b7..6e7ff72c9c 100644 --- a/src/mathed/InsetMathChar.h +++ b/src/mathed/InsetMathChar.h @@ -51,11 +51,7 @@ public: /// char_type getChar() const { return char_; } /// - bool isMathBin() const; - /// - bool isMathRel() const; - /// - bool isMathPunct() const; + MathClass mathClass() const; /// InsetCode lyxCode() const { return MATH_CHAR_CODE; } diff --git a/src/mathed/InsetMathDelim.cpp b/src/mathed/InsetMathDelim.cpp index 68e4430514..4ab179e7b2 100644 --- a/src/mathed/InsetMathDelim.cpp +++ b/src/mathed/InsetMathDelim.cpp @@ -115,7 +115,7 @@ void InsetMathDelim::metrics(MetricsInfo & mi, Dimension & dim) const dw_ = 8; if (dw_ < 4) dw_ = 4; - dim.wid = dim0.width() + 2 * dw_ + 2 * mathed_thinmuskip(mi.base.font); + dim.wid = dim0.width() + 2 * dw_; dim.asc = max(a0, d0) + h0; dim.des = max(a0, d0) - h0; } @@ -125,10 +125,9 @@ void InsetMathDelim::draw(PainterInfo & pi, int x, int y) const { Dimension const dim = dimension(*pi.base.bv); int const b = y - dim.asc; - int const skip = mathed_thinmuskip(pi.base.font); - cell(0).draw(pi, x + dw_ + skip, y); - mathed_draw_deco(pi, x + skip, b, dw_, dim.height(), left_); - mathed_draw_deco(pi, x + dim.width() - dw_ - skip, + cell(0).draw(pi, x + dw_, y); + mathed_draw_deco(pi, x, b, dw_, dim.height(), left_); + mathed_draw_deco(pi, x + dim.width() - dw_, b, dw_, dim.height(), right_); setPosCache(pi, x, y); } diff --git a/src/mathed/InsetMathDelim.h b/src/mathed/InsetMathDelim.h index 3a09ede2f3..5a7e816404 100644 --- a/src/mathed/InsetMathDelim.h +++ b/src/mathed/InsetMathDelim.h @@ -30,6 +30,8 @@ public: InsetMathDelim * asDelimInset() { return this; } /// InsetMathDelim const * asDelimInset() const { return this; } + /// + MathClass mathClass() const { return MC_INNER; } /// is it (...)? bool isParenthesis() const; /// is it [...]? diff --git a/src/mathed/InsetMathFrac.cpp b/src/mathed/InsetMathFrac.cpp index ab876e060d..263587ed6e 100644 --- a/src/mathed/InsetMathFrac.cpp +++ b/src/mathed/InsetMathFrac.cpp @@ -123,6 +123,31 @@ bool InsetMathFrac::idxBackward(Cursor & cur) const } +MathClass InsetMathFrac::mathClass() const +{ + // Generalized fractions are of inner class (see The TeXbook, p. 292) + // But stuff from the unit/nicefrac packages are not real fractions. + MathClass mc = MC_ORD; + switch (kind_) { + case ATOP: + case OVER: + case FRAC: + case DFRAC: + case TFRAC: + case CFRAC: + case CFRACLEFT: + case CFRACRIGHT: + mc = MC_INNER; + break; + case NICEFRAC: + case UNITFRAC: + case UNIT: + break; + } + return mc; +} + + void InsetMathFrac::metrics(MetricsInfo & mi, Dimension & dim) const { Dimension dim0, dim1, dim2; diff --git a/src/mathed/InsetMathFrac.h b/src/mathed/InsetMathFrac.h index c030c8a51a..96b62930ba 100644 --- a/src/mathed/InsetMathFrac.h +++ b/src/mathed/InsetMathFrac.h @@ -62,6 +62,8 @@ public: /// bool idxBackward(Cursor &) const; /// + MathClass mathClass() const; + /// void metrics(MetricsInfo & mi, Dimension & dim) const; /// void draw(PainterInfo &, int x, int y) const; @@ -117,6 +119,8 @@ public: void write(WriteStream & os) const; /// void normalize(NormalStream &) const; + /// Generalized fractions are of inner class (see The TeXbook, p.292) + MathClass mathClass() const { return MC_INNER; } /// void metrics(MetricsInfo & mi, Dimension & dim) const; /// diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp index e2ceb5c903..dc943bb520 100644 --- a/src/mathed/InsetMathHull.cpp +++ b/src/mathed/InsetMathHull.cpp @@ -108,7 +108,7 @@ namespace { size_t firstRelOp(MathData const & ar) { for (MathData::const_iterator it = ar.begin(); it != ar.end(); ++it) - if ((*it)->isMathRel()) + if ((*it)->mathClass() == MC_REL) return it - ar.begin(); return ar.size(); } diff --git a/src/mathed/InsetMathScript.cpp b/src/mathed/InsetMathScript.cpp index b4cd5909be..8098a1a2d8 100644 --- a/src/mathed/InsetMathScript.cpp +++ b/src/mathed/InsetMathScript.cpp @@ -273,6 +273,19 @@ int InsetMathScript::nker(BufferView const * bv) const } +MathClass InsetMathScript::mathClass() const +{ + // FIXME: this is a hack, since the class will not be correct if + // the nucleus has several elements. + // The correct implementation would require to linearize the nucleus. + if (nuc().empty()) + return MC_ORD; + else + // return the class of last element since this is the one that counts. + return nuc().back()->mathClass(); +} + + void InsetMathScript::metrics(MetricsInfo & mi, Dimension & dim) const { Dimension dim0; diff --git a/src/mathed/InsetMathScript.h b/src/mathed/InsetMathScript.h index e84886b7d3..d0707439b9 100644 --- a/src/mathed/InsetMathScript.h +++ b/src/mathed/InsetMathScript.h @@ -33,6 +33,8 @@ public: /// mode_type currentMode() const { return MATH_MODE; } /// + MathClass mathClass() const; + /// void metrics(MetricsInfo & mi, Dimension & dim) const; /// void draw(PainterInfo & pi, int x, int y) const; diff --git a/src/mathed/InsetMathStackrel.cpp b/src/mathed/InsetMathStackrel.cpp index 9412d99182..3dda0dae24 100644 --- a/src/mathed/InsetMathStackrel.cpp +++ b/src/mathed/InsetMathStackrel.cpp @@ -52,6 +52,13 @@ bool InsetMathStackrel::idxUpDown(Cursor & cur, bool up) const } +MathClass InsetMathStackrel::mathClass() const +{ + // FIXME: update this when/if \stackbin is supported + return MC_REL; +} + + void InsetMathStackrel::metrics(MetricsInfo & mi, Dimension & dim) const { Dimension dim1; diff --git a/src/mathed/InsetMathStackrel.h b/src/mathed/InsetMathStackrel.h index 91862a7792..d6ac815182 100644 --- a/src/mathed/InsetMathStackrel.h +++ b/src/mathed/InsetMathStackrel.h @@ -24,6 +24,8 @@ public: /// bool idxUpDown(Cursor &, bool up) const; /// + MathClass mathClass() const; + /// void metrics(MetricsInfo & mi, Dimension & dim) const; /// void draw(PainterInfo & pi, int x, int y) const; @@ -35,7 +37,7 @@ public: void mathmlize(MathStream &) const; /// void htmlize(HtmlStream &) const; - /// + /// void validate(LaTeXFeatures &) const; /// InsetCode lyxCode() const { return MATH_STACKREL_CODE; } diff --git a/src/mathed/InsetMathSymbol.cpp b/src/mathed/InsetMathSymbol.cpp index 620ca226a2..01bafe614d 100644 --- a/src/mathed/InsetMathSymbol.cpp +++ b/src/mathed/InsetMathSymbol.cpp @@ -70,7 +70,7 @@ void InsetMathSymbol::metrics(MetricsInfo & mi, Dimension & dim) const dim.asc += h_; dim.des -= h_; } - // set striptable_ + // set scriptable_ scriptable_ = false; if (mi.base.style == LM_ST_DISPLAY) if (sym_->inset == "cmex" || sym_->inset == "esint" || @@ -92,30 +92,21 @@ InsetMath::mode_type InsetMathSymbol::currentMode() const } -bool InsetMathSymbol::isMathBin() const -{ - return sym_->extra == "mathbin"; -} - - -bool InsetMathSymbol::isMathRel() const -{ - return sym_->extra == "mathrel"; -} - - -bool InsetMathSymbol::isMathPunct() const -{ - return sym_->extra == "mathpunct"; -} - - bool InsetMathSymbol::isOrdAlpha() const { return sym_->extra == "mathord" || sym_->extra == "mathalpha"; } +MathClass InsetMathSymbol::mathClass() const +{ + if (sym_->extra == "func" || sym_->extra == "funclim") + return MC_OP; + MathClass const mc = string_to_class(sym_->extra); + return (mc == MC_UNKNOWN) ? MC_ORD : mc; +} + + bool InsetMathSymbol::isScriptable() const { return scriptable_; diff --git a/src/mathed/InsetMathSymbol.h b/src/mathed/InsetMathSymbol.h index 6ca3ded7d1..67b33fd85a 100644 --- a/src/mathed/InsetMathSymbol.h +++ b/src/mathed/InsetMathSymbol.h @@ -40,11 +40,7 @@ public: /// mode_type currentMode() const; /// - bool isMathRel() const; - /// - bool isMathBin() const; - /// - bool isMathPunct() const; + MathClass mathClass() const; /// bool isOrdAlpha() const; /// do we take scripts? diff --git a/src/mathed/MathClass.cpp b/src/mathed/MathClass.cpp new file mode 100644 index 0000000000..fae7654334 --- /dev/null +++ b/src/mathed/MathClass.cpp @@ -0,0 +1,82 @@ +/** + * \file MathClass.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Jean-Marc Lasgouttes + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "MathClass.h" + +#include "support/docstring.h" +#include "support/lassert.h" + +using namespace std; + +namespace lyx { + + +docstring const class_to_string(MathClass const mc) +{ + string s; + switch (mc) { + case MC_ORD: + s = "mathord"; + break; + case MC_OP: + s = "mathop"; + break; + case MC_BIN: + s = "mathbin"; + break; + case MC_REL: + s = "mathrel"; + break; + case MC_OPEN: + s = "mathopen"; + break; + case MC_CLOSE: + s = "mathclose"; + break; + case MC_PUNCT: + s = "mathpunct"; + break; + case MC_INNER: + s = "mathinner"; + break; + case MC_UNKNOWN: + LATTEST(false); + s = "mathord"; + } + return from_ascii(s); +} + + +MathClass string_to_class(docstring const &s) +{ + if (s == "mathop") + return MC_OP; + else if (s == "mathbin") + return MC_BIN; + else if (s == "mathrel") + return MC_REL; + else if (s == "mathopen") + return MC_OPEN; + else if (s == "mathclose") + return MC_CLOSE; + else if (s == "mathpunct") + return MC_PUNCT; + else if (s == "mathinner") + return MC_INNER; + else if (s == "mathord") + return MC_ORD; + else + return MC_UNKNOWN; +} + + +} // namespace lyx diff --git a/src/mathed/MathClass.h b/src/mathed/MathClass.h new file mode 100644 index 0000000000..ceedd8db07 --- /dev/null +++ b/src/mathed/MathClass.h @@ -0,0 +1,64 @@ +// -*- C++ -*- +/** + * \file MathClass.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Jean-Marc Lasgouttes + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef MATH_CLASS_H +#define MATH_CLASS_H + +#include "support/strfwd.h" + +namespace lyx { + + +/* The TeXbook, p. 158: + * + * There are thirteen kinds of atoms, each of which might act + * differently in a formula; for example, ‘(’ is an Open atom because + * it comes from an opening. Here is a complete list of the different + * kinds: + + * + Ord: an ordinary atom like ‘x’ + * + Op: a large operator atom like ‘\sum’ + * + Bin: a binary operation atom like ‘+’ + * + Rel: a relation atom like ‘=’ + * + Open: an opening atom like ‘(’ + * + Close: a closing atom like ‘)’ + * + Punct: a punctuation atom like ‘,’ + * + Inner: an inner atom like ‘\frac{1}{2}’ + * + Over: an overline atom like ‘\overline{x}’ + * + Under: an underline atom like ‘\underline{x}’ + * + Acc: an accented atom like ‘\hat{x}’ + * + Rad: a radical atom like ‘\sqrt{2}’ + * + Vcent: a vbox to be centered, produced by \vcenter. + * + * Over, Under, Acc, Rad and Vcent are not considered in the enum + * below. The relvant elements will be considered as Ord. + */ +enum MathClass { + MC_ORD, + MC_OP, + MC_BIN, + MC_REL, + MC_OPEN, + MC_CLOSE, + MC_PUNCT, + MC_INNER, + MC_UNKNOWN +}; + + +MathClass string_to_class(docstring const &); + +docstring const class_to_string(MathClass); + + +} // namespace lyx + +#endif diff --git a/src/mathed/MathSupport.cpp b/src/mathed/MathSupport.cpp index 0c610b1e69..9d79a8abfa 100644 --- a/src/mathed/MathSupport.cpp +++ b/src/mathed/MathSupport.cpp @@ -671,13 +671,6 @@ void mathedSymbolDim(MetricsInfo & mi, Dimension & dim, latexkeys const * sym) std::string const font = italic_upcase_greek ? "cmm" : sym->inset; Changer dummy = mi.base.changeFontSet(font); mathed_string_dim(mi.base.font, sym->draw, dim); - // seperate things a bit - if (sym->extra == "mathbin") - dim.wid += 2 * mathed_medmuskip(mi.base.font); - else if (sym->extra == "mathrel") - dim.wid += 2 * mathed_thickmuskip(mi.base.font); - else if (sym->extra == "mathpunct") - dim.wid += mathed_thinmuskip(mi.base.font); } @@ -693,10 +686,6 @@ void mathedSymbolDraw(PainterInfo & pi, int x, int y, latexkeys const * sym) sym->extra == "mathalpha" && pi.base.fontname == "mathit"; std::string const font = italic_upcase_greek ? "cmm" : sym->inset; - if (sym->extra == "mathbin") - x += mathed_medmuskip(pi.base.font); - else if (sym->extra == "mathrel") - x += mathed_thickmuskip(pi.base.font); Changer dummy = pi.base.changeFontSet(font); pi.draw(x, y, sym->draw); From f6df4e7985a8e35e3603445f9f6ee8c569d95aba Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Mon, 22 Aug 2016 14:15:28 +0200 Subject: [PATCH 2/7] Implement computation of spacing according to the TeXBook This implements the relevant math typography rules described in the Appendix G of the TeXbook. More precisely, for each atom + the class is computed by implementing rules 5 and 6 of Appendix G + the spacing is computed according to the table p. 170 This code is not used at this point. --- src/mathed/MathClass.cpp | 98 ++++++++++++++++++++++++++++++++++++++ src/mathed/MathClass.h | 5 ++ src/mathed/MathSupport.cpp | 3 ++ 3 files changed, 106 insertions(+) diff --git a/src/mathed/MathClass.cpp b/src/mathed/MathClass.cpp index fae7654334..a46aad3794 100644 --- a/src/mathed/MathClass.cpp +++ b/src/mathed/MathClass.cpp @@ -11,10 +11,17 @@ #include #include "MathClass.h" +#include "MathSupport.h" +#include "MetricsInfo.h" +#include "FontInfo.h" + +#include "support/debug.h" #include "support/docstring.h" #include "support/lassert.h" +#include + using namespace std; namespace lyx { @@ -79,4 +86,95 @@ MathClass string_to_class(docstring const &s) } +/* + * The TeXbook presents in Appendix G a set of 22 rules (!) explaining + * how to typeset mathematic formulas. Of interest here are rules 5 + * and 6: + + * 5. If the current item is a Bin atom, and if this was the first + * atom in the list, or if the most recent previous atom was Bin, + * Op, Rel, Open, or Punct, change the current Bin to Ord [and + * continue with Rule 14. Otherwise continue with Rule 17] + * + * 6. If the current item is a Rel or Close or Punct atom, and if the + * most recent previous atom was Bin, change that previous Bin to + * Ord. [Continue with Rule 17.] + */ +void update_class(MathClass & mc, MathClass const prev, MathClass const next) +{ + if (mc == MC_BIN + && (prev == MC_BIN || prev == MC_OP || prev == MC_OPEN + || prev == MC_PUNCT || prev == MC_REL + || next == MC_CLOSE || next == MC_PUNCT || next == MC_REL)) + mc = MC_ORD; +} + + +/* + * This table of spacing between two classes can be found p. 170 of + * The TeXbook. + * + * The line is the class of the first class, and the column the second + * class. The number encodes the spacing between the two atoms, as + * follows + * + * + 0: no spacing + * + 1: thin mu skip + * + 2: med mu skip + * + 3: thick mu skip + * + 9: should never happen + * + negative value: either 0 if the atom is in script or scriptscript mode, + * or the spacing given by the absolute value. + */ +int pair_spc[MC_UNKNOWN][MC_UNKNOWN] = { +// ORD OP BIN REL OPEN CLOSE PUNCT INNER + { 0, 1, -2, -3, 0, 0, 0, -1}, // ORD + { 1, 1, 9, -3, 0, 0, 0, -1}, // OP + { -2, -2, 9, 9, -2, 9, 9, -2}, // BIN + { -3, -3, 9, 0, -3, 0, 0, -3}, // REL + { 0, 0, 9, 0, 0, 0, 0, 0}, // OPEN + { 0, 1, -2, -3, 0, 0, 0, -1}, // CLOSE + { -1, -1, 9, -1, -1, -1, -1, -1}, // PUNCT + { -1, 1, -2, -3, -1, 0, -1, -1}, // INNER +}; + + +int class_spacing(MathClass const mc1, MathClass const mc2, + MetricsBase const & mb) +{ + int spc_code = pair_spc[mc1][mc2]; + //lyxerr << class_to_string(mc1) << "+" << class_to_string(mc2) + // << "=" << spc_code << " @" << mb.style << endl; + if (spc_code < 0) { + switch (mb.style) { + case LM_ST_DISPLAY: + case LM_ST_TEXT: + spc_code = abs(spc_code); + break; + case LM_ST_SCRIPT: + case LM_ST_SCRIPTSCRIPT: + spc_code = 0; + } + } + + int spc = 0; + switch(spc_code) { + case 0: + break; + case 1: + spc = mathed_thinmuskip(mb.font); + break; + case 2: + spc = mathed_medmuskip(mb.font); + break; + case 3: + spc = mathed_thickmuskip(mb.font); + break; + default: + LYXERR0("Impossible pair of classes: (" << mc1 << ", " << mc2 << ")"); + LATTEST(false); + } + return spc; +} + } // namespace lyx diff --git a/src/mathed/MathClass.h b/src/mathed/MathClass.h index ceedd8db07..169bfdb51a 100644 --- a/src/mathed/MathClass.h +++ b/src/mathed/MathClass.h @@ -16,6 +16,7 @@ namespace lyx { +class MetricsBase; /* The TeXbook, p. 158: * @@ -58,6 +59,10 @@ MathClass string_to_class(docstring const &); docstring const class_to_string(MathClass); +void update_class(MathClass & mc, MathClass const prev, MathClass const next); + +int class_spacing(MathClass const mc1, MathClass const mc2, + MetricsBase const & mb); } // namespace lyx diff --git a/src/mathed/MathSupport.cpp b/src/mathed/MathSupport.cpp index 9d79a8abfa..3d708406d3 100644 --- a/src/mathed/MathSupport.cpp +++ b/src/mathed/MathSupport.cpp @@ -528,6 +528,9 @@ int mathed_font_em(FontInfo const & font) * punctuation, and is put around inner objects, except where these * are followed by a close or preceded by an open symbol, and except * if the other object is a large operator or a binary relation. + * + * See the file MathClass.cpp for a formal implementation of the rules + * above. */ int mathed_thinmuskip(FontInfo font) From bf56e2c8e1afa857cd5e313c19948040e41b8227 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Wed, 16 Nov 2016 15:07:00 +0100 Subject: [PATCH 3/7] Set correctly the spacing between atoms in MathData * new MathRow class which contains the description of a MathData object in terms of math class and spacing + macros and their arguments used in the MathData object are linearized (replaced with their contents) so that all math insets are typeset as a string together. To this end, we introduce a method addToMathRow to InsetMath and MathData. This method allows to linearize recursively a MathData object. + It is then necessary to set manually the dimension and position of the macros and arguments. + the class class and spacing are computed using the MathClass helpers. The MathRow data is cached in the MathData object in a bufferview-dependent way (different dpi for different screens). * delegate most of the work MathData::metrics/draw to MathRow metrics/draw. The case of draw is trickier, since many draw() methods rely on their metrics without any spacing added. --- src/Makefile.am | 2 + src/mathed/InsetMath.cpp | 11 ++ src/mathed/InsetMath.h | 8 +- src/mathed/MathData.cpp | 116 +++++----------- src/mathed/MathData.h | 10 ++ src/mathed/MathMacro.cpp | 51 ++++++- src/mathed/MathMacro.h | 12 +- src/mathed/MathRow.cpp | 292 +++++++++++++++++++++++++++++++++++++++ src/mathed/MathRow.h | 137 ++++++++++++++++++ 9 files changed, 553 insertions(+), 86 deletions(-) create mode 100644 src/mathed/MathRow.cpp create mode 100644 src/mathed/MathRow.h diff --git a/src/Makefile.am b/src/Makefile.am index fc135af00e..5990df7683 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -458,6 +458,7 @@ SOURCEFILESMATHED = \ mathed/MathMacroArgument.cpp \ mathed/MathMacroTemplate.cpp \ mathed/MathParser.cpp \ + mathed/MathRow.cpp \ mathed/MathStream.cpp \ mathed/MathSupport.cpp \ mathed/TextPainter.cpp @@ -530,6 +531,7 @@ HEADERFILESMATHED = \ mathed/MathMacroTemplate.h \ mathed/MathParser.h \ mathed/MathParser_flags.h \ + mathed/MathRow.h \ mathed/ReplaceData.h \ mathed/MathStream.h \ mathed/MathSupport.h \ diff --git a/src/mathed/InsetMath.cpp b/src/mathed/InsetMath.cpp index aec53d0518..a8642c14ac 100644 --- a/src/mathed/InsetMath.cpp +++ b/src/mathed/InsetMath.cpp @@ -13,6 +13,7 @@ #include "InsetMath.h" #include "MathData.h" +#include "MathRow.h" #include "MathStream.h" #include "support/debug.h" @@ -55,6 +56,16 @@ MathClass InsetMath::mathClass() const } +bool InsetMath::addToMathRow(MathRow & mrow, MetricsInfo const &) const +{ + MathRow::Element e; + e.inset = this; + e.mclass = mathClass(); + mrow.push_back(e); + return true; +} + + void InsetMath::dump() const { lyxerr << "---------------------------------------------" << endl; diff --git a/src/mathed/InsetMath.h b/src/mathed/InsetMath.h index e791099b72..39490106b0 100644 --- a/src/mathed/InsetMath.h +++ b/src/mathed/InsetMath.h @@ -53,7 +53,10 @@ inclusion in the "real LyX insets" FormulaInset and FormulaMacroInset. */ +class Cursor; class OutputParams; +class MetricsInfo; + class InsetMathArray; class InsetMathAMSArray; class InsetMathBrace; @@ -72,7 +75,6 @@ class InsetMathSpace; class InsetMathSpecialChar; class InsetMathSymbol; class InsetMathUnknown; - class InsetMathRef; class HtmlStream; @@ -87,7 +89,7 @@ class WriteStream; class MathData; class MathMacroTemplate; class MathMacro; -class Cursor; +class MathRow; class TextPainter; class TextMetricsInfo; class ReplaceData; @@ -164,6 +166,8 @@ public: /// The class of the math object (used primarily for spacing) virtual MathClass mathClass() const; + /// Add this inset to a math row. Return true if contents got added + virtual bool addToMathRow(MathRow &, MetricsInfo const & mi) const; /// identifies things that can get scripts virtual bool isScriptable() const { return false; } diff --git a/src/mathed/MathData.cpp b/src/mathed/MathData.cpp index bd4d53ead2..8b7a89dfc6 100644 --- a/src/mathed/MathData.cpp +++ b/src/mathed/MathData.cpp @@ -30,12 +30,11 @@ #include "mathed/InsetMathUnknown.h" -#include "support/debug.h" -#include "support/docstream.h" - #include "frontends/FontMetrics.h" #include "frontends/Painter.h" +#include "support/debug.h" +#include "support/docstream.h" #include "support/gettext.h" #include "support/lassert.h" #include "support/lyxalgo.h" @@ -218,6 +217,34 @@ void MathData::touch() const } +bool MathData::addToMathRow(MathRow & mrow, MetricsInfo const & mi) const +{ + bool has_contents = false; + BufferView * bv = mi.base.bv; + MathData * ar = const_cast(this); + ar->updateMacros(&bv->cursor(), mi.macrocontext, + InternalUpdate); + + // FIXME: for completion, try to insert the relevant data in the + // mathrow (like is done for text rows). We could add a pair of + // InsetMathColor inset, but these come with extra spacing of + // their own. + DocIterator const & inlineCompletionPos = bv->inlineCompletionPos(); + bool const has_completion = inlineCompletionPos.inMathed() + && &inlineCompletionPos.cell() == this; + size_t const compl_pos = has_completion ? inlineCompletionPos.pos() : 0; + + for (size_t i = 0 ; i < size() ; ++i) { + has_contents |= (*this)[i]->addToMathRow(mrow, mi); + if (i + 1 == compl_pos) { + mrow.back().compl_text = bv->inlineCompletion(); + mrow.back().compl_unique_to = bv->inlineCompletionUniqueChars(); + } + } + return has_contents; +} + + #if 0 namespace { @@ -247,7 +274,6 @@ void MathData::metrics(MetricsInfo & mi, Dimension & dim) const mindes_ = (3 * xascent) / 4; slevel_ = (4 * xascent) / 5; sshift_ = xascent / 4; - kerning_ = 0; if (empty()) { // Cache the dimension. @@ -255,45 +281,17 @@ void MathData::metrics(MetricsInfo & mi, Dimension & dim) const return; } - Cursor & cur = mi.base.bv->cursor(); - const_cast(this)->updateMacros(&cur, mi.macrocontext, InternalUpdate); + MathRow mrow(mi, this); + mrow_cache_[mi.base.bv] = mrow; + mrow.metrics(mi, dim); + kerning_ = mrow.kerning(mi.base.bv); - DocIterator const & inlineCompletionPos = mi.base.bv->inlineCompletionPos(); - MathData const * inlineCompletionData = 0; - if (inlineCompletionPos.inMathed()) - inlineCompletionData = &inlineCompletionPos.cell(); - - dim.asc = 0; - dim.wid = 0; - Dimension d; - CoordCache::Insets & coords = mi.base.bv->coordCache().insets(); - for (pos_type i = 0, n = size(); i != n; ++i) { - MathAtom const & at = operator[](i); - at->metrics(mi, d); - coords.add(at.nucleus(), d); - dim += d; - if (i == n - 1) - kerning_ = at->kerning(mi.base.bv); - - // HACK to draw completion suggestion inline - if (inlineCompletionData != this - || size_t(inlineCompletionPos.pos()) != i + 1) - continue; - - docstring const & completion = mi.base.bv->inlineCompletion(); - if (completion.length() == 0) - continue; - - FontInfo font = mi.base.font; - augmentFont(font, "mathnormal"); - dim.wid += mathed_string_width(font, completion); - } // Cache the dimension. mi.base.bv->coordCache().arrays().add(this, dim); } -void MathData::draw(PainterInfo & pi, int x, int y) const +void MathData::draw(PainterInfo & pi, int const x, int const y) const { //lyxerr << "MathData::draw: x: " << x << " y: " << y << endl; BufferView & bv = *pi.base.bv; @@ -313,48 +311,8 @@ void MathData::draw(PainterInfo & pi, int x, int y) const || x >= bv. workWidth()) return; - DocIterator const & inlineCompletionPos = bv.inlineCompletionPos(); - MathData const * inlineCompletionData = 0; - if (inlineCompletionPos.inMathed()) - inlineCompletionData = &inlineCompletionPos.cell(); - - CoordCache::Insets & coords = pi.base.bv->coordCache().insets(); - for (size_t i = 0, n = size(); i != n; ++i) { - MathAtom const & at = operator[](i); - coords.add(at.nucleus(), x, y); - at->drawSelection(pi, x, y); - at->draw(pi, x, y); - x += coords.dim(at.nucleus()).wid; - - // Is the inline completion here? - if (inlineCompletionData != this - || size_t(inlineCompletionPos.pos()) != i + 1) - continue; - docstring const & completion = bv.inlineCompletion(); - if (completion.length() == 0) - continue; - FontInfo f = pi.base.font; - augmentFont(f, "mathnormal"); - - // draw the unique and the non-unique completion part - // Note: this is not time-critical as it is - // only done once per screen. - size_t uniqueTo = bv.inlineCompletionUniqueChars(); - docstring s1 = completion.substr(0, uniqueTo); - docstring s2 = completion.substr(uniqueTo); - - if (!s1.empty()) { - f.setColor(Color_inlinecompletion); - pi.pain.text(x, y, s1, f); - x += mathed_string_width(f, s1); - } - - if (!s2.empty()) { - f.setColor(Color_nonunique_inlinecompletion); - pi.pain.text(x, y, s2, f); - x += mathed_string_width(f, s2); - } - } + MathRow const & mrow = mrow_cache_[pi.base.bv]; + mrow.draw(pi, x, y); } diff --git a/src/mathed/MathData.h b/src/mathed/MathData.h index 4b79f805fe..fa82ee95e6 100644 --- a/src/mathed/MathData.h +++ b/src/mathed/MathData.h @@ -16,7 +16,9 @@ #define MATH_DATA_H #include "Dimension.h" + #include "MathAtom.h" +#include "MathRow.h" #include "OutputEnums.h" @@ -24,6 +26,7 @@ #include #include +#include namespace lyx { @@ -117,6 +120,10 @@ public: MathAtom & operator[](pos_type); /// checked read access MathAtom const & operator[](pos_type) const; + + /// Add this array to a math row. Return true if contents got added + bool addToMathRow(MathRow &, MetricsInfo const & mi) const; + /// rebuild cached metrics information void metrics(MetricsInfo & mi, Dimension & dim) const; /// @@ -177,6 +184,9 @@ protected: mutable int kerning_; Buffer * buffer_; + /// cached object that describes typeset data + mutable std::map mrow_cache_; + private: /// is this an exact match at this position? bool find1(MathData const & ar, size_type pos) const; diff --git a/src/mathed/MathMacro.cpp b/src/mathed/MathMacro.cpp index 4a94e03189..c4401d2b69 100644 --- a/src/mathed/MathMacro.cpp +++ b/src/mathed/MathMacro.cpp @@ -68,6 +68,27 @@ public: /// InsetCode lyxCode() const { return ARGUMENT_PROXY_CODE; } /// + bool addToMathRow(MathRow & mrow, MetricsInfo const & mi) const + { + MathRow::Element e(MathRow::BEG_ARG); + e.macro = mathMacro_; + e.ar = &mathMacro_->cell(idx_); + mrow.push_back(e); + + mathMacro_->macro()->unlock(); + bool const has_contents = mathMacro_->cell(idx_).addToMathRow(mrow, mi); + mathMacro_->macro()->lock(); + + e.type = MathRow::END_ARG; + mrow.push_back(e); + + if (has_contents) + return true; + // if there was no contents, then we insert the empty macro inset + // instead. + return InsetMath::addToMathRow(mrow, mi); + } + /// void metrics(MetricsInfo & mi, Dimension & dim) const { mathMacro_->macro()->unlock(); mathMacro_->cell(idx_).metrics(mi, dim); @@ -266,6 +287,34 @@ MathMacro::~MathMacro() } +bool MathMacro::addToMathRow(MathRow & mrow, MetricsInfo const & mi) const +{ + // set edit mode for which we will have calculated row. + // This is the same as what is done in metrics(). + d->editing_[mi.base.bv] = editMode(mi.base.bv); + + if (displayMode() == MathMacro::DISPLAY_NORMAL + && !d->editing_[mi.base.bv]) { + MathRow::Element e(MathRow::BEG_MACRO); + e.macro = this; + mrow.push_back(e); + + d->macro_->lock(); + bool const has_contents = d->expanded_.addToMathRow(mrow, mi); + d->macro_->unlock(); + + e.type = MathRow::END_MACRO; + mrow.push_back(e); + + if (has_contents) + return true; + // if there was no contents, then we insert the empty macro inset + // instead. + } + return InsetMath::addToMathRow(mrow, mi); +} + + Inset * MathMacro::clone() const { MathMacro * copy = new MathMacro(*this); @@ -344,7 +393,7 @@ bool MathMacro::editMode(BufferView const * bv) const { } -MacroData const * MathMacro::macro() +MacroData const * MathMacro::macro() const { return d->macro_; } diff --git a/src/mathed/MathMacro.h b/src/mathed/MathMacro.h index 1a8654ac40..9c6fdb1ce9 100644 --- a/src/mathed/MathMacro.h +++ b/src/mathed/MathMacro.h @@ -37,6 +37,10 @@ public: /// virtual MathMacro const * asMacro() const { return this; } /// + /// If the macro is in normal edit mode, dissolve its contents in + /// the row. Otherwise, just insert the inset. + bool addToMathRow(MathRow &, MetricsInfo const & mi) const; + /// void draw(PainterInfo & pi, int x, int y) const; /// draw selection background void drawSelection(PainterInfo & pi, int x, int y) const; @@ -45,6 +49,8 @@ public: { drawMarkers2(pi, x, y); } /// void metrics(MetricsInfo & mi, Dimension & dim) const; + /// was the macro in edit mode when computing metrics? + bool editMetrics(BufferView const * bv) const; /// int kerning(BufferView const * bv) const; /// get cursor position @@ -117,6 +123,8 @@ public: /// docstring name() const; /// + MacroData const * macro() const; + /// docstring macroName() const; /// bool validName() const; @@ -151,10 +159,6 @@ protected: /// attach arguments (maybe less than arity at the end of an MathData), /// including the optional ones (even if it can be empty here) void attachArguments(std::vector const & args, size_t arity, int optionals); - /// - MacroData const * macro(); - /// - bool editMetrics(BufferView const * bv) const; private: /// diff --git a/src/mathed/MathRow.cpp b/src/mathed/MathRow.cpp new file mode 100644 index 0000000000..55513bb923 --- /dev/null +++ b/src/mathed/MathRow.cpp @@ -0,0 +1,292 @@ +/** + * \file MathRow.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Jean-Marc Lasgouttes + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "MathRow.h" + +#include "InsetMath.h" +#include "MathClass.h" +#include "MathData.h" +#include "MathMacro.h" +#include "MathSupport.h" + +#include "BufferView.h" +#include "CoordCache.h" +#include "MetricsInfo.h" + +#include "frontends/Painter.h" + +#include "support/debug.h" +#include "support/docstring.h" +#include "support/lassert.h" + +#include + +using namespace std; + +namespace lyx { + + +MathRow::Element::Element(Type t, MathClass const mc) + : type(t), + inset(0), mclass(mc), before(0), after(0), compl_unique_to(0), + macro(0) +{} + + +MathRow::MathRow(MetricsInfo const & mi, MathData const * ar) +{ + if (ar->empty()) + return; + + // First there is a dummy element of type "open" + push_back(Element(BEGIN, MC_OPEN)); + + // Then insert the MathData argument + ar->addToMathRow(*this, mi); + + // Finally there is a dummy element of type "close" + push_back(Element(END, MC_CLOSE)); + + /* Do spacing only in math mode. This test is a bit clumsy, + * but it is used in other places for guessing the current mode. + */ + if (!isMathFont(mi.base.fontname)) + return; + + // update classes + for (int i = 1 ; i != static_cast(elements_.size()) - 1 ; ++i) { + if (elements_[i].type != INSET) + continue; + update_class(elements_[i].mclass, elements_[before(i)].mclass, + elements_[after(i)].mclass); + } + + // set spacing + // We go to the end to handle spacing at the end of equation + for (int i = 1 ; i != static_cast(elements_.size()) ; ++i) { + if (elements_[i].type != INSET) + continue; + Element & bef = elements_[before(i)]; + int spc = class_spacing(bef.mclass, elements_[i].mclass, mi.base); + bef.after = spc / 2; + // this is better than spc / 2 to avoid rounding problems + elements_[i].before = spc - spc / 2; + } + // Do not lose spacing allocated to extremities + if (!elements_.empty()) { + elements_[after(0)].before += elements_.front().after; + elements_[before(elements_.size() - 1)].after += elements_.back().before; + } +} + + +int MathRow::before(int i) const +{ + do + --i; + while (elements_[i].type != BEGIN + && elements_[i].type != INSET); + + return i; +} + + +int MathRow::after(int i) const +{ + do + ++i; + while (elements_[i].type != END + && elements_[i].type != INSET); + + return i; +} + + +void MathRow::metrics(MetricsInfo & mi, Dimension & dim) const +{ + dim.asc = 0; + dim.wid = 0; + // In order to compute the dimension of macros and their + // arguments, it is necessary to keep track of them. + map dim_macros; + map dim_arrays; + CoordCache & coords = mi.base.bv->coordCache(); + + for (Element const & e : elements_) { + Dimension d; + switch (e.type) { + case BEGIN: + case END: + break; + case INSET: + e.inset->metrics(mi, d); + d.wid += e.before + e.after; + coords.insets().add(e.inset, d); + dim += d; + // Now add the dimension to current macros and arguments. + for (auto & dim_macro : dim_macros) + dim_macro.second += d; + for (auto & dim_array : dim_arrays) + dim_array.second += d; + break; + case BEG_MACRO: + e.macro->macro()->lock(); + // Add a macro to current list + dim_macros[e.macro] = Dimension(); + break; + case END_MACRO: + LATTEST(dim_macros.find(e.macro) != dim_macros.end()); + e.macro->macro()->unlock(); + // Cache the dimension of the macro and remove it from + // tracking map. + coords.insets().add(e.macro, dim_macros[e.macro]); + dim_macros.erase(e.macro); + break; + // This is basically like macros + case BEG_ARG: + if (e.macro) + e.macro->macro()->unlock(); + dim_arrays[e.ar] = Dimension(); + break; + case END_ARG: + LATTEST(dim_arrays.find(e.ar) != dim_arrays.end()); + if (e.macro) + e.macro->macro()->lock(); + coords.arrays().add(e.ar, dim_arrays[e.ar]); + dim_arrays.erase(e.ar); + break; + } + + if (e.compl_text.empty()) + continue; + FontInfo font = mi.base.font; + augmentFont(font, "mathnormal"); + dim.wid += mathed_string_width(font, e.compl_text); + } + LATTEST(dim_macros.empty() && dim_arrays.empty()); +} + + +void MathRow::draw(PainterInfo & pi, int x, int const y) const +{ + CoordCache & coords = pi.base.bv->coordCache(); + for (Element const & e : elements_) { + Dimension d; + switch (e.type) { + case INSET: { + // This is hackish: the math inset does not know that space + // has been added before and after it; we alter its dimension + // while it is drawing, because it relies on this value. + Dimension const d = coords.insets().dim(e.inset); + Dimension d2 = d; + d2.wid -= e.before + e.after; + coords.insets().add(e.inset, d2); + e.inset->drawSelection(pi, x + e.before, y); + e.inset->draw(pi, x + e.before, y); + coords.insets().add(e.inset, x, y); + coords.insets().add(e.inset, d); + x += d.wid; + break; + } + case BEG_MACRO: + coords.insets().add(e.macro, x, y); + break; + case BEG_ARG: + coords.arrays().add(e.ar, x, y); + // if the macro is being edited, then the painter is in + // monochrome mode. + if (e.macro->editMetrics(pi.base.bv)) + pi.pain.leaveMonochromeMode(); + break; + case END_ARG: + if (e.macro->editMetrics(pi.base.bv)) + pi.pain.enterMonochromeMode(Color_mathbg, Color_mathmacroblend); + break; + case BEGIN: + case END: + case END_MACRO: + break; + } + + if (e.compl_text.empty()) + continue; + FontInfo f = pi.base.font; + augmentFont(f, "mathnormal"); + + // draw the unique and the non-unique completion part + // Note: this is not time-critical as it is + // only done once per screen. + docstring const s1 = e.compl_text.substr(0, e.compl_unique_to); + docstring const s2 = e.compl_text.substr(e.compl_unique_to); + + if (!s1.empty()) { + f.setColor(Color_inlinecompletion); + pi.pain.text(x, y, s1, f); + x += mathed_string_width(f, s1); + } + if (!s2.empty()) { + f.setColor(Color_nonunique_inlinecompletion); + pi.pain.text(x, y, s2, f); + x += mathed_string_width(f, s2); + } + } +} + + +int MathRow::kerning(BufferView const * bv) const +{ + if (elements_.empty()) + return 0; + InsetMath const * inset = elements_[before(elements_.size() - 1)].inset; + return inset ? inset->kerning(bv) : 0; +} + + +ostream & operator<<(ostream & os, MathRow::Element const & e) +{ + switch (e.type) { + case MathRow::BEGIN: + os << "{"; + break; + case MathRow::END: + os << "}"; + break; + case MathRow::INSET: + os << "<" << e.before << "-" + << to_utf8(class_to_string(e.mclass)) + << "-" << e.after << ">"; + break; + case MathRow::BEG_MACRO: + os << "\\" << to_utf8(e.macro->name()) << "["; + break; + case MathRow::END_MACRO: + os << "]"; + break; + case MathRow::BEG_ARG: + os << "#("; + break; + case MathRow::END_ARG: + os << ")"; + break; + } + return os; +} + + +ostream & operator<<(ostream & os, MathRow const & mrow) +{ + for (MathRow::Element const & e : mrow) + os << e << " "; + return os; +} + +} // namespace lyx diff --git a/src/mathed/MathRow.h b/src/mathed/MathRow.h new file mode 100644 index 0000000000..d0260e2e10 --- /dev/null +++ b/src/mathed/MathRow.h @@ -0,0 +1,137 @@ +// -*- C++ -*- +/** + * \file MathRow.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Jean-Marc Lasgouttes + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef MATH_ROW_H +#define MATH_ROW_H + +#include "MathClass.h" + +#include "support/docstring.h" + +#include + +namespace lyx { + +class BufferView; +class Dimension; +class MetricsInfo; +class PainterInfo; + +class InsetMath; +class MathData; +class MathMacro; + +/* + * While for editing purpose it is important that macros are counted + * as a single element, this is not the case for display. To get the + * spacing correct, it is necessary to dissolve all the macros that + * can be, along with their arguments. Then one obtains a + * representation of the MathData contents as a string of insets and + * then spacing can be done properly. + * + * This is the purpose of the MathRow class. + */ +class MathRow +{ +public: + // What row elements can be + enum Type { + INSET, // this element is a plain inset + BEG_MACRO, // a macro begins here + END_MACRO, // a macro ends here + BEG_ARG, // a macro argument begins here + END_ARG, // a macro argument ends here + BEGIN, // dummy element before row + END, // dummy element after row + }; + + // An elements, together with its spacing + struct Element + { + /// + Element(Type t = INSET, MathClass const mc = MC_ORD); + + /// Classifies the contents of the object + Type type; + + /// When type is INSET + /// the math inset + InsetMath const * inset; + /// the class of the inset + MathClass mclass; + /// the spacing around the inset + int before, after; + // Non empty when there is a completion to draw + docstring compl_text; + // the number of characters forming the unique part. + size_t compl_unique_to; + + /// When type is BEG_MACRO, END_MACRO, BEG_ARG, END_ARG + /// the math macro + MathMacro const * macro; + + // type is BEG_ARG, END_ARG + MathData const * ar; + }; + + /// + MathRow() {}; + /// + typedef std::vector Elements; + /// + typedef Elements::iterator iterator; + /// + typedef Elements::const_iterator const_iterator; + /// + iterator begin() { return elements_.begin(); } + /// + iterator end() { return elements_.end(); } + /// + const_iterator begin() const { return elements_.begin(); } + /// + const_iterator end() const { return elements_.end(); } + // + void push_back(Element const & e) { elements_.push_back(e); } + // + Element & back() { return elements_.back(); } + + // create the math row by unwinding all macros in the MathData and + // compute the spacings. + MathRow(MetricsInfo const & mi, MathData const * ar); + + // + void metrics(MetricsInfo & mi, Dimension & dim) const; + // + void draw(PainterInfo & pi, int const x, int const y) const; + + /// superscript kerning + int kerning(BufferView const *) const; + +private: + // Index of the first inset element before position i + int before(int i) const; + // Index of the first inset element after position i + int after(int i) const; + + /// + Elements elements_; +}; + +/// +std::ostream & operator<<(std::ostream & os, MathRow::Element const & elt); + +/// +std::ostream & operator<<(std::ostream & os, MathRow const & mrow); + + +} // namespace lyx + +#endif From 0b5c2a85077330a59befa82dfa4d212f78cf8855 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Wed, 5 Oct 2016 00:25:38 +0200 Subject: [PATCH 4/7] Add support for \mathbin and friends All they do is change the class of the elements that they contain. --- src/Makefile.am | 2 ++ src/insets/InsetCode.h | 2 ++ src/mathed/InsetMathClass.cpp | 57 +++++++++++++++++++++++++++++++++++ src/mathed/InsetMathClass.h | 50 ++++++++++++++++++++++++++++++ src/mathed/MathFactory.cpp | 6 +++- 5 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 src/mathed/InsetMathClass.cpp create mode 100644 src/mathed/InsetMathClass.h diff --git a/src/Makefile.am b/src/Makefile.am index 5990df7683..f87d0290b3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -403,6 +403,7 @@ SOURCEFILESMATHED = \ mathed/InsetMathCancelto.cpp \ mathed/InsetMathCases.cpp \ mathed/InsetMathChar.cpp \ + mathed/InsetMathClass.cpp \ mathed/InsetMathColor.cpp \ mathed/InsetMathComment.cpp \ mathed/InsetMathDecoration.cpp \ @@ -475,6 +476,7 @@ HEADERFILESMATHED = \ mathed/InsetMathCancelto.h \ mathed/InsetMathCases.h \ mathed/InsetMathChar.h \ + mathed/InsetMathClass.h \ mathed/InsetMathColor.h \ mathed/InsetMathComment.h \ mathed/InsetMathDelim.h \ diff --git a/src/insets/InsetCode.h b/src/insets/InsetCode.h index 1df6800d2d..7d4632cd16 100644 --- a/src/insets/InsetCode.h +++ b/src/insets/InsetCode.h @@ -235,6 +235,8 @@ enum InsetCode { /// IPADECO_CODE, /// + MATH_CLASS_CODE, + /// INSET_CODE_SIZE }; diff --git a/src/mathed/InsetMathClass.cpp b/src/mathed/InsetMathClass.cpp new file mode 100644 index 0000000000..931a68b9a4 --- /dev/null +++ b/src/mathed/InsetMathClass.cpp @@ -0,0 +1,57 @@ +/** + * \file InsetMathClass.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathClass.h" + +#include "support/docstream.h" + + +namespace lyx { + +InsetMathClass::InsetMathClass(Buffer * buf, MathClass mc) + : InsetMathNest(buf, 1), math_class_(mc) +{} + + +Inset * InsetMathClass::clone() const +{ + return new InsetMathClass(*this); +} + + +void InsetMathClass::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(0).metrics(mi, dim); + metricsMarkers(dim); +} + + +void InsetMathClass::draw(PainterInfo & pi, int x, int y) const +{ + cell(0).draw(pi, x + 1, y); + drawMarkers(pi, x, y); +} + + +docstring InsetMathClass::name() const +{ + return class_to_string(math_class_); +} + + +void InsetMathClass::infoize(odocstream & os) const +{ + os << name() << " "; +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathClass.h b/src/mathed/InsetMathClass.h new file mode 100644 index 0000000000..f50040d3b4 --- /dev/null +++ b/src/mathed/InsetMathClass.h @@ -0,0 +1,50 @@ +// -*- C++ -*- +/** + * \file InsetMathClass.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author André Pönitz + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef MATH_CLASSINSET_H +#define MATH_CLASSINSET_H + +#include "MathClass.h" + +#include "InsetMathNest.h" + + +namespace lyx { + + +/// Support for LaTeX's \\mathxxx class-changing commands + +class InsetMathClass : public InsetMathNest { +public: + /// + InsetMathClass(Buffer * buf, MathClass); + /// + docstring name() const; + /// + MathClass mathClass() const { return math_class_; } + /// + void metrics(MetricsInfo & mi, Dimension & dim) const; + /// + void draw(PainterInfo & pi, int x, int y) const; + /// + void infoize(odocstream & os) const; + /// + InsetCode lyxCode() const { return MATH_CLASS_CODE; } + +private: + virtual Inset * clone() const; + /// + MathClass math_class_; +}; + + +} // namespace lyx +#endif diff --git a/src/mathed/MathFactory.cpp b/src/mathed/MathFactory.cpp index bb7be8ba6b..f00093746f 100644 --- a/src/mathed/MathFactory.cpp +++ b/src/mathed/MathFactory.cpp @@ -19,6 +19,7 @@ #include "InsetMathCancel.h" #include "InsetMathCancelto.h" #include "InsetMathCases.h" +#include "InsetMathClass.h" #include "InsetMathColor.h" #include "InsetMathDecoration.h" #include "InsetMathDots.h" @@ -662,10 +663,13 @@ MathAtom createInsetMath(docstring const & s, Buffer * buf) return MathAtom(new InsetMathSpecialChar(s)); if (s == " ") return MathAtom(new InsetMathSpace(" ", "")); - if (s == "regexp") return MathAtom(new InsetMathHull(buf, hullRegexp)); + MathClass const mc = string_to_class(s); + if (mc != MC_UNKNOWN) + return MathAtom(new InsetMathClass(buf, mc)); + return MathAtom(new MathMacro(buf, s)); } From f3f9b083d180412a62a50bdef06ab236dca5fc9d Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Wed, 5 Oct 2016 00:25:38 +0200 Subject: [PATCH 5/7] Only display a blue rectangle for editable empty insets Empty insets should use a minimal amount of space, especially when they are part of a built-in macro in lib/symbols. With this change, blue rectangles signal actually editable places. Empty macros in editable data are shown as grey boxes, but they do not appear when further nested. This is done by adding a new type BOX of MathRow::Element object and a MetricsInfo::macro_nesting that keeps track of macros (and is reset to 0 in editable macro arguments). --- src/Dimension.h | 2 + src/MetricsInfo.cpp | 2 +- src/MetricsInfo.h | 2 + src/mathed/InsetMath.cpp | 4 +- src/mathed/InsetMath.h | 2 +- src/mathed/MathData.cpp | 14 +----- src/mathed/MathData.h | 2 +- src/mathed/MathMacro.cpp | 102 +++++++++++++++++++++++++++------------ src/mathed/MathMacro.h | 2 +- src/mathed/MathRow.cpp | 64 ++++++++++++++++-------- src/mathed/MathRow.h | 12 ++++- 11 files changed, 137 insertions(+), 71 deletions(-) diff --git a/src/Dimension.h b/src/Dimension.h index bd8f10d8f2..0607be6eba 100644 --- a/src/Dimension.h +++ b/src/Dimension.h @@ -32,6 +32,8 @@ public: void operator+=(Dimension const & dim); /// set to empty box void clear() { wid = asc = des = 0; } + /// check if box is empty + bool empty() const { return wid == 0 && asc == 0 && wid == 0; } /// get height int height() const { return asc + des; } /// get ascent diff --git a/src/MetricsInfo.cpp b/src/MetricsInfo.cpp index ea3bf0247e..02bbab3fd0 100644 --- a/src/MetricsInfo.cpp +++ b/src/MetricsInfo.cpp @@ -88,7 +88,7 @@ Changer MetricsBase::changeFontSet(string const & name, bool cond) MetricsInfo::MetricsInfo(BufferView * bv, FontInfo font, int textwidth, MacroContext const & mc) - : base(bv, font, textwidth), macrocontext(mc) + : base(bv, font, textwidth), macro_nesting(0), macrocontext(mc) {} diff --git a/src/MetricsInfo.h b/src/MetricsInfo.h index d2dd8b7bcf..415fe25076 100644 --- a/src/MetricsInfo.h +++ b/src/MetricsInfo.h @@ -101,6 +101,8 @@ public: /// MetricsBase base; + /// count wether the current mathdata is nested in macro(s) + int macro_nesting; /// The context to resolve macros MacroContext const & macrocontext; }; diff --git a/src/mathed/InsetMath.cpp b/src/mathed/InsetMath.cpp index a8642c14ac..d2182a5652 100644 --- a/src/mathed/InsetMath.cpp +++ b/src/mathed/InsetMath.cpp @@ -56,9 +56,9 @@ MathClass InsetMath::mathClass() const } -bool InsetMath::addToMathRow(MathRow & mrow, MetricsInfo const &) const +bool InsetMath::addToMathRow(MathRow & mrow, MetricsInfo & mi) const { - MathRow::Element e; + MathRow::Element e(MathRow::INSET, mi); e.inset = this; e.mclass = mathClass(); mrow.push_back(e); diff --git a/src/mathed/InsetMath.h b/src/mathed/InsetMath.h index 39490106b0..f8e70c7293 100644 --- a/src/mathed/InsetMath.h +++ b/src/mathed/InsetMath.h @@ -167,7 +167,7 @@ public: /// The class of the math object (used primarily for spacing) virtual MathClass mathClass() const; /// Add this inset to a math row. Return true if contents got added - virtual bool addToMathRow(MathRow &, MetricsInfo const & mi) const; + virtual bool addToMathRow(MathRow &, MetricsInfo & mi) const; /// identifies things that can get scripts virtual bool isScriptable() const { return false; } diff --git a/src/mathed/MathData.cpp b/src/mathed/MathData.cpp index 8b7a89dfc6..f2100afb34 100644 --- a/src/mathed/MathData.cpp +++ b/src/mathed/MathData.cpp @@ -31,7 +31,6 @@ #include "mathed/InsetMathUnknown.h" #include "frontends/FontMetrics.h" -#include "frontends/Painter.h" #include "support/debug.h" #include "support/docstream.h" @@ -217,7 +216,7 @@ void MathData::touch() const } -bool MathData::addToMathRow(MathRow & mrow, MetricsInfo const & mi) const +bool MathData::addToMathRow(MathRow & mrow, MetricsInfo & mi) const { bool has_contents = false; BufferView * bv = mi.base.bv; @@ -275,12 +274,6 @@ void MathData::metrics(MetricsInfo & mi, Dimension & dim) const slevel_ = (4 * xascent) / 5; sshift_ = xascent / 4; - if (empty()) { - // Cache the dimension. - mi.base.bv->coordCache().arrays().add(this, dim); - return; - } - MathRow mrow(mi, this); mrow_cache_[mi.base.bv] = mrow; mrow.metrics(mi, dim); @@ -299,11 +292,6 @@ void MathData::draw(PainterInfo & pi, int const x, int const y) const Dimension const & dim = bv.coordCache().getArrays().dim(this); - if (empty()) { - pi.pain.rectangle(x, y - dim.ascent(), dim.width(), dim.height(), Color_mathline); - return; - } - // don't draw outside the workarea if (y + dim.descent() <= 0 || y - dim.ascent() >= bv.workHeight() diff --git a/src/mathed/MathData.h b/src/mathed/MathData.h index fa82ee95e6..9eae46671a 100644 --- a/src/mathed/MathData.h +++ b/src/mathed/MathData.h @@ -122,7 +122,7 @@ public: MathAtom const & operator[](pos_type) const; /// Add this array to a math row. Return true if contents got added - bool addToMathRow(MathRow &, MetricsInfo const & mi) const; + bool addToMathRow(MathRow &, MetricsInfo & mi) const; /// rebuild cached metrics information void metrics(MetricsInfo & mi, Dimension & dim) const; diff --git a/src/mathed/MathMacro.cpp b/src/mathed/MathMacro.cpp index c4401d2b69..a748821113 100644 --- a/src/mathed/MathMacro.cpp +++ b/src/mathed/MathMacro.cpp @@ -68,28 +68,49 @@ public: /// InsetCode lyxCode() const { return ARGUMENT_PROXY_CODE; } /// - bool addToMathRow(MathRow & mrow, MetricsInfo const & mi) const + bool addToMathRow(MathRow & mrow, MetricsInfo & mi) const { - MathRow::Element e(MathRow::BEG_ARG); - e.macro = mathMacro_; - e.ar = &mathMacro_->cell(idx_); - mrow.push_back(e); + // macro arguments are in macros + LATTEST(mi.macro_nesting > 0); + if (mi.macro_nesting == 1) + mi.macro_nesting = 0; + + MathRow::Element e_beg(MathRow::BEG_ARG, mi); + e_beg.macro = mathMacro_; + e_beg.ar = &mathMacro_->cell(idx_); + mrow.push_back(e_beg); mathMacro_->macro()->unlock(); - bool const has_contents = mathMacro_->cell(idx_).addToMathRow(mrow, mi); + bool has_contents = mathMacro_->cell(idx_).addToMathRow(mrow, mi); mathMacro_->macro()->lock(); - e.type = MathRow::END_ARG; - mrow.push_back(e); + // if there was no contents, and the contents is editable, + // then we insert a box instead. + if (!has_contents && mi.macro_nesting == 0) { + MathRow::Element e(MathRow::BOX, mi); + e.color = Color_mathline; + mrow.push_back(e); + has_contents = true; + } - if (has_contents) - return true; - // if there was no contents, then we insert the empty macro inset - // instead. - return InsetMath::addToMathRow(mrow, mi); + if (mi.macro_nesting == 0) + mi.macro_nesting = 1; + + MathRow::Element e_end(MathRow::END_ARG, mi); + e_end.macro = mathMacro_; + e_end.ar = &mathMacro_->cell(idx_); + + mrow.push_back(e_end); + + return has_contents; } /// void metrics(MetricsInfo & mi, Dimension & dim) const { + // macro arguments are in macros + LATTEST(mi.macro_nesting > 0); + if (mi.macro_nesting == 1) + mi.macro_nesting = 0; + mathMacro_->macro()->unlock(); mathMacro_->cell(idx_).metrics(mi, dim); @@ -98,6 +119,8 @@ public: def_.metrics(mi, dim); mathMacro_->macro()->lock(); + if (mi.macro_nesting == 0) + mi.macro_nesting = 1; } // write(), normalize(), infoize() and infoize2() are not needed since // MathMacro uses the definition and not the expanded cells. @@ -287,31 +310,42 @@ MathMacro::~MathMacro() } -bool MathMacro::addToMathRow(MathRow & mrow, MetricsInfo const & mi) const +bool MathMacro::addToMathRow(MathRow & mrow, MetricsInfo & mi) const { // set edit mode for which we will have calculated row. // This is the same as what is done in metrics(). d->editing_[mi.base.bv] = editMode(mi.base.bv); - if (displayMode() == MathMacro::DISPLAY_NORMAL - && !d->editing_[mi.base.bv]) { - MathRow::Element e(MathRow::BEG_MACRO); - e.macro = this; + if (displayMode() != MathMacro::DISPLAY_NORMAL + || d->editing_[mi.base.bv]) + return InsetMath::addToMathRow(mrow, mi); + + MathRow::Element e_beg(MathRow::BEG_MACRO, mi); + e_beg.macro = this; + mrow.push_back(e_beg); + + ++mi.macro_nesting; + + d->macro_->lock(); + bool has_contents = d->expanded_.addToMathRow(mrow, mi); + d->macro_->unlock(); + + // if there was no contents and the array is editable, then we + // insert a grey box instead. + if (!has_contents && mi.macro_nesting == 1) { + MathRow::Element e(MathRow::BOX, mi); + e.color = Color_mathmacroblend; mrow.push_back(e); - - d->macro_->lock(); - bool const has_contents = d->expanded_.addToMathRow(mrow, mi); - d->macro_->unlock(); - - e.type = MathRow::END_MACRO; - mrow.push_back(e); - - if (has_contents) - return true; - // if there was no contents, then we insert the empty macro inset - // instead. + has_contents = true; } - return InsetMath::addToMathRow(mrow, mi); + + --mi.macro_nesting; + + MathRow::Element e_end(MathRow::END_MACRO, mi); + e_end.macro = this; + mrow.push_back(e_end); + + return has_contents; } @@ -407,6 +441,9 @@ bool MathMacro::editMetrics(BufferView const * bv) const void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const { + // the macro contents is not editable (except the arguments) + ++mi.macro_nesting; + // set edit mode for which we will have calculated metrics. But only d->editing_[mi.base.bv] = editMode(mi.base.bv); @@ -495,6 +532,9 @@ void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const dim.des += 2; } } + + // restore macro nesting + --mi.macro_nesting; } diff --git a/src/mathed/MathMacro.h b/src/mathed/MathMacro.h index 9c6fdb1ce9..4eb93ba534 100644 --- a/src/mathed/MathMacro.h +++ b/src/mathed/MathMacro.h @@ -39,7 +39,7 @@ public: /// /// If the macro is in normal edit mode, dissolve its contents in /// the row. Otherwise, just insert the inset. - bool addToMathRow(MathRow &, MetricsInfo const & mi) const; + bool addToMathRow(MathRow &, MetricsInfo & mi) const; /// void draw(PainterInfo & pi, int x, int y) const; /// draw selection background diff --git a/src/mathed/MathRow.cpp b/src/mathed/MathRow.cpp index 55513bb923..8b9378bbc6 100644 --- a/src/mathed/MathRow.cpp +++ b/src/mathed/MathRow.cpp @@ -22,6 +22,7 @@ #include "CoordCache.h" #include "MetricsInfo.h" +#include "frontends/FontMetrics.h" #include "frontends/Painter.h" #include "support/debug.h" @@ -35,26 +36,33 @@ using namespace std; namespace lyx { -MathRow::Element::Element(Type t, MathClass const mc) - : type(t), - inset(0), mclass(mc), before(0), after(0), compl_unique_to(0), - macro(0) +MathRow::Element::Element(Type t, MetricsInfo &mi) + : type(t), macro_nesting(mi.macro_nesting), + inset(0), mclass(MC_ORD), before(0), after(0), compl_unique_to(0), + macro(0), color(Color_red) {} -MathRow::MathRow(MetricsInfo const & mi, MathData const * ar) +MathRow::MathRow(MetricsInfo & mi, MathData const * ar) { - if (ar->empty()) - return; - // First there is a dummy element of type "open" - push_back(Element(BEGIN, MC_OPEN)); + push_back(Element(BEGIN, mi)); + back().mclass = MC_OPEN; // Then insert the MathData argument - ar->addToMathRow(*this, mi); + bool const has_contents = ar->addToMathRow(*this, mi); + + // empty arrays are visible when they are editable + // we reserve the necessary space anyway (even if nothing gets drawn) + if (!has_contents) { + Element e(BOX, mi); + e.color = Color_mathline; + push_back(e); + } // Finally there is a dummy element of type "close" - push_back(Element(END, MC_CLOSE)); + push_back(Element(END, mi)); + back().mclass = MC_CLOSE; /* Do spacing only in math mode. This test is a bit clumsy, * but it is used in other places for guessing the current mode. @@ -120,9 +128,9 @@ void MathRow::metrics(MetricsInfo & mi, Dimension & dim) const map dim_macros; map dim_arrays; CoordCache & coords = mi.base.bv->coordCache(); - for (Element const & e : elements_) { Dimension d; + mi.macro_nesting = e.macro_nesting; switch (e.type) { case BEGIN: case END: @@ -131,12 +139,6 @@ void MathRow::metrics(MetricsInfo & mi, Dimension & dim) const e.inset->metrics(mi, d); d.wid += e.before + e.after; coords.insets().add(e.inset, d); - dim += d; - // Now add the dimension to current macros and arguments. - for (auto & dim_macro : dim_macros) - dim_macro.second += d; - for (auto & dim_array : dim_arrays) - dim_array.second += d; break; case BEG_MACRO: e.macro->macro()->lock(); @@ -164,6 +166,19 @@ void MathRow::metrics(MetricsInfo & mi, Dimension & dim) const coords.arrays().add(e.ar, dim_arrays[e.ar]); dim_arrays.erase(e.ar); break; + case BOX: + d = theFontMetrics(mi.base.font).dimension('I'); + d.wid += e.before + e.after; + break; + } + + if (!d.empty()) { + dim += d; + // Now add the dimension to current macros and arguments. + for (auto & dim_macro : dim_macros) + dim_macro.second += d; + for (auto & dim_array : dim_arrays) + dim_array.second += d; } if (e.compl_text.empty()) @@ -180,7 +195,6 @@ void MathRow::draw(PainterInfo & pi, int x, int const y) const { CoordCache & coords = pi.base.bv->coordCache(); for (Element const & e : elements_) { - Dimension d; switch (e.type) { case INSET: { // This is hackish: the math inset does not know that space @@ -211,6 +225,15 @@ void MathRow::draw(PainterInfo & pi, int x, int const y) const if (e.macro->editMetrics(pi.base.bv)) pi.pain.enterMonochromeMode(Color_mathbg, Color_mathmacroblend); break; + case BOX: { + Dimension const d = theFontMetrics(pi.base.font).dimension('I'); + // the box is not visible in non-editable context (except for grey macro boxes). + if (e.macro_nesting == 0 || e.color == Color_mathmacroblend) + pi.pain.rectangle(x + e.before, y - d.ascent(), + d.width(), d.height(), e.color); + x += d.wid; + break; + } case BEGIN: case END: case END_MACRO: @@ -277,6 +300,9 @@ ostream & operator<<(ostream & os, MathRow::Element const & e) case MathRow::END_ARG: os << ")"; break; + case MathRow::BOX: + os << "@"; + break; } return os; } diff --git a/src/mathed/MathRow.h b/src/mathed/MathRow.h index d0260e2e10..3d31e1cbcb 100644 --- a/src/mathed/MathRow.h +++ b/src/mathed/MathRow.h @@ -14,6 +14,8 @@ #include "MathClass.h" +#include "ColorCode.h" + #include "support/docstring.h" #include @@ -51,16 +53,19 @@ public: END_ARG, // a macro argument ends here BEGIN, // dummy element before row END, // dummy element after row + BOX // an empty box }; // An elements, together with its spacing struct Element { /// - Element(Type t = INSET, MathClass const mc = MC_ORD); + Element(Type t, MetricsInfo & mi); /// Classifies the contents of the object Type type; + /// count wether the current mathdata is nested in macro(s) + int macro_nesting; /// When type is INSET /// the math inset @@ -80,6 +85,9 @@ public: // type is BEG_ARG, END_ARG MathData const * ar; + + // type is BOX + ColorCode color; }; /// @@ -105,7 +113,7 @@ public: // create the math row by unwinding all macros in the MathData and // compute the spacings. - MathRow(MetricsInfo const & mi, MathData const * ar); + MathRow(MetricsInfo & mi, MathData const * ar); // void metrics(MetricsInfo & mi, Dimension & dim) const; From 9a9a6a8c8f12cb8b0e713a9a1ed3c5763fa25c66 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Mon, 14 Nov 2016 18:01:56 +0100 Subject: [PATCH 6/7] Skip drawing of markers in non-editable math data There is no reason to reserve pixel space in macros replacement text, which is not editable. This makes macros more compact and eases the writing of lib/symbols. * introduce new InsetMath::drawMarkers and friends that do nothing when nested inside a macro. This required to move macro_nesting inside MetricsBase, and to pass MetricsInfo & to metricsMarkers. * keep track of nesting when drawing rows or macros. --- src/MetricsInfo.cpp | 6 ++-- src/MetricsInfo.h | 4 +-- src/mathed/InsetMath.cpp | 34 ++++++++++++++++++++- src/mathed/InsetMath.h | 9 ++++++ src/mathed/InsetMathBoldSymbol.cpp | 2 +- src/mathed/InsetMathBox.cpp | 8 ++--- src/mathed/InsetMathBrace.cpp | 2 +- src/mathed/InsetMathCancel.cpp | 2 +- src/mathed/InsetMathCancelto.cpp | 2 +- src/mathed/InsetMathClass.cpp | 2 +- src/mathed/InsetMathColor.cpp | 2 +- src/mathed/InsetMathComment.cpp | 2 +- src/mathed/InsetMathDecoration.cpp | 2 +- src/mathed/InsetMathEnsureMath.cpp | 2 +- src/mathed/InsetMathEnv.cpp | 2 +- src/mathed/InsetMathFont.cpp | 2 +- src/mathed/InsetMathFontOld.cpp | 2 +- src/mathed/InsetMathFrac.cpp | 4 +-- src/mathed/InsetMathGrid.cpp | 2 +- src/mathed/InsetMathLefteqn.cpp | 2 +- src/mathed/InsetMathOverset.cpp | 2 +- src/mathed/InsetMathPhantom.cpp | 2 +- src/mathed/InsetMathRoot.cpp | 2 +- src/mathed/InsetMathScript.cpp | 2 +- src/mathed/InsetMathSideset.cpp | 2 +- src/mathed/InsetMathSize.cpp | 2 +- src/mathed/InsetMathSqrt.cpp | 2 +- src/mathed/InsetMathStackrel.cpp | 2 +- src/mathed/InsetMathUnderset.cpp | 2 +- src/mathed/InsetMathXArrow.cpp | 2 +- src/mathed/MathMacro.cpp | 49 +++++++++++++++++++----------- src/mathed/MathMacroTemplate.cpp | 2 +- src/mathed/MathRow.cpp | 5 +-- 33 files changed, 112 insertions(+), 57 deletions(-) diff --git a/src/MetricsInfo.cpp b/src/MetricsInfo.cpp index 02bbab3fd0..fdde05f3d7 100644 --- a/src/MetricsInfo.cpp +++ b/src/MetricsInfo.cpp @@ -38,8 +38,8 @@ namespace lyx { MetricsBase::MetricsBase(BufferView * b, FontInfo f, int w) : bv(b), font(move(f)), style(LM_ST_TEXT), fontname("mathnormal"), - textwidth(w), solid_line_thickness_(1), solid_line_offset_(1), - dotted_line_thickness_(1) + textwidth(w), macro_nesting(0), + solid_line_thickness_(1), solid_line_offset_(1), dotted_line_thickness_(1) { if (lyxrc.zoom >= 200) { // derive the line thickness from zoom factor @@ -88,7 +88,7 @@ Changer MetricsBase::changeFontSet(string const & name, bool cond) MetricsInfo::MetricsInfo(BufferView * bv, FontInfo font, int textwidth, MacroContext const & mc) - : base(bv, font, textwidth), macro_nesting(0), macrocontext(mc) + : base(bv, font, textwidth), macrocontext(mc) {} diff --git a/src/MetricsInfo.h b/src/MetricsInfo.h index 415fe25076..a48b45c563 100644 --- a/src/MetricsInfo.h +++ b/src/MetricsInfo.h @@ -65,6 +65,8 @@ public: std::string fontname; /// This is the width available in pixels int textwidth; + /// count wether the current mathdata is nested in macro(s) + int macro_nesting; /// Temporarily change a full font. Changer changeFontSet(std::string const & font, bool cond = true); @@ -101,8 +103,6 @@ public: /// MetricsBase base; - /// count wether the current mathdata is nested in macro(s) - int macro_nesting; /// The context to resolve macros MacroContext const & macrocontext; }; diff --git a/src/mathed/InsetMath.cpp b/src/mathed/InsetMath.cpp index d2182a5652..cbf33cdf87 100644 --- a/src/mathed/InsetMath.cpp +++ b/src/mathed/InsetMath.cpp @@ -16,13 +16,15 @@ #include "MathRow.h" #include "MathStream.h" +#include "MetricsInfo.h" + #include "support/debug.h" #include "support/docstream.h" #include "support/gettext.h" +#include "support/lassert.h" #include "support/lstrings.h" #include "support/textutils.h" -#include "support/lassert.h" using namespace std; @@ -65,6 +67,36 @@ bool InsetMath::addToMathRow(MathRow & mrow, MetricsInfo & mi) const return true; } +void InsetMath::metricsMarkers(MetricsInfo & mi, Dimension & dim, + int framesize) const +{ + if (!mi.base.macro_nesting) + Inset::metricsMarkers(dim, framesize); +} + + +void InsetMath::metricsMarkers2(MetricsInfo & mi, Dimension & dim, + int framesize) const +{ + if (!mi.base.macro_nesting) + Inset::metricsMarkers2(dim, framesize); +} + + +void InsetMath::drawMarkers(PainterInfo & pi, int x, int y) const +{ + if (!pi.base.macro_nesting) + Inset::drawMarkers(pi, x, y); +} + + +void InsetMath::drawMarkers2(PainterInfo & pi, int x, int y) const +{ + if (!pi.base.macro_nesting) + Inset::drawMarkers2(pi, x, y); +} + + void InsetMath::dump() const { diff --git a/src/mathed/InsetMath.h b/src/mathed/InsetMath.h index f8e70c7293..e8c893bda5 100644 --- a/src/mathed/InsetMath.h +++ b/src/mathed/InsetMath.h @@ -169,6 +169,15 @@ public: /// Add this inset to a math row. Return true if contents got added virtual bool addToMathRow(MathRow &, MetricsInfo & mi) const; + /// draw four angular markers + void drawMarkers(PainterInfo & pi, int x, int y) const; + /// draw two angular markers + void drawMarkers2(PainterInfo & pi, int x, int y) const; + /// add space for markers + void metricsMarkers(MetricsInfo & mi, Dimension & dim, int framesize = 1) const; + /// add space for markers + void metricsMarkers2(MetricsInfo & mi, Dimension & dim, int framesize = 1) const; + /// identifies things that can get scripts virtual bool isScriptable() const { return false; } /// will this get written as a single block in {..} diff --git a/src/mathed/InsetMathBoldSymbol.cpp b/src/mathed/InsetMathBoldSymbol.cpp index 215bd5ff30..ade29f7de1 100644 --- a/src/mathed/InsetMathBoldSymbol.cpp +++ b/src/mathed/InsetMathBoldSymbol.cpp @@ -51,7 +51,7 @@ void InsetMathBoldSymbol::metrics(MetricsInfo & mi, Dimension & dim) const { //Changer dummy = mi.base.changeFontSet("mathbf"); cell(0).metrics(mi, dim); - metricsMarkers(dim); + metricsMarkers(mi, dim); ++dim.wid; // for 'double stroke' } diff --git a/src/mathed/InsetMathBox.cpp b/src/mathed/InsetMathBox.cpp index e9e483c29f..d0ac82f1a6 100644 --- a/src/mathed/InsetMathBox.cpp +++ b/src/mathed/InsetMathBox.cpp @@ -83,7 +83,7 @@ void InsetMathBox::metrics(MetricsInfo & mi, Dimension & dim) const { Changer dummy = mi.base.changeFontSet("textnormal"); cell(0).metrics(mi, dim); - metricsMarkers(dim); + metricsMarkers(mi, dim); } @@ -135,7 +135,7 @@ void InsetMathFBox::metrics(MetricsInfo & mi, Dimension & dim) const { Changer dummy = mi.base.changeFontSet("textnormal"); cell(0).metrics(mi, dim); - metricsMarkers2(dim, 3); // 1 pixel space, 1 frame, 1 space + metricsMarkers2(mi, dim, 3); // 1 pixel space, 1 frame, 1 space } @@ -246,7 +246,7 @@ void InsetMathMakebox::metrics(MetricsInfo & mi, Dimension & dim) const dim.des += 1; } - metricsMarkers(dim); + metricsMarkers(mi, dim); } @@ -360,7 +360,7 @@ InsetMathBoxed::InsetMathBoxed(Buffer * buf) void InsetMathBoxed::metrics(MetricsInfo & mi, Dimension & dim) const { cell(0).metrics(mi, dim); - metricsMarkers2(dim, 3); // 1 pixel space, 1 frame, 1 space + metricsMarkers2(mi, dim, 3); // 1 pixel space, 1 frame, 1 space } diff --git a/src/mathed/InsetMathBrace.cpp b/src/mathed/InsetMathBrace.cpp index 52ccc01b83..6870fa609d 100644 --- a/src/mathed/InsetMathBrace.cpp +++ b/src/mathed/InsetMathBrace.cpp @@ -55,7 +55,7 @@ void InsetMathBrace::metrics(MetricsInfo & mi, Dimension & dim) const dim.asc = max(dim0.asc, t.asc); dim.des = max(dim0.des, t.des); dim.wid = dim0.width() + 2 * t.wid; - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathCancel.cpp b/src/mathed/InsetMathCancel.cpp index dcda5b63ea..0a8aad90fa 100644 --- a/src/mathed/InsetMathCancel.cpp +++ b/src/mathed/InsetMathCancel.cpp @@ -38,7 +38,7 @@ Inset * InsetMathCancel::clone() const void InsetMathCancel::metrics(MetricsInfo & mi, Dimension & dim) const { cell(0).metrics(mi, dim); - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathCancelto.cpp b/src/mathed/InsetMathCancelto.cpp index 6a04cfa246..6170cbd6fa 100644 --- a/src/mathed/InsetMathCancelto.cpp +++ b/src/mathed/InsetMathCancelto.cpp @@ -47,7 +47,7 @@ void InsetMathCancelto::metrics(MetricsInfo & mi, Dimension & dim) const dim.asc = max(dim0.ascent() + 2, dim0.ascent() + dim1.ascent()) + 2 + 8; dim.des = max(dim0.descent() - 2, dim1.descent()) + 2; dim.wid = dim0.width() + dim1.width() + 10; - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathClass.cpp b/src/mathed/InsetMathClass.cpp index 931a68b9a4..0237f250d0 100644 --- a/src/mathed/InsetMathClass.cpp +++ b/src/mathed/InsetMathClass.cpp @@ -31,7 +31,7 @@ Inset * InsetMathClass::clone() const void InsetMathClass::metrics(MetricsInfo & mi, Dimension & dim) const { cell(0).metrics(mi, dim); - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathColor.cpp b/src/mathed/InsetMathColor.cpp index 0a6d0aa6b9..966fe5e99a 100644 --- a/src/mathed/InsetMathColor.cpp +++ b/src/mathed/InsetMathColor.cpp @@ -49,7 +49,7 @@ Inset * InsetMathColor::clone() const void InsetMathColor::metrics(MetricsInfo & mi, Dimension & dim) const { cell(0).metrics(mi, dim); - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathComment.cpp b/src/mathed/InsetMathComment.cpp index ff91991aa8..b8c157b2c2 100644 --- a/src/mathed/InsetMathComment.cpp +++ b/src/mathed/InsetMathComment.cpp @@ -50,7 +50,7 @@ Inset * InsetMathComment::clone() const void InsetMathComment::metrics(MetricsInfo & mi, Dimension & dim) const { cell(0).metrics(mi, dim); - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathDecoration.cpp b/src/mathed/InsetMathDecoration.cpp index cd34d4d241..acc49743fa 100644 --- a/src/mathed/InsetMathDecoration.cpp +++ b/src/mathed/InsetMathDecoration.cpp @@ -122,7 +122,7 @@ void InsetMathDecoration::metrics(MetricsInfo & mi, Dimension & dim) const dim.des += dh_ + 2; } - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathEnsureMath.cpp b/src/mathed/InsetMathEnsureMath.cpp index d1e69fb6c2..382c6fedd8 100644 --- a/src/mathed/InsetMathEnsureMath.cpp +++ b/src/mathed/InsetMathEnsureMath.cpp @@ -41,7 +41,7 @@ void InsetMathEnsureMath::metrics(MetricsInfo & mi, Dimension & dim) const bool really_change_font = isTextFont(mi.base.fontname); Changer dummy = mi.base.changeFontSet("mathnormal", really_change_font); cell(0).metrics(mi, dim); - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathEnv.cpp b/src/mathed/InsetMathEnv.cpp index cc613fd440..7582201e61 100644 --- a/src/mathed/InsetMathEnv.cpp +++ b/src/mathed/InsetMathEnv.cpp @@ -39,7 +39,7 @@ Inset * InsetMathEnv::clone() const void InsetMathEnv::metrics(MetricsInfo & mi, Dimension & dim) const { cell(0).metrics(mi, dim); - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathFont.cpp b/src/mathed/InsetMathFont.cpp index 40623f6ec6..825cf332c4 100644 --- a/src/mathed/InsetMathFont.cpp +++ b/src/mathed/InsetMathFont.cpp @@ -86,7 +86,7 @@ void InsetMathFont::metrics(MetricsInfo & mi, Dimension & dim) const { Changer dummy = mi.base.changeFontSet(font()); cell(0).metrics(mi, dim); - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathFontOld.cpp b/src/mathed/InsetMathFontOld.cpp index 20f3b1d45b..aa574bd1c6 100644 --- a/src/mathed/InsetMathFontOld.cpp +++ b/src/mathed/InsetMathFontOld.cpp @@ -61,7 +61,7 @@ void InsetMathFontOld::metrics(MetricsInfo & mi, Dimension & dim) const Changer dummy = mi.base.changeFontSet(fontname, really_change_font); cell(0).metrics(mi, dim); - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathFrac.cpp b/src/mathed/InsetMathFrac.cpp index 263587ed6e..6254924db8 100644 --- a/src/mathed/InsetMathFrac.cpp +++ b/src/mathed/InsetMathFrac.cpp @@ -207,7 +207,7 @@ void InsetMathFrac::metrics(MetricsInfo & mi, Dimension & dim) const dim.des = dim1.height() + 2 - 5; } } - metricsMarkers(dim); + metricsMarkers(mi, dim); } @@ -582,7 +582,7 @@ void InsetMathBinom::metrics(MetricsInfo & mi, Dimension & dim) const dim.asc = dim0.height() + 4 + 5; dim.des = dim1.height() + 4 - 5; dim.wid = max(dim0.wid, dim1.wid) + 2 * dw(dim.height()) + 4; - metricsMarkers2(dim); + metricsMarkers2(mi, dim); } diff --git a/src/mathed/InsetMathGrid.cpp b/src/mathed/InsetMathGrid.cpp index 053958d1c5..fca8f380d2 100644 --- a/src/mathed/InsetMathGrid.cpp +++ b/src/mathed/InsetMathGrid.cpp @@ -588,7 +588,7 @@ void InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const } */ dim.wid += leftMargin() + rightMargin(); - metricsMarkers2(dim); + metricsMarkers2(mi, dim); // Cache the inset dimension. setDimCache(mi, dim); } diff --git a/src/mathed/InsetMathLefteqn.cpp b/src/mathed/InsetMathLefteqn.cpp index ec4fe7e9b0..176c7431cf 100644 --- a/src/mathed/InsetMathLefteqn.cpp +++ b/src/mathed/InsetMathLefteqn.cpp @@ -34,7 +34,7 @@ void InsetMathLefteqn::metrics(MetricsInfo & mi, Dimension & dim) const dim.asc += 2; dim.des += 2; dim.wid = 4; - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathOverset.cpp b/src/mathed/InsetMathOverset.cpp index f05bbd7df7..b791c2482f 100644 --- a/src/mathed/InsetMathOverset.cpp +++ b/src/mathed/InsetMathOverset.cpp @@ -39,7 +39,7 @@ void InsetMathOverset::metrics(MetricsInfo & mi, Dimension & dim) const dim.wid = max(dim0.width(), dim1.wid) + 4; dim.asc = dim1.asc + dim0.height() + 4; dim.des = dim1.des; - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathPhantom.cpp b/src/mathed/InsetMathPhantom.cpp index 4a190ea760..6d0b88df78 100644 --- a/src/mathed/InsetMathPhantom.cpp +++ b/src/mathed/InsetMathPhantom.cpp @@ -39,7 +39,7 @@ Inset * InsetMathPhantom::clone() const void InsetMathPhantom::metrics(MetricsInfo & mi, Dimension & dim) const { cell(0).metrics(mi, dim); - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathRoot.cpp b/src/mathed/InsetMathRoot.cpp index 2b4b668b9d..aa0a81bce1 100644 --- a/src/mathed/InsetMathRoot.cpp +++ b/src/mathed/InsetMathRoot.cpp @@ -47,7 +47,7 @@ void InsetMathRoot::metrics(MetricsInfo & mi, Dimension & dim) const dim.asc = max(dim0.ascent() + 5, dim1.ascent()) + 2; dim.des = max(dim0.descent() - 5, dim1.descent()) + 2; dim.wid = dim0.width() + dim1.width() + 10; - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathScript.cpp b/src/mathed/InsetMathScript.cpp index 8098a1a2d8..7363c88554 100644 --- a/src/mathed/InsetMathScript.cpp +++ b/src/mathed/InsetMathScript.cpp @@ -333,7 +333,7 @@ void InsetMathScript::metrics(MetricsInfo & mi, Dimension & dim) const dim.des = max(nd, des); } else dim.des = nd; - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathSideset.cpp b/src/mathed/InsetMathSideset.cpp index 37f437db4f..b04eca7730 100644 --- a/src/mathed/InsetMathSideset.cpp +++ b/src/mathed/InsetMathSideset.cpp @@ -221,7 +221,7 @@ void InsetMathSideset::metrics(MetricsInfo & mi, Dimension & dim) const int nd = ndes(bv); int des = dyb(bv) + max(dimbl.descent(), dimbr.descent()); dim.des = max(nd, des); - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathSize.cpp b/src/mathed/InsetMathSize.cpp index 31cdb6a9e8..46ea29b30f 100644 --- a/src/mathed/InsetMathSize.cpp +++ b/src/mathed/InsetMathSize.cpp @@ -45,7 +45,7 @@ void InsetMathSize::metrics(MetricsInfo & mi, Dimension & dim) const { Changer dummy = mi.base.changeStyle(style_); cell(0).metrics(mi, dim); - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathSqrt.cpp b/src/mathed/InsetMathSqrt.cpp index d04eab3abf..3e49abccb2 100644 --- a/src/mathed/InsetMathSqrt.cpp +++ b/src/mathed/InsetMathSqrt.cpp @@ -41,7 +41,7 @@ void InsetMathSqrt::metrics(MetricsInfo & mi, Dimension & dim) const dim.asc += 4; dim.des += 2; dim.wid += 12; - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathStackrel.cpp b/src/mathed/InsetMathStackrel.cpp index 3dda0dae24..e34448a419 100644 --- a/src/mathed/InsetMathStackrel.cpp +++ b/src/mathed/InsetMathStackrel.cpp @@ -77,7 +77,7 @@ void InsetMathStackrel::metrics(MetricsInfo & mi, Dimension & dim) const dim.asc = dim1.ascent() + dim0.height() + 4; dim.des = dim1.descent(); } - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathUnderset.cpp b/src/mathed/InsetMathUnderset.cpp index 46f5277543..2027cf2337 100644 --- a/src/mathed/InsetMathUnderset.cpp +++ b/src/mathed/InsetMathUnderset.cpp @@ -40,7 +40,7 @@ void InsetMathUnderset::metrics(MetricsInfo & mi, Dimension & dim) const dim.wid = max(dim0.width(), dim1.width()) + 4; dim.asc = dim1.ascent(); dim.des = dim1.descent() + dim0.height() + 4; - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/InsetMathXArrow.cpp b/src/mathed/InsetMathXArrow.cpp index 96fdc83aac..a4c1c12c75 100644 --- a/src/mathed/InsetMathXArrow.cpp +++ b/src/mathed/InsetMathXArrow.cpp @@ -51,7 +51,7 @@ void InsetMathXArrow::metrics(MetricsInfo & mi, Dimension & dim) const dim.wid = max(dim0.width(), dim1.width()) + 10; dim.asc = dim0.height() + 10; dim.des = dim1.height(); - metricsMarkers(dim); + metricsMarkers(mi, dim); } diff --git a/src/mathed/MathMacro.cpp b/src/mathed/MathMacro.cpp index a748821113..a5b1803f6d 100644 --- a/src/mathed/MathMacro.cpp +++ b/src/mathed/MathMacro.cpp @@ -71,9 +71,9 @@ public: bool addToMathRow(MathRow & mrow, MetricsInfo & mi) const { // macro arguments are in macros - LATTEST(mi.macro_nesting > 0); - if (mi.macro_nesting == 1) - mi.macro_nesting = 0; + LATTEST(mi.base.macro_nesting > 0); + if (mi.base.macro_nesting == 1) + mi.base.macro_nesting = 0; MathRow::Element e_beg(MathRow::BEG_ARG, mi); e_beg.macro = mathMacro_; @@ -86,15 +86,15 @@ public: // if there was no contents, and the contents is editable, // then we insert a box instead. - if (!has_contents && mi.macro_nesting == 0) { + if (!has_contents && mi.base.macro_nesting == 0) { MathRow::Element e(MathRow::BOX, mi); e.color = Color_mathline; mrow.push_back(e); has_contents = true; } - if (mi.macro_nesting == 0) - mi.macro_nesting = 1; + if (mi.base.macro_nesting == 0) + mi.base.macro_nesting = 1; MathRow::Element e_end(MathRow::END_ARG, mi); e_end.macro = mathMacro_; @@ -107,9 +107,9 @@ public: /// void metrics(MetricsInfo & mi, Dimension & dim) const { // macro arguments are in macros - LATTEST(mi.macro_nesting > 0); - if (mi.macro_nesting == 1) - mi.macro_nesting = 0; + LATTEST(mi.base.macro_nesting > 0); + if (mi.base.macro_nesting == 1) + mi.base.macro_nesting = 0; mathMacro_->macro()->unlock(); mathMacro_->cell(idx_).metrics(mi, dim); @@ -119,8 +119,8 @@ public: def_.metrics(mi, dim); mathMacro_->macro()->lock(); - if (mi.macro_nesting == 0) - mi.macro_nesting = 1; + if (mi.base.macro_nesting == 0) + mi.base.macro_nesting = 1; } // write(), normalize(), infoize() and infoize2() are not needed since // MathMacro uses the definition and not the expanded cells. @@ -138,6 +138,10 @@ public: void octave(OctaveStream & os) const { os << mathMacro_->cell(idx_); } /// void draw(PainterInfo & pi, int x, int y) const { + LATTEST(pi.base.macro_nesting > 0); + if (pi.base.macro_nesting == 1) + pi.base.macro_nesting = 0; + if (mathMacro_->editMetrics(pi.base.bv)) { // The only way a ArgumentProxy can appear is in a cell of the // MathMacro. Moreover the cells are only drawn in the DISPLAY_FOLDED @@ -155,6 +159,9 @@ public: def_.draw(pi, x, y); } else mathMacro_->cell(idx_).draw(pi, x, y); + + if (pi.base.macro_nesting == 0) + pi.base.macro_nesting = 1; } /// size_t idx() const { return idx_; } @@ -324,7 +331,7 @@ bool MathMacro::addToMathRow(MathRow & mrow, MetricsInfo & mi) const e_beg.macro = this; mrow.push_back(e_beg); - ++mi.macro_nesting; + ++mi.base.macro_nesting; d->macro_->lock(); bool has_contents = d->expanded_.addToMathRow(mrow, mi); @@ -332,14 +339,14 @@ bool MathMacro::addToMathRow(MathRow & mrow, MetricsInfo & mi) const // if there was no contents and the array is editable, then we // insert a grey box instead. - if (!has_contents && mi.macro_nesting == 1) { + if (!has_contents && mi.base.macro_nesting == 1) { MathRow::Element e(MathRow::BOX, mi); e.color = Color_mathmacroblend; mrow.push_back(e); has_contents = true; } - --mi.macro_nesting; + --mi.base.macro_nesting; MathRow::Element e_end(MathRow::END_MACRO, mi); e_end.macro = this; @@ -442,7 +449,7 @@ bool MathMacro::editMetrics(BufferView const * bv) const void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const { // the macro contents is not editable (except the arguments) - ++mi.macro_nesting; + ++mi.base.macro_nesting; // set edit mode for which we will have calculated metrics. But only d->editing_[mi.base.bv] = editMode(mi.base.bv); @@ -457,7 +464,7 @@ void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const dim.wid += bsdim.width() + 1; dim.asc = max(bsdim.ascent(), dim.ascent()); dim.des = max(bsdim.descent(), dim.descent()); - metricsMarkers(dim); + metricsMarkers(mi, dim); } else if (lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_LIST && d->editing_[mi.base.bv]) { // Macro will be edited in a old-style list mode here: @@ -497,7 +504,7 @@ void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const dim.asc += 1; dim.des += 1; dim.wid += 2; - metricsMarkers2(dim); + metricsMarkers2(mi, dim); } else { LBUFERR(d->macro_); @@ -534,7 +541,7 @@ void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const } // restore macro nesting - --mi.macro_nesting; + --mi.base.macro_nesting; } @@ -703,6 +710,9 @@ void MathMacro::draw(PainterInfo & pi, int x, int y) const dim.height() - 2, Color_mathmacroframe); drawMarkers2(pi, expx, expy); } else { + // the macro contents is not editable (except the arguments) + ++pi.base.macro_nesting; + bool drawBox = lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_INLINE_BOX; bool upshape = currentMode() == TEXT_MODE; Changer dummy = pi.base.font.changeShape(upshape ? UP_SHAPE @@ -737,8 +747,11 @@ void MathMacro::draw(PainterInfo & pi, int x, int y) const } else d->expanded_.draw(pi, expx, expy); + --pi.base.macro_nesting; + if (!drawBox) drawMarkers(pi, x, y); + } // edit mode changed? diff --git a/src/mathed/MathMacroTemplate.cpp b/src/mathed/MathMacroTemplate.cpp index cf7427205d..b4d1c1cfcb 100644 --- a/src/mathed/MathMacroTemplate.cpp +++ b/src/mathed/MathMacroTemplate.cpp @@ -269,7 +269,7 @@ Inset * InsetMathWrapper::clone() const void InsetMathWrapper::metrics(MetricsInfo & mi, Dimension & dim) const { value_->metrics(mi, dim); - //metricsMarkers2(dim); + //metricsMarkers2(mi, dim); } diff --git a/src/mathed/MathRow.cpp b/src/mathed/MathRow.cpp index 8b9378bbc6..3dbfda6974 100644 --- a/src/mathed/MathRow.cpp +++ b/src/mathed/MathRow.cpp @@ -37,7 +37,7 @@ namespace lyx { MathRow::Element::Element(Type t, MetricsInfo &mi) - : type(t), macro_nesting(mi.macro_nesting), + : type(t), macro_nesting(mi.base.macro_nesting), inset(0), mclass(MC_ORD), before(0), after(0), compl_unique_to(0), macro(0), color(Color_red) {} @@ -130,7 +130,7 @@ void MathRow::metrics(MetricsInfo & mi, Dimension & dim) const CoordCache & coords = mi.base.bv->coordCache(); for (Element const & e : elements_) { Dimension d; - mi.macro_nesting = e.macro_nesting; + mi.base.macro_nesting = e.macro_nesting; switch (e.type) { case BEGIN: case END: @@ -195,6 +195,7 @@ void MathRow::draw(PainterInfo & pi, int x, int const y) const { CoordCache & coords = pi.base.bv->coordCache(); for (Element const & e : elements_) { + pi.base.macro_nesting = e.macro_nesting; switch (e.type) { case INSET: { // This is hackish: the math inset does not know that space From 7335ee8ea3a5c39b5011571c0d7719174ad13a6a Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Mon, 14 Nov 2016 15:33:51 +0100 Subject: [PATCH 7/7] Cleanup of lib/symbols Try as far as possible to use the same definitions as in the LaTeX files. An example of that is the definition and subsequent use of \joinrel, \relbar and \Relbar. This is mostly Guillaume's work. --- lib/symbols | 90 +++++++++++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/lib/symbols b/lib/symbols index 481aa8186c..aadcd0d006 100644 --- a/lib/symbols +++ b/lib/symbols @@ -300,8 +300,7 @@ spadesuit cmsy 127 170 mathord ♠ # We define lyxnot as mathrel in order to have proper alignment lyxnot cmsy 54 47 mathrel / hiddensymbol iffont cmsy -# 10mu is the extra space added to relation operators -\def\not{\lyxnot\kern-20mu} +\def\not{\lyxnot\mathrel{\kern-11mu}} else \def\not{\kern4mu\lyxnot\kern-19mu} endif @@ -669,7 +668,7 @@ hslash msb 125 0 mathord ℏ hbar msb 126 0 mathord ℏ backepsilon msb 127 0 mathrel ϶ -lyxbar cmsy 161 0 mathord — hiddensymbol +lyxbar cmsy 161 0 mathrel — hiddensymbol lyxminus cmsy 161 0 mathbin — hiddensymbol lyxplus cmr 43 43 mathbin + hiddensymbol lyxeq cmr 61 61 mathord = hiddensymbol @@ -795,7 +794,7 @@ APLup wasy 0 0 x x APLdown wasy 70 0 x x APLinput wasy 125 0 x x APLcomment wasy 127 0 x x -\def\APLinv{\div\kern-17.9mu\APLbox} wasysym +\def\APLinv{\mathord{\div\kern-13.9mu\APLbox}} wasysym APLuparrowbox wasy 110 0 x ⍐ APLdownarrowbox wasy 111 0 x ⍗ APLleftarrowbox wasy 112 0 x ⍇ @@ -976,15 +975,15 @@ bignplus stmry 112 0 mathop x stmaryrd # caution: named hugenpl #Largerrbracketbot stmry 126 0 mathclose x stmaryrd # only in the font, not the .sty caution: named Hugerrbracketbot in the font #rrbracketex stmry 127 0 mathclose x stmaryrd # only in the font, not the .sty caution: named Hugerrbracketex in the font -\def\varcopyright{c\kern-14mu\varbigcirc} stmaryrd -\def\longarrownot{\kern5.5mu\arrownot\kern-5.5mu} stmaryrd -\def\Longarrownot{\kern5.5mu\Arrownot\kern-5.5mu} stmaryrd -\def\Mapsto{\Mapstochar\kern-9mu\Rightarrow} stmaryrd +\def\varcopyright{\mathord{c\kern-11mu\varbigcirc}} stmaryrd +\def\longarrownot{\mathrel{\kern5.5mu}\arrownot\mathrel{\kern-5.5mu}} stmaryrd +\def\Longarrownot{\mathrel{\kern5.5mu}\Arrownot\mathrel{\kern-5.5mu}} stmaryrd +\def\Mapsto{\Mapstochar\mathrel{\kern-2mu}\Rightarrow} stmaryrd \def\mapsfrom{\leftarrow\kern-9mu\mapsfromchar} stmaryrd \def\Mapsfrom{\Leftarrow\kern-9mu\Mapsfromchar} stmaryrd -\def\Longmapsto{\Mapstochar\kern-7mu\Longrightarrow} stmaryrd -\def\longmapsfrom{\longleftarrow\kern-7mu\mapsfromchar} stmaryrd -\def\Longmapsfrom{\Longleftarrow\kern-7mu\Mapsfromchar} stmaryrd +\def\Longmapsto{\Mapstochar\Longrightarrow} stmaryrd +\def\longmapsfrom{\longleftarrow\mapsfromchar} stmaryrd +\def\Longmapsfrom{\Longleftarrow\mathrel{\kern1mu}\Mapsfromchar} stmaryrd # symbols from the mhchem package, all of them are equivalent to a math symbol # mhchem is not loaded because these commands can only be used inside @@ -1115,21 +1114,21 @@ pod lyxblacktext 0 0 func x amsmath # mathtools.sty -vcentcolon cmr 58 58 mathrel : mathtools -ordinarycolon cmr 58 58 mathrel : mathtools -\def\dblcolon{\vcentcolon\kern-10.9mu\vcentcolon} mathrel :: mathtools -\def\coloneqq{\vcentcolon\kern-11.2mu=} mathrel ≔ mathtools -\def\Coloneqq{\dblcolon\kern-11.2mu=} mathrel ::= mathtools -\def\coloneq{\vcentcolon\kern-11.2mu-} mathrel :- mathtools -\def\Coloneq{\dblcolon\kern-11.2mu-} mathrel ::- mathtools -\def\eqqcolon{=\kern-11.2mu\vcentcolon} mathrel ≕ mathtools -\def\Eqqcolon{=\kern-11.2mu\dblcolon} mathrel =:: mathtools -\def\eqcolon{-\kern-11.2mu\vcentcolon} mathrel -: mathtools -\def\Eqcolon{-\kern-11.2mu\dblcolon} mathrel -:: mathtools -\def\colonapprox{\vcentcolon\kern-11.2mu\approx} mathrel :≈ mathtools -\def\Colonapprox{\dblcolon\kern-11.2mu\approx} mathrel ::≈ mathtools -\def\colonsim{\vcentcolon\kern-11.2mu\sim} mathrel :∼ mathtools -\def\Colonsim{\dblcolon\kern-11.2mu\sim} mathrel ::∼ mathtools +vcentcolon cmr 58 58 mathrel : mathtools +ordinarycolon cmr 58 58 mathrel : mathtools +\def\dblcolon{\vcentcolon\mathrel{\kern-0.9mu}\vcentcolon} mathrel :: mathtools +\def\coloneqq{\vcentcolon\mathrel{\kern-1.2mu}=} mathrel ≔ mathtools +\def\Coloneqq{\dblcolon\mathrel{\kern-1.2mu}=} mathrel ::= mathtools +\def\coloneq{\vcentcolon\mathrel{\kern-1.2mu}\mathrel{-}} mathrel :- mathtools +\def\Coloneq{\dblcolon\mathrel{\kern-1.2mu}\mathrel{-}} mathrel ::- mathtools +\def\eqqcolon{=\mathrel{\kern-1.2mu}\vcentcolon} mathrel ≕ mathtools +\def\Eqqcolon{=\mathrel{\kern-1.2mu}\dblcolon} mathrel =:: mathtools +\def\eqcolon{\mathrel{-}\mathrel{\kern-1.2mu}\vcentcolon} mathrel -: mathtools +\def\Eqcolon{\mathrel{-}\mathrel{\kern-1.2mu}\dblcolon} mathrel -:: mathtools +\def\colonapprox{\vcentcolon\mathrel{\kern-1.2mu}\approx} mathrel :≈ mathtools +\def\Colonapprox{\dblcolon\mathrel{\kern-1.2mu}\approx} mathrel ::≈ mathtools +\def\colonsim{\vcentcolon\mathrel{\kern-1.2mu}\sim} mathrel :∼ mathtools +\def\Colonsim{\dblcolon\mathrel{\kern-1.2mu}\sim} mathrel ::∼ mathtools # @@ -1144,50 +1143,53 @@ ordinarycolon cmr 58 58 mathrel : mathtools \def\notin{\not\in} mathrel ∉ \def\slash{/} -\def\longleftrightarrow{\leftarrow\kern-12.5mu\rightarrow} -\def\Longleftrightarrow{\Leftarrow\kern-12.5mu\Rightarrow} -\def\iff{\Leftarrow\kern-12.5mu\Rightarrow} +\def\joinrel{\mathrel{\kern-3mu}} +\def\relbar{\lyxbar} +\def\Relbar{\mathrel{=}} +\def\longleftrightarrow{\leftarrow\joinrel\rightarrow} +\def\Longleftrightarrow{\Leftarrow\joinrel\Rightarrow} +\def\iff{\Leftarrow\joinrel\Rightarrow} \def\doteq{\stackrel{\cdot}{=}} iffont cmsy -\def\longrightarrow{\lyxbar\kern-11mu\rightarrow} mathrel ⟶ -\def\longleftarrow{\leftarrow\kern-11mu\lyxbar} mathrel ⟵ -\def\Longrightarrow{\lyxeq\kern-9.5mu\Rightarrow} mathrel ⟹ -\def\Longleftarrow{\Leftarrow\kern-9.5mu\lyxeq} mathrel ⟸ +\def\longrightarrow{\relbar\joinrel\rightarrow} mathrel ⟶ +\def\longleftarrow{\leftarrow\joinrel\relbar} mathrel ⟵ +\def\Longrightarrow{\Relbar\joinrel\Rightarrow} mathrel ⟹ +\def\Longleftarrow{\Leftarrow\joinrel\Relbar} mathrel ⟸ \def\implies{\Longrightarrow} mathrel ⟹ amsmath \def\impliedby{\Longleftarrow} mathrel ⟸ amsmath -\def\mapsto{\mapstochar\kern-9mu\rightarrow} mathrel ↤ -\def\longmapsto{\mapstochar\kern-6mu\lyxbar\kern-11mu\rightarrow} mathrel ⟻ -\def\models{\vert\kern-3mu\lyxeq} mathrel ⊨ +\def\mapsto{\mapstochar\mathrel{\kern-2mu}\rightarrow} mathrel ↤ +\def\longmapsto{\mapstochar\joinrel\relbar\joinrel\rightarrow} mathrel ⟻ +\def\models{\mathrel{\vert}\joinrel\Relbar} mathrel ⊨ else \def\implies{=>} mathrel ⟹ amsmath \def\impliedby{<=} mathrel ⟸ amsmath endif iffont cmm -\def\hookrightarrow{\lhook\kern-12mu\rightarrow} mathrel ↪ -\def\hookleftarrow{\leftarrow\kern-12mu\rhook} mathrel ↩ -\def\bowtie{\triangleright\kern-10mu\triangleleft} mathrel ⋈ +\def\hookrightarrow{\lhook\joinrel\rightarrow} mathrel ↪ +\def\hookleftarrow{\leftarrow\joinrel\rhook} mathrel ↩ +\def\bowtie{\mathrel\triangleright\joinrel\mathrel\triangleleft} mathrel ⋈ endif iffont msa -\def\dashrightarrow{\lyxdabar\lyxdabar\lyxright} mathrel ⤏ amssymb -\def\dashleftarrow{\lyxleft\lyxdabar\lyxdabar} mathrel ⤎ amssymb +\def\dashrightarrow{\mathrel{\lyxdabar\lyxdabar\lyxright}} mathrel ⤏ amssymb +\def\dashleftarrow{\mathrel{\lyxleft\lyxdabar\lyxdabar}} mathrel ⤎ amssymb else \def\dashrightarrow{- - \rightarrow} mathrel ⤏ amssymb \def\dashleftarrow{\leftarrow{} - -} mathrel ⤎ amssymb endif \def\dasharrow{\dashrightarrow} mathrel ⤏ amssymb iffont msb -\def\Join{\ltimes\kern-22mu\rtimes} amssymb +\def\Join{\mathrel{\ltimes\kern-13.5mu\rtimes}} amssymb else \def\Join{|x|} amssymb endif -# Fixme: latin-1 chars in text file +# FIXME: UTF-8 chars in text file \def\AA{\AA}{Å} textmode Å amstext,lyxmathsym \def\O{\O}{Ø} textmode Ø amstext,lyxmathsym iffont cmsy # The \sim is placed too high... -\def\cong{\stackrel{_\sim}{=}} mathrel ≅ +\def\cong{\stackrel{\sim}{=}} mathrel ≅ lyxsurd cmsy 112 0 mathord √ \def\surd{^\lyxsurd} mathord √ \def\textdegree{\kern-1mu^{\circ}\kern-4mu} textmode ° textcomp,amstext,lyxmathsym