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_ == CFRAC || kind_ == CFRACLEFT
161 || kind_ == CFRACRIGHT) {
162 // cfrac is always in display size
163 StyleChanger dummy2(mi.base, LM_ST_DISPLAY);
164 cell(0).metrics(mi, dim0);
165 cell(1).metrics(mi, dim1);
166 dim.wid = max(dim0.wid, dim1.wid) + 2;
167 dim.asc = dim0.height() + 2 + 5;
168 dim.des = dim1.height() + 2 - 5;
169 } else if (kind_ == UNITFRAC) {
170 ShapeChanger dummy2(mi.base.font, UP_SHAPE);
171 dim.wid = dim0.width() + dim1.wid + 5;
172 dim.asc = dim0.height() + 5;
173 dim.des = dim1.height() - 5;
174 } else if (kind_ == DFRAC) {
175 // dfrac is in always in display size
176 StyleChanger dummy2(mi.base, LM_ST_DISPLAY);
177 cell(0).metrics(mi, dim0);
178 cell(1).metrics(mi, dim1);
179 dim.wid = max(dim0.wid, dim1.wid) + 2;
180 dim.asc = dim0.height() + 2 + 5;
181 dim.des = dim1.height() + 2 - 5;
182 } else if (kind_ == TFRAC) {
183 // tfrac is in always in text size
184 StyleChanger dummy2(mi.base, LM_ST_SCRIPT);
185 cell(0).metrics(mi, dim0);
186 cell(1).metrics(mi, dim1);
187 dim.wid = max(dim0.wid, dim1.wid) + 2;
188 dim.asc = dim0.height() + 2 + 5;
189 dim.des = dim1.height() + 2 - 5;
192 dim.wid = max(dim0.wid, dim1.wid) + 2;
193 dim.asc = dim0.height() + 2 + 5;
194 dim.des = dim1.height() + 2 - 5;
201 void InsetMathFrac::draw(PainterInfo & pi, int x, int y) const
203 setPosCache(pi, x, y);
204 Dimension const dim = dimension(*pi.base.bv);
205 Dimension const dim0 = cell(0).dimension(*pi.base.bv);
206 int m = x + dim.wid / 2;
207 if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
209 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
210 cell(0).draw(pi, x + 1, y);
211 } else if (nargs() == 2) {
212 cell(0).draw(pi, x + 1, y);
213 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
214 cell(1).draw(pi, x + dim0.width() + 5, y);
216 cell(2).draw(pi, x + 1, y);
217 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
218 FracChanger dummy(pi.base);
219 Dimension const dim1 = cell(1).dimension(*pi.base.bv);
220 Dimension const dim2 = cell(2).dimension(*pi.base.bv);
221 int xx = x + dim2.wid + 5;
222 cell(0).draw(pi, xx + 2,
224 cell(1).draw(pi, xx + dim0.width() + 5,
228 FracChanger dummy(pi.base);
229 Dimension const dim1 = cell(1).dimension(*pi.base.bv);
230 if (kind_ == NICEFRAC) {
231 cell(0).draw(pi, x + 2,
233 cell(1).draw(pi, x + dim0.width() + 5,
235 } else if (kind_ == UNITFRAC) {
236 ShapeChanger dummy2(pi.base.font, UP_SHAPE);
237 cell(0).draw(pi, x + 2,
239 cell(1).draw(pi, x + dim0.width() + 5,
241 } else if (kind_ == CFRAC || kind_ == CFRACLEFT
242 || kind_ == CFRACRIGHT) {
243 // cfrac is always in display size
244 StyleChanger dummy2(pi.base, LM_ST_DISPLAY);
245 Dimension const dim0 = cell(0).dimension(*pi.base.bv);
246 Dimension const dim1 = cell(1).dimension(*pi.base.bv);
247 int m = x + dim.wid / 2;
249 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5);
250 else if (kind_ == CFRACLEFT)
251 cell(0).draw(pi, x + 2, y - dim0.des - 2 - 5);
252 else if (kind_ == CFRACRIGHT)
253 cell(0).draw(pi, x + dim.wid - dim0.wid - 2,
254 y - dim0.des - 2 - 5);
255 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5);
256 } else if (kind_ == DFRAC) {
257 // dfrac is in always in display size
258 StyleChanger dummy2(pi.base, LM_ST_DISPLAY);
259 //Dimension const dim = dimension(*pi.base.bv);
260 Dimension const dim0 = cell(0).dimension(*pi.base.bv);
261 Dimension const dim1 = cell(1).dimension(*pi.base.bv);
262 int m = x + dim.wid / 2;
263 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5);
264 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5);
265 } else if (kind_ == TFRAC) {
266 // tfrac is in always in text size
267 StyleChanger dummy2(pi.base, LM_ST_SCRIPT);
268 Dimension const dim0 = cell(0).dimension(*pi.base.bv);
269 Dimension const dim1 = cell(1).dimension(*pi.base.bv);
270 int m = x + dim.wid / 2;
271 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5);
272 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5);
275 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5);
276 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5);
279 if (kind_ == NICEFRAC || kind_ == UNITFRAC) {
283 xx += cell(2).dimension(*pi.base.bv).wid + 5;
284 pi.pain.line(xx + dim0.wid,
287 y - dim.asc + 2, Color_math);
289 if (kind_ == FRAC || kind_ == CFRAC || kind_ == CFRACLEFT
290 || kind_ == CFRACRIGHT || kind_ == DFRAC
291 || kind_ == TFRAC || kind_ == OVER)
292 pi.pain.line(x + 1, y - 5,
293 x + dim.wid - 2, y - 5, Color_math);
294 drawMarkers(pi, x, y);
298 void InsetMathFrac::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
300 Dimension dim0, dim1;
301 cell(0).metricsT(mi, dim0);
302 cell(1).metricsT(mi, dim1);
303 dim.wid = max(dim0.width(), dim1.wid);
304 dim.asc = dim0.height() + 1;
305 dim.des = dim1.height();
309 void InsetMathFrac::drawT(TextPainter & /*pain*/, int /*x*/, int /*y*/) const
314 int m = x + dim.width() / 2;
315 cell(0).drawT(pain, m - dim0.width() / 2, y - dim0.des - 1);
316 cell(1).drawT(pain, m - dim1.wid / 2, y + dim1.asc);
317 // ASCII art: ignore niceties
318 if (kind_ == FRAC || kind_ == OVER || kind_ == NICEFRAC || kind_ == UNITFRAC)
319 pain.horizontalLine(x, y, dim.width());
324 void InsetMathFrac::write(WriteStream & os) const
326 MathEnsurer ensurer(os);
329 // \\atop is only for compatibility, \\binom is the
331 os << '{' << cell(0) << "\\atop " << cell(1) << '}';
334 // \\over is only for compatibility, normalize this to \\frac
335 os << "\\frac{" << cell(0) << "}{" << cell(1) << '}';
344 InsetMathNest::write(os);
346 os << "\\unitfrac[" << cell(2) << "]{" << cell(0) << "}{" << cell(1) << '}';
350 os << "\\unit[" << cell(0) << "]{" << cell(1) << '}';
352 os << "\\unit{" << cell(0) << '}';
355 os << "\\cfrac[l]{" << cell(0) << "}{" << cell(1) << '}';
358 os << "\\cfrac[r]{" << cell(0) << "}{" << cell(1) << '}';
364 docstring InsetMathFrac::name() const
368 return from_ascii("frac");
372 return from_ascii("cfrac");
374 return from_ascii("dfrac");
376 return from_ascii("tfrac");
378 return from_ascii("over");
380 return from_ascii("nicefrac");
382 return from_ascii("unitfrac");
384 return from_ascii("unit");
386 return from_ascii("atop");
388 // shut up stupid compiler
393 bool InsetMathFrac::extraBraces() const
395 return kind_ == ATOP || kind_ == OVER;
399 void InsetMathFrac::maple(MapleStream & os) const
401 os << '(' << cell(0) << ")/(" << cell(1) << ')';
405 void InsetMathFrac::mathematica(MathematicaStream & os) const
407 os << '(' << cell(0) << ")/(" << cell(1) << ')';
411 void InsetMathFrac::octave(OctaveStream & os) const
413 os << '(' << cell(0) << ")/(" << cell(1) << ')';
417 void InsetMathFrac::mathmlize(MathStream & os) const
421 os << MTag("mfrac") << cell(0) << cell(1) << ETag("mfrac");
424 os << MTag("mdfrac") << cell(0) << cell(1) << ETag("mdfrac");
427 os << MTag("mtfrac") << cell(0) << cell(1) << ETag("mtfrac");
433 void InsetMathFrac::validate(LaTeXFeatures & features) const
435 if (kind_ == NICEFRAC || kind_ == UNITFRAC || kind_ == UNIT)
436 features.require("units");
437 if (kind_ == CFRAC || kind_ == CFRACLEFT || kind_ == CFRACRIGHT
438 || kind_ == DFRAC || kind_ == TFRAC)
439 features.require("amsmath");
440 InsetMathNest::validate(features);
444 /////////////////////////////////////////////////////////////////////
448 /////////////////////////////////////////////////////////////////////
451 InsetMathBinom::InsetMathBinom(Kind kind)
456 Inset * InsetMathBinom::clone() const
458 return new InsetMathBinom(*this);
462 int InsetMathBinom::dw(int height) const
473 void InsetMathBinom::metrics(MetricsInfo & mi, Dimension & dim) const
475 Dimension dim0, dim1;
477 // FIXME: for an unknown reason the cells must be set directly
478 // after the StyleChanger and cannot be set after the if case
479 if (kind_ == DBINOM) {
480 StyleChanger dummy(mi.base, LM_ST_DISPLAY);
481 cell(0).metrics(mi, dim0);
482 cell(1).metrics(mi, dim1);
483 } else if (kind_ == TBINOM) {
484 StyleChanger dummy(mi.base, LM_ST_SCRIPT);
485 cell(0).metrics(mi, dim0);
486 cell(1).metrics(mi, dim1);
488 FracChanger dummy(mi.base);
489 cell(0).metrics(mi, dim0);
490 cell(1).metrics(mi, dim1);
492 dim.asc = dim0.height() + 4 + 5;
493 dim.des = dim1.height() + 4 - 5;
494 dim.wid = max(dim0.wid, dim1.wid) + 2 * dw(dim.height()) + 4;
495 metricsMarkers2(dim);
499 void InsetMathBinom::draw(PainterInfo & pi, int x, int y) const
501 Dimension const dim = dimension(*pi.base.bv);
502 Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
503 Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
504 // define the binom brackets
505 docstring const bra = kind_ == BRACE ? from_ascii("{") :
506 kind_ == BRACK ? from_ascii("[") : from_ascii("(");
507 docstring const ket = kind_ == BRACE ? from_ascii("}") :
508 kind_ == BRACK ? from_ascii("]") : from_ascii(")");
510 int m = x + dim.width() / 2;
511 // FIXME: for an unknown reason the cells must be drawn directly
512 // after the StyleChanger and cannot be drawn after the if case
513 if (kind_ == DBINOM) {
514 StyleChanger dummy(pi.base, LM_ST_DISPLAY);
515 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 3 - 5);
516 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
517 } else if (kind_ == TBINOM) {
518 StyleChanger dummy(pi.base, LM_ST_SCRIPT);
519 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 3 - 5);
520 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
522 FracChanger dummy2(pi.base);
523 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 3 - 5);
524 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
526 // draw the brackets and the marker
527 mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()),
529 mathed_draw_deco(pi, x + dim.width() - dw(dim.height()),
530 y - dim.ascent(), dw(dim.height()), dim.height(), ket);
531 drawMarkers2(pi, x, y);
535 bool InsetMathBinom::extraBraces() const
537 return kind_ == CHOOSE || kind_ == BRACE || kind_ == BRACK;
541 void InsetMathBinom::write(WriteStream & os) const
543 MathEnsurer ensurer(os);
546 os << "\\binom{" << cell(0) << "}{" << cell(1) << '}';
549 os << "\\dbinom{" << cell(0) << "}{" << cell(1) << '}';
552 os << "\\tbinom{" << cell(0) << "}{" << cell(1) << '}';
555 os << '{' << cell(0) << " \\choose " << cell(1) << '}';
558 os << '{' << cell(0) << " \\brace " << cell(1) << '}';
561 os << '{' << cell(0) << " \\brack " << cell(1) << '}';
567 void InsetMathBinom::normalize(NormalStream & os) const
569 os << "[binom " << cell(0) << ' ' << cell(1) << ']';
573 void InsetMathBinom::mathmlize(MathStream & os) const
577 os << MTag("mbinom") << cell(0) << cell(1) << ETag("mbinom");
580 os << MTag("mdbinom") << cell(0) << cell(1) << ETag("mdbinom");
583 os << MTag("mtbinom") << cell(0) << cell(1) << ETag("mtbinom");
589 void InsetMathBinom::validate(LaTeXFeatures & features) const
592 features.require("binom");
593 if (kind_ == DBINOM || kind_ == TBINOM)
594 features.require("amsmath");
595 InsetMathNest::validate(features);