X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2FInsetMathHull.cpp;h=0f7e9a85df7fbd1b39362121b8f326772999a8f9;hb=ebe6612e2661f49dcfae6103f056c27afd47751f;hp=538eee163a213c9ea6a464ac46bd36bdcbf494ed;hpb=29cebc7fb0bb3ab5acf2759ff4b964657ad59495;p=lyx.git diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp index 538eee163a..0f7e9a85df 100644 --- a/src/mathed/InsetMathHull.cpp +++ b/src/mathed/InsetMathHull.cpp @@ -14,6 +14,9 @@ #include "InsetMathChar.h" #include "InsetMathColor.h" +#include "InsetMathFrac.h" +#include "InsetMathNest.h" +#include "InsetMathScript.h" #include "MathExtern.h" #include "MathFactory.h" #include "MathStream.h" @@ -32,10 +35,14 @@ #include "LaTeXFeatures.h" #include "LyXRC.h" #include "MacroTable.h" +#include "InsetMathMacro.h" +#include "InsetMathMacroTemplate.h" +#include "MetricsInfo.h" #include "output_xhtml.h" #include "Paragraph.h" #include "ParIterator.h" #include "sgml.h" +#include "TexRow.h" #include "TextClass.h" #include "TextPainter.h" #include "TocBackend.h" @@ -52,11 +59,12 @@ #include "frontends/Painter.h" #include "support/convert.h" -#include "support/lassert.h" #include "support/debug.h" -#include "support/filetools.h" #include "support/gettext.h" +#include "support/filetools.h" +#include "support/lassert.h" #include "support/lstrings.h" +#include "support/RefChanger.h" #include @@ -73,17 +81,25 @@ namespace { int getCols(HullType type) { switch (type) { - case hullEqnArray: - return 3; - case hullAlign: - case hullFlAlign: - case hullAlignAt: - case hullXAlignAt: - case hullXXAlignAt: - return 2; - default: - return 1; + case hullEqnArray: + return 3; + case hullAlign: + case hullFlAlign: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + return 2; + case hullUnknown: + case hullNone: + case hullSimple: + case hullEquation: + case hullMultline: + case hullGather: + case hullRegexp: + return 1; } + // avoid warning + return 0; } @@ -92,7 +108,7 @@ namespace { size_t firstRelOp(MathData const & ar) { for (MathData::const_iterator it = ar.begin(); it != ar.end(); ++it) - if ((*it)->isRelOp()) + if ((*it)->mathClass() == MC_REL) return it - ar.begin(); return ar.size(); } @@ -104,7 +120,38 @@ namespace { } -} // end anon namespace + // writes a preamble for underlined or struck out math display + void writeMathdisplayPreamble(WriteStream & os) + { + if (os.strikeoutMath()) { + if (os.ulemCmd() == WriteStream::UNDERLINE) + os << "\\raisebox{-\\belowdisplayshortskip}{" + "\\lyxmathsout{\\parbox[b]{\\linewidth}{"; + else + os << "\\lyxmathsout{\\parbox{\\linewidth}{"; + } else if (os.ulemCmd() == WriteStream::UNDERLINE) + os << "\\raisebox{-\\belowdisplayshortskip}{" + "\\parbox[b]{\\linewidth}{"; + else if (os.ulemCmd() == WriteStream::STRIKEOUT) + os << "\\parbox{\\linewidth}{"; + } + + + // writes a postamble for underlined or struck out math display + void writeMathdisplayPostamble(WriteStream & os) + { + if (os.strikeoutMath()) { + if (os.ulemCmd() == WriteStream::UNDERLINE) + os << "}"; + os << "}}\\\\\n"; + } else if (os.ulemCmd() == WriteStream::UNDERLINE) + os << "}}\\\\\n"; + else if (os.ulemCmd() == WriteStream::STRIKEOUT) + os << "}\\\\\n"; + } + + +} // namespace HullType hullType(docstring const & s) @@ -121,38 +168,39 @@ HullType hullType(docstring const & s) if (s == "gather") return hullGather; if (s == "flalign") return hullFlAlign; if (s == "regexp") return hullRegexp; - lyxerr << "unknown hull type '" << to_utf8(s) << "'" << endl; - return HullType(-1); + lyxerr << "unknown hull type '" << to_utf8(s) << "'" << endl; + return hullUnknown; } docstring hullName(HullType type) { switch (type) { - case hullNone: return from_ascii("none"); - case hullSimple: return from_ascii("simple"); - case hullEquation: return from_ascii("equation"); - case hullEqnArray: return from_ascii("eqnarray"); - case hullAlign: return from_ascii("align"); - case hullAlignAt: return from_ascii("alignat"); - case hullXAlignAt: return from_ascii("xalignat"); - case hullXXAlignAt: return from_ascii("xxalignat"); - case hullMultline: return from_ascii("multline"); - case hullGather: return from_ascii("gather"); - case hullFlAlign: return from_ascii("flalign"); - case hullRegexp: return from_ascii("regexp"); - default: - lyxerr << "unknown hull type '" << type << "'" << endl; - return from_ascii("none"); + case hullNone: return from_ascii("none"); + case hullSimple: return from_ascii("simple"); + case hullEquation: return from_ascii("equation"); + case hullEqnArray: return from_ascii("eqnarray"); + case hullAlign: return from_ascii("align"); + case hullAlignAt: return from_ascii("alignat"); + case hullXAlignAt: return from_ascii("xalignat"); + case hullXXAlignAt: return from_ascii("xxalignat"); + case hullMultline: return from_ascii("multline"); + case hullGather: return from_ascii("gather"); + case hullFlAlign: return from_ascii("flalign"); + case hullRegexp: return from_ascii("regexp"); + case hullUnknown: + lyxerr << "unknown hull type" << endl; + break; } + return from_ascii("none"); } static InsetLabel * dummy_pointer = 0; InsetMathHull::InsetMathHull(Buffer * buf) : InsetMathGrid(buf, 1, 1), type_(hullNone), numbered_(1, NUMBER), - numbers_(1, empty_docstring()), label_(1, dummy_pointer), - preview_(new RenderPreview(this)), use_preview_(false) + numbers_(1, empty_docstring()), label_(1, dummy_pointer), + preview_(new RenderPreview(this)) { //lyxerr << "sizeof InsetMath: " << sizeof(InsetMath) << endl; //lyxerr << "sizeof MetricsInfo: " << sizeof(MetricsInfo) << endl; @@ -166,8 +214,8 @@ InsetMathHull::InsetMathHull(Buffer * buf) InsetMathHull::InsetMathHull(Buffer * buf, HullType type) : InsetMathGrid(buf, getCols(type), 1), type_(type), numbered_(1, NUMBER), - numbers_(1, empty_docstring()), label_(1, dummy_pointer), - preview_(new RenderPreview(this)), use_preview_(false) + numbers_(1, empty_docstring()), label_(1, dummy_pointer), + preview_(new RenderPreview(this)) { buffer_ = buf; initMath(); @@ -232,7 +280,7 @@ void InsetMathHull::setBuffer(Buffer & buffer) namespace { const char * counters_to_save[] = {"section", "chapter"}; unsigned int const numcnts = sizeof(counters_to_save)/sizeof(char *); -} +} // namespace void InsetMathHull::updateBuffer(ParIterator const & it, UpdateType utype) @@ -268,8 +316,12 @@ void InsetMathHull::updateBuffer(ParIterator const & it, UpdateType utype) counter_map[eqstr] = cnts.value(eqstr); for (size_t i = 0; i != label_.size(); ++i) { if (numbered(i)) { - cnts.step(eqstr, utype); - numbers_[i] = cnts.theCounter(eqstr, lang); + Paragraph const & par = it.paragraph(); + if (!par.isDeleted(it.pos())) { + cnts.step(eqstr, utype); + numbers_[i] = cnts.theCounter(eqstr, lang); + } else + numbers_[i] = from_ascii("#"); } else numbers_[i] = empty_docstring(); } @@ -286,7 +338,8 @@ void InsetMathHull::updateBuffer(ParIterator const & it, UpdateType utype) } -void InsetMathHull::addToToc(DocIterator const & pit, bool output_active) const +void InsetMathHull::addToToc(DocIterator const & pit, bool output_active, + UpdateType utype, TocBackend & backend) const { if (!buffer_) { //FIXME: buffer_ should be set at creation for this inset! Problem is @@ -295,21 +348,48 @@ void InsetMathHull::addToToc(DocIterator const & pit, bool output_active) const return; } - Toc & toc = buffer().tocBackend().toc("equation"); - + TocBuilder & b = backend.builder("equation"); + // compute first and last item + row_type first = nrows(); + for (row_type row = 0; row != nrows(); ++row) + if (numbered(row)) { + first = row; + break; + } + if (first == nrows()) + // no equation + return; + row_type last = nrows() - 1; + for (; last != 0; --last) + if (numbered(last)) + break; + // add equation numbers + b.pushItem(pit, docstring(), output_active); + if (first != last) + b.argumentItem(bformat(from_ascii("(%1$s-%2$s)"), + numbers_[first], numbers_[last])); for (row_type row = 0; row != nrows(); ++row) { if (!numbered(row)) continue; if (label_[row]) - label_[row]->addToToc(pit, output_active); - toc.push_back(TocItem(pit, 0, nicelabel(row), output_active)); + label_[row]->addToToc(pit, output_active, utype, backend); + docstring label = nicelabel(row); + if (first == last) + // this is the only equation + b.argumentItem(label); + else { + // insert as sub-items + b.pushItem(pit, label, output_active); + b.pop(); + } } + b.pop(); } Inset * InsetMathHull::editXY(Cursor & cur, int x, int y) { - if (use_preview_) { + if (previewState(&cur.bv())) { edit(cur, true); return this; } @@ -319,9 +399,26 @@ Inset * InsetMathHull::editXY(Cursor & cur, int x, int y) InsetMath::mode_type InsetMathHull::currentMode() const { - if (type_ == hullNone) + switch (type_) { + case hullNone: return UNDECIDED_MODE; + // definitely math mode ... + case hullUnknown: + case hullSimple: + case hullEquation: + case hullMultline: + case hullGather: + case hullEqnArray: + case hullAlign: + case hullFlAlign: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + case hullRegexp: + return MATH_MODE; + } + // avoid warning return MATH_MODE; } @@ -342,73 +439,79 @@ bool InsetMathHull::idxLast(Cursor & cur) const } +// FIXME: InsetMathGrid should be changed to let the real column alignment be +// given by a virtual method like displayColAlign, because the values produced +// by defaultColAlign can be invalidated by lfuns such as add-column. For the +// moment the values produced by defaultColAlign are not used, notably because +// alignment is not implemented in the LyXHTML output. char InsetMathHull::defaultColAlign(col_type col) { - if (type_ == hullEqnArray) - return "rcl"[col]; - if (type_ == hullMultline) - return 'c'; - if (type_ == hullGather) - return 'c'; - if (type_ >= hullAlign) - return "rl"[col & 1]; - return 'c'; + return colAlign(type_, col); } -char InsetMathHull::displayColAlign(col_type col, row_type row) const +char InsetMathHull::displayColAlign(idx_type idx) const { - if (type_ == hullMultline) { - if (row == 0) + switch (type_) { + case hullMultline: { + row_type const r = row(idx); + if (r == 0) return 'l'; - if (row == nrows() - 1) + if (r == nrows() - 1) return 'r'; + return 'c'; } - return InsetMathGrid::displayColAlign(col, row); + case hullEqnArray: + case hullGather: + case hullAlign: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + case hullFlAlign: + return colAlign(type_, col(idx)); + default: + break; + } + return InsetMathGrid::displayColAlign(idx); +} + + +int InsetMathHull::displayColSpace(col_type col) const +{ + return colSpace(type_, col); } +// FIXME: same comment as for defaultColAlign applies. int InsetMathHull::defaultColSpace(col_type col) { - if (type_ == hullAlign || type_ == hullAlignAt) - return 0; - if (type_ == hullXAlignAt) - return (col & 1) ? 20 : 0; - if (type_ == hullXXAlignAt || type_ == hullFlAlign) - return (col & 1) ? 40 : 0; - return 0; + return colSpace(type_, col); } -docstring InsetMathHull::standardFont() const +string InsetMathHull::standardFont() const { - docstring font_name; switch (type_) { case hullRegexp: - font_name = from_ascii("texttt"); - break; + return "texttt"; case hullNone: - font_name = from_ascii("lyxnochange"); - break; + return "lyxnochange"; default: - font_name = from_ascii("mathnormal"); + return "mathnormal"; } - return font_name; } ColorCode InsetMathHull::standardColor() const { - ColorCode color; switch (type_) { case hullRegexp: case hullNone: - color = Color_foreground; - break; + return Color_foreground; + default: - color = Color_math; + return Color_math; } - return color; } @@ -443,13 +546,12 @@ void InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const if (display()) dim.des += displayMargin(); } - // Cache the inset dimension. - setDimCache(mi, dim); return; } - FontSetChanger dummy1(mi.base, standardFont()); - StyleChanger dummy2(mi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT); + Changer dummy1 = mi.base.changeFontSet(standardFont()); + Changer dummy2 = mi.base.font.changeStyle(display() ? LM_ST_DISPLAY + : LM_ST_TEXT); // let the cells adjust themselves InsetMathGrid::metrics(mi, dim); @@ -460,26 +562,18 @@ void InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const } if (numberedType()) { - FontSetChanger dummy(mi.base, from_ascii("mathbf")); + Changer dummy = mi.base.changeFontSet("mathrm"); int l = 0; for (row_type row = 0; row < nrows(); ++row) l = max(l, mathed_string_width(mi.base.font, nicelabel(row))); if (l) - dim.wid += 30 + l; + // Value was hardcoded to 30 pixels + dim.wid += Length(0.3, Length::IN).inPixels(mi.base) + l; } - if (type_ == hullRegexp) - dim.wid += 2; - // make it at least as high as the current font - int asc = 0; - int des = 0; - math_font_max_dim(mi.base.font, asc, des); - dim.asc = max(dim.asc, asc); - dim.des = max(dim.des, des); - // Cache the inset dimension. - // FIXME: This will overwrite InsetMathGrid dimension, is that OK? - setDimCache(mi, dim); + // reserve some space for marker. + dim.wid += 2; } @@ -502,14 +596,33 @@ ColorCode InsetMathHull::backgroundColor(PainterInfo const & pi) const } +void InsetMathHull::drawMarkers(PainterInfo & pi, int x, int y) const +{ + ColorCode pen_color = mouseHovered(pi.base.bv) || editing(pi.base.bv)? + Color_mathframe : Color_mathcorners; + // If the corners have the same color as the background, do not paint them. + if (lcolor.getX11Name(Color_mathbg) == lcolor.getX11Name(pen_color)) + return; + + Inset::drawMarkers(pi, x, y); + Dimension const dim = dimension(*pi.base.bv); + int const t = x + dim.width() - 1; + int const a = y - dim.ascent(); + pi.pain.line(x, a + 3, x, a, pen_color); + pi.pain.line(t, a + 3, t, a, pen_color); + pi.pain.line(x, a, x + 3, a, pen_color); + pi.pain.line(t - 3, a, t, a, pen_color); +} + + void InsetMathHull::drawBackground(PainterInfo & pi, int x, int y) const { Dimension const dim = dimension(*pi.base.bv); if (previewTooSmall(dim)) { - pi.pain.fillRectangle(x, y - 2 * ERROR_FRAME_WIDTH, + pi.pain.fillRectangle(x, y - 2 * ERROR_FRAME_WIDTH, dim.wid, dim.asc + dim.des, backgroundColor(pi)); return; - } + } pi.pain.fillRectangle(x + 1, y - dim.asc + 1, dim.wid - 2, dim.asc + dim.des - 1, pi.backgroundColor(this)); } @@ -518,16 +631,17 @@ void InsetMathHull::drawBackground(PainterInfo & pi, int x, int y) const void InsetMathHull::draw(PainterInfo & pi, int x, int y) const { BufferView const * const bv = pi.base.bv; - use_preview_ = previewState(bv); + Dimension const dim = dimension(*bv); - if (type_ == hullRegexp) { - Dimension const dim = dimension(*bv); - pi.pain.rectangle(x + 1, y - dim.ascent() + 1, - dim.width() - 2, dim.height() - 2, Color_regexpframe); - } + if (type_ == hullRegexp) + pi.pain.rectangle(x + 2, y - dim.ascent() + 1, + dim.width() - 3, dim.height() - 2, Color_regexpframe); - if (use_preview_) { - Dimension const dim = dimension(*bv); + if (previewState(bv)) { + // Do not draw change tracking cue if taken care of by RowPainter + // already. + Changer dummy = !canPaintChange(*bv) ? make_change(pi.change_, Change()) + : Changer(); if (previewTooSmall(dim)) { // we have an extra frame preview_->draw(pi, x + ERROR_FRAME_WIDTH, y); @@ -535,29 +649,52 @@ void InsetMathHull::draw(PainterInfo & pi, int x, int y) const // one pixel gap in front preview_->draw(pi, x + 1, y); } - setPosCache(pi, x, y); return; } ColorCode color = pi.selected && lyxrc.use_system_colors ? Color_selectiontext : standardColor(); bool const really_change_color = pi.base.font.color() == Color_none; - ColorChanger dummy0(pi.base.font, color, really_change_color); - FontSetChanger dummy1(pi.base, standardFont()); - StyleChanger dummy2(pi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT); + Changer dummy0 = really_change_color ? pi.base.font.changeColor(color) + : Changer(); + Changer dummy1 = pi.base.changeFontSet(standardFont()); + Changer dummy2 = pi.base.font.changeStyle(display() ? LM_ST_DISPLAY + : LM_ST_TEXT); + + int xmath = x; + BufferParams::MathNumber const math_number = buffer().params().getMathNumber(); + if (numberedType() && math_number == BufferParams::LEFT) { + Changer dummy = pi.base.changeFontSet("mathrm"); + int l = 0; + for (row_type row = 0; row < nrows(); ++row) + l = max(l, mathed_string_width(pi.base.font, nicelabel(row))); + + if (l) + // Value was hardcoded to 30 pixels + xmath += Length(0.3, Length::IN).inPixels(pi.base) + l; + } - InsetMathGrid::draw(pi, x + 1, y); + InsetMathGrid::draw(pi, xmath + 1, y); + drawMarkers(pi, x, y); if (numberedType()) { - int const xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20; + Changer dummy = pi.base.changeFontSet("mathrm"); for (row_type row = 0; row < nrows(); ++row) { int const yy = y + rowinfo_[row].offset_; - FontSetChanger dummy(pi.base, from_ascii("mathrm")); docstring const nl = nicelabel(row); - pi.draw(xx, yy, nl); + if (math_number == BufferParams::LEFT) + pi.draw(x, yy, nl); + else { + int l = mathed_string_width(pi.base.font, nl); + pi.draw(x + dim.wid - l, yy, nl); + } } } - setPosCache(pi, x, y); + + // drawing change line + if (canPaintChange(*bv)) + pi.change_.paintCue(pi, x + 1, y + 1 - dim.asc, + x + dim.wid, y + dim.des); } @@ -567,7 +704,8 @@ void InsetMathHull::metricsT(TextMetricsInfo const & mi, Dimension & dim) const InsetMathGrid::metricsT(mi, dim); } else { odocstringstream os; - WriteStream wi(os, false, true, WriteStream::wsDefault); + otexrowstream ots(os); + WriteStream wi(ots, false, true, WriteStream::wsDefault); write(wi); dim.wid = os.str().size(); dim.asc = 1; @@ -582,7 +720,8 @@ void InsetMathHull::drawT(TextPainter & pain, int x, int y) const InsetMathGrid::drawT(pain, x, y); } else { odocstringstream os; - WriteStream wi(os, false, true, WriteStream::wsDefault); + otexrowstream ots(os); + WriteStream wi(ots, false, true, WriteStream::wsDefault); write(wi); pain.draw(x, y, os.str().c_str()); } @@ -600,7 +739,8 @@ static docstring latexString(InsetMathHull const & inset) static Encoding const * encoding = 0; if (inset.isBufferValid()) encoding = &(inset.buffer().params().encoding()); - WriteStream wi(ls, false, true, WriteStream::wsPreview, encoding); + otexrowstream ots(ls); + WriteStream wi(ots, false, true, WriteStream::wsPreview, encoding); inset.write(wi); return ls.str(); } @@ -622,6 +762,64 @@ void InsetMathHull::addPreview(DocIterator const & inset_pos, } +void InsetMathHull::usedMacros(MathData const & md, DocIterator const & pos, + MacroNameSet & macros, MacroNameSet & defs) const +{ + MacroNameSet::iterator const end = macros.end(); + + for (size_t i = 0; i < md.size(); ++i) { + InsetMathMacro const * mi = md[i].nucleus()->asMacro(); + InsetMathMacroTemplate const * mt = md[i].nucleus()->asMacroTemplate(); + InsetMathScript const * si = md[i].nucleus()->asScriptInset(); + InsetMathFracBase const * fi = md[i].nucleus()->asFracBaseInset(); + InsetMathGrid const * gi = md[i].nucleus()->asGridInset(); + InsetMathNest const * ni = md[i].nucleus()->asNestInset(); + if (mi) { + // Look for macros in the arguments of this macro. + for (idx_type idx = 0; idx < mi->nargs(); ++idx) + usedMacros(mi->cell(idx), pos, macros, defs); + // Make sure this is a macro defined in the document + // (as we also spot the macros in the symbols file) + // or that we have not already accounted for it. + docstring const name = mi->name(); + if (macros.find(name) == end) + continue; + macros.erase(name); + // Look for macros in the definition of this macro. + MathData ar(pos.buffer()); + MacroData const * data = + pos.buffer()->getMacro(name, pos, true); + if (data) { + odocstringstream macro_def; + data->write(macro_def, true); + macro_def << endl; + defs.insert(macro_def.str()); + asArray(data->definition(), ar); + } + usedMacros(ar, pos, macros, defs); + } else if (mt) { + MathData ar(pos.buffer()); + asArray(mt->definition(), ar); + usedMacros(ar, pos, macros, defs); + } else if (si) { + if (!si->nuc().empty()) + usedMacros(si->nuc(), pos, macros, defs); + if (si->hasDown()) + usedMacros(si->down(), pos, macros, defs); + if (si->hasUp()) + usedMacros(si->up(), pos, macros, defs); + } else if (fi || gi) { + idx_type nidx = fi ? fi->nargs() : gi->nargs(); + for (idx_type idx = 0; idx < nidx; ++idx) + usedMacros(fi ? fi->cell(idx) : gi->cell(idx), + pos, macros, defs); + } else if (ni) { + usedMacros(ni->cell(0), pos, macros, defs); + } + } +} + + void InsetMathHull::preparePreview(DocIterator const & pos, bool forexport) const { @@ -635,16 +833,32 @@ void InsetMathHull::preparePreview(DocIterator const & pos, // collect macros at this position MacroNameSet macros; buffer->listMacroNames(macros); - MacroNameSet::iterator it = macros.begin(); - MacroNameSet::iterator end = macros.end(); - odocstringstream macro_preamble; - for (; it != end; ++it) { - MacroData const * data = buffer->getMacro(*it, pos, true); - if (data) { - data->write(macro_preamble, true); - macro_preamble << endl; - } - } + + // collect definitions only for the macros used in this inset + MacroNameSet defs; + for (idx_type idx = 0; idx < nargs(); ++idx) + usedMacros(cell(idx), pos, macros, defs); + + MacroNameSet::iterator it = defs.begin(); + MacroNameSet::iterator end = defs.end(); + docstring macro_preamble; + for (; it != end; ++it) + macro_preamble.append(*it); + + // set the font series and size for this snippet + DocIterator dit = pos.getInnerText(); + Paragraph const & par = dit.paragraph(); + Font font = par.getFontSettings(buffer->params(), dit.pos()); + font.fontInfo().realize(par.layout().font); + string const lsize = font.latexSize(); + docstring setfont; + docstring endfont; + if (font.fontInfo().series() == BOLD_SERIES) { + setfont += from_ascii("\\textbf{"); + endfont += '}'; + } + if (lsize != "normalsize" && !prefixIs(lsize, "error")) + setfont += from_ascii("\\" + lsize + '\n'); docstring setcnt; if (forexport && haveNumbers()) { @@ -667,8 +881,8 @@ void InsetMathHull::preparePreview(DocIterator const & pos, '{' + convert(num) + '}'; } } - docstring const snippet = macro_preamble.str() + - setcnt + latexString(*this); + docstring const snippet = macro_preamble + setfont + setcnt + + latexString(*this) + endfont; LYXERR(Debug::MACROS, "Preview snippet: " << snippet); preview_->addPreview(snippet, *buffer, forexport); } @@ -750,20 +964,22 @@ bool InsetMathHull::numbered(row_type row) const bool InsetMathHull::ams() const { switch (type_) { - case hullAlign: - case hullFlAlign: - case hullMultline: - case hullGather: - case hullAlignAt: - case hullXAlignAt: - case hullXXAlignAt: - return true; - case hullNone: - case hullSimple: - case hullEquation: - case hullEqnArray: - case hullRegexp: - break; + case hullAlign: + case hullFlAlign: + case hullMultline: + case hullGather: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + return true; + case hullUnknown: + case hullRegexp: + return false; + case hullNone: + case hullSimple: + case hullEquation: + case hullEqnArray: + break; } for (size_t row = 0; row < numbered_.size(); ++row) if (numbered_[row] == NOTAG) @@ -772,23 +988,90 @@ bool InsetMathHull::ams() const } +bool InsetMathHull::outerDisplay() const +{ + switch (type_) { + case hullEquation: + case hullEqnArray: + case hullAlign: + case hullFlAlign: + case hullGather: + case hullMultline: + return true; + case hullNone: + case hullSimple: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + case hullUnknown: + case hullRegexp: + break; + } + return false; +} + + Inset::DisplayType InsetMathHull::display() const { - if (type_ == hullSimple || type_ == hullNone || type_ == hullRegexp) + switch (type_) { + case hullUnknown: + case hullSimple: + case hullNone: + case hullRegexp: return Inline; + case hullEqnArray: + case hullAlign: + case hullFlAlign: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + case hullEquation: + case hullMultline: + case hullGather: + if (buffer().params().is_math_indent) + return AlignLeft; + else + return AlignCenter; + } + // avoid warning return AlignCenter; } + +int InsetMathHull::indent(BufferView const & bv) const +{ + // FIXME: set this in the textclass. This value is what the article class uses. + static Length default_indent(2.5, Length::EM); + if (display() != Inline && buffer().params().is_math_indent) { + Length const & len = buffer().params().getMathIndent(); + if (len.empty()) + return bv.inPixels(default_indent); + else + return bv.inPixels(len); + } else + return Inset::indent(bv); +} + + bool InsetMathHull::numberedType() const { - if (type_ == hullNone) - return false; - if (type_ == hullSimple) - return false; - if (type_ == hullXXAlignAt) - return false; - if (type_ == hullRegexp) + switch (type_) { + case hullUnknown: + case hullNone: + case hullSimple: + case hullXXAlignAt: + case hullRegexp: return false; + case hullEqnArray: + case hullAlign: + case hullFlAlign: + case hullAlignAt: + case hullXAlignAt: + case hullEquation: + case hullMultline: + case hullGather: + break; + } for (row_type row = 0; row < nrows(); ++row) if (numbered(row)) return true; @@ -804,14 +1087,17 @@ void InsetMathHull::validate(LaTeXFeatures & features) const if (type_ == hullRegexp) { features.require("color"); - string frcol = lcolor.getLaTeXName(Color_regexpframe); - string bgcol = "white"; + docstring frcol = from_utf8(lcolor.getLaTeXName(Color_regexpframe)); + docstring bgcol = from_ascii("white"); features.addPreambleSnippet( - string("\\newcommand{\\regexp}[1]{\\fcolorbox{") - + frcol + string("}{") - + bgcol + string("}{\\ensuremath{\\mathtt{#1}}}}")); + "\\newcommand{\\regexp}[1]{\\fcolorbox{" + + frcol + "}{" + + bgcol + "}{\\ensuremath{\\mathtt{#1}}}}"); features.addPreambleSnippet( - string("\\newcommand{\\endregexp}{}")); + from_ascii("\\newcommand{\\endregexp}{}")); + } else if (outerDisplay() && features.inDeletedInset() + && !features.mustProvide("ct-dvipost")) { + features.require("ct-tikz-math-sout"); } // Validation is necessary only if not using AMS math. @@ -843,16 +1129,22 @@ void InsetMathHull::header_write(WriteStream & os) const break; case hullSimple: + if (os.ulemCmd()) + os << "\\mbox{"; os << '$'; + os.startOuterRow(); if (cell(0).empty()) os << ' '; break; case hullEquation: + writeMathdisplayPreamble(os); + os << "\n"; + os.startOuterRow(); if (n) - os << "\n\\begin{equation" << star(n) << "}\n"; + os << "\\begin{equation" << star(n) << "}\n"; else - os << "\n\\[\n"; + os << "\\[\n"; break; case hullEqnArray: @@ -860,17 +1152,24 @@ void InsetMathHull::header_write(WriteStream & os) const case hullFlAlign: case hullGather: case hullMultline: - os << "\n\\begin{" << hullName(type_) << star(n) << "}\n"; + writeMathdisplayPreamble(os); + os << "\n"; + os.startOuterRow(); + os << "\\begin{" << hullName(type_) << star(n) << "}\n"; break; case hullAlignAt: case hullXAlignAt: - os << "\n\\begin{" << hullName(type_) << star(n) << '}' + os << "\n"; + os.startOuterRow(); + os << "\\begin{" << hullName(type_) << star(n) << '}' << '{' << static_cast((ncols() + 1)/2) << "}\n"; break; case hullXXAlignAt: - os << "\n\\begin{" << hullName(type_) << '}' + os << "\n"; + os.startOuterRow(); + os << "\\begin{" << hullName(type_) << '}' << '{' << static_cast((ncols() + 1)/2) << "}\n"; break; @@ -878,8 +1177,10 @@ void InsetMathHull::header_write(WriteStream & os) const os << "\\regexp{"; break; - default: - os << "\n\\begin{unknown" << star(n) << "}\n"; + case hullUnknown: + os << "\n"; + os.startOuterRow(); + os << "\\begin{unknown" << star(n) << "}\n"; break; } } @@ -896,27 +1197,42 @@ void InsetMathHull::footer_write(WriteStream & os) const case hullSimple: os << '$'; + if (os.ulemCmd()) + os << "}"; break; case hullEquation: + os << "\n"; + os.startOuterRow(); if (n) - os << "\n\\end{equation" << star(n) << "}\n"; + os << "\\end{equation" << star(n) << "}\n"; else - os << "\n\\]\n"; + os << "\\]\n"; + writeMathdisplayPostamble(os); break; case hullEqnArray: case hullAlign: case hullFlAlign: - case hullAlignAt: - case hullXAlignAt: case hullGather: case hullMultline: - os << "\n\\end{" << hullName(type_) << star(n) << "}\n"; + os << "\n"; + os.startOuterRow(); + os << "\\end{" << hullName(type_) << star(n) << "}\n"; + writeMathdisplayPostamble(os); + break; + + case hullAlignAt: + case hullXAlignAt: + os << "\n"; + os.startOuterRow(); + os << "\\end{" << hullName(type_) << star(n) << "}\n"; break; case hullXXAlignAt: - os << "\n\\end{" << hullName(type_) << "}\n"; + os << "\n"; + os.startOuterRow(); + os << "\\end{" << hullName(type_) << "}\n"; break; case hullRegexp: @@ -924,10 +1240,35 @@ void InsetMathHull::footer_write(WriteStream & os) const os << "\\endregexp{}}"; break; - default: - os << "\n\\end{unknown" << star(n) << "}\n"; + case hullUnknown: + os << "\n"; + os.startOuterRow(); + os << "\\end{unknown" << star(n) << "}\n"; + break; + } +} + + +bool InsetMathHull::allowsTabularFeatures() const +{ + switch (type_) { + case hullEqnArray: + case hullAlign: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + case hullFlAlign: + case hullMultline: + case hullGather: + return true; + case hullNone: + case hullSimple: + case hullEquation: + case hullRegexp: + case hullUnknown: break; } + return false; } @@ -1132,10 +1473,46 @@ void InsetMathHull::setType(HullType type) } +bool InsetMathHull::isMutable(HullType type) +{ + switch (type) { + case hullNone: + case hullSimple: + case hullEquation: + case hullEqnArray: + case hullAlign: + case hullFlAlign: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + case hullMultline: + case hullGather: + return true; + case hullUnknown: + case hullRegexp: + return false; + } + // avoid warning + return false; +} + + void InsetMathHull::mutate(HullType newtype) { //lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'" << endl; + if (newtype == type_) + return; + + // This guards the algorithm below it, which is designed with certain types + // in mind. + if (!isMutable(newtype) || !isMutable(type_)) { + lyxerr << "mutation from '" << to_utf8(hullName(type_)) + << "' to '" << to_utf8(hullName(newtype)) + << "' not implemented" << endl; + return; + } + // we try to move along the chain // none <-> simple <-> equation <-> eqnarray -> *align* -> multline, gather -+ // ^ | @@ -1144,22 +1521,14 @@ void InsetMathHull::mutate(HullType newtype) // directly supported because it handles labels and numbering for // "down mutation". - if (newtype == type_) { - // done - } - - else if (newtype < hullNone) { - // unknown type - dump(); - } - - else if (type_ == hullNone) { + switch (type_) { + case hullNone: setType(hullSimple); numbered(0, false); mutate(newtype); - } + break; - else if (type_ == hullSimple) { + case hullSimple: if (newtype == hullNone) { setType(hullNone); numbered(0, false); @@ -1168,95 +1537,138 @@ void InsetMathHull::mutate(HullType newtype) numbered(0, label_[0] ? true : false); mutate(newtype); } - } + break; - else if (type_ == hullEquation) { - if (newtype < type_) { + case hullEquation: + switch (newtype) { + case hullNone: + case hullSimple: setType(hullSimple); numbered(0, false); mutate(newtype); - } else if (newtype == hullEqnArray) { + break; + case hullEqnArray: // split it "nicely" on the first relop splitTo3Cols(); setType(hullEqnArray); - } else if (newtype == hullMultline || newtype == hullGather) { + break; + case hullMultline: + case hullGather: setType(newtype); - } else { + break; + default: + // *align* // split it "nicely" splitTo2Cols(); setType(hullAlign); mutate(newtype); + break; } - } + break; - else if (type_ == hullEqnArray) { - if (newtype < type_) { + case hullEqnArray: + switch (newtype) { + case hullNone: + case hullSimple: + case hullEquation: glueall(newtype); mutate(newtype); - } else { // align & Co. + break; + default: + // align & Co. changeCols(2); setType(hullAlign); mutate(newtype); + break; } - } + break; - else if (type_ == hullAlign || type_ == hullAlignAt || - type_ == hullXAlignAt || type_ == hullFlAlign) { - if (newtype < hullAlign) { + case hullAlign: + case hullAlignAt: + case hullXAlignAt: + case hullFlAlign: + switch (newtype) { + case hullNone: + case hullSimple: + case hullEquation: + case hullEqnArray: changeCols(3); setType(hullEqnArray); mutate(newtype); - } else if (newtype == hullGather || newtype == hullMultline) { + break; + case hullGather: + case hullMultline: changeCols(1); setType(newtype); - } else if (newtype == hullXXAlignAt) { + break; + case hullXXAlignAt: for (row_type row = 0; row < nrows(); ++row) numbered(row, false); setType(newtype); - } else { + break; + default: setType(newtype); + break; } - } + break; - else if (type_ == hullXXAlignAt) { + case hullXXAlignAt: for (row_type row = 0; row < nrows(); ++row) numbered(row, false); - if (newtype < hullAlign) { + switch (newtype) { + case hullNone: + case hullSimple: + case hullEquation: + case hullEqnArray: changeCols(3); setType(hullEqnArray); mutate(newtype); - } else if (newtype == hullGather || newtype == hullMultline) { + break; + case hullGather: + case hullMultline: changeCols(1); setType(newtype); - } else { + break; + default: setType(newtype); + break; } - } + break; - else if (type_ == hullMultline || type_ == hullGather) { - if (newtype == hullGather || newtype == hullMultline) + case hullMultline: + case hullGather: + switch (newtype) { + case hullGather: + case hullMultline: setType(newtype); - else if (newtype == hullAlign || newtype == hullFlAlign || - newtype == hullAlignAt || newtype == hullXAlignAt) { + break; + case hullAlign: + case hullFlAlign: + case hullAlignAt: + case hullXAlignAt: splitTo2Cols(); setType(newtype); - } else if (newtype == hullXXAlignAt) { + break; + case hullXXAlignAt: splitTo2Cols(); for (row_type row = 0; row < nrows(); ++row) numbered(row, false); setType(newtype); - } else { + break; + default: + // first we mutate to EqnArray splitTo3Cols(); setType(hullEqnArray); mutate(newtype); + break; } - } + break; - else { - lyxerr << "mutation from '" << to_utf8(hullName(type_)) - << "' to '" << to_utf8(hullName(newtype)) - << "' not implemented" << endl; - } + default: + // we passed the guard so we should not be here + LASSERT("Mutation not implemented, but should have been.", return); + break; + }// switch } @@ -1283,7 +1695,6 @@ docstring InsetMathHull::eolString(row_type row, bool fragile, bool latex, return res + InsetMathGrid::eolString(row, fragile, latex, last_eoln); } - void InsetMathHull::write(WriteStream & os) const { ModeSpecifier specifier(os, MATH_MODE); @@ -1303,7 +1714,7 @@ void InsetMathHull::normalize(NormalStream & os) const void InsetMathHull::infoize(odocstream & os) const { - os << "Type: " << hullName(type_); + os << bformat(_("Type: %1$s"), hullName(type_)); } @@ -1335,7 +1746,12 @@ void InsetMathHull::doExtern(Cursor & cur, FuncRequest & func) } // only inline, display or eqnarray math is allowed - if (getType() > hullEqnArray) { + switch (getType()) { + case hullSimple: + case hullEquation: + case hullEqnArray: + break; + default: frontend::Alert::warning(_("Bad math environment"), _("Computation cannot be performed for AMS " "math environments.\nChange the math " @@ -1420,7 +1836,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd) if (type_ == hullSimple || type_ == hullEquation) { cur.recordUndoInset(); bool const align = - cur.bv().buffer().params().use_package("amsmath") == BufferParams::package_on; + cur.bv().buffer().params().use_package("amsmath") != BufferParams::package_off; mutate(align ? hullAlign : hullEqnArray); // mutate() may change labels and such. cur.forceBufferUpdate(); @@ -1582,12 +1998,25 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_MATH_DISPLAY: { cur.recordUndoInset(); mutate(type_ == hullSimple ? hullEquation : hullSimple); - cur.idx() = 0; - cur.pos() = cur.lastpos(); - //cur.dispatched(FINISHED); + // if the cursor is in a cell that got merged, move it to + // start of the hull inset. + if (cur.idx() > 0) { + cur.idx() = 0; + cur.pos() = 0; + } + if (cur.pos() > cur.lastpos()) + cur.pos() = cur.lastpos(); + break; } + case LFUN_TABULAR_FEATURE: + if (!allowsTabularFeatures()) + cur.undispatched(); + else + InsetMathGrid::doDispatch(cur, cmd); + break; + default: InsetMathGrid::doDispatch(cur, cmd); break; @@ -1595,6 +2024,21 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd) } +namespace { + +bool allowDisplayMath(Cursor const & cur) +{ + LATTEST(cur.depth() > 1); + Cursor tmpcur = cur; + tmpcur.pop(); + FuncStatus status; + FuncRequest cmd(LFUN_MATH_DISPLAY); + return tmpcur.getStatus(cmd, status) && status.enabled(); +} + +} // namespace + + bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & status) const { @@ -1619,32 +2063,15 @@ bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd, case LFUN_MATH_MUTATE: { HullType const ht = hullType(cmd.argument()); status.setOnOff(type_ == ht); - status.setEnabled(true); + status.setEnabled(isMutable(ht) && isMutable(type_)); - if (ht != hullSimple) { - Cursor tmpcur = cur; - while (!tmpcur.empty()) { - InsetCode code = tmpcur.inset().lyxCode(); - if (code == BOX_CODE) { - return true; - } else if (code == TABULAR_CODE) { - FuncRequest tmpcmd(LFUN_MATH_DISPLAY); - if (tmpcur.getStatus(tmpcmd, status) && !status.enabled()) - return true; - } - tmpcur.pop_back(); - } - } + if (ht != hullSimple && status.enabled()) + status.setEnabled(allowDisplayMath(cur)); return true; } case LFUN_MATH_DISPLAY: { - bool enable = true; - if (cur.depth() > 1) { - Inset const & in = cur[cur.depth()-2].inset(); - if (in.lyxCode() == SCRIPT_CODE) - enable = display() != Inline; - } - status.setEnabled(enable); + status.setEnabled(display() != Inline || allowDisplayMath(cur)); + status.setOnOff(display() != Inline); return true; } @@ -1701,13 +2128,10 @@ bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd, } return InsetMathGrid::getStatus(cur, cmd, status); - case LFUN_INSET_MODIFY: { - istringstream is(to_utf8(cmd.argument())); - string s; - is >> s; - if (s != "tabular") - return InsetMathGrid::getStatus(cur, cmd, status); - is >> s; + case LFUN_TABULAR_FEATURE: { + if (!allowsTabularFeatures()) + return false; + string s = cmd.getArg(0); if (!rowChangeOK() && (s == "append-row" || s == "delete-row" @@ -1728,16 +2152,6 @@ bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd, status.setEnabled(false); return true; } - if ((type_ == hullSimple - || type_ == hullEquation - || type_ == hullNone) && - (s == "add-hline-above" || s == "add-hline-below")) { - status.message(bformat( - from_utf8(N_("Can't add horizontal grid lines in '%1$s'")), - hullName(type_))); - status.setEnabled(false); - return true; - } if (s == "add-vline-left" || s == "add-vline-right") { status.message(bformat( from_utf8(N_("Can't add vertical grid lines in '%1$s'")), @@ -1757,9 +2171,24 @@ bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd, default: return InsetMathGrid::getStatus(cur, cmd, status); } +} + + +int InsetMathHull::leftMargin() const +{ + return (getType() == hullSimple) ? 0 : InsetMathGrid::leftMargin(); +} + + +int InsetMathHull::rightMargin() const +{ + return (getType() == hullSimple) ? 0 : InsetMathGrid::rightMargin(); +} + - // This cannot really happen, but inserted to shut-up gcc - return InsetMathGrid::getStatus(cur, cmd, status); +int InsetMathHull::border() const +{ + return (getType() == hullSimple) ? 0 : InsetMathGrid::border(); } @@ -1835,7 +2264,7 @@ void InsetMathHull::revealCodes(Cursor & cur) const if (!cur.inMathed()) return; odocstringstream os; - cur.info(os); + cur.info(os, false); cur.message(os.str()); /* // write something to the minibuffer @@ -1913,7 +2342,8 @@ bool InsetMathHull::searchForward(BufferView * bv, string const & str, void InsetMathHull::write(ostream & os) const { odocstringstream oss; - WriteStream wi(oss, false, false, WriteStream::wsDefault); + otexrowstream ots(oss); + WriteStream wi(ots, false, false, WriteStream::wsDefault); oss << "Formula "; write(wi); os << to_utf8(oss.str()); @@ -1955,8 +2385,9 @@ int InsetMathHull::plaintext(odocstringstream & os, } odocstringstream oss; + otexrowstream ots(oss); Encoding const * const enc = encodings.fromLyXName("utf8"); - WriteStream wi(oss, false, true, WriteStream::wsDefault, enc); + WriteStream wi(ots, false, true, WriteStream::wsDefault, enc); // Fix Bug #6139 if (type_ == hullRegexp) @@ -1969,7 +2400,7 @@ int InsetMathHull::plaintext(odocstringstream & os, // and do not include the newline. if (op.for_toc || op.for_tooltip || oss.str().size() >= max_length) break; - if (r < nrows() - 1) + if (r < nrows() - 1) wi << "\n"; } } @@ -1996,12 +2427,13 @@ int InsetMathHull::docbook(odocstream & os, OutputParams const & runparams) cons ++ms.tab(); ms.cr(); ms.os() << '<' << bname << '>'; odocstringstream ls; + otexstream ols(ls); if (runparams.flavor == OutputParams::XML) { ms << MTag("alt role='tex' "); // Workaround for db2latex: db2latex always includes equations with // \ensuremath{} or \begin{display}\end{display} // so we strip LyX' math environment - WriteStream wi(ls, false, false, WriteStream::wsDefault, runparams.encoding); + WriteStream wi(ols, false, false, WriteStream::wsDefault, runparams.encoding); InsetMathGrid::write(wi); ms << from_utf8(subst(subst(to_utf8(ls.str()), "&", "&"), "<", "<")); ms << ETag("alt"); @@ -2011,12 +2443,9 @@ int InsetMathHull::docbook(odocstream & os, OutputParams const & runparams) cons InsetMathGrid::mathmlize(ms); ms << ETag("math"); } else { - TexRow texrow; - texrow.reset(); - otexstream ols(ls, texrow); ms << MTag("alt role='tex'"); latex(ols, runparams); - res = texrow.rows(); + res = ols.texrow().rows(); ms << from_utf8(subst(subst(to_utf8(ls.str()), "&", "&"), "<", "<")); ms << ETag("alt"); } @@ -2221,7 +2650,9 @@ docstring InsetMathHull::xhtml(XHTMLStream & xs, OutputParams const & op) const // ) // but what follows is equivalent, since we'll enter only if either (a) we // tried and failed with MathML or HTML or (b) didn't try yet at all but - // aren't doing LaTeX, in which case we are doing Images. + // aren't doing LaTeX. + // + // so this is for Images. if (!success && mathtype != BufferParams::LaTeX) { graphics::PreviewImage const * pimage = 0; if (!op.dryrun) { @@ -2248,7 +2679,7 @@ docstring InsetMathHull::xhtml(XHTMLStream & xs, OutputParams const & op) const string const tag = (getType() == hullSimple) ? "span" : "div"; xs << html::CR() - << html::StartTag(tag) + << html::StartTag(tag, "style = \"text-align: center;\"") << html::CompTag("img", "src=\"" + filename + "\" alt=\"Mathematical Equation\"") << html::EndTag(tag) << html::CR(); @@ -2263,7 +2694,8 @@ docstring InsetMathHull::xhtml(XHTMLStream & xs, OutputParams const & op) const // Unfortunately, we cannot use latexString() because we do not want // $...$ or whatever. odocstringstream ls; - WriteStream wi(ls, false, true, WriteStream::wsPreview); + otexrowstream ots(ls); + WriteStream wi(ots, false, true, WriteStream::wsPreview); ModeSpecifier specifier(wi, MATH_MODE); mathAsLatex(wi); docstring const latex = ls.str(); @@ -2290,11 +2722,13 @@ void InsetMathHull::toString(odocstream & os) const } -void InsetMathHull::forOutliner(docstring & os, size_t) const +void InsetMathHull::forOutliner(docstring & os, size_t const, bool const) const { odocstringstream ods; OutputParams op(0); op.for_toc = true; + // FIXME: this results in spilling TeX into the LyXHTML output since the + // outliner is used to generate the LyXHTML list of figures/etc. plaintext(ods, op); os += ods.str(); } @@ -2311,4 +2745,12 @@ void InsetMathHull::recordLocation(DocIterator const & di) docit_ = di; } + +bool InsetMathHull::canPaintChange(BufferView const &) const +{ + // We let RowPainter do it seamlessly for inline insets + return display() != Inline; +} + + } // namespace lyx