]> git.lyx.org Git - lyx.git/blob - src/mathed/InsetMathFrac.cpp
Fix bug #9544: Mark file clean after we write it.
[lyx.git] / src / mathed / InsetMathFrac.cpp
1 /**
2  * \file InsetMathFracBase.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  * \author André Pönitz
8  * \author Uwe Stöhr
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "InsetMathFrac.h"
16
17 #include "Cursor.h"
18 #include "LaTeXFeatures.h"
19 #include "MathData.h"
20 #include "MathStream.h"
21 #include "MathSupport.h"
22 #include "MetricsInfo.h"
23 #include "TextPainter.h"
24
25 #include "support/lassert.h"
26 #include "frontends/Painter.h"
27
28 using namespace std;
29
30 namespace lyx {
31
32 /////////////////////////////////////////////////////////////////////
33 //
34 // InsetMathFracBase
35 //
36 /////////////////////////////////////////////////////////////////////
37
38
39 InsetMathFracBase::InsetMathFracBase(Buffer * buf, idx_type ncells)
40         : InsetMathNest(buf, ncells)
41 {}
42
43
44 bool InsetMathFracBase::idxUpDown(Cursor & cur, bool up) const
45 {
46         // If we only have one cell, target = 0, otherwise
47         // target = up ? 0 : 1, since upper cell has idx 0
48         InsetMath::idx_type target = nargs() > 1 ? !up : 0;
49         if (cur.idx() == target)
50                 return false;
51         cur.idx() = target;
52         cur.pos() = cell(target).x2pos(&cur.bv(), cur.x_target());
53         return true;
54 }
55
56
57
58 /////////////////////////////////////////////////////////////////////
59 //
60 // InsetMathFrac
61 //
62 /////////////////////////////////////////////////////////////////////
63
64
65 InsetMathFrac::InsetMathFrac(Buffer * buf, Kind kind, InsetMath::idx_type ncells)
66         : InsetMathFracBase(buf, ncells), kind_(kind)
67 {}
68
69
70 Inset * InsetMathFrac::clone() const
71 {
72         return new InsetMathFrac(*this);
73 }
74
75
76 InsetMathFrac * InsetMathFrac::asFracInset()
77 {
78         return kind_ == ATOP ? 0 : this;
79 }
80
81
82 InsetMathFrac const * InsetMathFrac::asFracInset() const
83 {
84         return kind_ == ATOP ? 0 : this;
85 }
86
87
88 bool InsetMathFrac::idxForward(Cursor & cur) const
89 {
90         InsetMath::idx_type target = 0;
91         if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
92                 if (nargs() == 3)
93                         target = 0;
94                 else if (nargs() == 2)
95                         target = 1;
96         } else
97                 return false;
98         if (cur.idx() == target)
99                 return false;
100         cur.idx() = target;
101         cur.pos() = cell(target).x2pos(&cur.bv(), cur.x_target());
102         return true;
103 }
104
105
106 bool InsetMathFrac::idxBackward(Cursor & cur) const
107 {
108         InsetMath::idx_type target = 0;
109         if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
110                 if (nargs() == 3)
111                         target = 2;
112                 else if (nargs() == 2)
113                         target = 0;
114         } else
115                 return false;
116         if (cur.idx() == target)
117                 return false;
118         cur.idx() = target;
119         cur.pos() = cell(target).x2pos(&cur.bv(), cur.x_target());
120         return true;
121 }
122
123
124 void InsetMathFrac::metrics(MetricsInfo & mi, Dimension & dim) const
125 {
126         Dimension dim0, dim1, dim2;
127
128         if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
129                 if (nargs() == 1) {
130                         ShapeChanger dummy2(mi.base.font, UP_SHAPE);
131                         cell(0).metrics(mi, dim0);
132                         dim.wid = dim0.width()+ 3;
133                         dim.asc = dim0.asc;
134                         dim.des = dim0.des;
135                 } else if (nargs() == 2) {
136                         cell(0).metrics(mi, dim0);
137                         ShapeChanger dummy2(mi.base.font, UP_SHAPE);
138                         cell(1).metrics(mi, dim1);
139                         dim.wid = dim0.width() + dim1.wid + 5;
140                         dim.asc = max(dim0.asc, dim1.asc);
141                         dim.des = max(dim0.des, dim1.des);
142                 } else {
143                         cell(2).metrics(mi, dim2);
144                         ShapeChanger dummy2(mi.base.font, UP_SHAPE);
145                         FracChanger dummy(mi.base);
146                         cell(0).metrics(mi, dim0);
147                         cell(1).metrics(mi, dim1);
148                         dim.wid = dim0.width() + dim1.wid + dim2.wid + 10;
149                         dim.asc = max(dim2.asc, dim0.height() + 5);
150                         dim.des = max(dim2.des, dim1.height() - 5);
151                 }
152         } else {
153                 // general cell metrics used for \frac
154                 FracChanger dummy(mi.base);
155                 cell(0).metrics(mi, dim0);
156                 cell(1).metrics(mi, dim1);
157                 if (nargs() == 3)
158                         cell(2).metrics(mi, dim2);
159                 // metrics for special fraction types
160                 if (kind_ == NICEFRAC) {
161                         dim.wid = dim0.width() + dim1.wid + 5;
162                         dim.asc = dim0.height() + 5;
163                         dim.des = dim1.height() - 5;
164                 } else if (kind_ == UNITFRAC) {
165                         ShapeChanger dummy2(mi.base.font, UP_SHAPE);
166                         dim.wid = dim0.width() + dim1.wid + 5;
167                         dim.asc = dim0.height() + 5;
168                         dim.des = dim1.height() - 5;
169                 } else {
170                         if (kind_ == CFRAC || kind_ == CFRACLEFT
171                                   || kind_ == CFRACRIGHT || kind_ == DFRAC) {
172                                 // \cfrac and \dfrac are always in display size
173                                 StyleChanger dummy2(mi.base, LM_ST_DISPLAY);
174                                 cell(0).metrics(mi, dim0);
175                                 cell(1).metrics(mi, dim1);
176                         } else if (kind_ == TFRAC) {
177                                 // tfrac is in always in text size
178                                 StyleChanger dummy2(mi.base, LM_ST_SCRIPT);
179                                 cell(0).metrics(mi, dim0);
180                                 cell(1).metrics(mi, dim1);
181                         }
182                         dim.wid = max(dim0.wid, dim1.wid) + 2;
183                         dim.asc = dim0.height() + 2 + 5;
184                         dim.des = dim1.height() + 2 - 5;
185                 }
186         }
187         metricsMarkers(dim);
188 }
189
190
191 void InsetMathFrac::draw(PainterInfo & pi, int x, int y) const
192 {
193         setPosCache(pi, x, y);
194         Dimension const dim = dimension(*pi.base.bv);
195         Dimension const dim0 = cell(0).dimension(*pi.base.bv);
196         if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
197                 if (nargs() == 1) {
198                         ShapeChanger dummy2(pi.base.font, UP_SHAPE);
199                         cell(0).draw(pi, x + 1, y);
200                 } else if (nargs() == 2) {
201                         cell(0).draw(pi, x + 1, y);
202                         ShapeChanger dummy2(pi.base.font, UP_SHAPE);
203                         cell(1).draw(pi, x + dim0.width() + 5, y);
204                 } else {
205                         cell(2).draw(pi, x + 1, y);
206                         ShapeChanger dummy2(pi.base.font, UP_SHAPE);
207                         FracChanger dummy(pi.base);
208                         Dimension const dim1 = cell(1).dimension(*pi.base.bv);
209                         Dimension const dim2 = cell(2).dimension(*pi.base.bv);
210                         int xx = x + dim2.wid + 5;
211                         cell(0).draw(pi, xx + 2, 
212                                          y - dim0.des - 5);
213                         cell(1).draw(pi, xx  + dim0.width() + 5, 
214                                          y + dim1.asc / 2);
215                 }
216         } else {
217                 FracChanger dummy(pi.base);
218                 Dimension const dim1 = cell(1).dimension(*pi.base.bv);
219                 int m = x + dim.wid / 2;
220                 if (kind_ == NICEFRAC) {
221                         cell(0).draw(pi, x + 2,
222                                         y - dim0.des - 5);
223                         cell(1).draw(pi, x + dim0.width() + 5,
224                                         y + dim1.asc / 2);
225                 } else if (kind_ == UNITFRAC) {
226                         ShapeChanger dummy2(pi.base.font, UP_SHAPE);
227                         cell(0).draw(pi, x + 2, y - dim0.des - 5);
228                         cell(1).draw(pi, x + dim0.width() + 5, y + dim1.asc / 2);
229                 } else if (kind_ == FRAC || kind_ == ATOP || kind_ == OVER) {
230                         cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5);
231                         cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5);
232                 } else if (kind_ == TFRAC) {
233                         // tfrac is in always in text size
234                         StyleChanger dummy2(pi.base, LM_ST_SCRIPT);
235                         cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5);
236                         cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5);
237                 } else {
238                         // \cfrac and \dfrac are always in display size
239                         StyleChanger dummy2(pi.base, LM_ST_DISPLAY);
240                         if (kind_ == CFRAC || kind_ == DFRAC)
241                                 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5);
242                         else if (kind_ == CFRACLEFT)
243                                 cell(0).draw(pi, x + 2, y - dim0.des - 2 - 5);
244                         else if (kind_ == CFRACRIGHT)
245                                 cell(0).draw(pi, x + dim.wid - dim0.wid - 2,
246                                         y - dim0.des - 2 - 5);
247                         cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5);
248                 }
249         }
250         if (kind_ == NICEFRAC || kind_ == UNITFRAC) {
251                 // Diag line:
252                 int xx = x;
253                 if (nargs() == 3)
254                         xx += cell(2).dimension(*pi.base.bv).wid + 5;
255                 pi.pain.line(xx + dim0.wid,
256                                 y + dim.des - 2,
257                                 xx + dim0.wid + 5,
258                                 y - dim.asc + 2, pi.base.font.color());
259         }
260         if (kind_ == FRAC || kind_ == CFRAC || kind_ == CFRACLEFT
261                 || kind_ == CFRACRIGHT || kind_ == DFRAC
262                 || kind_ == TFRAC || kind_ == OVER)
263                 pi.pain.line(x + 1, y - 5,
264                                 x + dim.wid - 2, y - 5, pi.base.font.color());
265         drawMarkers(pi, x, y);
266 }
267
268
269 void InsetMathFrac::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
270 {
271         Dimension dim0, dim1;
272         cell(0).metricsT(mi, dim0);
273         cell(1).metricsT(mi, dim1);
274         dim.wid = max(dim0.width(), dim1.wid);
275         dim.asc = dim0.height() + 1;
276         dim.des = dim1.height();
277 }
278
279
280 void InsetMathFrac::drawT(TextPainter & /*pain*/, int /*x*/, int /*y*/) const
281 {
282         // FIXME: BROKEN!
283         /*
284         Dimension dim;
285         int m = x + dim.width() / 2;
286         cell(0).drawT(pain, m - dim0.width() / 2, y - dim0.des - 1);
287         cell(1).drawT(pain, m - dim1.wid / 2, y + dim1.asc);
288         // ASCII art: ignore niceties
289         if (kind_ == FRAC || kind_ == OVER || kind_ == NICEFRAC || kind_ == UNITFRAC)
290                 pain.horizontalLine(x, y, dim.width());
291         */
292 }
293
294
295 void InsetMathFrac::write(WriteStream & os) const
296 {
297         MathEnsurer ensurer(os);
298         switch (kind_) {
299         case ATOP:
300                 // \\atop is only for compatibility, \\binom is the
301                 // LaTeX2e successor
302                 os << '{' << cell(0) << "\\atop " << cell(1) << '}';
303                 break;
304         case OVER:
305                 // \\over is only for compatibility, normalize this to \\frac
306                 os << "\\frac{" << cell(0) << "}{" << cell(1) << '}';
307                 break;
308         case FRAC:
309         case DFRAC:
310         case TFRAC:
311         case NICEFRAC:
312         case CFRAC:
313         case UNITFRAC:
314                 if (nargs() == 2)
315                         InsetMathNest::write(os);
316                 else
317                         os << "\\unitfrac[" << cell(2) << "]{" << cell(0) << "}{" << cell(1) << '}';
318                 break;
319         case UNIT:
320                 if (nargs() == 2)
321                         os << "\\unit[" << cell(0) << "]{" << cell(1) << '}';
322                 else
323                         os << "\\unit{" << cell(0) << '}';
324                 break;
325         case CFRACLEFT:
326                 os << "\\cfrac[l]{" << cell(0) << "}{" << cell(1) << '}';
327                 break;
328         case CFRACRIGHT:
329                 os << "\\cfrac[r]{" << cell(0) << "}{" << cell(1) << '}';
330                 break;
331         }
332 }
333
334
335 docstring InsetMathFrac::name() const
336 {
337         switch (kind_) {
338         case FRAC:
339                 return from_ascii("frac");
340         case CFRAC:
341         case CFRACLEFT:
342         case CFRACRIGHT:
343                 return from_ascii("cfrac");
344         case DFRAC:
345                 return from_ascii("dfrac");
346         case TFRAC:
347                 return from_ascii("tfrac");
348         case OVER:
349                 return from_ascii("over");
350         case NICEFRAC:
351                 return from_ascii("nicefrac");
352         case UNITFRAC:
353                 return from_ascii("unitfrac");
354         case UNIT:
355                 return from_ascii("unit");
356         case ATOP:
357                 return from_ascii("atop");
358         }
359         // shut up stupid compiler
360         return docstring();
361 }
362
363
364 bool InsetMathFrac::extraBraces() const
365 {
366         return kind_ == ATOP || kind_ == OVER;
367 }
368
369
370 void InsetMathFrac::maple(MapleStream & os) const
371 {
372         if (nargs() != 2) {
373                 // Someone who knows about maple should fix this.
374                 LASSERT(false, return);
375         }
376         os << '(' << cell(0) << ")/(" << cell(1) << ')';
377 }
378
379
380 void InsetMathFrac::mathematica(MathematicaStream & os) const
381 {
382         if (nargs() != 2) {
383                 // Someone who knows about mathematica should fix this.
384                 LASSERT(false, return);
385         }
386         os << '(' << cell(0) << ")/(" << cell(1) << ')';
387 }
388
389
390 void InsetMathFrac::octave(OctaveStream & os) const
391 {
392         if (nargs() != 2) {
393                 // Someone who knows about octave should fix this.
394                 LASSERT(false, return);
395         }
396         os << '(' << cell(0) << ")/(" << cell(1) << ')';
397 }
398
399
400 void InsetMathFrac::mathmlize(MathStream & os) const
401 {
402         switch (kind_) {
403         case ATOP:
404                 os << MTag("mfrac", "linethickeness='0'")
405                    << MTag("mrow") << cell(0) << ETag("mrow")
406                          << MTag("mrow") << cell(1) << ETag("mrow")
407                          << ETag("mfrac");
408                 break;
409
410         // we do not presently distinguish these
411         case OVER:
412         case FRAC:
413         case DFRAC:
414         case TFRAC:
415         case CFRAC:
416         case CFRACLEFT:
417         case CFRACRIGHT:
418                 os << MTag("mfrac")
419                    << MTag("mrow") << cell(0) << ETag("mrow")
420                          << MTag("mrow") << cell(1) << ETag("mrow")
421                          << ETag("mfrac");
422                 break;
423
424         case NICEFRAC:
425                 os << MTag("mfrac", "bevelled='true'")
426                    << MTag("mrow") << cell(0) << ETag("mrow")
427                          << MTag("mrow") << cell(1) << ETag("mrow")
428                          << ETag("mfrac");
429                 break;
430
431         case UNITFRAC:
432                 if (nargs() == 3)
433                         os << cell(2);
434                 os << MTag("mfrac", "bevelled='true'")
435                    << MTag("mrow") << cell(0) << ETag("mrow")
436                          << MTag("mrow") << cell(1) << ETag("mrow")
437                          << ETag("mfrac");
438                 break;
439
440         case UNIT:
441                 // FIXME This is not right, because we still output mi, etc,
442                 // when we output the cell. So we need to prevent that somehow.
443                 if (nargs() == 2)
444                         os << cell(0) 
445                            << MTag("mstyle mathvariant='normal'") 
446                            << cell(1) 
447                            << ETag("mstyle");
448                 else
449                         os << MTag("mstyle mathvariant='normal'") 
450                            << cell(0)
451                            << ETag("mstyle");
452         }
453 }
454
455
456 void InsetMathFrac::htmlize(HtmlStream & os) const
457 {
458         switch (kind_) {
459         case ATOP:
460                 os << MTag("span", "class='frac'")
461                          << MTag("span", "class='numer'") << cell(0) << ETag("span")
462                          << MTag("span", "class='numer'") << cell(1) << ETag("span")
463                          << ETag("span");
464                 break;
465
466         // we do not presently distinguish these
467         case OVER:
468         case FRAC:
469         case DFRAC:
470         case TFRAC:
471         case CFRAC:
472         case CFRACLEFT:
473         case CFRACRIGHT:
474                 os << MTag("span", "class='frac'")
475                          << MTag("span", "class='numer'") << cell(0) << ETag("span")
476                          << MTag("span", "class='denom'") << cell(1) << ETag("span")
477                          << ETag("span");
478                 break;
479
480         case NICEFRAC:
481                 os << cell(0) << '/' << cell(1);
482                 break;
483
484         case UNITFRAC:
485                 if (nargs() == 3)
486                         os << cell(2) << ' ';
487                 os << cell(0) << '/' << cell(1);
488                 break;
489
490         case UNIT:
491                 // FIXME This is not right, because we still output i, etc,
492                 // when we output the cell. So we need to prevent that somehow.
493                 if (nargs() == 2)
494                         os << cell(0) 
495                            << MTag("span") 
496                            << cell(1) 
497                            << ETag("span");
498                 else
499                         os << MTag("span") 
500                            << cell(0)
501                            << ETag("span");
502         }
503 }
504
505
506 void InsetMathFrac::validate(LaTeXFeatures & features) const
507 {
508         if (kind_ == NICEFRAC || kind_ == UNITFRAC || kind_ == UNIT)
509                 features.require("units");
510         if (kind_ == CFRAC || kind_ == CFRACLEFT || kind_ == CFRACRIGHT
511                   || kind_ == DFRAC || kind_ == TFRAC)
512                 features.require("amsmath");
513         if (features.runparams().math_flavor == OutputParams::MathAsHTML)
514                 // CSS adapted from eLyXer
515                 features.addCSSSnippet(
516                         "span.frac{display: inline-block; vertical-align: middle; text-align:center;}\n"
517                         "span.numer{display: block;}\n"
518                         "span.denom{display: block; border-top: thin solid #000040;}");
519         InsetMathNest::validate(features);
520 }
521
522
523 /////////////////////////////////////////////////////////////////////
524 //
525 // InsetMathBinom
526 //
527 /////////////////////////////////////////////////////////////////////
528
529
530 InsetMathBinom::InsetMathBinom(Buffer * buf, Kind kind)
531         : InsetMathFracBase(buf), kind_(kind)
532 {}
533
534
535 Inset * InsetMathBinom::clone() const
536 {
537         return new InsetMathBinom(*this);
538 }
539
540
541 int InsetMathBinom::dw(int height) const
542 {
543         int w = height / 5;
544         if (w > 15)
545                 w = 15;
546         if (w < 6)
547                 w = 6;
548         return w;
549 }
550
551
552 void InsetMathBinom::metrics(MetricsInfo & mi, Dimension & dim) const
553 {
554         Dimension dim0, dim1;
555
556         // FIXME: for an unknown reason the cells must be set directly
557         // after the StyleChanger and cannot be set after the if case
558         if (kind_ == DBINOM) {
559                 StyleChanger dummy(mi.base, LM_ST_DISPLAY);
560                 cell(0).metrics(mi, dim0);
561                 cell(1).metrics(mi, dim1);
562         } else if (kind_ == TBINOM) {
563                 StyleChanger dummy(mi.base, LM_ST_SCRIPT);
564                 cell(0).metrics(mi, dim0);
565                 cell(1).metrics(mi, dim1);
566         } else {
567                 FracChanger dummy(mi.base);
568                 cell(0).metrics(mi, dim0);
569                 cell(1).metrics(mi, dim1);
570         }
571         dim.asc = dim0.height() + 4 + 5;
572         dim.des = dim1.height() + 4 - 5;
573         dim.wid = max(dim0.wid, dim1.wid) + 2 * dw(dim.height()) + 4;
574         metricsMarkers2(dim);
575 }
576
577
578 void InsetMathBinom::draw(PainterInfo & pi, int x, int y) const
579 {
580         Dimension const dim = dimension(*pi.base.bv);
581         Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
582         Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
583         // define the binom brackets
584         docstring const bra = kind_ == BRACE ? from_ascii("{") :
585                 kind_ == BRACK ? from_ascii("[") : from_ascii("(");
586         docstring const ket = kind_ == BRACE ? from_ascii("}") :
587                 kind_ == BRACK ? from_ascii("]") : from_ascii(")");
588
589         int m = x + dim.width() / 2;
590         // FIXME: for an unknown reason the cells must be drawn directly
591         // after the StyleChanger and cannot be drawn after the if case
592         if (kind_ == DBINOM) {
593                 StyleChanger dummy(pi.base, LM_ST_DISPLAY);
594                 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 3 - 5);
595                 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
596         } else if (kind_ == TBINOM) {
597                 StyleChanger dummy(pi.base, LM_ST_SCRIPT);
598                 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 3 - 5);
599                 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
600         } else {
601                 FracChanger dummy2(pi.base);
602                 cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 3 - 5);
603                 cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
604         }
605         // draw the brackets and the marker
606         mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()),
607                 dim.height(), bra);
608         mathed_draw_deco(pi, x + dim.width() - dw(dim.height()),
609                 y - dim.ascent(), dw(dim.height()), dim.height(), ket);
610         drawMarkers2(pi, x, y);
611 }
612
613
614 bool InsetMathBinom::extraBraces() const
615 {
616         return kind_ == CHOOSE || kind_ == BRACE || kind_ == BRACK;
617 }
618
619
620 void InsetMathBinom::write(WriteStream & os) const
621 {
622         MathEnsurer ensurer(os);
623         switch (kind_) {
624         case BINOM:
625                 os << "\\binom{" << cell(0) << "}{" << cell(1) << '}';
626                 break;
627         case DBINOM:
628                 os << "\\dbinom{" << cell(0) << "}{" << cell(1) << '}';
629                 break;
630         case TBINOM:
631                 os << "\\tbinom{" << cell(0) << "}{" << cell(1) << '}';
632                 break;
633         case CHOOSE:
634                 os << '{' << cell(0) << " \\choose " << cell(1) << '}';
635                 break;
636         case BRACE:
637                 os << '{' << cell(0) << " \\brace " << cell(1) << '}';
638                 break;
639         case BRACK:
640                 os << '{' << cell(0) << " \\brack " << cell(1) << '}';
641                 break;
642         }
643 }
644
645
646 void InsetMathBinom::normalize(NormalStream & os) const
647 {
648         os << "[binom " << cell(0) << ' ' << cell(1) << ']';
649 }
650
651
652 void InsetMathBinom::mathmlize(MathStream & os) const
653 {
654         char ldelim = ' ';
655         char rdelim = ' ';
656         switch (kind_) {
657         case BINOM:
658         case TBINOM:
659         case DBINOM:
660         case CHOOSE:
661                 ldelim = '(';
662                 rdelim = ')';
663                 break;
664         case BRACE:
665                 ldelim = '{';
666                 rdelim = '}';
667                 break;
668         case BRACK:
669                 ldelim = '[';
670                 rdelim = ']';
671                 break;
672         }
673         os << "<mo fence='true' stretchy='true' form='prefix'>" << ldelim << "</mo>"
674            << "<mfrac linethickness='0'>"
675            << cell(0) << cell(1)
676            << "</mfrac>"
677            << "<mo fence='true' stretchy='true' form='postfix'>" << rdelim << "</mo>";
678 }
679
680
681 void InsetMathBinom::htmlize(HtmlStream & os) const
682 {
683         char ldelim = ' ';
684         char rdelim = ' ';
685         switch (kind_) {
686         case BINOM:
687         case TBINOM:
688         case DBINOM:
689         case CHOOSE:
690                 ldelim = '(';
691                 rdelim = ')';
692                 break;
693         case BRACE:
694                 ldelim = '{';
695                 rdelim = '}';
696                 break;
697         case BRACK:
698                 ldelim = '[';
699                 rdelim = ']';
700                 break;
701         }
702         os << MTag("span", "class='binomdelim'") << ldelim << ETag("span") << '\n'
703            << MTag("span", "class='binom'") << '\n'
704            << MTag("span") << cell(0) << ETag("span") << '\n'
705            << MTag("span") << cell(1) << ETag("span") << '\n'
706            << ETag("span") << '\n'
707                  << MTag("span", "class='binomdelim'") << rdelim << ETag("span") << '\n';
708 }
709
710
711 void InsetMathBinom::validate(LaTeXFeatures & features) const
712 {
713         if (features.runparams().isLaTeX()) {
714                 if (kind_ == BINOM)
715                         features.require("binom");
716                 if (kind_ == DBINOM || kind_ == TBINOM)
717                         features.require("amsmath");
718         } else if (features.runparams().math_flavor == OutputParams::MathAsHTML)
719                 features.addCSSSnippet(
720                         "span.binom{display: inline-block; vertical-align: bottom; text-align:center;}\n"
721                         "span.binom span{display: block;}\n"
722                         "span.binomdelim{font-size: 2em;}");
723         InsetMathNest::validate(features);
724 }
725
726
727 } // namespace lyx