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"
29 /////////////////////////////////////////////////////////////////////
33 /////////////////////////////////////////////////////////////////////
36 InsetMathFracBase::InsetMathFracBase(idx_type ncells)
37 : InsetMathNest(ncells)
41 bool InsetMathFracBase::idxUpDown(Cursor & cur, bool up) const
43 InsetMath::idx_type target = !up; // up ? 0 : 1, since upper cell has idx 0
44 if (cur.idx() == target)
47 cur.pos() = cell(target).x2pos(cur.x_target());
53 /////////////////////////////////////////////////////////////////////
57 /////////////////////////////////////////////////////////////////////
60 InsetMathFrac::InsetMathFrac(Kind kind, InsetMath::idx_type ncells)
61 : InsetMathFracBase(ncells), kind_(kind)
65 Inset * InsetMathFrac::clone() const
67 return new InsetMathFrac(*this);
71 InsetMathFrac * InsetMathFrac::asFracInset()
73 return kind_ == ATOP ? 0 : this;
77 InsetMathFrac const * InsetMathFrac::asFracInset() const
79 return kind_ == ATOP ? 0 : this;
83 bool InsetMathFrac::idxForward(Cursor & cur) const
85 InsetMath::idx_type target = 0;
86 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
89 else if (nargs() == 2)
93 if (cur.idx() == target)
96 cur.pos() = cell(target).x2pos(cur.x_target());
101 bool InsetMathFrac::idxBackward(Cursor & cur) const
103 InsetMath::idx_type target = 0;
104 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
107 else if (nargs() == 2)
111 if (cur.idx() == target)
114 cur.pos() = cell(target).x2pos(cur.x_target());
119 void InsetMathFrac::metrics(MetricsInfo & mi, Dimension & dim) const
121 Dimension dim0, dim1, dim2;
123 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
125 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
126 cell(0).metrics(mi, dim0);
127 dim.wid = dim0.width()+ 3;
130 } else if (nargs() == 2) {
131 cell(0).metrics(mi, dim0);
132 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
133 cell(1).metrics(mi, dim1);
134 dim.wid = dim0.width() + dim1.wid + 5;
135 dim.asc = std::max(dim0.asc, dim1.asc);
136 dim.des = std::max(dim0.des, dim1.des);
138 cell(2).metrics(mi, dim2);
139 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
140 FracChanger dummy(mi.base);
141 cell(0).metrics(mi, dim0);
142 cell(1).metrics(mi, dim1);
143 dim.wid = dim0.width() + dim1.wid + dim2.wid + 10;
144 dim.asc = std::max(dim2.asc, dim0.height() + 5);
145 dim.des = std::max(dim2.des, dim1.height() - 5);
148 FracChanger dummy(mi.base);
149 cell(0).metrics(mi, dim0);
150 cell(1).metrics(mi, dim1);
152 cell(2).metrics(mi, dim2);
154 if (kind_ == NICEFRAC) {
155 dim.wid = dim0.width() + dim1.wid + 5;
156 dim.asc = dim0.height() + 5;
157 dim.des = dim1.height() - 5;
158 } else if (kind_ == UNITFRAC) {
159 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
160 dim.wid = dim0.width() + dim1.wid + 5;
161 dim.asc = dim0.height() + 5;
162 dim.des = dim1.height() - 5;
164 dim.wid = std::max(dim0.width(), dim1.wid) + 2;
165 dim.asc = dim0.height() + 2 + 5;
166 dim.des = dim1.height() + 2 - 5;
170 // Cache the inset dimension.
171 setDimCache(mi, dim);
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 = std::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
271 os << '{' << cell(0) << "\\atop " << cell(1) << '}';
274 // \\over is only for compatibility, normalize this to \\frac
275 os << "\\frac{" << cell(0) << "}{" << cell(1) << '}';
281 InsetMathNest::write(os);
283 os << "\\unitfrac[" << cell(2) << "]{" << cell(0) << "}{" << cell(1) << '}';
287 os << "\\unit[" << cell(0) << "]{" << cell(1) << '}';
289 os << "\\unit{" << cell(0) << '}';
295 docstring InsetMathFrac::name() const
299 return from_ascii("frac");
301 return from_ascii("over");
303 return from_ascii("nicefrac");
305 return from_ascii("unitfrac");
307 return from_ascii("unit");
309 return from_ascii("atop");
311 // shut up stupid compiler
316 bool InsetMathFrac::extraBraces() const
318 return kind_ == ATOP || kind_ == OVER;
322 void InsetMathFrac::maple(MapleStream & os) const
324 os << '(' << cell(0) << ")/(" << cell(1) << ')';
328 void InsetMathFrac::mathematica(MathematicaStream & os) const
330 os << '(' << cell(0) << ")/(" << cell(1) << ')';
334 void InsetMathFrac::octave(OctaveStream & os) const
336 os << '(' << cell(0) << ")/(" << cell(1) << ')';
340 void InsetMathFrac::mathmlize(MathStream & os) const
342 os << MTag("mfrac") << cell(0) << cell(1) << ETag("mfrac");
346 void InsetMathFrac::validate(LaTeXFeatures & features) const
348 if (kind_ == NICEFRAC || kind_ == UNITFRAC || kind_ == UNIT)
349 features.require("units");
350 InsetMathNest::validate(features);
354 /////////////////////////////////////////////////////////////////////
358 /////////////////////////////////////////////////////////////////////
361 Inset * InsetMathDFrac::clone() const
363 return new InsetMathDFrac(*this);
367 void InsetMathDFrac::metrics(MetricsInfo & mi, Dimension & dim) const
369 Dimension dim0, dim1;
370 cell(0).metrics(mi, dim0);
371 cell(1).metrics(mi, dim1);
372 dim.wid = std::max(dim0.wid, dim1.wid) + 2;
373 dim.asc = dim0.height() + 2 + 5;
374 dim.des = dim1.height() + 2 - 5;
375 // Cache the inset dimension.
376 setDimCache(mi, dim);
380 void InsetMathDFrac::draw(PainterInfo & pi, int x, int y) const
382 Dimension const dim = dimension(*pi.base.bv);
383 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
384 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
385 int m = x + dim.wid / 2;
386 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5);
387 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5);
388 pi.pain.line(x + 1, y - 5, x + dim.wid - 2, y - 5, Color_math);
389 setPosCache(pi, x, y);
393 docstring InsetMathDFrac::name() const
395 return from_ascii("dfrac");
399 void InsetMathDFrac::mathmlize(MathStream & os) const
401 os << MTag("mdfrac") << cell(0) << cell(1) << ETag("mdfrac");
405 void InsetMathDFrac::validate(LaTeXFeatures & features) const
407 features.require("amsmath");
408 InsetMathNest::validate(features);
412 /////////////////////////////////////////////////////////////////////
416 /////////////////////////////////////////////////////////////////////
419 Inset * InsetMathTFrac::clone() const
421 return new InsetMathTFrac(*this);
425 void InsetMathTFrac::metrics(MetricsInfo & mi, Dimension & dim) const
427 StyleChanger dummy(mi.base, LM_ST_SCRIPT);
429 cell(0).metrics(mi, dim0);
431 cell(1).metrics(mi, dim1);
432 dim.wid = std::max(dim0.width(), dim1.width()) + 2;
433 dim.asc = dim0.height() + 2 + 5;
434 dim.des = dim1.height() + 2 - 5;
435 // Cache the inset dimension.
436 setDimCache(mi, dim);
440 void InsetMathTFrac::draw(PainterInfo & pi, int x, int y) const
442 StyleChanger dummy(pi.base, LM_ST_SCRIPT);
443 Dimension const dim = dimension(*pi.base.bv);
444 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
445 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
446 int m = x + dim.wid / 2;
447 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.descent() - 2 - 5);
448 cell(1).draw(pi, m - dim1.width() / 2, y + dim1.ascent() + 2 - 5);
449 pi.pain.line(x + 1, y - 5, x + dim.wid - 2, y - 5, Color_math);
450 setPosCache(pi, x, y);
454 docstring InsetMathTFrac::name() const
456 return from_ascii("tfrac");
460 void InsetMathTFrac::mathmlize(MathStream & os) const
462 os << MTag("mtfrac") << cell(0) << cell(1) << ETag("mtfrac");
466 void InsetMathTFrac::validate(LaTeXFeatures & features) const
468 features.require("amsmath");
469 InsetMathNest::validate(features);
473 /////////////////////////////////////////////////////////////////////
477 /////////////////////////////////////////////////////////////////////
480 InsetMathBinom::InsetMathBinom(bool choose)
485 Inset * InsetMathBinom::clone() const
487 return new InsetMathBinom(*this);
491 int InsetMathBinom::dw(int height) const
502 void InsetMathBinom::metrics(MetricsInfo & mi, Dimension & dim) const
504 FracChanger dummy(mi.base);
505 Dimension dim0, dim1;
506 cell(0).metrics(mi, dim0);
507 cell(1).metrics(mi, dim1);
508 dim.asc = dim0.height() + 4 + 5;
509 dim.des = dim1.height() + 4 - 5;
510 dim.wid = std::max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
511 metricsMarkers2(dim);
512 // Cache the inset dimension.
513 setDimCache(mi, dim);
517 void InsetMathBinom::draw(PainterInfo & pi, int x, int y) const
519 Dimension const dim = dimension(*pi.base.bv);
520 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
521 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
522 int m = x + dim.width() / 2;
523 FracChanger dummy(pi.base);
524 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.des - 3 - 5);
525 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
526 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()), dim.height(), from_ascii("("));
527 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()), y - dim.ascent(),
528 dw(dim.height()), dim.height(), from_ascii(")"));
529 drawMarkers2(pi, x, y);
533 bool InsetMathBinom::extraBraces() const
539 void InsetMathBinom::write(WriteStream & os) const
542 os << '{' << cell(0) << " \\choose " << cell(1) << '}';
544 os << "\\binom{" << cell(0) << "}{" << cell(1) << '}';
548 void InsetMathBinom::normalize(NormalStream & os) const
550 os << "[binom " << cell(0) << ' ' << cell(1) << ']';
554 /////////////////////////////////////////////////////////////////////
558 /////////////////////////////////////////////////////////////////////
560 Inset * InsetMathDBinom::clone() const
562 return new InsetMathDBinom(*this);
566 int InsetMathDBinom::dw(int height) const
577 void InsetMathDBinom::metrics(MetricsInfo & mi, Dimension & dim) const
579 Dimension dim0, dim1;
580 cell(0).metrics(mi, dim0);
581 cell(1).metrics(mi, dim1);
582 dim.asc = dim0.height() + 4 + 5;
583 dim.des = dim1.height() + 4 - 5;
584 dim.wid = std::max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
585 metricsMarkers2(dim);
586 // Cache the inset dimension.
587 setDimCache(mi, dim);
591 void InsetMathDBinom::draw(PainterInfo & pi, int x, int y) const
593 Dimension const dim = dimension(*pi.base.bv);
594 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
595 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
596 int m = x + dim.width() / 2;
597 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.des - 3 - 5);
598 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
599 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()), dim.height(), from_ascii("("));
600 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()), y - dim.ascent(),
601 dw(dim.height()), dim.height(), from_ascii(")"));
602 drawMarkers2(pi, x, y);
606 docstring InsetMathDBinom::name() const
608 return from_ascii("dbinom");
611 void InsetMathDBinom::mathmlize(MathStream & os) const
613 os << MTag("mdbinom") << cell(0) << cell(1) << ETag("mdbinom");
616 void InsetMathDBinom::validate(LaTeXFeatures & features) const
618 features.require("amsmath");
619 InsetMathNest::validate(features);
623 /////////////////////////////////////////////////////////////////////
627 /////////////////////////////////////////////////////////////////////
629 Inset * InsetMathTBinom::clone() const
631 return new InsetMathTBinom(*this);
635 int InsetMathTBinom::dw(int height) const
646 void InsetMathTBinom::metrics(MetricsInfo & mi, Dimension & dim) const
648 StyleChanger dummy(mi.base, LM_ST_SCRIPT);
649 Dimension dim0, dim1;
650 cell(0).metrics(mi, dim0);
651 cell(1).metrics(mi, dim1);
652 dim.asc = dim0.height() + 4 + 5;
653 dim.des = dim1.height() + 4 - 5;
654 dim.wid = std::max(dim0.width(), dim1.wid) + 2 * dw(dim.height()) + 4;
655 metricsMarkers2(dim);
656 // Cache the inset dimension.
657 setDimCache(mi, dim);
661 void InsetMathTBinom::draw(PainterInfo & pi, int x, int y) const
663 StyleChanger dummy(pi.base, LM_ST_SCRIPT);
664 Dimension const dim = dimension(*pi.base.bv);
665 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
666 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
667 int m = x + dim.width() / 2;
668 cell(0).draw(pi, m - dim0.width() / 2, y - dim0.des - 3 - 5);
669 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
670 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()), dim.height(), from_ascii("("));
671 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()), y - dim.ascent(),
672 dw(dim.height()), dim.height(), from_ascii(")"));
673 drawMarkers2(pi, x, y);
677 docstring InsetMathTBinom::name() const
679 return from_ascii("tbinom");
682 void InsetMathTBinom::mathmlize(MathStream & os) const
684 os << MTag("mtbinom") << cell(0) << cell(1) << ETag("mtbinom");
687 void InsetMathTBinom::validate(LaTeXFeatures & features) const
689 features.require("amsmath");
690 InsetMathNest::validate(features);