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