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