2 * \file math_scriptinset.C
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS.
13 #include "math_scriptinset.h"
14 #include "math_data.h"
15 #include "math_mathmlstream.h"
16 #include "math_support.h"
17 #include "math_symbolinset.h"
18 #include "dispatchresult.h"
21 #include "funcrequest.h"
23 #include <boost/assert.hpp>
32 MathScriptInset::MathScriptInset()
33 : MathNestInset(1), cell_1_is_up_(false), limits_(0)
37 MathScriptInset::MathScriptInset(bool up)
38 : MathNestInset(2), cell_1_is_up_(up), limits_(0)
42 MathScriptInset::MathScriptInset(MathAtom const & at, bool up)
43 : MathNestInset(2), cell_1_is_up_(up), limits_(0)
45 BOOST_ASSERT(nargs() >= 1);
46 cell(0).push_back(at);
51 auto_ptr<InsetBase> MathScriptInset::clone() const
53 return auto_ptr<InsetBase>(new MathScriptInset(*this));
57 MathScriptInset const * MathScriptInset::asScriptInset() const
63 MathScriptInset * MathScriptInset::asScriptInset()
69 bool MathScriptInset::idxFirst(LCursor & cur) const
77 bool MathScriptInset::idxLast(LCursor & cur) const
80 cur.pos() = nuc().size();
85 MathArray const & MathScriptInset::down() const
90 BOOST_ASSERT(nargs() > 1);
93 return nargs() == 3 ? cell(2) : cell(1);
98 MathArray & MathScriptInset::down()
103 BOOST_ASSERT(nargs() > 1);
106 return nargs() == 3 ? cell(2) : cell(1);
111 MathArray const & MathScriptInset::up() const
113 BOOST_ASSERT(nargs() > 1);
118 MathArray & MathScriptInset::up()
120 BOOST_ASSERT(nargs() > 1);
125 void MathScriptInset::ensure(bool up)
128 // just nucleus so far
129 cells_.push_back(MathArray());
131 } else if (nargs() == 2 && !has(up)) {
133 cells_.push_back(cell(1));
136 cells_.push_back(MathArray());
142 MathArray const & MathScriptInset::nuc() const
148 MathArray & MathScriptInset::nuc()
154 int MathScriptInset::dy0() const
159 int des = down().ascent();
168 int MathScriptInset::dy1() const
173 int asc = up().descent();
183 int MathScriptInset::dx0() const
185 BOOST_ASSERT(hasDown());
186 return hasLimits() ? (dim_.wid - down().width()) / 2 : nwid();
190 int MathScriptInset::dx1() const
192 BOOST_ASSERT(hasUp());
193 return hasLimits() ? (dim_.wid - up().width()) / 2 : nwid();
197 int MathScriptInset::dxx() const
199 return hasLimits() ? (dim_.wid - nwid()) / 2 : 0;
203 int MathScriptInset::nwid() const
205 return nuc().size() ? nuc().width() : 2;
209 int MathScriptInset::nasc() const
211 return nuc().size() ? nuc().ascent() : 5;
215 int MathScriptInset::ndes() const
217 return nuc().size() ? nuc().descent() : 0;
221 void MathScriptInset::metrics(MetricsInfo & mi, Dimension & dim) const
224 ScriptChanger dummy(mi.base);
233 dim.wid = max(dim.wid, up().width());
235 dim.wid = max(dim.wid, down().width());
238 dim.wid = max(dim.wid, up().width());
240 dim.wid = max(dim.wid, down().width());
243 dim.asc = dy1() + (hasUp() ? up().ascent() : 0);
244 dim.des = dy0() + (hasDown() ? down().descent() : 0);
250 void MathScriptInset::draw(PainterInfo & pi, int x, int y) const
253 nuc().draw(pi, x + dxx(), y);
255 nuc().setXY(x + dxx(), y);
256 if (editing(pi.base.bv))
257 drawStr(pi, pi.base.font, x + dxx(), y, ".");
259 ScriptChanger dummy(pi.base);
261 up().draw(pi, x + dx1(), y - dy1());
263 down().draw(pi, x + dx0(), y + dy0());
264 drawMarkers(pi, x, y);
268 void MathScriptInset::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
271 up().metricsT(mi, dim);
273 down().metricsT(mi, dim);
274 nuc().metricsT(mi, dim);
278 void MathScriptInset::drawT(TextPainter & pain, int x, int y) const
281 nuc().drawT(pain, x + dxx(), y);
283 up().drawT(pain, x + dx1(), y - dy1());
285 down().drawT(pain, x + dx0(), y + dy0());
290 bool MathScriptInset::hasLimits() const
298 // we can only display limits if the nucleus wants some
301 if (!nuc().back()->isScriptable())
304 // per default \int has limits beside the \int even in displayed formulas
305 if (nuc().back()->asSymbolInset())
306 if (nuc().back()->asSymbolInset()->name().find("int") != string::npos)
309 // assume "real" limits for everything else
314 void MathScriptInset::removeScript(bool up)
317 if (up == cell_1_is_up_)
319 } else if (nargs() == 3) {
321 swap(cells_[1], cells_[2]);
322 cell_1_is_up_ = false;
324 cell_1_is_up_ = true;
330 bool MathScriptInset::has(bool up) const
332 return idxOfScript(up);
336 bool MathScriptInset::hasUp() const
338 //lyxerr << "hasUp: " << bool(idxOfScript(true)) << endl;
339 //lyxerr << "1up: " << bool(cell_1_is_up_) << endl;
340 return idxOfScript(true);
344 bool MathScriptInset::hasDown() const
346 //lyxerr << "hasDown: " << bool(idxOfScript(false)) << endl;
347 //lyxerr << "1up: " << bool(cell_1_is_up_) << endl;
348 return idxOfScript(false);
352 InsetBase::idx_type MathScriptInset::idxOfScript(bool up) const
357 return cell_1_is_up_ == up ? 1 : 0;
366 bool MathScriptInset::idxRight(LCursor &) const
372 bool MathScriptInset::idxLeft(LCursor &) const
378 bool MathScriptInset::idxUpDown(LCursor & cur, bool up) const
381 if (cur.idx() == 0) {
382 // don't go up/down if there is no cell in this direction
385 // go up/down only if in the last position
386 // or in the first position of something with displayed limits
387 if (cur.pos() == cur.lastpos() || (cur.pos() == 0 && hasLimits())) {
388 cur.idx() = idxOfScript(up);
396 if (cur.idx() == idxOfScript(true)) {
397 // can't go further up
400 // otherwise go to last position in the nucleus
402 cur.pos() = cur.lastpos();
407 if (cur.idx() == idxOfScript(false)) {
408 // can't go further down
411 // otherwise go to last position in the nucleus
413 cur.pos() = cur.lastpos();
421 void MathScriptInset::write(WriteStream & os) const
425 //if (nuc().back()->takesLimits()) {
433 lyxerr[Debug::MATHED] << "suppressing {} when writing"
439 if (hasDown() && down().size())
440 os << "_{" << down() << '}';
442 if (hasUp() && up().size())
443 os << "^{" << up() << '}';
445 if (lock_ && !os.latex())
450 void MathScriptInset::normalize(NormalStream & os) const
452 bool d = hasDown() && down().size();
453 bool u = hasUp() && up().size();
468 os << down() << ' ' << up() << ']';
476 void MathScriptInset::maple(MapleStream & os) const
480 if (hasDown() && down().size())
481 os << '[' << down() << ']';
482 if (hasUp() && up().size())
483 os << "^(" << up() << ')';
487 void MathScriptInset::mathematica(MathematicaStream & os) const
489 bool d = hasDown() && down().size();
490 bool u = hasUp() && up().size();
494 os << "Subscript[" << nuc();
500 os << "^(" << up() << ')';
504 os << ',' << down() << ']';
509 void MathScriptInset::mathmlize(MathMLStream & os) const
511 bool d = hasDown() && down().size();
512 bool u = hasUp() && up().size();
515 os << MTag("msubsup");
527 os << down() << up() << ETag("msubsup");
529 os << up() << ETag("msup");
531 os << down() << ETag("msub");
535 void MathScriptInset::octave(OctaveStream & os) const
539 if (hasDown() && down().size())
540 os << '[' << down() << ']';
541 if (hasUp() && up().size())
542 os << "^(" << up() << ')';
546 void MathScriptInset::infoize(std::ostream & os) const
552 void MathScriptInset::infoize2(std::ostream & os) const
555 os << (limits_ == 1 ? ", Displayed limits" : ", Inlined limits");
559 void MathScriptInset::notifyCursorLeaves(idx_type idx)
561 MathNestInset::notifyCursorLeaves(idx);
563 // remove empty scripts if possible
564 if (idx == 2 && nargs() > 2 && cell(2).empty()) {
565 removeScript(false); // must be a subscript...
566 } else if (idx == 1 && nargs() > 1 && cell(1).empty()) {
568 cell_1_is_up_ = false;
571 } else if (nargs() == 1) {
578 void MathScriptInset::priv_dispatch(LCursor & cur, FuncRequest & cmd)
580 //lyxerr << "MathScriptInset: request: " << cmd << std::endl;
582 if (cmd.action == LFUN_MATH_LIMITS) {
583 if (!cmd.argument.empty()) {
584 if (cmd.argument == "limits")
586 else if (cmd.argument == "nolimits")
590 } else if (limits_ == 0)
591 limits_ = hasLimits() ? -1 : 1;
597 MathNestInset::priv_dispatch(cur, cmd);