2 * \file InsetMathFracBase.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alejandro Aguilar Sierra
9 * Full author contact details are available in file CREDITS.
14 #include "InsetMathFrac.h"
17 #include "LaTeXFeatures.h"
19 #include "MathStream.h"
20 #include "MathSupport.h"
21 #include "MetricsInfo.h"
22 #include "TextPainter.h"
24 #include "frontends/Painter.h"
30 /////////////////////////////////////////////////////////////////////
34 /////////////////////////////////////////////////////////////////////
37 InsetMathFracBase::InsetMathFracBase(idx_type ncells)
38 : InsetMathNest(ncells)
42 bool InsetMathFracBase::idxUpDown(Cursor & cur, bool up) const
44 InsetMath::idx_type target = !up; // up ? 0 : 1, since upper cell has idx 0
45 if (cur.idx() == target)
48 cur.pos() = cell(target).x2pos(&cur.bv(), cur.x_target());
54 /////////////////////////////////////////////////////////////////////
58 /////////////////////////////////////////////////////////////////////
61 InsetMathFrac::InsetMathFrac(Kind kind, InsetMath::idx_type ncells)
62 : InsetMathFracBase(ncells), kind_(kind)
66 Inset * InsetMathFrac::clone() const
68 return new InsetMathFrac(*this);
72 InsetMathFrac * InsetMathFrac::asFracInset()
74 return kind_ == ATOP ? 0 : this;
78 InsetMathFrac const * InsetMathFrac::asFracInset() const
80 return kind_ == ATOP ? 0 : this;
84 bool InsetMathFrac::idxForward(Cursor & cur) const
86 InsetMath::idx_type target = 0;
87 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
90 else if (nargs() == 2)
94 if (cur.idx() == target)
97 cur.pos() = cell(target).x2pos(&cur.bv(), cur.x_target());
102 bool InsetMathFrac::idxBackward(Cursor & cur) const
104 InsetMath::idx_type target = 0;
105 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
108 else if (nargs() == 2)
112 if (cur.idx() == target)
115 cur.pos() = cell(target).x2pos(&cur.bv(), cur.x_target());
120 void InsetMathFrac::metrics(MetricsInfo & mi, Dimension & dim) const
122 Dimension dim0, dim1, dim2;
124 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
126 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
127 cell(0).metrics(mi, dim0);
128 dim.wid = dim0.width()+ 3;
131 } else if (nargs() == 2) {
132 cell(0).metrics(mi, dim0);
133 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
134 cell(1).metrics(mi, dim1);
135 dim.wid = dim0.width() + dim1.wid + 5;
136 dim.asc = max(dim0.asc, dim1.asc);
137 dim.des = max(dim0.des, dim1.des);
139 cell(2).metrics(mi, dim2);
140 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
141 FracChanger dummy(mi.base);
142 cell(0).metrics(mi, dim0);
143 cell(1).metrics(mi, dim1);
144 dim.wid = dim0.width() + dim1.wid + dim2.wid + 10;
145 dim.asc = max(dim2.asc, dim0.height() + 5);
146 dim.des = max(dim2.des, dim1.height() - 5);
149 FracChanger dummy(mi.base);
150 cell(0).metrics(mi, dim0);
151 cell(1).metrics(mi, dim1);
153 cell(2).metrics(mi, dim2);
155 if (kind_ == NICEFRAC) {
156 dim.wid = dim0.width() + dim1.wid + 5;
157 dim.asc = dim0.height() + 5;
158 dim.des = dim1.height() - 5;
159 } else if (kind_ == UNITFRAC) {
160 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
161 dim.wid = dim0.width() + dim1.wid + 5;
162 dim.asc = dim0.height() + 5;
163 dim.des = dim1.height() - 5;
165 dim.wid = max(dim0.width(), dim1.wid) + 2;
166 dim.asc = dim0.height() + 2 + 5;
167 dim.des = dim1.height() + 2 - 5;
174 void InsetMathFrac::draw(PainterInfo & pi, int x, int y) const
176 setPosCache(pi, x, y);
177 Dimension const dim = dimension(*pi.base.bv);
178 Dimension const dim0 = cell(0).dimension(*pi.base.bv);
179 int m = x + dim.wid / 2;
180 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
182 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
183 cell(0).draw(pi, x + 1, y);
184 } else if (nargs() == 2) {
185 cell(0).draw(pi, x + 1, y);
186 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
187 cell(1).draw(pi, x + dim0.width() + 5, y);
189 cell(2).draw(pi, x + 1, y);
190 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
191 FracChanger dummy(pi.base);
192 Dimension const dim1 = cell(1).dimension(*pi.base.bv);
193 Dimension const dim2 = cell(2).dimension(*pi.base.bv);
194 int xx = x + dim2.wid + 5;
195 cell(0).draw(pi, xx + 2,
197 cell(1).draw(pi, xx + dim0.width() + 5,
201 FracChanger dummy(pi.base);
202 Dimension const dim1 = cell(1).dimension(*pi.base.bv);
203 if (kind_ == NICEFRAC) {
204 cell(0).draw(pi, x + 2,
206 cell(1).draw(pi, x + dim0.width() + 5,
208 } else if (kind_ == UNITFRAC) {
209 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
210 cell(0).draw(pi, x + 2,
212 cell(1).draw(pi, x + dim0.width() + 5,
215 // Classical fraction
216 cell(0).draw(pi, m - dim0.width() / 2,
217 y - dim0.des - 2 - 5);
218 cell(1).draw(pi, m - dim1.wid / 2,
219 y + dim1.asc + 2 - 5);
222 if (kind_ == NICEFRAC || kind_ == UNITFRAC) {
226 xx += cell(2).dimension(*pi.base.bv).wid + 5;
228 pi.pain.line(xx + dim0.wid,
231 y - dim.asc + 2, Color_math);
233 if (kind_ == FRAC || kind_ == OVER)
234 pi.pain.line(x + 1, y - 5,
235 x + dim.wid - 2, y - 5, Color_math);
236 drawMarkers(pi, x, y);
240 void InsetMathFrac::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
242 Dimension dim0, dim1;
243 cell(0).metricsT(mi, dim0);
244 cell(1).metricsT(mi, dim1);
245 dim.wid = max(dim0.width(), dim1.wid);
246 dim.asc = dim0.height() + 1;
247 dim.des = dim1.height();
251 void InsetMathFrac::drawT(TextPainter & /*pain*/, int /*x*/, int /*y*/) const
256 int m = x + dim.width() / 2;
257 cell(0).drawT(pain, m - dim0.width() / 2, y - dim0.des - 1);
258 cell(1).drawT(pain, m - dim1.wid / 2, y + dim1.asc);
259 // ASCII art: ignore niceties
260 if (kind_ == FRAC || kind_ == OVER || kind_ == NICEFRAC || kind_ == UNITFRAC)
261 pain.horizontalLine(x, y, dim.width());
266 void InsetMathFrac::write(WriteStream & os) const
268 bool brace = os.pendingBrace();
269 os.pendingBrace(false);
270 if (os.latex() && os.textMode()) {
271 os << "\\ensuremath{";
278 os << '{' << cell(0) << "\\atop " << cell(1) << '}';
281 // \\over is only for compatibility, normalize this to \\frac
282 os << "\\frac{" << cell(0) << "}{" << cell(1) << '}';
288 InsetMathNest::write(os);
290 os << "\\unitfrac[" << cell(2) << "]{" << cell(0) << "}{" << cell(1) << '}';
294 os << "\\unit[" << cell(0) << "]{" << cell(1) << '}';
296 os << "\\unit{" << cell(0) << '}';
300 os.pendingBrace(brace);
304 docstring InsetMathFrac::name() const
308 return from_ascii("frac");
310 return from_ascii("over");
312 return from_ascii("nicefrac");
314 return from_ascii("unitfrac");
316 return from_ascii("unit");
318 return from_ascii("atop");
320 // shut up stupid compiler
325 bool InsetMathFrac::extraBraces() const
327 return kind_ == ATOP || kind_ == OVER;
331 void InsetMathFrac::maple(MapleStream & os) const
333 os << '(' << cell(0) << ")/(" << cell(1) << ')';
337 void InsetMathFrac::mathematica(MathematicaStream & os) const
339 os << '(' << cell(0) << ")/(" << cell(1) << ')';
343 void InsetMathFrac::octave(OctaveStream & os) const
345 os << '(' << cell(0) << ")/(" << cell(1) << ')';
349 void InsetMathFrac::mathmlize(MathStream & os) const
351 os << MTag("mfrac") << cell(0) << cell(1) << ETag("mfrac");
355 void InsetMathFrac::validate(LaTeXFeatures & features) const
357 if (kind_ == NICEFRAC || kind_ == UNITFRAC || kind_ == UNIT)
358 features.require("units");
359 InsetMathNest::validate(features);
363 /////////////////////////////////////////////////////////////////////
367 /////////////////////////////////////////////////////////////////////
370 Inset * InsetMathDFrac::clone() const
372 return new InsetMathDFrac(*this);
376 void InsetMathDFrac::metrics(MetricsInfo & mi, Dimension & dim) const
378 Dimension dim0, dim1;
379 cell(0).metrics(mi, dim0);
380 cell(1).metrics(mi, dim1);
381 dim.wid = max(dim0.wid, dim1.wid) + 2;
382 dim.asc = dim0.height() + 2 + 5;
383 dim.des = dim1.height() + 2 - 5;
387 void InsetMathDFrac::draw(PainterInfo & pi, int x, int y) const
389 Dimension const dim = dimension(*pi.base.bv);
390 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
391 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
392 int m = x + dim.wid / 2;
393 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5);
394 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5);
395 pi.pain.line(x + 1, y - 5, x + dim.wid - 2, y - 5, Color_math);
396 setPosCache(pi, x, y);
400 docstring InsetMathDFrac::name() const
402 return from_ascii("dfrac");
406 void InsetMathDFrac::mathmlize(MathStream & os) const
408 os << MTag("mdfrac") << cell(0) << cell(1) << ETag("mdfrac");
412 void InsetMathDFrac::validate(LaTeXFeatures & features) const
414 features.require("amsmath");
415 InsetMathNest::validate(features);
419 /////////////////////////////////////////////////////////////////////
423 /////////////////////////////////////////////////////////////////////
426 Inset * InsetMathTFrac::clone() const
428 return new InsetMathTFrac(*this);
432 void InsetMathTFrac::metrics(MetricsInfo & mi, Dimension & dim) const
434 StyleChanger dummy(mi.base, LM_ST_SCRIPT);
436 cell(0).metrics(mi, dim0);
438 cell(1).metrics(mi, dim1);
439 dim.wid = max(dim0.width(), dim1.width()) + 2;
440 dim.asc = dim0.height() + 2 + 5;
441 dim.des = dim1.height() + 2 - 5;
445 void InsetMathTFrac::draw(PainterInfo & pi, int x, int y) const
447 StyleChanger dummy(pi.base, LM_ST_SCRIPT);
448 Dimension const dim = dimension(*pi.base.bv);
449 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
450 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
451 int m = x + dim.wid / 2;
452 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.descent() - 2 - 5);
453 cell(1).draw(pi, m - dim1.width() / 2, y + dim1.ascent() + 2 - 5);
454 pi.pain.line(x + 1, y - 5, x + dim.wid - 2, y - 5, Color_math);
455 setPosCache(pi, x, y);
459 docstring InsetMathTFrac::name() const
461 return from_ascii("tfrac");
465 void InsetMathTFrac::mathmlize(MathStream & os) const
467 os << MTag("mtfrac") << cell(0) << cell(1) << ETag("mtfrac");
471 void InsetMathTFrac::validate(LaTeXFeatures & features) const
473 features.require("amsmath");
474 InsetMathNest::validate(features);
478 /////////////////////////////////////////////////////////////////////
482 /////////////////////////////////////////////////////////////////////
485 InsetMathBinom::InsetMathBinom(Kind kind)
490 Inset * InsetMathBinom::clone() const
492 return new InsetMathBinom(*this);
496 int InsetMathBinom::dw(int height) const
507 void InsetMathBinom::metrics(MetricsInfo & mi, Dimension & dim) const
509 FracChanger dummy(mi.base);
510 Dimension dim0, dim1;
511 cell(0).metrics(mi, dim0);
512 cell(1).metrics(mi, dim1);
513 dim.asc = dim0.height() + 4 + 5;
514 dim.des = dim1.height() + 4 - 5;
515 dim.wid = max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
516 metricsMarkers2(dim);
520 void InsetMathBinom::draw(PainterInfo & pi, int x, int y) const
522 Dimension const dim = dimension(*pi.base.bv);
523 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
524 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
525 docstring const bra = kind_ == BRACE ? from_ascii("{") :
526 kind_ == BRACK ? from_ascii("[") : from_ascii("(");
527 docstring const ket = kind_ == BRACE ? from_ascii("}") :
528 kind_ == BRACK ? from_ascii("]") : from_ascii(")");
529 int m = x + dim.width() / 2;
530 FracChanger dummy(pi.base);
531 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.des - 3 - 5);
532 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
533 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()), dim.height(), bra);
534 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()), y - dim.ascent(),
535 dw(dim.height()), dim.height(), ket);
536 drawMarkers2(pi, x, y);
540 bool InsetMathBinom::extraBraces() const
542 return kind_ == CHOOSE || kind_ == BRACE || kind_ == BRACK;
546 void InsetMathBinom::write(WriteStream & os) const
548 bool brace = os.pendingBrace();
549 os.pendingBrace(false);
550 if (os.latex() && os.textMode()) {
551 os << "\\ensuremath{";
558 os << "\\binom{" << cell(0) << "}{" << cell(1) << '}';
561 os << '{' << cell(0) << " \\choose " << cell(1) << '}';
564 os << '{' << cell(0) << " \\brace " << cell(1) << '}';
567 os << '{' << cell(0) << " \\brack " << cell(1) << '}';
571 os.pendingBrace(brace);
575 void InsetMathBinom::normalize(NormalStream & os) const
577 os << "[binom " << cell(0) << ' ' << cell(1) << ']';
581 void InsetMathBinom::validate(LaTeXFeatures & features) const
584 features.require("binom");
585 InsetMathNest::validate(features);
589 /////////////////////////////////////////////////////////////////////
593 /////////////////////////////////////////////////////////////////////
595 Inset * InsetMathDBinom::clone() const
597 return new InsetMathDBinom(*this);
601 int InsetMathDBinom::dw(int height) const
612 void InsetMathDBinom::metrics(MetricsInfo & mi, Dimension & dim) const
614 Dimension dim0, dim1;
615 cell(0).metrics(mi, dim0);
616 cell(1).metrics(mi, dim1);
617 dim.asc = dim0.height() + 4 + 5;
618 dim.des = dim1.height() + 4 - 5;
619 dim.wid = max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
620 metricsMarkers2(dim);
624 void InsetMathDBinom::draw(PainterInfo & pi, int x, int y) const
626 Dimension const dim = dimension(*pi.base.bv);
627 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
628 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
629 int m = x + dim.width() / 2;
630 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.des - 3 - 5);
631 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
632 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()), dim.height(), from_ascii("("));
633 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()), y - dim.ascent(),
634 dw(dim.height()), dim.height(), from_ascii(")"));
635 drawMarkers2(pi, x, y);
639 docstring InsetMathDBinom::name() const
641 return from_ascii("dbinom");
644 void InsetMathDBinom::mathmlize(MathStream & os) const
646 os << MTag("mdbinom") << cell(0) << cell(1) << ETag("mdbinom");
649 void InsetMathDBinom::validate(LaTeXFeatures & features) const
651 features.require("amsmath");
652 InsetMathNest::validate(features);
656 /////////////////////////////////////////////////////////////////////
660 /////////////////////////////////////////////////////////////////////
662 Inset * InsetMathTBinom::clone() const
664 return new InsetMathTBinom(*this);
668 int InsetMathTBinom::dw(int height) const
679 void InsetMathTBinom::metrics(MetricsInfo & mi, Dimension & dim) const
681 StyleChanger dummy(mi.base, LM_ST_SCRIPT);
682 Dimension dim0, dim1;
683 cell(0).metrics(mi, dim0);
684 cell(1).metrics(mi, dim1);
685 dim.asc = dim0.height() + 4 + 5;
686 dim.des = dim1.height() + 4 - 5;
687 dim.wid = max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
688 metricsMarkers2(dim);
692 void InsetMathTBinom::draw(PainterInfo & pi, int x, int y) const
694 StyleChanger dummy(pi.base, LM_ST_SCRIPT);
695 Dimension const dim = dimension(*pi.base.bv);
696 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
697 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
698 int m = x + dim.width() / 2;
699 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.des - 3 - 5);
700 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
701 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()), dim.height(), from_ascii("("));
702 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()), y - dim.ascent(),
703 dw(dim.height()), dim.height(), from_ascii(")"));
704 drawMarkers2(pi, x, y);
708 docstring InsetMathTBinom::name() const
710 return from_ascii("tbinom");
713 void InsetMathTBinom::mathmlize(MathStream & os) const
715 os << MTag("mtbinom") << cell(0) << cell(1) << ETag("mtbinom");
718 void InsetMathTBinom::validate(LaTeXFeatures & features) const
720 features.require("amsmath");
721 InsetMathNest::validate(features);