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 "TextPainter.h"
23 #include "frontends/Painter.h"
28 /////////////////////////////////////////////////////////////////////
32 /////////////////////////////////////////////////////////////////////
35 InsetMathFracBase::InsetMathFracBase(idx_type ncells)
36 : InsetMathNest(ncells)
40 bool InsetMathFracBase::idxUpDown(Cursor & cur, bool up) const
42 InsetMath::idx_type target = !up; // up ? 0 : 1, since upper cell has idx 0
43 if (cur.idx() == target)
46 cur.pos() = cell(target).x2pos(cur.x_target());
52 /////////////////////////////////////////////////////////////////////
56 /////////////////////////////////////////////////////////////////////
59 InsetMathFrac::InsetMathFrac(Kind kind, InsetMath::idx_type ncells)
60 : InsetMathFracBase(ncells), kind_(kind)
64 Inset * InsetMathFrac::clone() const
66 return new InsetMathFrac(*this);
70 InsetMathFrac * InsetMathFrac::asFracInset()
72 return kind_ == ATOP ? 0 : this;
76 InsetMathFrac const * InsetMathFrac::asFracInset() const
78 return kind_ == ATOP ? 0 : this;
82 bool InsetMathFrac::idxForward(Cursor & cur) const
84 InsetMath::idx_type target = 0;
85 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
88 else if (nargs() == 2)
92 if (cur.idx() == target)
95 cur.pos() = cell(target).x2pos(cur.x_target());
100 bool InsetMathFrac::idxBackward(Cursor & cur) const
102 InsetMath::idx_type target = 0;
103 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
106 else if (nargs() == 2)
110 if (cur.idx() == target)
113 cur.pos() = cell(target).x2pos(cur.x_target());
118 void InsetMathFrac::metrics(MetricsInfo & mi, Dimension & dim) const
120 Dimension dim0, dim1, dim2;
122 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
124 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
125 cell(0).metrics(mi, dim0);
126 dim.wid = dim0.width()+ 3;
129 } else if (nargs() == 2) {
130 cell(0).metrics(mi, dim0);
131 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
132 cell(1).metrics(mi, dim1);
133 dim.wid = dim0.width() + dim1.wid + 5;
134 dim.asc = std::max(dim0.asc, dim1.asc);
135 dim.des = std::max(dim0.des, dim1.des);
137 cell(2).metrics(mi, dim2);
138 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
139 FracChanger dummy(mi.base);
140 cell(0).metrics(mi, dim0);
141 cell(1).metrics(mi, dim1);
142 dim.wid = dim0.width() + dim1.wid + dim2.wid + 10;
143 dim.asc = std::max(dim2.asc, dim0.height() + 5);
144 dim.des = std::max(dim2.des, dim1.height() - 5);
147 FracChanger dummy(mi.base);
148 cell(0).metrics(mi, dim0);
149 cell(1).metrics(mi, dim1);
151 cell(2).metrics(mi, dim2);
153 if (kind_ == NICEFRAC) {
154 dim.wid = dim0.width() + dim1.wid + 5;
155 dim.asc = dim0.height() + 5;
156 dim.des = dim1.height() - 5;
157 } else if (kind_ == UNITFRAC) {
158 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
159 dim.wid = dim0.width() + dim1.wid + 5;
160 dim.asc = dim0.height() + 5;
161 dim.des = dim1.height() - 5;
163 dim.wid = std::max(dim0.width(), dim1.wid) + 2;
164 dim.asc = dim0.height() + 2 + 5;
165 dim.des = dim1.height() + 2 - 5;
169 // Cache the inset dimension.
170 setDimCache(mi, dim);
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 = std::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
270 os << '{' << cell(0) << "\\atop " << cell(1) << '}';
273 // \\over is only for compatibility, normalize this to \\frac
274 os << "\\frac{" << cell(0) << "}{" << cell(1) << '}';
280 InsetMathNest::write(os);
282 os << "\\unitfrac[" << cell(2) << "]{" << cell(0) << "}{" << cell(1) << '}';
286 os << "\\unit[" << cell(0) << "]{" << cell(1) << '}';
288 os << "\\unit{" << cell(0) << '}';
294 docstring InsetMathFrac::name() const
298 return from_ascii("frac");
300 return from_ascii("over");
302 return from_ascii("nicefrac");
304 return from_ascii("unitfrac");
306 return from_ascii("unit");
308 return from_ascii("atop");
310 // shut up stupid compiler
315 bool InsetMathFrac::extraBraces() const
317 return kind_ == ATOP || kind_ == OVER;
321 void InsetMathFrac::maple(MapleStream & os) const
323 os << '(' << cell(0) << ")/(" << cell(1) << ')';
327 void InsetMathFrac::mathematica(MathematicaStream & os) const
329 os << '(' << cell(0) << ")/(" << cell(1) << ')';
333 void InsetMathFrac::octave(OctaveStream & os) const
335 os << '(' << cell(0) << ")/(" << cell(1) << ')';
339 void InsetMathFrac::mathmlize(MathStream & os) const
341 os << MTag("mfrac") << cell(0) << cell(1) << ETag("mfrac");
345 void InsetMathFrac::validate(LaTeXFeatures & features) const
347 if (kind_ == NICEFRAC || kind_ == UNITFRAC || kind_ == UNIT)
348 features.require("units");
349 InsetMathNest::validate(features);
353 /////////////////////////////////////////////////////////////////////
357 /////////////////////////////////////////////////////////////////////
360 Inset * InsetMathDFrac::clone() const
362 return new InsetMathDFrac(*this);
366 void InsetMathDFrac::metrics(MetricsInfo & mi, Dimension & dim) const
368 Dimension dim0, dim1;
369 cell(0).metrics(mi, dim0);
370 cell(1).metrics(mi, dim1);
371 dim.wid = std::max(dim0.wid, dim1.wid) + 2;
372 dim.asc = dim0.height() + 2 + 5;
373 dim.des = dim1.height() + 2 - 5;
374 // Cache the inset dimension.
375 setDimCache(mi, dim);
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 = std::max(dim0.width(), dim1.width()) + 2;
432 dim.asc = dim0.height() + 2 + 5;
433 dim.des = dim1.height() + 2 - 5;
434 // Cache the inset dimension.
435 setDimCache(mi, dim);
439 void InsetMathTFrac::draw(PainterInfo & pi, int x, int y) const
441 StyleChanger dummy(pi.base, LM_ST_SCRIPT);
442 Dimension const dim = dimension(*pi.base.bv);
443 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
444 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
445 int m = x + dim.wid / 2;
446 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.descent() - 2 - 5);
447 cell(1).draw(pi, m - dim1.width() / 2, y + dim1.ascent() + 2 - 5);
448 pi.pain.line(x + 1, y - 5, x + dim.wid - 2, y - 5, Color_math);
449 setPosCache(pi, x, y);
453 docstring InsetMathTFrac::name() const
455 return from_ascii("tfrac");
459 void InsetMathTFrac::mathmlize(MathStream & os) const
461 os << MTag("mtfrac") << cell(0) << cell(1) << ETag("mtfrac");
465 void InsetMathTFrac::validate(LaTeXFeatures & features) const
467 features.require("amsmath");
468 InsetMathNest::validate(features);
472 /////////////////////////////////////////////////////////////////////
476 /////////////////////////////////////////////////////////////////////
479 InsetMathBinom::InsetMathBinom(bool choose)
484 Inset * InsetMathBinom::clone() const
486 return new InsetMathBinom(*this);
490 int InsetMathBinom::dw(int height) const
501 void InsetMathBinom::metrics(MetricsInfo & mi, Dimension & dim) const
503 FracChanger dummy(mi.base);
504 Dimension dim0, dim1;
505 cell(0).metrics(mi, dim0);
506 cell(1).metrics(mi, dim1);
507 dim.asc = dim0.height() + 4 + 5;
508 dim.des = dim1.height() + 4 - 5;
509 dim.wid = std::max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
510 metricsMarkers2(dim);
511 // Cache the inset dimension.
512 setDimCache(mi, dim);
516 void InsetMathBinom::draw(PainterInfo & pi, int x, int y) const
518 Dimension const dim = dimension(*pi.base.bv);
519 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
520 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
521 int m = x + dim.width() / 2;
522 FracChanger dummy(pi.base);
523 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.des - 3 - 5);
524 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
525 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()), dim.height(), from_ascii("("));
526 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()), y - dim.ascent(),
527 dw(dim.height()), dim.height(), from_ascii(")"));
528 drawMarkers2(pi, x, y);
532 bool InsetMathBinom::extraBraces() const
538 void InsetMathBinom::write(WriteStream & os) const
541 os << '{' << cell(0) << " \\choose " << cell(1) << '}';
543 os << "\\binom{" << cell(0) << "}{" << cell(1) << '}';
547 void InsetMathBinom::normalize(NormalStream & os) const
549 os << "[binom " << cell(0) << ' ' << cell(1) << ']';
553 /////////////////////////////////////////////////////////////////////
557 /////////////////////////////////////////////////////////////////////
559 Inset * InsetMathDBinom::clone() const
561 return new InsetMathDBinom(*this);
565 int InsetMathDBinom::dw(int height) const
576 void InsetMathDBinom::metrics(MetricsInfo & mi, Dimension & dim) const
578 Dimension dim0, dim1;
579 cell(0).metrics(mi, dim0);
580 cell(1).metrics(mi, dim1);
581 dim.asc = dim0.height() + 4 + 5;
582 dim.des = dim1.height() + 4 - 5;
583 dim.wid = std::max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
584 metricsMarkers2(dim);
585 // Cache the inset dimension.
586 setDimCache(mi, dim);
590 void InsetMathDBinom::draw(PainterInfo & pi, int x, int y) const
592 Dimension const dim = dimension(*pi.base.bv);
593 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
594 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
595 int m = x + dim.width() / 2;
596 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.des - 3 - 5);
597 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
598 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()), dim.height(), from_ascii("("));
599 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()), y - dim.ascent(),
600 dw(dim.height()), dim.height(), from_ascii(")"));
601 drawMarkers2(pi, x, y);
605 docstring InsetMathDBinom::name() const
607 return from_ascii("dbinom");
610 void InsetMathDBinom::mathmlize(MathStream & os) const
612 os << MTag("mdbinom") << cell(0) << cell(1) << ETag("mdbinom");
615 void InsetMathDBinom::validate(LaTeXFeatures & features) const
617 features.require("amsmath");
618 InsetMathNest::validate(features);
622 /////////////////////////////////////////////////////////////////////
626 /////////////////////////////////////////////////////////////////////
628 Inset * InsetMathTBinom::clone() const
630 return new InsetMathTBinom(*this);
634 int InsetMathTBinom::dw(int height) const
645 void InsetMathTBinom::metrics(MetricsInfo & mi, Dimension & dim) const
647 StyleChanger dummy(mi.base, LM_ST_SCRIPT);
648 Dimension dim0, dim1;
649 cell(0).metrics(mi, dim0);
650 cell(1).metrics(mi, dim1);
651 dim.asc = dim0.height() + 4 + 5;
652 dim.des = dim1.height() + 4 - 5;
653 dim.wid = std::max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
654 metricsMarkers2(dim);
655 // Cache the inset dimension.
656 setDimCache(mi, dim);
660 void InsetMathTBinom::draw(PainterInfo & pi, int x, int y) const
662 StyleChanger dummy(pi.base, LM_ST_SCRIPT);
663 Dimension const dim = dimension(*pi.base.bv);
664 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
665 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
666 int m = x + dim.width() / 2;
667 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.des - 3 - 5);
668 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
669 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()), dim.height(), from_ascii("("));
670 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()), y - dim.ascent(),
671 dw(dim.height()), dim.height(), from_ascii(")"));
672 drawMarkers2(pi, x, y);
676 docstring InsetMathTBinom::name() const
678 return from_ascii("tbinom");
681 void InsetMathTBinom::mathmlize(MathStream & os) const
683 os << MTag("mtbinom") << cell(0) << cell(1) << ETag("mtbinom");
686 void InsetMathTBinom::validate(LaTeXFeatures & features) const
688 features.require("amsmath");
689 InsetMathNest::validate(features);