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