X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2Fmath_scriptinset.C;h=11f858c31a6b16a329471a8eeeaff9087edbc80c;hb=57501b93064a6deed43e415beed45606054d86ad;hp=eeccab358e9a3ed6b51f50408ee3de6a4e0c7f4a;hpb=990069f5463dd0b57e0ea1f792b15a320ed8358a;p=lyx.git diff --git a/src/mathed/math_scriptinset.C b/src/mathed/math_scriptinset.C index eeccab358e..11f858c31a 100644 --- a/src/mathed/math_scriptinset.C +++ b/src/mathed/math_scriptinset.C @@ -1,47 +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(3), limits_(0) -{ - script_[0] = false; - script_[1] = false; -} + : MathNestInset(1), cell_1_is_up_(false), limits_(0) +{} MathScriptInset::MathScriptInset(bool up) - : MathNestInset(3), limits_(0) -{ - script_[0] = !up; - script_[1] = up; -} + : MathNestInset(2), cell_1_is_up_(up), limits_(0) +{} MathScriptInset::MathScriptInset(MathAtom const & at, bool up) - : MathNestInset(3), limits_(0) + : MathNestInset(2), cell_1_is_up_(up), limits_(0) { - script_[0] = !up; - script_[1] = up; - cell(2).push_back(at); + 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)); } @@ -57,61 +66,80 @@ MathScriptInset * MathScriptInset::asScriptInset() } -bool MathScriptInset::idxFirst(idx_type & idx, pos_type & pos) const +bool MathScriptInset::idxFirst(LCursor & cur) const { - idx = 2; - pos = nuc().size(); + cur.idx() = 0; + cur.pos() = 0; return true; } -bool MathScriptInset::idxLast(idx_type & idx, pos_type & pos) const +bool MathScriptInset::idxLast(LCursor & cur) const { - idx = 2; - pos = nuc().size(); + 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::down() +MathArray & MathScriptInset::down() { - return xcell(0); + if (nargs() == 3) + return cell(2); + BOOST_ASSERT(nargs() > 1); + return cell(1); } -MathXArray const & MathScriptInset::up() const +MathArray const & MathScriptInset::up() const { - return xcell(1); + BOOST_ASSERT(nargs() > 1); + return cell(1); } -MathXArray & MathScriptInset::up() +MathArray & MathScriptInset::up() { - return xcell(1); + 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()); + } + } } -MathXArray const & MathScriptInset::nuc() const +MathArray const & MathScriptInset::nuc() const { - return xcell(2); + return cell(0); } -MathXArray & MathScriptInset::nuc() +MathArray & MathScriptInset::nuc() { - return xcell(2); + return cell(0); } @@ -139,80 +167,88 @@ int MathScriptInset::dy1() const asc += na + 2; else asc = max(asc, na); - asc = max(asc, mathed_char_ascent(font_, 'I')); + asc = max(asc, 5); return asc; } int MathScriptInset::dx0() const { - lyx::Assert(hasDown()); - return hasLimits() ? (dim_.w - down().width()) / 2 : nwid(); + BOOST_ASSERT(hasDown()); + return hasLimits() ? (dim_.wid - down().width()) / 2 : nwid(); } int MathScriptInset::dx1() const { - lyx::Assert(hasUp()); - return hasLimits() ? (dim_.w - up().width()) / 2 : nwid(); + BOOST_ASSERT(hasUp()); + return hasLimits() ? (dim_.wid - up().width()) / 2 : nwid(); } int MathScriptInset::dxx() const { - return hasLimits() ? (dim_.w - nwid()) / 2 : 0; + return hasLimits() ? (dim_.wid - nwid()) / 2 : 0; } int MathScriptInset::nwid() const { - return nuc().size() ? nuc().width() : mathed_char_width(font_, '.'); + return nuc().size() ? nuc().width() : 2; } int MathScriptInset::nasc() const { - return nuc().size() ? nuc().ascent() : mathed_char_ascent(font_, 'I'); + return nuc().size() ? nuc().ascent() : 5; } int MathScriptInset::ndes() const { - return nuc().size() ? nuc().descent() : mathed_char_descent(font_, 'I'); + return nuc().size() ? nuc().descent() : 0; } -void MathScriptInset::metrics(MathMetricsInfo & mi) const +void MathScriptInset::metrics(MetricsInfo & mi, Dimension & dim) const { - MathNestInset::metrics(mi); - MathScriptChanger dummy(mi.base); - dim_.w = 0; + 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_.w = nwid(); + dim.wid = nwid(); if (hasUp()) - dim_.w = max(dim_.w, up().width()); + dim.wid = max(dim.wid, up().width()); if (hasDown()) - dim_.w = max(dim_.w, down().width()); + dim.wid = max(dim.wid, down().width()); } else { if (hasUp()) - dim_.w = max(dim_.w, up().width()); + dim.wid = max(dim.wid, up().width()); if (hasDown()) - dim_.w = max(dim_.w, down().width()); - dim_.w += nwid(); + dim.wid = max(dim.wid, down().width()); + dim.wid += nwid(); } - dim_.a = dy1() + (hasUp() ? up().ascent() : 0); - dim_.d = dy0() + (hasDown() ? down().descent() : 0); - metricsMarkers(); + dim.asc = dy1() + (hasUp() ? up().ascent() : 0); + dim.des = dy0() + (hasDown() ? down().descent() : 0); + metricsMarkers(dim); + dim_ = dim; } -void MathScriptInset::draw(MathPainterInfo & pi, int x, int y) const +void MathScriptInset::draw(PainterInfo & pi, int x, int y) const { if (nuc().size()) nuc().draw(pi, x + dxx(), y); - else if (editing()) - drawStr(pi, font_, x + dxx(), y, "."); - MathScriptChanger dummy(pi.base); + 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()) @@ -221,13 +257,13 @@ void MathScriptInset::draw(MathPainterInfo & pi, int x, int y) const } -void MathScriptInset::metricsT(TextMetricsInfo const & mi) const +void MathScriptInset::metricsT(TextMetricsInfo const & mi, Dimension & dim) const { if (hasUp()) - up().metricsT(mi); + up().metricsT(mi, dim); if (hasDown()) - down().metricsT(mi); - nuc().metricsT(mi); + down().metricsT(mi, dim); + nuc().metricsT(mi, dim); } @@ -267,99 +303,144 @@ bool MathScriptInset::hasLimits() const } -void MathScriptInset::removeEmptyScripts() -{ - for (int i = 0; i <= 1; ++i) - if (script_[i] && cell(i).size() == 0) { - cell(i).clear(); - 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::empty() const +bool MathScriptInset::hasUp() const { - return !script_[0] && !script_[1] && cell(2).empty(); + //lyxerr << "1up: " << bool(cell_1_is_up_) << endl; + //lyxerr << "hasUp: " << bool(idxOfScript(true)) << endl; + return idxOfScript(true); } -bool MathScriptInset::hasUp() const +bool MathScriptInset::hasDown() const { - return script_[1]; + //lyxerr << "1up: " << bool(cell_1_is_up_) << endl; + //lyxerr << "hasDown: " << bool(idxOfScript(false)) << endl; + return idxOfScript(false); } -bool MathScriptInset::hasDown() const +InsetBase::idx_type MathScriptInset::idxOfScript(bool up) const { - return script_[0]; + 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(idx_type &, pos_type &) const +bool MathScriptInset::idxRight(LCursor &) const { return false; } -bool MathScriptInset::idxLeft(idx_type &, pos_type &) const +bool MathScriptInset::idxLeft(LCursor &) const { return false; } -bool MathScriptInset::idxUpDown(idx_type & idx, pos_type & pos, bool up, - int) const +bool MathScriptInset::idxUpDown(LCursor & cur, bool up) const { - if ((idx == 1 && up) || (idx == 0 && !up)) + // 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; + } - // in nuclues? - if (idx == 2) { - idx = up; - pos = 0; - } else { - idx = 2; - pos = cell(2).size(); + // 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; } - 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::write(WriteStream & os) const { if (nuc().size()) { - os << nuc().data(); - if (nuc().back()->takesLimits()) { + os << nuc(); + //if (nuc().back()->takesLimits()) { if (limits_ == -1) os << "\\nolimits "; if (limits_ == 1) os << "\\limits "; - } + //} } else { if (os.firstitem()) - lyxerr[Debug::MATHED] << "suppressing {} when writing\n"; + lyxerr[Debug::MATHED] << "suppressing {} when writing" + << endl; else os << "{}"; } if (hasDown() && down().size()) - os << "_{" << down().data() << '}'; + os << "_{" << down() << '}'; if (hasUp() && up().size()) - os << "^{" << up().data() << '}'; + os << "^{" << up() << '}'; + + if (lock_ && !os.latex()) + os << "\\lyxlock "; } @@ -376,52 +457,53 @@ void MathScriptInset::normalize(NormalStream & os) const os << "[sub "; if (nuc().size()) - os << nuc().data() << ' '; + os << nuc() << ' '; else os << "[par]"; if (u && d) - os << down().data() << ' ' << up().data() << ']'; + os << down() << ' ' << up() << ']'; else if (d) - os << down().data() << ']'; + os << down() << ']'; else if (u) - os << up().data() << ']'; + os << up() << ']'; } -void MathScriptInset::maplize(MapleStream & os) const +void MathScriptInset::maple(MapleStream & os) const { if (nuc().size()) - os << nuc().data(); + os << nuc(); if (hasDown() && down().size()) - os << '[' << down().data() << ']'; + os << '[' << down() << ']'; if (hasUp() && up().size()) - os << "^(" << up().data() << ')'; + os << "^(" << up() << ')'; } -void MathScriptInset::mathematicize(MathematicaStream & os) const +void MathScriptInset::mathematica(MathematicaStream & os) const { bool d = hasDown() && down().size(); bool u = hasUp() && up().size(); if (nuc().size()) { - if (d) - os << "Subscript[" << nuc().data(); + if (d) + os << "Subscript[" << nuc(); else - os << nuc().data(); + os << nuc(); } if (u) - os << "^(" << up().data() << ")"; + os << "^(" << up() << ')'; - if (nuc().size()) + if (nuc().size()) { if (d) - os << "," << down().data() << "]"; + os << ',' << down() << ']'; + } } -void MathScriptInset::mathmlize( MathMLStream & os) const +void MathScriptInset::mathmlize(MathMLStream & os) const { bool d = hasDown() && down().size(); bool u = hasUp() && up().size(); @@ -434,32 +516,82 @@ void MathScriptInset::mathmlize( MathMLStream & os) const os << MTag("msub"); if (nuc().size()) - os << nuc().data(); + 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::octavize(OctaveStream & os) const +void MathScriptInset::octave(OctaveStream & os) const { if (nuc().size()) - os << nuc().data(); + os << nuc(); if (hasDown() && down().size()) - os << '[' << down().data() << ']'; + os << '[' << down() << ']'; if (hasUp() && up().size()) - os << "^(" << up().data() << ')'; + os << "^(" << up() << ')'; } void MathScriptInset::infoize(std::ostream & os) const +{ + os << "Scripts"; +} + + +void MathScriptInset::infoize2(std::ostream & os) const { if (limits_) - os << (limits_ == 1 ? "Displayed limits" : "Inlined 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); }