X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2Fmath_scriptinset.C;h=11f858c31a6b16a329471a8eeeaff9087edbc80c;hb=57501b93064a6deed43e415beed45606054d86ad;hp=5c5aa5c7e3c79acc4379e31763da7e77b5df7bcb;hpb=faf2f08712362b2b39422bf8680ae2248f345940;p=lyx.git diff --git a/src/mathed/math_scriptinset.C b/src/mathed/math_scriptinset.C index 5c5aa5c7e3..11f858c31a 100644 --- a/src/mathed/math_scriptinset.C +++ b/src/mathed/math_scriptinset.C @@ -1,34 +1,56 @@ -#ifdef __GNUG__ -#pragma implementation -#endif +/** + * \file math_scriptinset.C + * 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 "math_scriptinset.h" +#include "math_data.h" +#include "math_mathmlstream.h" #include "math_support.h" #include "math_symbolinset.h" -#include "math_mathmlstream.h" -#include "support/LAssert.h" +#include "dispatchresult.h" +#include "cursor.h" #include "debug.h" +#include "funcrequest.h" + +#include + +using std::string; +using std::max; +using std::auto_ptr; +using std::endl; + MathScriptInset::MathScriptInset() - : MathNestInset(2), limits_(0) -{ - script_[0] = false; - script_[1] = false; -} + : MathNestInset(1), cell_1_is_up_(false), limits_(0) +{} MathScriptInset::MathScriptInset(bool up) - : MathNestInset(2), limits_(0) + : MathNestInset(2), cell_1_is_up_(up), limits_(0) +{} + + +MathScriptInset::MathScriptInset(MathAtom const & at, bool up) + : MathNestInset(2), cell_1_is_up_(up), limits_(0) { - script_[0] = !up; - script_[1] = up; + BOOST_ASSERT(nargs() >= 1); + cell(0).push_back(at); } -MathInset * MathScriptInset::clone() const + +auto_ptr MathScriptInset::clone() const { - return new MathScriptInset(*this); + return auto_ptr(new MathScriptInset(*this)); } @@ -44,198 +66,236 @@ MathScriptInset * MathScriptInset::asScriptInset() } -MathXArray const & MathScriptInset::up() const +bool MathScriptInset::idxFirst(LCursor & cur) const +{ + cur.idx() = 0; + cur.pos() = 0; + return true; +} + + +bool MathScriptInset::idxLast(LCursor & cur) const { - return xcell(1); + cur.idx() = 0; + cur.pos() = nuc().size(); + return true; } -MathXArray const & MathScriptInset::down() const +MathArray const & MathScriptInset::down() const { - return xcell(0); + if (nargs() == 3) + return cell(2); + BOOST_ASSERT(nargs() > 1); + return cell(1); } -MathXArray & MathScriptInset::up() +MathArray & MathScriptInset::down() { - return xcell(1); + if (nargs() == 3) + return cell(2); + BOOST_ASSERT(nargs() > 1); + return cell(1); } -MathXArray & MathScriptInset::down() +MathArray const & MathScriptInset::up() const { - return xcell(0); + BOOST_ASSERT(nargs() > 1); + return cell(1); +} + + +MathArray & MathScriptInset::up() +{ + BOOST_ASSERT(nargs() > 1); + return cell(1); } void MathScriptInset::ensure(bool up) { - script_[up] = true; + if (nargs() == 1) { + // just nucleus so far + cells_.push_back(MathArray()); + cell_1_is_up_ = up; + } else if (nargs() == 2 && !has(up)) { + if (up) { + cells_.push_back(cell(1)); + cell(1).clear(); + } else { + cells_.push_back(MathArray()); + } + } +} + + +MathArray const & MathScriptInset::nuc() const +{ + return cell(0); +} + + +MathArray & MathScriptInset::nuc() +{ + return cell(0); } -int MathScriptInset::dy0(MathInset const * nuc) const +int MathScriptInset::dy0() const { - int nd = ndes(nuc); + int nd = ndes(); if (!hasDown()) return nd; int des = down().ascent(); - if (hasLimits(nuc)) + if (hasLimits()) des += nd + 2; - else - des = std::max(des, nd); + else + des = max(des, nd); return des; } -int MathScriptInset::dy1(MathInset const * nuc) const +int MathScriptInset::dy1() const { - int na = nasc(nuc); + int na = nasc(); if (!hasUp()) return na; int asc = up().descent(); - if (hasLimits(nuc)) + if (hasLimits()) asc += na + 2; - else - asc = std::max(asc, na); - asc = std::max(asc, mathed_char_ascent(LM_TC_VAR, mi_, 'I')); + else + asc = max(asc, na); + asc = max(asc, 5); return asc; } -int MathScriptInset::dx0(MathInset const * nuc) const +int MathScriptInset::dx0() const { - lyx::Assert(hasDown()); - return hasLimits(nuc) ? (width2(nuc) - down().width()) / 2 : nwid(nuc); + BOOST_ASSERT(hasDown()); + return hasLimits() ? (dim_.wid - down().width()) / 2 : nwid(); } -int MathScriptInset::dx1(MathInset const * nuc) const +int MathScriptInset::dx1() const { - lyx::Assert(hasUp()); - return hasLimits(nuc) ? (width2(nuc) - up().width()) / 2 : nwid(nuc); + BOOST_ASSERT(hasUp()); + return hasLimits() ? (dim_.wid - up().width()) / 2 : nwid(); } -int MathScriptInset::dxx(MathInset const * nuc) const +int MathScriptInset::dxx() const { - //lyx::Assert(nuc()); - return hasLimits(nuc) ? (width2(nuc) - nwid(nuc)) / 2 : 0; + return hasLimits() ? (dim_.wid - nwid()) / 2 : 0; } -int MathScriptInset::ascent2(MathInset const * nuc) const +int MathScriptInset::nwid() const { - return dy1(nuc) + (hasUp() ? up().ascent() : 0); + return nuc().size() ? nuc().width() : 2; } -int MathScriptInset::descent2(MathInset const * nuc) const +int MathScriptInset::nasc() const { - return dy0(nuc) + (hasDown() ? down().descent() : 0); + return nuc().size() ? nuc().ascent() : 5; } -int MathScriptInset::width2(MathInset const * nuc) const +int MathScriptInset::ndes() const { - int wid = 0; - if (hasLimits(nuc)) { - wid = nwid(nuc); + return nuc().size() ? nuc().descent() : 0; +} + + +void MathScriptInset::metrics(MetricsInfo & mi, Dimension & dim) const +{ + cell(0).metrics(mi); + ScriptChanger dummy(mi.base); + if (nargs() > 1) + cell(1).metrics(mi); + if (nargs() > 2) + cell(2).metrics(mi); + dim.wid = 0; + if (hasLimits()) { + dim.wid = nwid(); if (hasUp()) - wid = std::max(wid, up().width()); + dim.wid = max(dim.wid, up().width()); if (hasDown()) - wid = std::max(wid, down().width()); + dim.wid = max(dim.wid, down().width()); } else { if (hasUp()) - wid = std::max(wid, up().width()); + dim.wid = max(dim.wid, up().width()); if (hasDown()) - wid = std::max(wid, down().width()); - wid += nwid(nuc); + dim.wid = max(dim.wid, down().width()); + dim.wid += nwid(); } - return wid; + dim.asc = dy1() + (hasUp() ? up().ascent() : 0); + dim.des = dy0() + (hasDown() ? down().descent() : 0); + metricsMarkers(dim); + dim_ = dim; } -int MathScriptInset::nwid(MathInset const * nuc) const +void MathScriptInset::draw(PainterInfo & pi, int x, int y) const { - return nuc ? - nuc->width() : - mathed_char_width(LM_TC_TEX, mi_, '.'); + if (nuc().size()) + nuc().draw(pi, x + dxx(), y); + else { + nuc().setXY(x + dxx(), y); + if (editing(pi.base.bv)) + drawStr(pi, pi.base.font, x + dxx(), y, "."); + } + ScriptChanger dummy(pi.base); + if (hasUp()) + up().draw(pi, x + dx1(), y - dy1()); + if (hasDown()) + down().draw(pi, x + dx0(), y + dy0()); + drawMarkers(pi, x, y); } -int MathScriptInset::nasc(MathInset const * nuc) const +void MathScriptInset::metricsT(TextMetricsInfo const & mi, Dimension & dim) const { - return nuc ? nuc->ascent() - : mathed_char_ascent(LM_TC_VAR, mi_, 'I'); + if (hasUp()) + up().metricsT(mi, dim); + if (hasDown()) + down().metricsT(mi, dim); + nuc().metricsT(mi, dim); } -int MathScriptInset::ndes(MathInset const * nuc) const +void MathScriptInset::drawT(TextPainter & pain, int x, int y) const { - return nuc ? nuc->descent() - : mathed_char_descent(LM_TC_VAR, mi_, 'I'); -} - - -void MathScriptInset::metrics(MathMetricsInfo const & mi) const -{ - metrics(0, mi); -} - - -void MathScriptInset::metrics(MathInset const * nuc, - MathMetricsInfo const & mi) const -{ - MathNestInset::metrics(mi); - if (nuc) - nuc->metrics(mi); - ascent_ = ascent2(nuc); - descent_ = descent2(nuc); - width_ = width2(nuc); -} - - -void MathScriptInset::draw(Painter & pain, int x, int y) const -{ - //lyxerr << "unexpected call to MathScriptInset::draw()\n"; - draw(0, pain, x, y); -} - - -void MathScriptInset::draw(MathInset const * nuc, Painter & pain, - int x, int y) const -{ - if (nuc) - nuc->draw(pain, x + dxx(nuc), y); - else - drawStr(pain, LM_TC_TEX, mi_, x + dxx(nuc), y, "."); - + if (nuc().size()) + nuc().drawT(pain, x + dxx(), y); if (hasUp()) - up().draw(pain, x + dx1(nuc), y - dy1(nuc)); - + up().drawT(pain, x + dx1(), y - dy1()); if (hasDown()) - down().draw(pain, x + dx0(nuc), y + dy0(nuc)); + down().drawT(pain, x + dx0(), y + dy0()); } -bool MathScriptInset::hasLimits(MathInset const * nuc) const + +bool MathScriptInset::hasLimits() const { - // obviuos cases + // obvious cases if (limits_ == 1) return true; if (limits_ == -1) return false; - // we can only display limits if the nucleus wants some - if (!nuc) + // we can only display limits if the nucleus wants some + if (!nuc().size()) return false; - if (!nuc->isScriptable()) + if (!nuc().back()->isScriptable()) return false; - + // per default \int has limits beside the \int even in displayed formulas - if (nuc->asSymbolInset()) - if (nuc->asSymbolInset()->name().find("int") != string::npos) + if (nuc().back()->asSymbolInset()) + if (nuc().back()->asSymbolInset()->name().find("int") != string::npos) return false; // assume "real" limits for everything else @@ -243,128 +303,210 @@ bool MathScriptInset::hasLimits(MathInset const * nuc) const } -void MathScriptInset::removeEmptyScripts() -{ - for (int i = 0; i <= 1; ++i) - if (script_[i] && !cell(i).size()) - script_[i] = false; -} - - void MathScriptInset::removeScript(bool up) { - cell(up).clear(); - script_[up] = false; + lyxerr << "MathNestInset::removeScript: 1 up: " << up << endl; + if (nargs() == 2) { + lyxerr << "MathNestInset::removeScript: a up: " << up << endl; + if (up == cell_1_is_up_) + cells_.pop_back(); + lyxerr << "MathNestInset::removeScript: b up: " << up << endl; + } else if (nargs() == 3) { + if (up == true) { + swap(cells_[1], cells_[2]); + cell_1_is_up_ = false; + } else { + cell_1_is_up_ = true; + } + cells_.pop_back(); + } + lyxerr << "MathNestInset::removeScript: 2 up: " << up << endl; } bool MathScriptInset::has(bool up) const { - return script_[up]; + return idxOfScript(up); } bool MathScriptInset::hasUp() const { - return script_[1]; + //lyxerr << "1up: " << bool(cell_1_is_up_) << endl; + //lyxerr << "hasUp: " << bool(idxOfScript(true)) << endl; + return idxOfScript(true); } bool MathScriptInset::hasDown() const { - return script_[0]; + //lyxerr << "1up: " << bool(cell_1_is_up_) << endl; + //lyxerr << "hasDown: " << bool(idxOfScript(false)) << endl; + return idxOfScript(false); } -bool MathScriptInset::idxRight(MathInset::idx_type &, - MathInset::pos_type &) const +InsetBase::idx_type MathScriptInset::idxOfScript(bool up) const +{ + if (nargs() == 1) + return 0; + if (nargs() == 2) + return (cell_1_is_up_ == up) ? 1 : 0; + if (nargs() == 3) + return up ? 1 : 2; + BOOST_ASSERT(false); + // Silence compiler + return 0; +} + + +bool MathScriptInset::idxRight(LCursor &) const { return false; } -bool MathScriptInset::idxLeft(MathInset::idx_type &, - MathInset::pos_type &) const +bool MathScriptInset::idxLeft(LCursor &) const { return false; } -void MathScriptInset::write(WriteStream & os) const -{ - //lyxerr << "unexpected call to MathScriptInset::write()\n"; - write2(0, os); +bool MathScriptInset::idxUpDown(LCursor & cur, bool up) const +{ + // in nucleus? + if (cur.idx() == 0) { + // don't go up/down if there is no cell in this direction + if (!has(up)) + return false; + // go up/down only if in the last position + // or in the first position of something with displayed limits + if (cur.pos() == cur.lastpos() || (cur.pos() == 0 && hasLimits())) { + cur.idx() = idxOfScript(up); + cur.pos() = 0; + return true; + } + return false; + } + + // Are we 'up'? + if (has(up) && cur.idx() == idxOfScript(true)) { + // can't go further up + if (up) + return false; + // otherwise go to last position in the nucleus + cur.idx() = 0; + cur.pos() = cur.lastpos(); + return true; + } + + // Are we 'down'? + if (has(up) && cur.idx() == idxOfScript(false)) { + // can't go further down + if (!up) + return false; + // otherwise go to last position in the nucleus + cur.idx() = 0; + cur.pos() = cur.lastpos(); + return true; + } + + return false; } -void MathScriptInset::write2(MathInset const * nuc, WriteStream & os) const +void MathScriptInset::write(WriteStream & os) const { - if (nuc) { - os << nuc; - if (nuc->takesLimits()) { + if (nuc().size()) { + os << nuc(); + //if (nuc().back()->takesLimits()) { if (limits_ == -1) os << "\\nolimits "; if (limits_ == 1) os << "\\limits "; - } - } else - if (os.firstitem()) - lyxerr << "suppressing {} \n"; - else - os << "{}"; - - if (hasDown() && down().data_.size()) - os << "_{" << down().data_ << '}'; + //} + } else { + if (os.firstitem()) + lyxerr[Debug::MATHED] << "suppressing {} when writing" + << endl; + else + os << "{}"; + } - if (hasUp() && up().data_.size()) - os << "^{" << up().data_ << '}'; -} + if (hasDown() && down().size()) + os << "_{" << down() << '}'; + if (hasUp() && up().size()) + os << "^{" << up() << '}'; -void MathScriptInset::normalize(NormalStream & os) const -{ - //lyxerr << "unexpected call to MathScriptInset::normalize()\n"; - normalize2(0, os); + if (lock_ && !os.latex()) + os << "\\lyxlock "; } -void MathScriptInset::normalize2(MathInset const * nuc, NormalStream & os) const +void MathScriptInset::normalize(NormalStream & os) const { - bool d = hasDown() && down().data_.size(); - bool u = hasUp() && up().data_.size(); + bool d = hasDown() && down().size(); + bool u = hasUp() && up().size(); - if (u) + if (u && d) + os << "[subsup "; + else if (u) os << "[sup "; - if (d) + else if (d) os << "[sub "; - - if (nuc) - os << nuc << ' '; + + if (nuc().size()) + os << nuc() << ' '; else os << "[par]"; - if (d) - os << down().data_ << ']'; - if (u) - os << up().data_ << ']'; + if (u && d) + os << down() << ' ' << up() << ']'; + else if (d) + os << down() << ']'; + else if (u) + os << up() << ']'; +} + + +void MathScriptInset::maple(MapleStream & os) const +{ + if (nuc().size()) + os << nuc(); + if (hasDown() && down().size()) + os << '[' << down() << ']'; + if (hasUp() && up().size()) + os << "^(" << up() << ')'; } -void MathScriptInset::maplize2(MathInset const * nuc, MapleStream & os) const +void MathScriptInset::mathematica(MathematicaStream & os) const { - if (nuc) - os << nuc; - if (hasDown() && down().data_.size()) - os << '[' << down().data_ << ']'; - if (hasUp() && up().data_.size()) - os << "^(" << up().data_ << ')'; + bool d = hasDown() && down().size(); + bool u = hasUp() && up().size(); + + if (nuc().size()) { + if (d) + os << "Subscript[" << nuc(); + else + os << nuc(); + } + + if (u) + os << "^(" << up() << ')'; + + if (nuc().size()) { + if (d) + os << ',' << down() << ']'; + } } -void MathScriptInset::mathmlize2(MathInset const * nuc, MathMLStream & os) const +void MathScriptInset::mathmlize(MathMLStream & os) const { - bool d = hasDown() && down().data_.size(); - bool u = hasUp() && up().data_.size(); + bool d = hasDown() && down().size(); + bool u = hasUp() && up().size(); if (u && d) os << MTag("msubsup"); @@ -373,28 +515,83 @@ void MathScriptInset::mathmlize2(MathInset const * nuc, MathMLStream & os) const else if (d) os << MTag("msub"); - if (nuc) - os << nuc; + if (nuc().size()) + os << nuc(); else os << ""; if (u && d) - os << down().data_ << up().data_ << ETag("msubsup"); + os << down() << up() << ETag("msubsup"); else if (u) - os << up().data_ << ETag("msup"); + os << up() << ETag("msup"); else if (d) - os << down().data_ << ETag("msub"); + os << down() << ETag("msub"); +} + + +void MathScriptInset::octave(OctaveStream & os) const +{ + if (nuc().size()) + os << nuc(); + if (hasDown() && down().size()) + os << '[' << down() << ']'; + if (hasUp() && up().size()) + os << "^(" << up() << ')'; } -void MathScriptInset::octavize2(MathInset const * nuc, OctaveStream & os) const +void MathScriptInset::infoize(std::ostream & os) const { - if (nuc) - os << nuc; - if (hasDown() && down().data_.size()) - os << '[' << down().data_ << ']'; - if (hasUp() && up().data_.size()) - os << "^(" << up().data_ << ')'; + os << "Scripts"; } +void MathScriptInset::infoize2(std::ostream & os) const +{ + if (limits_) + os << (limits_ == 1 ? ", Displayed limits" : ", Inlined limits"); +} + + +void MathScriptInset::notifyCursorLeaves(LCursor & cur) +{ + MathNestInset::notifyCursorLeaves(cur); + + // remove empty scripts if possible + if (nargs() > 2 && cur.idx() == 2 && cell(2).empty()) { + // must be a subscript... + removeScript(false); + // sanitize cursor, even if this slice will be removed immediately + cur.idx() = 0; + cur.pos() = 0; + } else if (nargs() > 1 && cur.idx() == 1 && cell(1).empty()) { + // could be either subscript or super script + removeScript(cell_1_is_up_); + // sanitize cursor, even if this slice will be removed immediately + cur.idx() = 0; + cur.pos() = 0; + } +} + + +void MathScriptInset::priv_dispatch(LCursor & cur, FuncRequest & cmd) +{ + //lyxerr << "MathScriptInset: request: " << cmd << std::endl; + + if (cmd.action == LFUN_MATH_LIMITS) { + if (!cmd.argument.empty()) { + if (cmd.argument == "limits") + limits_ = 1; + else if (cmd.argument == "nolimits") + limits_ = -1; + else + limits_ = 0; + } else if (limits_ == 0) + limits_ = hasLimits() ? -1 : 1; + else + limits_ = 0; + return; + } + + MathNestInset::priv_dispatch(cur, cmd); +}