]> git.lyx.org Git - lyx.git/blob - src/mathed/math_support.C
rename LFUN enum values according to their command (as used in th minibuffer/bind...
[lyx.git] / src / mathed / math_support.C
1 /**
2  * \file math_support.C
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 "math_support.h"
15 #include "math_data.h"
16 #include "math_inset.h"
17 #include "math_mathmlstream.h"
18 #include "math_parser.h"
19
20 #include "debug.h"
21 #include "LColor.h"
22
23 #include "frontends/Painter.h"
24 #include "frontends/font_metrics.h"
25 #include "frontends/lyx_gui.h"
26
27 #include <map>
28 #include <sstream>
29
30
31 using std::string;
32 using std::max;
33 using std::endl;
34
35
36 ///
37 class Matrix {
38 public:
39         ///
40         Matrix(int, double, double);
41         ///
42         void transform(double &, double &);
43 private:
44         ///
45         double m_[2][2];
46 };
47
48
49 Matrix::Matrix(int code, double x, double y)
50 {
51         double const cs = (code & 1) ? 0 : (1 - code);
52         double const sn = (code & 1) ? (2 - code) : 0;
53         m_[0][0] =  cs * x;
54         m_[0][1] =  sn * x;
55         m_[1][0] = -sn * y;
56         m_[1][1] =  cs * y;
57 }
58
59
60 void Matrix::transform(double & x, double & y)
61 {
62         double xx = m_[0][0] * x + m_[0][1] * y;
63         double yy = m_[1][0] * x + m_[1][1] * y;
64         x = xx;
65         y = yy;
66 }
67
68
69
70 namespace {
71
72 /*
73  * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
74  * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
75  */
76
77
78 double const parenthHigh[] = {
79         2, 13,
80         0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
81         0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
82         0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
83         0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
84         0.9840, 0.9986,
85         0
86 };
87
88
89 double const parenth[] = {
90         2, 13,
91         0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
92         0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
93         0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
94         0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
95         0.9930, 0.9919,
96         0
97 };
98
99
100 double const brace[] = {
101         2, 21,
102         0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
103         0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
104         0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
105         0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
106         0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
107         0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
108         0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
109         0
110 };
111
112
113 double const arrow[] = {
114         4, 7,
115         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
116         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
117         0.9500, 0.7500,
118         3, 0.5000, 0.1500, 0.5000, 0.9500,
119         0
120 };
121
122
123 double const Arrow[] = {
124         4, 7,
125         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
126         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
127         0.9500, 0.7500,
128         3, 0.3500, 0.5000, 0.3500, 0.9500,
129         3, 0.6500, 0.5000, 0.6500, 0.9500,
130         0
131 };
132
133
134 double const udarrow[] = {
135         2, 3,
136         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
137         2, 3,
138         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
139         1, 0.5, 0.2,  0.5, 0.8,
140         0
141 };
142
143
144 double const Udarrow[] = {
145         2, 3,
146         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
147         2, 3,
148         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
149         1, 0.35, 0.2, 0.35, 0.8,
150         1, 0.65, 0.2, 0.65, 0.8,
151         0
152 };
153
154
155 double const brack[] = {
156         2, 4,
157         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
158         0
159 };
160
161
162 double const corner[] = {
163         2, 3,
164         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,
165         0
166 };
167
168
169 double const angle[] = {
170         2, 3,
171         1, 0,  0.05, 0.5,  1, 1,
172         0
173 };
174
175
176 double const slash[] = {
177         1, 0.95, 0.05, 0.05, 0.95,
178         0
179 };
180
181
182 double const hline[] = {
183         1, 0.00, 0.5, 1.0, 0.5,
184         0
185 };
186
187
188 double const ddot[] = {
189         1, 0.2, 0.5,  0.3, 0.5,
190         1, 0.7, 0.5,  0.8, 0.5,
191         0
192 };
193
194
195 double const dddot[] = {
196         1, 0.1, 0.5,  0.2, 0.5,
197         1, 0.45, 0.5, 0.55, 0.5,
198         1, 0.8, 0.5,  0.9, 0.5,
199         0
200 };
201
202
203 double const hline3[] = {
204         1, 0.1,   0,  0.15,  0,
205         1, 0.475, 0,  0.525, 0,
206         1, 0.85,  0,  0.9,   0,
207         0
208 };
209
210
211 double const dline3[] = {
212         1, 0.1,   0.1,   0.15,  0.15,
213         1, 0.475, 0.475, 0.525, 0.525,
214         1, 0.85,  0.85,  0.9,   0.9,
215         0
216 };
217
218
219 double const hlinesmall[] = {
220         1, 0.4, 0.5, 0.6, 0.5,
221         0
222 };
223
224
225 double const ring[] = {
226         2, 5,
227         0.5, 0.8,  0.8, 0.5,  0.5, 0.2,  0.2, 0.5,  0.5, 0.8,
228         0
229 };
230
231
232 double const vert[] = {
233         1, 0.5, 0.05,  0.5, 0.95,
234         0
235 };
236
237
238 double const  Vert[] = {
239         1, 0.3, 0.05,  0.3, 0.95,
240         1, 0.7, 0.05,  0.7, 0.95,
241         0
242 };
243
244
245 double const tilde[] = {
246         2, 4,
247         0.00, 0.8,  0.25, 0.2,  0.75, 0.8,  1.00, 0.2,
248         0
249 };
250
251
252 struct deco_struct {
253         double const * data;
254         int angle;
255 };
256
257 struct named_deco_struct {
258         char const * name;
259         double const * data;
260         int angle;
261 };
262
263 named_deco_struct deco_table[] = {
264         // Decorations
265         {"widehat",             angle,    3 },
266         {"widetilde",           tilde,    0 },
267         {"underbar",            hline,    0 },
268         {"underline",           hline,    0 },
269         {"overline",            hline,    0 },
270         {"underbrace",          brace,    1 },
271         {"overbrace",           brace,    3 },
272         {"overleftarrow",       arrow,    1 },
273         {"overrightarrow",      arrow,    3 },
274         {"overleftrightarrow",  udarrow,  1 },
275         {"xleftarrow",          arrow,    1 },
276         {"xrightarrow",         arrow,    3 },
277         {"underleftarrow",      arrow,    1 },
278         {"underrightarrow",     arrow,    3 },
279         {"underleftrightarrow", udarrow,  1 },
280
281         // Delimiters
282         {"(",              parenth,    0 },
283         {")",              parenth,    2 },
284         {"{",              brace,      0 },
285         {"}",              brace,      2 },
286         {"lbrace",         brace,      0 },
287         {"rbrace",         brace,      2 },
288         {"[",              brack,      0 },
289         {"]",              brack,      2 },
290         {"|",              vert,       0 },
291         {"/",              slash,      0 },
292         {"vert",           vert,       0 },
293         {"Vert",           Vert,       0 },
294         {"'",              slash,      1 },
295         {"backslash",      slash,      1 },
296         {"langle",         angle,      0 },
297         {"lceil",          corner,     0 },
298         {"lfloor",         corner,     1 },
299         {"rangle",         angle,      2 },
300         {"rceil",          corner,     3 },
301         {"rfloor",         corner,     2 },
302         {"downarrow",      arrow,      2 },
303         {"Downarrow",      Arrow,      2 },
304         {"uparrow",        arrow,      0 },
305         {"Uparrow",        Arrow,      0 },
306         {"updownarrow",    udarrow,    0 },
307         {"Updownarrow",    Udarrow,    0 },
308
309         // Accents
310         {"ddot",           ddot,       0 },
311         {"dddot",          dddot,      0 },
312         {"hat",            angle,      3 },
313         {"grave",          slash,      1 },
314         {"acute",          slash,      0 },
315         {"tilde",          tilde,      0 },
316         {"bar",            hline,      0 },
317         {"dot",            hlinesmall, 0 },
318         {"check",          angle,      1 },
319         {"breve",          parenth,    1 },
320         {"vec",            arrow,      3 },
321         {"mathring",       ring,       0 },
322
323         // Dots
324         {"dots",           hline3,     0 },
325         {"ldots",          hline3,     0 },
326         {"cdots",          hline3,     0 },
327         {"vdots",          hline3,     1 },
328         {"ddots",          dline3,     0 },
329         {"dotsb",          hline3,     0 },
330         {"dotsc",          hline3,     0 },
331         {"dotsi",          hline3,     0 },
332         {"dotsm",          hline3,     0 },
333         {"dotso",          hline3,     0 }
334 };
335
336
337 std::map<string, deco_struct> deco_list;
338
339 // sort the table on startup
340 class init_deco_table {
341 public:
342         init_deco_table() {
343                 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
344                 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
345                         deco_struct d;
346                         d.data  = p->data;
347                         d.angle = p->angle;
348                         deco_list[p->name]= d;
349                 }
350         }
351 };
352
353 static init_deco_table dummy;
354
355
356 deco_struct const * search_deco(string const & name)
357 {
358         std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
359         return (p == deco_list.end()) ? 0 : &(p->second);
360 }
361
362
363 } // namespace anon
364
365
366 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
367 {
368         dim.des = font_metrics::descent(c, font);
369         dim.asc = font_metrics::ascent(c, font);
370         dim.wid = mathed_char_width(font, c);
371 }
372
373
374 int mathed_char_ascent(LyXFont const & font, unsigned char c)
375 {
376         return font_metrics::ascent(c, font);
377 }
378
379
380 int mathed_char_descent(LyXFont const & font, unsigned char c)
381 {
382         return font_metrics::descent(c, font);
383 }
384
385
386 int mathed_char_width(LyXFont const & font, unsigned char c)
387 {
388         return font_metrics::width(c, font);
389 }
390
391
392 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
393 {
394 #if 1
395         dim.asc = 0;
396         dim.des = 0;
397         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
398                 dim.asc = max(dim.asc, font_metrics::ascent(*it, font));
399                 dim.des = max(dim.des, font_metrics::descent(*it, font));
400         }
401 #else
402         dim.asc = font_metrics::maxAscent(font);
403         dim.des = font_metrics::maxDescent(font);
404 #endif
405         dim.wid = font_metrics::width(s, font);
406 }
407
408
409 int mathed_string_width(LyXFont const & font, string const & s)
410 {
411         return font_metrics::width(s, font);
412 }
413
414
415 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
416         string const & name)
417 {
418         if (name == ".") {
419                 pi.pain.line(x + w/2, y, x + w/2, y + h,
420                           LColor::cursor, Painter::line_onoffdash);
421                 return;
422         }
423
424         deco_struct const * mds = search_deco(name);
425         if (!mds) {
426                 lyxerr << "Deco was not found. Programming error?" << endl;
427                 lyxerr << "name: '" << name << "'" << endl;
428                 return;
429         }
430
431         int const n = (w < h) ? w : h;
432         int const r = mds->angle;
433         double const * d = mds->data;
434
435         if (h > 70 && (name == "(" || name == ")"))
436                 d = parenthHigh;
437
438         Matrix mt(r, w, h);
439         Matrix sqmt(r, n, n);
440
441         if (r > 0 && r < 3)
442                 y += h;
443
444         if (r >= 2)
445                 x += w;
446
447         for (int i = 0; d[i]; ) {
448                 int code = int(d[i++]);
449                 if (code & 1) {  // code == 1 || code == 3
450                         double xx = d[i++];
451                         double yy = d[i++];
452                         double x2 = d[i++];
453                         double y2 = d[i++];
454                         if (code == 3)
455                                 sqmt.transform(xx, yy);
456                         else
457                                 mt.transform(xx, yy);
458                         mt.transform(x2, y2);
459                         pi.pain.line(
460                                 int(x + xx + 0.5), int(y + yy + 0.5),
461                                 int(x + x2 + 0.5), int(y + y2 + 0.5),
462                                 LColor::math);
463                 } else {
464                         int xp[32];
465                         int yp[32];
466                         int const n = int(d[i++]);
467                         for (int j = 0; j < n; ++j) {
468                                 double xx = d[i++];
469                                 double yy = d[i++];
470 //           lyxerr << ' ' << xx << ' ' << yy << ' ';
471                                 if (code == 4)
472                                         sqmt.transform(xx, yy);
473                                 else
474                                         mt.transform(xx, yy);
475                                 xp[j] = int(x + xx + 0.5);
476                                 yp[j] = int(y + yy + 0.5);
477                                 //  lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
478                         }
479                         pi.pain.lines(xp, yp, n, LColor::math);
480                 }
481         }
482 }
483
484
485 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
486 {
487         LyXFont f = pi.base.font;
488         f.setColor(LColor::latex);
489         pi.pain.text(x, y, str, f);
490 }
491
492
493 void drawStrBlack(PainterInfo & pi, int x, int y, string const & str)
494 {
495         LyXFont f = pi.base.font;
496         f.setColor(LColor::foreground);
497         pi.pain.text(x, y, str, f);
498 }
499
500
501 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
502 {
503         asc = font_metrics::maxAscent(font);
504         des = font_metrics::maxDescent(font);
505 }
506
507
508 struct fontinfo {
509         string cmd_;
510         LyXFont::FONT_FAMILY family_;
511         LyXFont::FONT_SERIES series_;
512         LyXFont::FONT_SHAPE  shape_;
513         LColor::color        color_;
514 };
515
516
517 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
518 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
519 LyXFont::FONT_SHAPE  const inh_shape  = LyXFont::INHERIT_SHAPE;
520
521
522 // mathnormal should be the first, otherwise the fallback further down
523 // does not work
524 fontinfo fontinfos[] = {
525         // math fonts
526         {"mathnormal",    LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
527                           LyXFont::ITALIC_SHAPE, LColor::math},
528         {"mathbf",        inh_family, LyXFont::BOLD_SERIES,
529                           inh_shape, LColor::math},
530         {"mathcal",       LyXFont::CMSY_FAMILY, inh_series,
531                           inh_shape, LColor::math},
532         {"mathfrak",      LyXFont::EUFRAK_FAMILY, inh_series,
533                           inh_shape, LColor::math},
534         {"mathrm",        LyXFont::ROMAN_FAMILY, inh_series,
535                           LyXFont::UP_SHAPE, LColor::math},
536         {"mathsf",        LyXFont::SANS_FAMILY, inh_series,
537                           inh_shape, LColor::math},
538         {"mathbb",        LyXFont::MSB_FAMILY, inh_series,
539                           inh_shape, LColor::math},
540         {"mathtt",        LyXFont::TYPEWRITER_FAMILY, inh_series,
541                           inh_shape, LColor::math},
542         {"mathit",        inh_family, inh_series,
543                           LyXFont::ITALIC_SHAPE, LColor::math},
544         {"cmex",          LyXFont::CMEX_FAMILY, inh_series,
545                           inh_shape, LColor::math},
546         {"cmm",           LyXFont::CMM_FAMILY, inh_series,
547                           inh_shape, LColor::math},
548         {"cmr",           LyXFont::CMR_FAMILY, inh_series,
549                           inh_shape, LColor::math},
550         {"cmsy",          LyXFont::CMSY_FAMILY, inh_series,
551                           inh_shape, LColor::math},
552         {"eufrak",        LyXFont::EUFRAK_FAMILY, inh_series,
553                           inh_shape, LColor::math},
554         {"msa",           LyXFont::MSA_FAMILY, inh_series,
555                           inh_shape, LColor::math},
556         {"msb",           LyXFont::MSB_FAMILY, inh_series,
557                           inh_shape, LColor::math},
558         {"wasy",          LyXFont::WASY_FAMILY, inh_series,
559                           inh_shape, LColor::none},
560
561         // Text fonts
562         {"text",          inh_family, inh_series,
563                           inh_shape, LColor::foreground},
564         {"textbf",        inh_family, LyXFont::BOLD_SERIES,
565                           inh_shape, LColor::foreground},
566         {"textit",        inh_family, inh_series,
567                           LyXFont::ITALIC_SHAPE, LColor::foreground},
568         {"textmd",        inh_family, LyXFont::MEDIUM_SERIES,
569                           inh_shape, LColor::foreground},
570         {"textnormal",    inh_family, inh_series,
571                           LyXFont::UP_SHAPE, LColor::foreground},
572         {"textrm",        LyXFont::ROMAN_FAMILY,
573                           inh_series, LyXFont::UP_SHAPE,LColor::foreground},
574         {"textsc",        inh_family, inh_series,
575                           LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
576         {"textsf",        LyXFont::SANS_FAMILY, inh_series,
577                           inh_shape, LColor::foreground},
578         {"textsl",        inh_family, inh_series,
579                           LyXFont::SLANTED_SHAPE, LColor::foreground},
580         {"texttt",        LyXFont::TYPEWRITER_FAMILY, inh_series,
581                           inh_shape, LColor::foreground},
582         {"textup",        inh_family, inh_series,
583                           LyXFont::UP_SHAPE, LColor::foreground},
584
585         // TIPA support
586         {"textipa",       inh_family, inh_series,
587                           inh_shape, LColor::foreground},
588
589         // LyX internal usage
590         {"lyxtex",        inh_family, inh_series,
591                           LyXFont::UP_SHAPE, LColor::latex},
592         {"lyxsymbol",     LyXFont::SYMBOL_FAMILY, inh_series,
593                           inh_shape, LColor::math},
594         {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
595                           inh_shape, LColor::math},
596         {"lyxblacktext",  LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
597                           LyXFont::UP_SHAPE, LColor::foreground},
598         {"lyxnochange",   inh_family, inh_series,
599                           inh_shape, LColor::foreground},
600         {"lyxfakebb",     LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
601                           LyXFont::UP_SHAPE, LColor::math},
602         {"lyxfakecal",    LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
603                           LyXFont::ITALIC_SHAPE, LColor::math},
604         {"lyxfakefrak",   LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
605                           LyXFont::ITALIC_SHAPE, LColor::math}
606 };
607
608
609 fontinfo * lookupFont(string const & name)
610 {
611         //lyxerr << "searching font '" << name << "'" << endl;
612         int const n = sizeof(fontinfos) / sizeof(fontinfo);
613         for (int i = 0; i < n; ++i)
614                 if (fontinfos[i].cmd_ == name) {
615                         //lyxerr << "found '" << i << "'" << endl;
616                         return fontinfos + i;
617                 }
618         return 0;
619 }
620
621
622 fontinfo * searchFont(string const & name)
623 {
624         fontinfo * f = lookupFont(name);
625         return f ? f : fontinfos;
626         // this should be mathnormal
627         //return searchFont("mathnormal");
628 }
629
630
631 bool isFontName(string const & name)
632 {
633         return lookupFont(name);
634 }
635
636
637 LyXFont getFont(string const & name)
638 {
639         LyXFont font;
640         augmentFont(font, name);
641         return font;
642 }
643
644
645 void fakeFont(string const & orig, string const & fake)
646 {
647         fontinfo * forig = searchFont(orig);
648         fontinfo * ffake = searchFont(fake);
649         if (forig && ffake) {
650                 forig->family_ = ffake->family_;
651                 forig->series_ = ffake->series_;
652                 forig->shape_  = ffake->shape_;
653                 forig->color_  = ffake->color_;
654         } else {
655                 lyxerr << "Can't fake font '" << orig << "' with '"
656                        << fake << "'" << endl;
657         }
658 }
659
660
661 void augmentFont(LyXFont & font, string const & name)
662 {
663         static bool initialized = false;
664         if (!initialized) {
665                 initialized = true;
666                 // fake fonts if necessary
667                 if (!lyx_gui::font_available(getFont("mathfrak")))
668                         fakeFont("mathfrak", "lyxfakefrak");
669                 if (!lyx_gui::font_available(getFont("mathcal")))
670                         fakeFont("mathcal", "lyxfakecal");
671         }
672         fontinfo * info = searchFont(name);
673         if (info->family_ != inh_family)
674                 font.setFamily(info->family_);
675         if (info->series_ != inh_series)
676                 font.setSeries(info->series_);
677         if (info->shape_ != inh_shape)
678                 font.setShape(info->shape_);
679         if (info->color_ != LColor::none)
680                 font.setColor(info->color_);
681 }
682
683
684 string asString(MathArray const & ar)
685 {
686         std::ostringstream os;
687         WriteStream ws(os);
688         ws << ar;
689         return os.str();
690 }
691
692
693 void asArray(string const & str, MathArray & ar)
694 {
695         mathed_parse_cell(ar, str);
696 }
697
698
699 string asString(MathInset const & inset)
700 {
701         std::ostringstream os;
702         WriteStream ws(os);
703         inset.write(ws);
704         return os.str();
705 }
706
707
708 string asString(MathAtom const & at)
709 {
710         std::ostringstream os;
711         WriteStream ws(os);
712         at->write(ws);
713         return os.str();
714 }