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
10 * Full author contact details are available in file CREDITS.
15 #include "InsetMathFrac.h"
18 #include "LaTeXFeatures.h"
20 #include "MathStream.h"
21 #include "MathSupport.h"
22 #include "MetricsInfo.h"
23 #include "TextPainter.h"
25 #include "frontends/Painter.h"
31 /////////////////////////////////////////////////////////////////////
35 /////////////////////////////////////////////////////////////////////
38 InsetMathFracBase::InsetMathFracBase(idx_type ncells)
39 : InsetMathNest(ncells)
43 bool InsetMathFracBase::idxUpDown(Cursor & cur, bool up) const
45 InsetMath::idx_type target = !up; // up ? 0 : 1, since upper cell has idx 0
46 if (cur.idx() == target)
49 cur.pos() = cell(target).x2pos(&cur.bv(), cur.x_target());
55 /////////////////////////////////////////////////////////////////////
59 /////////////////////////////////////////////////////////////////////
62 InsetMathFrac::InsetMathFrac(Kind kind, InsetMath::idx_type ncells)
63 : InsetMathFracBase(ncells), kind_(kind)
67 Inset * InsetMathFrac::clone() const
69 return new InsetMathFrac(*this);
73 InsetMathFrac * InsetMathFrac::asFracInset()
75 return kind_ == ATOP ? 0 : this;
79 InsetMathFrac const * InsetMathFrac::asFracInset() const
81 return kind_ == ATOP ? 0 : this;
85 bool InsetMathFrac::idxForward(Cursor & cur) const
87 InsetMath::idx_type target = 0;
88 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
91 else if (nargs() == 2)
95 if (cur.idx() == target)
98 cur.pos() = cell(target).x2pos(&cur.bv(), cur.x_target());
103 bool InsetMathFrac::idxBackward(Cursor & cur) const
105 InsetMath::idx_type target = 0;
106 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
109 else if (nargs() == 2)
113 if (cur.idx() == target)
116 cur.pos() = cell(target).x2pos(&cur.bv(), cur.x_target());
121 void InsetMathFrac::metrics(MetricsInfo & mi, Dimension & dim) const
123 Dimension dim0, dim1, dim2;
125 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
127 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
128 cell(0).metrics(mi, dim0);
129 dim.wid = dim0.width()+ 3;
132 } else if (nargs() == 2) {
133 cell(0).metrics(mi, dim0);
134 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
135 cell(1).metrics(mi, dim1);
136 dim.wid = dim0.width() + dim1.wid + 5;
137 dim.asc = max(dim0.asc, dim1.asc);
138 dim.des = max(dim0.des, dim1.des);
140 cell(2).metrics(mi, dim2);
141 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
142 FracChanger dummy(mi.base);
143 cell(0).metrics(mi, dim0);
144 cell(1).metrics(mi, dim1);
145 dim.wid = dim0.width() + dim1.wid + dim2.wid + 10;
146 dim.asc = max(dim2.asc, dim0.height() + 5);
147 dim.des = max(dim2.des, dim1.height() - 5);
150 FracChanger dummy(mi.base);
151 cell(0).metrics(mi, dim0);
152 cell(1).metrics(mi, dim1);
154 cell(2).metrics(mi, dim2);
156 if (kind_ == NICEFRAC) {
157 dim.wid = dim0.width() + dim1.wid + 5;
158 dim.asc = dim0.height() + 5;
159 dim.des = dim1.height() - 5;
160 } else if (kind_ == UNITFRAC) {
161 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
162 dim.wid = dim0.width() + dim1.wid + 5;
163 dim.asc = dim0.height() + 5;
164 dim.des = dim1.height() - 5;
166 dim.wid = max(dim0.width(), dim1.wid) + 2;
167 dim.asc = dim0.height() + 2 + 5;
168 dim.des = dim1.height() + 2 - 5;
175 void InsetMathFrac::draw(PainterInfo & pi, int x, int y) const
177 setPosCache(pi, x, y);
178 Dimension const dim = dimension(*pi.base.bv);
179 Dimension const dim0 = cell(0).dimension(*pi.base.bv);
180 int m = x + dim.wid / 2;
181 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
183 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
184 cell(0).draw(pi, x + 1, y);
185 } else if (nargs() == 2) {
186 cell(0).draw(pi, x + 1, y);
187 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
188 cell(1).draw(pi, x + dim0.width() + 5, y);
190 cell(2).draw(pi, x + 1, y);
191 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
192 FracChanger dummy(pi.base);
193 Dimension const dim1 = cell(1).dimension(*pi.base.bv);
194 Dimension const dim2 = cell(2).dimension(*pi.base.bv);
195 int xx = x + dim2.wid + 5;
196 cell(0).draw(pi, xx + 2,
198 cell(1).draw(pi, xx + dim0.width() + 5,
202 FracChanger dummy(pi.base);
203 Dimension const dim1 = cell(1).dimension(*pi.base.bv);
204 if (kind_ == NICEFRAC) {
205 cell(0).draw(pi, x + 2,
207 cell(1).draw(pi, x + dim0.width() + 5,
209 } else if (kind_ == UNITFRAC) {
210 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
211 cell(0).draw(pi, x + 2,
213 cell(1).draw(pi, x + dim0.width() + 5,
216 // Classical fraction
217 cell(0).draw(pi, m - dim0.width() / 2,
218 y - dim0.des - 2 - 5);
219 cell(1).draw(pi, m - dim1.wid / 2,
220 y + dim1.asc + 2 - 5);
223 if (kind_ == NICEFRAC || kind_ == UNITFRAC) {
227 xx += cell(2).dimension(*pi.base.bv).wid + 5;
229 pi.pain.line(xx + dim0.wid,
232 y - dim.asc + 2, Color_math);
234 if (kind_ == FRAC || kind_ == OVER)
235 pi.pain.line(x + 1, y - 5,
236 x + dim.wid - 2, y - 5, Color_math);
237 drawMarkers(pi, x, y);
241 void InsetMathFrac::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
243 Dimension dim0, dim1;
244 cell(0).metricsT(mi, dim0);
245 cell(1).metricsT(mi, dim1);
246 dim.wid = max(dim0.width(), dim1.wid);
247 dim.asc = dim0.height() + 1;
248 dim.des = dim1.height();
252 void InsetMathFrac::drawT(TextPainter & /*pain*/, int /*x*/, int /*y*/) const
257 int m = x + dim.width() / 2;
258 cell(0).drawT(pain, m - dim0.width() / 2, y - dim0.des - 1);
259 cell(1).drawT(pain, m - dim1.wid / 2, y + dim1.asc);
260 // ASCII art: ignore niceties
261 if (kind_ == FRAC || kind_ == OVER || kind_ == NICEFRAC || kind_ == UNITFRAC)
262 pain.horizontalLine(x, y, dim.width());
267 void InsetMathFrac::write(WriteStream & os) const
269 MathEnsurer ensurer(os);
272 os << '{' << cell(0) << "\\atop " << cell(1) << '}';
275 // \\over is only for compatibility, normalize this to \\frac
276 os << "\\frac{" << cell(0) << "}{" << cell(1) << '}';
282 InsetMathNest::write(os);
284 os << "\\unitfrac[" << cell(2) << "]{" << cell(0) << "}{" << cell(1) << '}';
288 os << "\\unit[" << cell(0) << "]{" << cell(1) << '}';
290 os << "\\unit{" << cell(0) << '}';
296 docstring InsetMathFrac::name() const
300 return from_ascii("frac");
302 return from_ascii("over");
304 return from_ascii("nicefrac");
306 return from_ascii("unitfrac");
308 return from_ascii("unit");
310 return from_ascii("atop");
312 // shut up stupid compiler
317 bool InsetMathFrac::extraBraces() const
319 return kind_ == ATOP || kind_ == OVER;
323 void InsetMathFrac::maple(MapleStream & os) const
325 os << '(' << cell(0) << ")/(" << cell(1) << ')';
329 void InsetMathFrac::mathematica(MathematicaStream & os) const
331 os << '(' << cell(0) << ")/(" << cell(1) << ')';
335 void InsetMathFrac::octave(OctaveStream & os) const
337 os << '(' << cell(0) << ")/(" << cell(1) << ')';
341 void InsetMathFrac::mathmlize(MathStream & os) const
343 os << MTag("mfrac") << cell(0) << cell(1) << ETag("mfrac");
347 void InsetMathFrac::validate(LaTeXFeatures & features) const
349 if (kind_ == NICEFRAC || kind_ == UNITFRAC || kind_ == UNIT)
350 features.require("units");
351 InsetMathNest::validate(features);
355 /////////////////////////////////////////////////////////////////////
359 /////////////////////////////////////////////////////////////////////
362 Inset * InsetMathDFrac::clone() const
364 return new InsetMathDFrac(*this);
368 void InsetMathDFrac::metrics(MetricsInfo & mi, Dimension & dim) const
370 Dimension dim0, dim1;
371 cell(0).metrics(mi, dim0);
372 cell(1).metrics(mi, dim1);
373 dim.wid = max(dim0.wid, dim1.wid) + 2;
374 dim.asc = dim0.height() + 2 + 5;
375 dim.des = dim1.height() + 2 - 5;
379 void InsetMathDFrac::draw(PainterInfo & pi, int x, int y) const
381 Dimension const dim = dimension(*pi.base.bv);
382 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
383 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
384 int m = x + dim.wid / 2;
385 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5);
386 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5);
387 pi.pain.line(x + 1, y - 5, x + dim.wid - 2, y - 5, Color_math);
388 setPosCache(pi, x, y);
392 docstring InsetMathDFrac::name() const
394 return from_ascii("dfrac");
398 void InsetMathDFrac::mathmlize(MathStream & os) const
400 os << MTag("mdfrac") << cell(0) << cell(1) << ETag("mdfrac");
404 void InsetMathDFrac::validate(LaTeXFeatures & features) const
406 features.require("amsmath");
407 InsetMathNest::validate(features);
411 /////////////////////////////////////////////////////////////////////
415 /////////////////////////////////////////////////////////////////////
418 Inset * InsetMathTFrac::clone() const
420 return new InsetMathTFrac(*this);
424 void InsetMathTFrac::metrics(MetricsInfo & mi, Dimension & dim) const
426 StyleChanger dummy(mi.base, LM_ST_SCRIPT);
428 cell(0).metrics(mi, dim0);
430 cell(1).metrics(mi, dim1);
431 dim.wid = max(dim0.width(), dim1.width()) + 2;
432 dim.asc = dim0.height() + 2 + 5;
433 dim.des = dim1.height() + 2 - 5;
437 void InsetMathTFrac::draw(PainterInfo & pi, int x, int y) const
439 StyleChanger dummy(pi.base, LM_ST_SCRIPT);
440 Dimension const dim = dimension(*pi.base.bv);
441 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
442 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
443 int m = x + dim.wid / 2;
444 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.descent() - 2 - 5);
445 cell(1).draw(pi, m - dim1.width() / 2, y + dim1.ascent() + 2 - 5);
446 pi.pain.line(x + 1, y - 5, x + dim.wid - 2, y - 5, Color_math);
447 setPosCache(pi, x, y);
451 docstring InsetMathTFrac::name() const
453 return from_ascii("tfrac");
457 void InsetMathTFrac::mathmlize(MathStream & os) const
459 os << MTag("mtfrac") << cell(0) << cell(1) << ETag("mtfrac");
463 void InsetMathTFrac::validate(LaTeXFeatures & features) const
465 features.require("amsmath");
466 InsetMathNest::validate(features);
470 /////////////////////////////////////////////////////////////////////
474 /////////////////////////////////////////////////////////////////////
477 Inset * InsetMathCFrac::clone() const
479 return new InsetMathCFrac(*this);
483 void InsetMathCFrac::metrics(MetricsInfo & mi, Dimension & dim) const
485 Dimension dim0, dim1;
486 cell(0).metrics(mi, dim0);
487 cell(1).metrics(mi, dim1);
488 dim.wid = max(dim0.wid, dim1.wid) + 2;
489 dim.asc = dim0.height() + 2 + 5;
490 dim.des = dim1.height() + 2 - 5;
494 void InsetMathCFrac::draw(PainterInfo & pi, int x, int y) const
496 Dimension const dim = dimension(*pi.base.bv);
497 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
498 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
499 int m = x + dim.wid / 2;
500 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5);
501 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5);
502 pi.pain.line(x + 1, y - 5, x + dim.wid - 2, y - 5, Color_math);
503 setPosCache(pi, x, y);
507 docstring InsetMathCFrac::name() const
509 return from_ascii("cfrac");
513 void InsetMathCFrac::mathmlize(MathStream & os) const
515 os << MTag("mcfrac") << cell(0) << cell(1) << ETag("mcfrac");
519 void InsetMathCFrac::validate(LaTeXFeatures & features) const
521 features.require("amsmath");
522 InsetMathNest::validate(features);
526 /////////////////////////////////////////////////////////////////////
530 /////////////////////////////////////////////////////////////////////
533 InsetMathBinom::InsetMathBinom(Kind kind)
538 Inset * InsetMathBinom::clone() const
540 return new InsetMathBinom(*this);
544 int InsetMathBinom::dw(int height) const
555 void InsetMathBinom::metrics(MetricsInfo & mi, Dimension & dim) const
557 FracChanger dummy(mi.base);
558 Dimension dim0, dim1;
559 cell(0).metrics(mi, dim0);
560 cell(1).metrics(mi, dim1);
561 dim.asc = dim0.height() + 4 + 5;
562 dim.des = dim1.height() + 4 - 5;
563 dim.wid = max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
564 metricsMarkers2(dim);
568 void InsetMathBinom::draw(PainterInfo & pi, int x, int y) const
570 Dimension const dim = dimension(*pi.base.bv);
571 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
572 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
573 docstring const bra = kind_ == BRACE ? from_ascii("{") :
574 kind_ == BRACK ? from_ascii("[") : from_ascii("(");
575 docstring const ket = kind_ == BRACE ? from_ascii("}") :
576 kind_ == BRACK ? from_ascii("]") : from_ascii(")");
577 int m = x + dim.width() / 2;
578 FracChanger dummy(pi.base);
579 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.des - 3 - 5);
580 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
581 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()), dim.height(), bra);
582 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()), y - dim.ascent(),
583 dw(dim.height()), dim.height(), ket);
584 drawMarkers2(pi, x, y);
588 bool InsetMathBinom::extraBraces() const
590 return kind_ == CHOOSE || kind_ == BRACE || kind_ == BRACK;
594 void InsetMathBinom::write(WriteStream & os) const
596 MathEnsurer ensurer(os);
599 os << "\\binom{" << cell(0) << "}{" << cell(1) << '}';
602 os << '{' << cell(0) << " \\choose " << cell(1) << '}';
605 os << '{' << cell(0) << " \\brace " << cell(1) << '}';
608 os << '{' << cell(0) << " \\brack " << cell(1) << '}';
614 void InsetMathBinom::normalize(NormalStream & os) const
616 os << "[binom " << cell(0) << ' ' << cell(1) << ']';
620 void InsetMathBinom::validate(LaTeXFeatures & features) const
623 features.require("binom");
624 InsetMathNest::validate(features);
628 /////////////////////////////////////////////////////////////////////
632 /////////////////////////////////////////////////////////////////////
634 Inset * InsetMathDBinom::clone() const
636 return new InsetMathDBinom(*this);
640 int InsetMathDBinom::dw(int height) const
651 void InsetMathDBinom::metrics(MetricsInfo & mi, Dimension & dim) const
653 Dimension dim0, dim1;
654 cell(0).metrics(mi, dim0);
655 cell(1).metrics(mi, dim1);
656 dim.asc = dim0.height() + 4 + 5;
657 dim.des = dim1.height() + 4 - 5;
658 dim.wid = max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
659 metricsMarkers2(dim);
663 void InsetMathDBinom::draw(PainterInfo & pi, int x, int y) const
665 Dimension const dim = dimension(*pi.base.bv);
666 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
667 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
668 int m = x + dim.width() / 2;
669 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.des - 3 - 5);
670 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
671 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()), dim.height(), from_ascii("("));
672 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()), y - dim.ascent(),
673 dw(dim.height()), dim.height(), from_ascii(")"));
674 drawMarkers2(pi, x, y);
678 docstring InsetMathDBinom::name() const
680 return from_ascii("dbinom");
683 void InsetMathDBinom::mathmlize(MathStream & os) const
685 os << MTag("mdbinom") << cell(0) << cell(1) << ETag("mdbinom");
688 void InsetMathDBinom::validate(LaTeXFeatures & features) const
690 features.require("amsmath");
691 InsetMathNest::validate(features);
695 /////////////////////////////////////////////////////////////////////
699 /////////////////////////////////////////////////////////////////////
701 Inset * InsetMathTBinom::clone() const
703 return new InsetMathTBinom(*this);
707 int InsetMathTBinom::dw(int height) const
718 void InsetMathTBinom::metrics(MetricsInfo & mi, Dimension & dim) const
720 StyleChanger dummy(mi.base, LM_ST_SCRIPT);
721 Dimension dim0, dim1;
722 cell(0).metrics(mi, dim0);
723 cell(1).metrics(mi, dim1);
724 dim.asc = dim0.height() + 4 + 5;
725 dim.des = dim1.height() + 4 - 5;
726 dim.wid = max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
727 metricsMarkers2(dim);
731 void InsetMathTBinom::draw(PainterInfo & pi, int x, int y) const
733 StyleChanger dummy(pi.base, LM_ST_SCRIPT);
734 Dimension const dim = dimension(*pi.base.bv);
735 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
736 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
737 int m = x + dim.width() / 2;
738 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.des - 3 - 5);
739 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
740 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()), dim.height(), from_ascii("("));
741 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()), y - dim.ascent(),
742 dw(dim.height()), dim.height(), from_ascii(")"));
743 drawMarkers2(pi, x, y);
747 docstring InsetMathTBinom::name() const
749 return from_ascii("tbinom");
752 void InsetMathTBinom::mathmlize(MathStream & os) const
754 os << MTag("mtbinom") << cell(0) << cell(1) << ETag("mtbinom");
757 void InsetMathTBinom::validate(LaTeXFeatures & features) const
759 features.require("amsmath");
760 InsetMathNest::validate(features);