X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2FMathData.cpp;h=610a3e20eb64ebae7e237f77baa6c67ccf8ff5bf;hb=43b16548b473d93b26489d8c4bbd9bf1e903a35f;hp=2a36e551aaebc5dc8a516b1998ae9f61c22325aa;hpb=e8f480e7c22ae29804ff0c386c54e86c9b72d3ce;p=lyx.git diff --git a/src/mathed/MathData.cpp b/src/mathed/MathData.cpp index 2a36e551aa..610a3e20eb 100644 --- a/src/mathed/MathData.cpp +++ b/src/mathed/MathData.cpp @@ -17,7 +17,7 @@ #include "InsetMathFont.h" #include "InsetMathScript.h" #include "MacroTable.h" -#include "MathMacro.h" +#include "InsetMathMacro.h" #include "MathStream.h" #include "MathSupport.h" #include "MetricsInfo.h" @@ -27,16 +27,17 @@ #include "BufferView.h" #include "CoordCache.h" #include "Cursor.h" +#include "Dimension.h" #include "mathed/InsetMathUnknown.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" #include @@ -46,11 +47,18 @@ namespace lyx { MathData::MathData(Buffer * buf, const_iterator from, const_iterator to) - : base_type(from, to), minasc_(0), mindes_(0), slevel_(0), - sshift_(0), kerning_(0), buffer_(buf) + : base_type(from, to), buffer_(buf) {} +void MathData::setBuffer(Buffer & b) +{ + buffer_ = &b; + for (MathAtom & at : *this) + at.nucleus()->setBuffer(b); +} + + MathAtom & MathData::operator[](pos_type pos) { LBUFERR(pos < size()); @@ -211,18 +219,14 @@ bool MathData::contains(MathData const & ar) const } -void MathData::touch() const -{ -} - - bool MathData::addToMathRow(MathRow & mrow, MetricsInfo & mi) const { bool has_contents = false; BufferView * bv = mi.base.bv; MathData * ar = const_cast(this); ar->updateMacros(&bv->cursor(), mi.macrocontext, - InternalUpdate); + InternalUpdate, mi.base.macro_nesting); + // FIXME: for completion, try to insert the relevant data in the // mathrow (like is done for text rows). We could add a pair of @@ -262,44 +266,91 @@ bool isInside(DocIterator const & it, MathData const & ar, #endif -void MathData::metrics(MetricsInfo & mi, Dimension & dim) const +void MathData::metrics(MetricsInfo & mi, Dimension & dim, bool tight) const { frontend::FontMetrics const & fm = theFontMetrics(mi.base.font); - dim = fm.dimension('I'); - int xascent = fm.dimension('x').ascent(); - if (xascent >= dim.asc) - xascent = (2 * dim.asc) / 3; + BufferView * bv = mi.base.bv; + int const Iascent = fm.dimension('I').ascent(); + int xascent = fm.xHeight(); + if (xascent >= Iascent) + xascent = (2 * Iascent) / 3; minasc_ = xascent; mindes_ = (3 * xascent) / 4; slevel_ = (4 * xascent) / 5; sshift_ = xascent / 4; MathRow mrow(mi, this); - mrow_cache_[mi.base.bv] = mrow; mrow.metrics(mi, dim); - kerning_ = mrow.kerning(mi.base.bv); - // Cache the dimension. - mi.base.bv->coordCache().arrays().add(this, dim); + // Set a minimal ascent/descent for the cell + if (tight) + // FIXME: this is the minimal ascent seen empirically, check + // what the TeXbook says. + dim.asc = max(dim.asc, fm.xHeight()); + else { + dim.asc = max(dim.asc, fm.maxAscent()); + dim.des = max(dim.des, fm.maxDescent()); + } + + // This is one of the the few points where the drawing font is known, + // so that we can set the caret vertical dimensions. + mrow.caret_dim.asc = min(dim.asc, fm.maxAscent()); + mrow.caret_dim.des = min(dim.des, fm.maxDescent()); + mrow.caret_dim.wid = fm.lineWidth(); + + /// do the same for math cells linearized in the row + MathRow caret_row = MathRow(mrow.caret_dim); + for (auto const & e : mrow) + if (e.type == MathRow::BEGIN && e.ar) + bv->setMathRow(e.ar, caret_row); + + // Cache row and dimension. + bv->setMathRow(this, mrow); + bv->coordCache().arrays().add(this, dim); } -void MathData::draw(PainterInfo & pi, int const x, int const y) const +void MathData::drawSelection(PainterInfo & pi, int const x, int const y) const { - //lyxerr << "MathData::draw: x: " << x << " y: " << y << endl; - BufferView & bv = *pi.base.bv; - setXY(bv, x, y); + BufferView const * bv = pi.base.bv; + Cursor const & cur = bv->cursor(); + InsetMath const * inset = cur.inset().asInsetMath(); + if (!cur.selection() || !inset || inset->nargs() == 0) + return; + + CursorSlice const s1 = cur.selBegin(); + CursorSlice const s2 = cur.selEnd(); + MathData const & c1 = inset->cell(s1.idx()); + + if (s1.idx() == s2.idx() && &c1 == this) { + // selection inside cell + Dimension const dim = bv->coordCache().getArrays().dim(&c1); + int const beg = c1.pos2x(bv, s1.pos()); + int const end = c1.pos2x(bv, s2.pos()); + pi.pain.fillRectangle(x + beg, y - dim.ascent(), + end - beg, dim.height(), Color_selection); + } else { + for (idx_type i = 0; i < inset->nargs(); ++i) { + MathData const & c = inset->cell(i); + if (&c == this && inset->idxBetween(i, s1.idx(), s2.idx())) { + // The whole cell is selected + Dimension const dim = bv->coordCache().getArrays().dim(&c); + pi.pain.fillRectangle(x, y - dim.ascent(), + dim.width(), dim.height(), + Color_selection); + } + } + } +} - Dimension const & dim = bv.coordCache().getArrays().dim(this); - // don't draw outside the workarea - if (y + dim.descent() <= 0 - || y - dim.ascent() >= bv.workHeight() - || x + dim.width() <= 0 - || x >= bv. workWidth()) - return; +void MathData::draw(PainterInfo & pi, int const x, int const y) const +{ + //lyxerr << "MathData::draw: x: " << x << " y: " << y << endl; + setXY(*pi.base.bv, x, y); - MathRow const & mrow = mrow_cache_[pi.base.bv]; + drawSelection(pi, x, y); + MathRow const & mrow = pi.base.bv->mathRow(this); mrow.draw(pi, x, y); } @@ -322,42 +373,48 @@ void MathData::drawT(TextPainter & pain, int x, int y) const // FIXME: Abdel 16/10/2006 // This drawT() method is never used, this is dead code. - for (const_iterator it = begin(), et = end(); it != et; ++it) { - (*it)->drawT(pain, x, y); - //x += (*it)->width_; + for (auto const & it : *this) { + it->drawT(pain, x, y); + //x += it->width_; x += 2; } } -void MathData::updateBuffer(ParIterator const & it, UpdateType utype) +int MathData::kerning(BufferView const * bv) const +{ + return bv->mathRow(this).kerning(bv); +} + + +void MathData::updateBuffer(ParIterator const & it, UpdateType utype, bool const deleted) { // pass down for (size_t i = 0, n = size(); i != n; ++i) { MathAtom & at = operator[](i); - at.nucleus()->updateBuffer(it, utype); + at.nucleus()->updateBuffer(it, utype, deleted); } } void MathData::updateMacros(Cursor * cur, MacroContext const & mc, - UpdateType utype) + UpdateType utype, int nesting) { // If we are editing a macro, we cannot update it immediately, // otherwise wrong undo steps will be recorded (bug 6208). InsetMath const * inmath = cur ? cur->inset().asInsetMath() : 0; - MathMacro const * inmacro = inmath ? inmath->asMacro() : 0; + InsetMathMacro const * inmacro = inmath ? inmath->asMacro() : 0; docstring const edited_name = inmacro ? inmacro->name() : docstring(); // go over the array and look for macros for (size_t i = 0; i < size(); ++i) { - MathMacro * macroInset = operator[](i).nucleus()->asMacro(); + InsetMathMacro * macroInset = operator[](i).nucleus()->asMacro(); if (!macroInset || macroInset->macroName().empty() || macroInset->macroName()[0] == '^' || macroInset->macroName()[0] == '_' || (macroInset->name() == edited_name && macroInset->displayMode() == - MathMacro::DISPLAY_UNFOLDED)) + InsetMathMacro::DISPLAY_UNFOLDED)) continue; // get macro @@ -371,23 +428,23 @@ void MathData::updateMacros(Cursor * cur, MacroContext const & mc, } // store old and compute new display mode - MathMacro::DisplayMode newDisplayMode; - MathMacro::DisplayMode oldDisplayMode = macroInset->displayMode(); + InsetMathMacro::DisplayMode newDisplayMode; + InsetMathMacro::DisplayMode oldDisplayMode = macroInset->displayMode(); newDisplayMode = macroInset->computeDisplayMode(); // arity changed or other reason to detach? - if (oldDisplayMode == MathMacro::DISPLAY_NORMAL + if (oldDisplayMode == InsetMathMacro::DISPLAY_NORMAL && (macroInset->arity() != macroNumArgs || macroInset->optionals() != macroOptionals - || newDisplayMode == MathMacro::DISPLAY_UNFOLDED)) + || newDisplayMode == InsetMathMacro::DISPLAY_UNFOLDED)) detachMacroParameters(cur, i); // the macro could have been copied while resizing this macroInset = operator[](i).nucleus()->asMacro(); // Cursor in \label? - if (newDisplayMode != MathMacro::DISPLAY_UNFOLDED - && oldDisplayMode == MathMacro::DISPLAY_UNFOLDED) { + if (newDisplayMode != InsetMathMacro::DISPLAY_UNFOLDED + && oldDisplayMode == InsetMathMacro::DISPLAY_UNFOLDED) { // put cursor in front of macro if (cur) { int macroSlice = cur->find(macroInset); @@ -401,19 +458,19 @@ void MathData::updateMacros(Cursor * cur, MacroContext const & mc, macroInset->setDisplayMode(newDisplayMode); // arity changed? - if (newDisplayMode == MathMacro::DISPLAY_NORMAL + if (newDisplayMode == InsetMathMacro::DISPLAY_NORMAL && (macroInset->arity() != macroNumArgs || macroInset->optionals() != macroOptionals)) { // is it a virgin macro which was never attached to parameters? bool fromInitToNormalMode - = (oldDisplayMode == MathMacro::DISPLAY_INIT - || oldDisplayMode == MathMacro::DISPLAY_INTERACTIVE_INIT) - && newDisplayMode == MathMacro::DISPLAY_NORMAL; + = (oldDisplayMode == InsetMathMacro::DISPLAY_INIT + || oldDisplayMode == InsetMathMacro::DISPLAY_INTERACTIVE_INIT) + && newDisplayMode == InsetMathMacro::DISPLAY_NORMAL; // if the macro was entered interactively (i.e. not by paste or during // loading), it should not be greedy, but the cursor should // automatically jump into the macro when behind - bool interactive = (oldDisplayMode == MathMacro::DISPLAY_INTERACTIVE_INIT); + bool interactive = (oldDisplayMode == InsetMathMacro::DISPLAY_INTERACTIVE_INIT); // attach parameters attachMacroParameters(cur, i, macroNumArgs, macroOptionals, @@ -430,14 +487,14 @@ void MathData::updateMacros(Cursor * cur, MacroContext const & mc, if (inset->asScriptInset()) inset = inset->asScriptInset()->nuc()[0].nucleus(); LASSERT(inset->asMacro(), continue); - inset->asMacro()->updateRepresentation(cur, mc, utype); + inset->asMacro()->updateRepresentation(cur, mc, utype, nesting + 1); } } void MathData::detachMacroParameters(DocIterator * cur, const size_type macroPos) { - MathMacro * macroInset = operator[](macroPos).nucleus()->asMacro(); + InsetMathMacro * macroInset = operator[](macroPos).nucleus()->asMacro(); // We store this now, because the inset pointer will be invalidated in the scond loop below size_t const optionals = macroInset->optionals(); @@ -568,7 +625,7 @@ void MathData::attachMacroParameters(Cursor * cur, const int macroOptionals, const bool fromInitToNormalMode, const bool interactiveInit, const size_t appetite) { - MathMacro * macroInset = operator[](macroPos).nucleus()->asMacro(); + InsetMathMacro * macroInset = operator[](macroPos).nucleus()->asMacro(); // start at atom behind the macro again, maybe with some new arguments // from the detach phase above, to add them back into the macro inset @@ -702,7 +759,9 @@ void MathData::collectOptionalParameters(Cursor * cur, params.push_back(optarg); // place cursor in optional argument of macro - if (thisSlice != -1 + // Note: The two expressions on the first line are equivalent + // (see caller), but making this explicit pleases coverity. + if (cur && thisSlice != -1 && thisPos >= int(pos) && thisPos <= int(right)) { int paramPos = max(0, thisPos - int(pos) - 1); vector x; @@ -742,7 +801,10 @@ void MathData::collectParameters(Cursor * cur, // fix cursor vector argSlices; int argPos = 0; - if (thisSlice != -1 && thisPos == int(pos)) + // Note: The two expressions on the first line are equivalent + // (see caller), but making this explicit pleases coverity. + if (cur && thisSlice != -1 + && thisPos == int(pos)) cur->cutOff(thisSlice, argSlices); // which kind of parameter is it? In {}? With index x^n? @@ -783,7 +845,10 @@ void MathData::collectParameters(Cursor * cur, } // put cursor in argument again - if (thisSlice != - 1 && thisPos == int(pos)) { + // Note: The first two expressions on the first line are + // equivalent (see caller), but making this explicit pleases + // coverity. + if (cur && thisSlice != -1 && thisPos == int(pos)) { cur->append(params.size() - 1, argPos); cur->append(argSlices); (*cur)[thisSlice].pos() = macroPos; @@ -888,6 +953,32 @@ int MathData::yo(BufferView const & bv) const } +MathClass MathData::mathClass() const +{ + MathClass res = MC_UNKNOWN; + for (MathAtom const & at : *this) { + MathClass mc = at->mathClass(); + if (res == MC_UNKNOWN) + res = mc; + else if (mc != MC_UNKNOWN && res != mc) + return MC_ORD; + } + return res == MC_UNKNOWN ? MC_ORD : res; +} + + +MathClass MathData::lastMathClass() const +{ + MathClass res = MC_ORD; + for (MathAtom const & at : *this) { + MathClass mc = at->mathClass(); + if (mc != MC_UNKNOWN) + res = mc; + } + return res; +} + + ostream & operator<<(ostream & os, MathData const & ar) { odocstringstream oss;