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.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.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.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;
171 // Cache the inset dimension.
172 setDimCache(mi, dim);
176 void InsetMathFrac::draw(PainterInfo & pi, int x, int y) const
178 setPosCache(pi, x, y);
179 Dimension const dim = dimension(*pi.base.bv);
180 Dimension const dim0 = cell(0).dimension(*pi.base.bv);
181 int m = x + dim.wid / 2;
182 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
184 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
185 cell(0).draw(pi, x + 1, y);
186 } else if (nargs() == 2) {
187 cell(0).draw(pi, x + 1, y);
188 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
189 cell(1).draw(pi, x + dim0.width() + 5, y);
191 cell(2).draw(pi, x + 1, y);
192 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
193 FracChanger dummy(pi.base);
194 Dimension const dim1 = cell(1).dimension(*pi.base.bv);
195 Dimension const dim2 = cell(2).dimension(*pi.base.bv);
196 int xx = x + dim2.wid + 5;
197 cell(0).draw(pi, xx + 2,
199 cell(1).draw(pi, xx + dim0.width() + 5,
203 FracChanger dummy(pi.base);
204 Dimension const dim1 = cell(1).dimension(*pi.base.bv);
205 if (kind_ == NICEFRAC) {
206 cell(0).draw(pi, x + 2,
208 cell(1).draw(pi, x + dim0.width() + 5,
210 } else if (kind_ == UNITFRAC) {
211 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
212 cell(0).draw(pi, x + 2,
214 cell(1).draw(pi, x + dim0.width() + 5,
217 // Classical fraction
218 cell(0).draw(pi, m - dim0.width() / 2,
219 y - dim0.des - 2 - 5);
220 cell(1).draw(pi, m - dim1.wid / 2,
221 y + dim1.asc + 2 - 5);
224 if (kind_ == NICEFRAC || kind_ == UNITFRAC) {
228 xx += cell(2).dimension(*pi.base.bv).wid + 5;
230 pi.pain.line(xx + dim0.wid,
233 y - dim.asc + 2, Color_math);
235 if (kind_ == FRAC || kind_ == OVER)
236 pi.pain.line(x + 1, y - 5,
237 x + dim.wid - 2, y - 5, Color_math);
238 drawMarkers(pi, x, y);
242 void InsetMathFrac::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
244 Dimension dim0, dim1;
245 cell(0).metricsT(mi, dim0);
246 cell(1).metricsT(mi, dim1);
247 dim.wid = max(dim0.width(), dim1.wid);
248 dim.asc = dim0.height() + 1;
249 dim.des = dim1.height();
253 void InsetMathFrac::drawT(TextPainter & pain, int x, int y) const
258 int m = x + dim.width() / 2;
259 cell(0).drawT(pain, m - dim0.width() / 2, y - dim0.des - 1);
260 cell(1).drawT(pain, m - dim1.wid / 2, y + dim1.asc);
261 // ASCII art: ignore niceties
262 if (kind_ == FRAC || kind_ == OVER || kind_ == NICEFRAC || kind_ == UNITFRAC)
263 pain.horizontalLine(x, y, dim.width());
268 void InsetMathFrac::write(WriteStream & os) const
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;
376 // Cache the inset dimension.
377 setDimCache(mi, dim);
381 void InsetMathDFrac::draw(PainterInfo & pi, int x, int y) const
383 Dimension const dim = dimension(*pi.base.bv);
384 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
385 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
386 int m = x + dim.wid / 2;
387 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5);
388 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5);
389 pi.pain.line(x + 1, y - 5, x + dim.wid - 2, y - 5, Color_math);
390 setPosCache(pi, x, y);
394 docstring InsetMathDFrac::name() const
396 return from_ascii("dfrac");
400 void InsetMathDFrac::mathmlize(MathStream & os) const
402 os << MTag("mdfrac") << cell(0) << cell(1) << ETag("mdfrac");
406 void InsetMathDFrac::validate(LaTeXFeatures & features) const
408 features.require("amsmath");
409 InsetMathNest::validate(features);
413 /////////////////////////////////////////////////////////////////////
417 /////////////////////////////////////////////////////////////////////
420 Inset * InsetMathTFrac::clone() const
422 return new InsetMathTFrac(*this);
426 void InsetMathTFrac::metrics(MetricsInfo & mi, Dimension & dim) const
428 StyleChanger dummy(mi.base, LM_ST_SCRIPT);
430 cell(0).metrics(mi, dim0);
432 cell(1).metrics(mi, dim1);
433 dim.wid = max(dim0.width(), dim1.width()) + 2;
434 dim.asc = dim0.height() + 2 + 5;
435 dim.des = dim1.height() + 2 - 5;
436 // Cache the inset dimension.
437 setDimCache(mi, dim);
441 void InsetMathTFrac::draw(PainterInfo & pi, int x, int y) const
443 StyleChanger dummy(pi.base, LM_ST_SCRIPT);
444 Dimension const dim = dimension(*pi.base.bv);
445 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
446 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
447 int m = x + dim.wid / 2;
448 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.descent() - 2 - 5);
449 cell(1).draw(pi, m - dim1.width() / 2, y + dim1.ascent() + 2 - 5);
450 pi.pain.line(x + 1, y - 5, x + dim.wid - 2, y - 5, Color_math);
451 setPosCache(pi, x, y);
455 docstring InsetMathTFrac::name() const
457 return from_ascii("tfrac");
461 void InsetMathTFrac::mathmlize(MathStream & os) const
463 os << MTag("mtfrac") << cell(0) << cell(1) << ETag("mtfrac");
467 void InsetMathTFrac::validate(LaTeXFeatures & features) const
469 features.require("amsmath");
470 InsetMathNest::validate(features);
474 /////////////////////////////////////////////////////////////////////
478 /////////////////////////////////////////////////////////////////////
481 InsetMathBinom::InsetMathBinom(bool choose)
486 Inset * InsetMathBinom::clone() const
488 return new InsetMathBinom(*this);
492 int InsetMathBinom::dw(int height) const
503 void InsetMathBinom::metrics(MetricsInfo & mi, Dimension & dim) const
505 FracChanger dummy(mi.base);
506 Dimension dim0, dim1;
507 cell(0).metrics(mi, dim0);
508 cell(1).metrics(mi, dim1);
509 dim.asc = dim0.height() + 4 + 5;
510 dim.des = dim1.height() + 4 - 5;
511 dim.wid = max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
512 metricsMarkers2(dim);
513 // Cache the inset dimension.
514 setDimCache(mi, dim);
518 void InsetMathBinom::draw(PainterInfo & pi, int x, int y) const
520 Dimension const dim = dimension(*pi.base.bv);
521 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
522 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
523 int m = x + dim.width() / 2;
524 FracChanger dummy(pi.base);
525 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.des - 3 - 5);
526 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
527 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()), dim.height(), from_ascii("("));
528 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()), y - dim.ascent(),
529 dw(dim.height()), dim.height(), from_ascii(")"));
530 drawMarkers2(pi, x, y);
534 bool InsetMathBinom::extraBraces() const
540 void InsetMathBinom::write(WriteStream & os) const
543 os << '{' << cell(0) << " \\choose " << cell(1) << '}';
545 os << "\\binom{" << cell(0) << "}{" << cell(1) << '}';
549 void InsetMathBinom::normalize(NormalStream & os) const
551 os << "[binom " << cell(0) << ' ' << cell(1) << ']';
555 /////////////////////////////////////////////////////////////////////
559 /////////////////////////////////////////////////////////////////////
561 Inset * InsetMathDBinom::clone() const
563 return new InsetMathDBinom(*this);
567 int InsetMathDBinom::dw(int height) const
578 void InsetMathDBinom::metrics(MetricsInfo & mi, Dimension & dim) const
580 Dimension dim0, dim1;
581 cell(0).metrics(mi, dim0);
582 cell(1).metrics(mi, dim1);
583 dim.asc = dim0.height() + 4 + 5;
584 dim.des = dim1.height() + 4 - 5;
585 dim.wid = max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
586 metricsMarkers2(dim);
587 // Cache the inset dimension.
588 setDimCache(mi, dim);
592 void InsetMathDBinom::draw(PainterInfo & pi, int x, int y) const
594 Dimension const dim = dimension(*pi.base.bv);
595 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
596 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
597 int m = x + dim.width() / 2;
598 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.des - 3 - 5);
599 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
600 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()), dim.height(), from_ascii("("));
601 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()), y - dim.ascent(),
602 dw(dim.height()), dim.height(), from_ascii(")"));
603 drawMarkers2(pi, x, y);
607 docstring InsetMathDBinom::name() const
609 return from_ascii("dbinom");
612 void InsetMathDBinom::mathmlize(MathStream & os) const
614 os << MTag("mdbinom") << cell(0) << cell(1) << ETag("mdbinom");
617 void InsetMathDBinom::validate(LaTeXFeatures & features) const
619 features.require("amsmath");
620 InsetMathNest::validate(features);
624 /////////////////////////////////////////////////////////////////////
628 /////////////////////////////////////////////////////////////////////
630 Inset * InsetMathTBinom::clone() const
632 return new InsetMathTBinom(*this);
636 int InsetMathTBinom::dw(int height) const
647 void InsetMathTBinom::metrics(MetricsInfo & mi, Dimension & dim) const
649 StyleChanger dummy(mi.base, LM_ST_SCRIPT);
650 Dimension dim0, dim1;
651 cell(0).metrics(mi, dim0);
652 cell(1).metrics(mi, dim1);
653 dim.asc = dim0.height() + 4 + 5;
654 dim.des = dim1.height() + 4 - 5;
655 dim.wid = max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
656 metricsMarkers2(dim);
657 // Cache the inset dimension.
658 setDimCache(mi, dim);
662 void InsetMathTBinom::draw(PainterInfo & pi, int x, int y) const
664 StyleChanger dummy(pi.base, LM_ST_SCRIPT);
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 InsetMathTBinom::name() const
680 return from_ascii("tbinom");
683 void InsetMathTBinom::mathmlize(MathStream & os) const
685 os << MTag("mtbinom") << cell(0) << cell(1) << ETag("mtbinom");
688 void InsetMathTBinom::validate(LaTeXFeatures & features) const
690 features.require("amsmath");
691 InsetMathNest::validate(features);