]> git.lyx.org Git - lyx.git/blob - src/mathed/math_support.C
remove no more needed hack for positioning the cursor with the mouse
[lyx.git] / src / mathed / math_support.C
1 #include <config.h>
2
3 #include <map>
4
5 #include "math_support.h"
6 #include "lyxfont.h"
7 #include "FontLoader.h"
8 #include "font.h"
9 #include "math_cursor.h"
10 #include "math_defs.h"
11 #include "math_inset.h"
12 #include "math_parser.h"
13 #include "Painter.h"
14 #include "debug.h"
15 #include "commandtags.h"
16
17 using std::map;
18 using std::endl;
19 using std::max;
20
21
22 ///
23 class Matrix {
24 public:
25         ///
26         Matrix(int, double, double);
27         ///
28         void transform(double &, double &);
29 private:
30         ///
31         double m_[2][2];
32 };
33
34
35 Matrix::Matrix(int code, double x, double y)
36 {
37         double const cs = (code & 1) ? 0 : (1 - code);
38         double const sn = (code & 1) ? (2 - code) : 0;
39         m_[0][0] =  cs * x;
40         m_[0][1] =  sn * x;
41         m_[1][0] = -sn * y;
42         m_[1][1] =  cs * y;
43 }
44
45
46 void Matrix::transform(double & x, double & y)
47 {
48         double xx = m_[0][0] * x + m_[0][1] * y;
49         double yy = m_[1][0] * x + m_[1][1] * y;
50         x = xx;
51         y = yy;
52 }
53
54
55 namespace {
56
57 LyXFont * MathFonts = 0;
58 bool font_available[LM_FONT_END];
59 bool font_available_initialized[LM_FONT_END];
60
61 enum MathFont {
62         FONT_IT,
63         FONT_SYMBOL,
64         FONT_SYMBOLI,
65         FONT_BF,
66         FONT_TT,
67         FONT_RM,
68         FONT_SF,
69         FONT_CMR,
70         FONT_CMSY,
71         FONT_CMM,
72         FONT_CMEX,
73         FONT_MSA,
74         FONT_MSB,
75         FONT_EUFRAK,
76         FONT_FAKEBB,
77         FONT_FAKECAL,
78         FONT_FAKEFRAK,
79         FONT_NUM
80 };
81
82 void mathed_init_fonts()
83 {
84         MathFonts = new LyXFont[FONT_NUM];
85
86         MathFonts[FONT_IT].setShape(LyXFont::ITALIC_SHAPE);
87
88         MathFonts[FONT_SYMBOL].setFamily(LyXFont::SYMBOL_FAMILY);
89
90         MathFonts[FONT_SYMBOLI].setFamily(LyXFont::SYMBOL_FAMILY);
91         MathFonts[FONT_SYMBOLI].setShape(LyXFont::ITALIC_SHAPE);
92
93         MathFonts[FONT_BF].setSeries(LyXFont::BOLD_SERIES);
94
95         MathFonts[FONT_TT].setFamily(LyXFont::TYPEWRITER_FAMILY);
96         MathFonts[FONT_RM].setFamily(LyXFont::ROMAN_FAMILY);
97         MathFonts[FONT_SF].setFamily(LyXFont::SANS_FAMILY);
98
99         MathFonts[FONT_CMR].setFamily(LyXFont::CMR_FAMILY);
100         MathFonts[FONT_CMSY].setFamily(LyXFont::CMSY_FAMILY);
101         MathFonts[FONT_CMM].setFamily(LyXFont::CMM_FAMILY);
102         MathFonts[FONT_CMEX].setFamily(LyXFont::CMEX_FAMILY);
103         MathFonts[FONT_MSA].setFamily(LyXFont::MSA_FAMILY);
104         MathFonts[FONT_MSB].setFamily(LyXFont::MSB_FAMILY);
105         MathFonts[FONT_EUFRAK].setFamily(LyXFont::EUFRAK_FAMILY);
106
107         MathFonts[FONT_FAKEBB].setFamily(LyXFont::TYPEWRITER_FAMILY);
108         MathFonts[FONT_FAKEBB].setSeries(LyXFont::BOLD_SERIES);
109
110         MathFonts[FONT_FAKECAL].setFamily(LyXFont::SANS_FAMILY);
111         MathFonts[FONT_FAKECAL].setShape(LyXFont::ITALIC_SHAPE);
112
113         MathFonts[FONT_FAKEFRAK].setFamily(LyXFont::SANS_FAMILY);
114         MathFonts[FONT_FAKEFRAK].setSeries(LyXFont::BOLD_SERIES);
115
116         for (int i = 0; i < LM_FONT_END; ++i)
117                 font_available_initialized[i] = false;
118 }
119
120
121 LyXFont const & whichFontBaseIntern(MathTextCodes type)
122 {
123         if (!MathFonts)
124                 mathed_init_fonts();
125
126         switch (type) {
127         case LM_TC_SYMB:
128         case LM_TC_BOLDSYMB:
129                 return MathFonts[FONT_SYMBOLI];
130
131         case LM_TC_VAR:
132         case LM_TC_IT:
133                 return MathFonts[FONT_IT];
134
135         case LM_TC_BF:
136                 return MathFonts[FONT_BF];
137
138         case LM_TC_BB:
139                 return MathFonts[FONT_MSB];
140
141         case LM_TC_CAL:
142                 return MathFonts[FONT_CMSY];
143
144         case LM_TC_TT:
145                 return MathFonts[FONT_TT];
146
147         case LM_TC_BOX:
148         case LM_TC_TEXTRM:
149         case LM_TC_CONST:
150         case LM_TC_TEX:
151         case LM_TC_RM:
152                 return MathFonts[FONT_RM];
153
154         case LM_TC_SF:
155                 return MathFonts[FONT_SF];
156
157         case LM_TC_CMR:
158                 return MathFonts[FONT_CMR];
159
160         case LM_TC_CMSY:
161                 return MathFonts[FONT_CMSY];
162
163         case LM_TC_CMM:
164                 return MathFonts[FONT_CMM];
165
166         case LM_TC_CMEX:
167                 return MathFonts[FONT_CMEX];
168
169         case LM_TC_MSA:
170                 return MathFonts[FONT_MSA];
171
172         case LM_TC_MSB:
173                 return MathFonts[FONT_MSB];
174
175         case LM_TC_EUFRAK:
176                 return MathFonts[FONT_EUFRAK];
177
178         default:
179                 break;
180         }
181         return MathFonts[1];
182 }
183
184
185 LyXFont const & whichFontBase(MathTextCodes type)
186 {
187         if (!MathFonts)
188                 mathed_init_fonts();
189
190         switch (type) {
191         case LM_TC_BB:
192                 if (math_font_available(LM_TC_MSB))
193                         return MathFonts[FONT_MSB];
194                 else
195                         return MathFonts[FONT_FAKEBB];
196
197         case LM_TC_CAL:
198                 if (math_font_available(LM_TC_CMSY))
199                         return MathFonts[FONT_CMSY];
200                 else
201                         return MathFonts[FONT_FAKECAL];
202
203         case LM_TC_EUFRAK:
204                 if (math_font_available(LM_TC_EUFRAK))
205                         return MathFonts[FONT_EUFRAK];
206                 else
207                         return MathFonts[FONT_FAKEFRAK];
208
209         default:
210                 break;
211         }
212         return whichFontBaseIntern(type);
213 }
214
215 } // namespace
216
217
218 void whichFont(LyXFont & f, MathTextCodes type, MathMetricsInfo const & size)
219 {
220         f = whichFontBase(type);
221         // use actual size
222         f.setSize(size.font.size());
223
224         switch (size.style) {
225         case LM_ST_DISPLAY:
226                 if (type == LM_TC_BOLDSYMB || type == LM_TC_CMEX) {
227                         f.incSize();
228                         f.incSize();
229                 }
230                 break;
231
232         case LM_ST_TEXT:
233                 break;
234
235         case LM_ST_SCRIPT:
236                 f.decSize();
237                 f.decSize();
238                 break;
239
240         case LM_ST_SCRIPTSCRIPT:
241                 f.decSize();
242                 f.decSize();
243                 f.decSize();
244                 break;
245
246         default:
247                 lyxerr << "Math Error: wrong font size: " << size.style << endl;
248                 break;
249         }
250
251         if (type != LM_TC_TEXTRM && type != LM_TC_BOX)
252                 f.setColor(LColor::math);
253
254         if (type == LM_TC_TEX)
255                 f.setColor(LColor::latex);
256 }
257
258
259 bool math_font_available(MathTextCodes type)
260 {
261         if (!font_available_initialized[type]) {
262                 font_available_initialized[type] = true;
263                 font_available[type] = fontloader.available(whichFontBaseIntern(type));
264                 if (!font_available[type])
265                         lyxerr[Debug::FONT] << "Math font " << type << " not available.\n";
266         }
267         return font_available[type];
268 }
269
270
271 namespace {
272
273 /*
274  * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
275  * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4= square polyline
276  */
277
278
279 double const parenthHigh[] = {
280         2, 13,
281         0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
282         0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
283         0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
284         0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
285         0.9840, 0.9986,
286         0
287 };
288
289
290 double const parenth[] = {
291         2, 13,
292         0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
293         0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
294         0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
295         0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
296         0.9930, 0.9919,
297         0
298 };
299
300
301 double const brace[] = {
302         2, 21,
303         0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
304         0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
305         0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
306         0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
307         0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
308         0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
309         0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
310         0
311 };
312
313
314 double const arrow[] = {
315         4, 7,
316         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
317         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
318         0.9500, 0.7500,
319         3, 0.5000, 0.1500, 0.5000, 0.9500,
320         0
321 };
322
323
324 double const Arrow[] = {
325         4, 7,
326         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
327         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
328         0.9500, 0.7500,
329         3, 0.3500, 0.5000, 0.3500, 0.9500,
330         3, 0.6500, 0.5000, 0.6500, 0.9500,
331         0
332 };
333
334
335 double const udarrow[] = {
336         2, 3,
337         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
338         2, 3,
339         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
340         1, 0.5, 0.2,  0.5, 0.8,
341         0
342 };
343
344
345 double const Udarrow[] = {
346         2, 3,
347         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
348         2, 3,
349         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
350         1, 0.35, 0.2, 0.35, 0.8,
351         1, 0.65, 0.2, 0.65, 0.8,
352         0
353 };
354
355
356 double const brack[] = {
357         2, 4,
358         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
359         0
360 };
361
362
363 double const corner[] = {
364         2, 3,
365         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,
366         0
367 };
368
369
370 double const angle[] = {
371         2, 3,
372         1, 0,  0.05, 0.5,  1, 1,
373         0
374 };
375
376
377 double const slash[] = {
378         1, 0.95, 0.05, 0.05, 0.95,
379         0
380 };
381
382
383 double const hline[] = {
384         1, 0.00, 0.5, 1.0, 0.5,
385         0
386 };
387
388
389 double const ddot[] = {
390         1, 0.2, 0.5,  0.3, 0.5,
391         1, 0.7, 0.5,  0.8, 0.5,
392         0
393 };
394
395
396 double const dddot[] = {
397         1, 0.1, 0.5,  0.2, 0.5,
398         1, 0.45, 0.5, 0.55, 0.5,
399         1, 0.8, 0.5,  0.9, 0.5,
400         0
401 };
402
403
404 double const hline3[] = {
405         1, 0.1,   0,  0.15,  0,
406         1, 0.475, 0,  0.525, 0,
407         1, 0.85,  0,  0.9,   0,
408         0
409 };
410
411
412 double const dline3[] = {
413         1, 0.1,   0.1,   0.15,  0.15,
414         1, 0.475, 0.475, 0.525, 0.525,
415         1, 0.85,  0.85,  0.9,   0.9,
416         0
417 };
418
419
420 double const hlinesmall[] = {
421         1, 0.4, 0.5, 0.6, 0.5,
422         0
423 };
424
425
426 double const vert[] = {
427         1, 0.5, 0.05,  0.5, 0.95,
428         0
429 };
430
431
432 double const  Vert[] = {
433         1, 0.3, 0.05,  0.3, 0.95,
434         1, 0.7, 0.05,  0.7, 0.95,
435         0
436 };
437
438
439 double const ring[] = {
440         2, 5,
441         0.5, 0.8,  0.8, 0.5,  0.5, 0.2,  0.2, 0.5,  0.5, 0.8,
442         0
443 };
444
445
446 double const tilde[] = {
447         2, 4,
448         0.05, 0.8,  0.25, 0.2,  0.75, 0.8,  0.95, 0.2,
449         0
450 };
451
452
453 struct deco_struct {
454         double const * data;
455         int angle;
456 };
457
458 struct named_deco_struct {
459         char const * name;
460         double const * data;
461         int angle;
462 };
463
464 named_deco_struct deco_table[] = {
465         // Decorations
466         {"widehat",        angle,      3 },
467         {"widetilde",      tilde,      0 },
468         {"underbar",       hline,      0 },
469         {"underline",      hline,      0 },
470         {"overline",       hline,      0 },
471         {"underbrace",     brace,      1 },
472         {"overbrace",      brace,      3 },
473         {"overleftarrow",  arrow,      1 },
474         {"overrightarrow", arrow,      3 },
475         {"overleftrightarrow", udarrow, 1 },
476         {"xleftarrow",     arrow,      1 },
477         {"xrightarrow",    arrow,      3 },
478         {"underleftarrow", arrow,      1 },
479         {"underrightarrow", arrow,     3 },
480         {"underleftrightarrow",udarrow, 1 },
481
482         // Delimiters
483         {"(",              parenth,    0 },
484         {")",              parenth,    2 },
485         {"{",              brace,      0 },
486         {"}",              brace,      2 },
487         {"[",              brack,      0 },
488         {"]",              brack,      2 },
489         {"|",              vert,       0 },
490         {"/",              slash,      0 },
491         {"Vert",           Vert,       0 },
492         {"'",              slash,      1 },
493         {"backslash",      slash,      1 },
494         {"langle",         angle,      0 },
495         {"lceil",          corner,     0 },
496         {"lfloor",         corner,     1 },
497         {"rangle",         angle,      2 },
498         {"rceil",          corner,     3 },
499         {"rfloor",         corner,     2 },
500         {"downarrow",      arrow,      2 },
501         {"Downarrow",      Arrow,      2 },
502         {"uparrow",        arrow,      0 },
503         {"Uparrow",        Arrow,      0 },
504         {"updownarrow",    udarrow,    0 },
505         {"Updownarrow",    Udarrow,    0 },
506
507         // Accents
508         {"ddot",           ddot,       0 },
509         {"dddot",          dddot,      0 },
510         {"hat",            angle,      3 },
511         {"grave",          slash,      1 },
512         {"acute",          slash,      0 },
513         {"tilde",          tilde,      0 },
514         {"bar",            hline,      0 },
515         {"dot",            hlinesmall, 0 },
516         {"check",          angle,      1 },
517         {"breve",          parenth,    1 },
518         {"vec",            arrow,      3 },
519         {"not",            slash,      0 },
520         {"mathring",       ring,       0 },
521
522         // Dots
523         {"ldots",          hline3,     0 },
524         {"cdots",          hline3,     0 },
525         {"vdots",          hline3,     1 },
526         {"ddots",          dline3,     0 }
527 };
528
529
530 map<string, deco_struct> deco_list;
531
532 // sort the table on startup
533 struct init_deco_table {
534         init_deco_table() {
535                 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
536                 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
537                         deco_struct d;
538                         d.data  = p->data;
539                         d.angle = p->angle;
540                         deco_list[p->name]= d;
541                 }
542         }
543 };
544
545 static init_deco_table dummy;
546
547
548 deco_struct const * search_deco(string const & name)
549 {
550         map<string, deco_struct>::const_iterator p = deco_list.find(name);
551         return (p == deco_list.end()) ? 0 : &(p->second);
552 }
553
554
555 } // namespace anon
556
557
558 void mathed_char_dim(LyXFont const & font,
559         unsigned char c, int & asc, int & des, int & wid)
560 {
561         des = lyxfont::descent(c, font);
562         asc = lyxfont::ascent(c, font);
563         wid = mathed_char_width(font, c);
564 }
565
566
567 int mathed_char_ascent(LyXFont const & font, unsigned char c)
568 {
569         return lyxfont::ascent(c, font);
570 }
571
572
573 int mathed_char_descent(LyXFont const & font, unsigned char c)
574 {
575         return lyxfont::descent(c, font);
576 }
577
578
579 int mathed_char_width(LyXFont const & font, unsigned char c)
580 {
581         return lyxfont::width(c, font);
582 }
583
584
585 void mathed_string_dim(LyXFont const & font,
586         string const & s, int & asc, int & des, int & wid)
587 {
588         asc = des = 0;
589         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
590                 des = max(des, lyxfont::descent(*it, font));
591                 asc = max(asc, lyxfont::ascent(*it, font));
592         }
593         wid = lyxfont::width(s, font);
594 }
595
596
597 int mathed_string_width(LyXFont const & font, string const & s)
598 {
599         return lyxfont::width(s, font);
600 }
601
602
603 int mathed_string_ascent(LyXFont const & font, string const & s)
604 {
605         int asc = 0;
606         for (string::const_iterator it = s.begin(); it != s.end(); ++it)
607                 asc = max(asc, lyxfont::ascent(*it, font));
608         return asc;
609 }
610
611
612 int mathed_string_descent(LyXFont const & font, string const & s)
613 {
614         int des = 0;
615         for (string::const_iterator it = s.begin(); it != s.end(); ++it)
616                 des = max(des, lyxfont::descent(*it, font));
617         return des;
618 }
619
620
621
622 void mathed_draw_deco(Painter & pain, int x, int y, int w, int h,
623         const string & name)
624 {
625         if (name == ".") {
626                 pain.line(x + w/2, y, x + w/2, y + h,
627                           LColor::mathcursor, Painter::line_onoffdash);
628                 return;
629         }
630
631         deco_struct const * mds = search_deco(name);
632         if (!mds) {
633                 lyxerr << "Deco was not found. Programming error?\n";
634                 lyxerr << "name: '" << name << "'\n";
635                 return;
636         }
637
638         int const n = (w < h) ? w : h;
639         int const r = mds->angle;
640         double const * d = mds->data;
641
642         if (h > 70 && (name == "(" || name == ")"))
643                 d = parenthHigh;
644
645         Matrix mt(r, w, h);
646         Matrix sqmt(r, n, n);
647
648         if (r > 0 && r < 3)
649                 y += h;
650
651         if (r >= 2)
652                 x += w;
653
654         for (int i = 0; d[i];) {
655                 int code = int(d[i++]);
656                 if (code & 1) {  // code == 1 || code == 3
657                         double xx = d[i++];
658                         double yy = d[i++];
659                         double x2 = d[i++];
660                         double y2 = d[i++];
661                         if (code == 3)
662                                 sqmt.transform(xx, yy);
663                         else
664                                 mt.transform(xx, yy);
665                         mt.transform(x2, y2);
666                         pain.line(x + int(xx), y + int(yy), x + int(x2), y + int(y2),
667                                         LColor::math);
668                 }       else {
669                         int xp[32];
670                         int yp[32];
671                         int const n = int(d[i++]);
672                         for (int j = 0; j < n; ++j) {
673                                 double xx = d[i++];
674                                 double yy = d[i++];
675 //           lyxerr << " " << xx << " " << yy << " ";
676                                 if (code == 4)
677                                         sqmt.transform(xx, yy);
678                                 else
679                                         mt.transform(xx, yy);
680                                 xp[j] = x + int(xx);
681                                 yp[j] = y + int(yy);
682                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
683                         }
684                         pain.lines(xp, yp, n, LColor::math);
685                 }
686         }
687 }
688
689
690 void mathed_draw_framebox(Painter & pain, int x, int y, MathInset const * p)
691 {
692         if (mathcursor && mathcursor->isInside(p))
693                 pain.rectangle(x, y - p->ascent(), p->width(), p->height(),
694                         LColor::mathframe);
695 }
696
697
698 // In the future maybe we use a better fonts renderer
699 void drawStr(Painter & pain, LyXFont const & font,
700         int x, int y, string const & str)
701 {
702         pain.text(x, y, str, font);
703 }
704
705
706 void drawChar(Painter & pain, LyXFont const & font, int x, int y, char c)
707 {
708         pain.text(x, y, c, font);
709 }
710
711
712 // decrease math size for super- and subscripts
713 void smallerStyleScript(MathMetricsInfo & st)
714 {
715         switch (st.style) {
716                 case LM_ST_DISPLAY:
717                 case LM_ST_TEXT:    st.style = LM_ST_SCRIPT; break;
718                 default:            st.style = LM_ST_SCRIPTSCRIPT;
719         }
720 }
721
722
723 // decrease math size for fractions
724 void smallerStyleFrac(MathMetricsInfo & st)
725 {
726         switch (st.style) {
727                 case LM_ST_DISPLAY: st.style = LM_ST_TEXT; break;
728                 case LM_ST_TEXT:    st.style = LM_ST_SCRIPT; break;
729                 default:            st.style = LM_ST_SCRIPTSCRIPT;
730         }
731 }
732
733
734 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
735 {
736         asc = lyxfont::maxAscent(font);
737         des = lyxfont::maxDescent(font);
738 }
739
740
741 char const * math_font_name(MathTextCodes code)
742 {
743         static char const * theFontNames[] = {
744                 "mathrm",
745                 "mathcal",
746                 "mathfrak",
747                 "mathbf",
748                 "mathbb",
749                 "mathsf",
750                 "mathtt",
751                 "mathit",
752                 "textrm"
753         };
754
755         if (code >= LM_TC_RM && code <= LM_TC_TEXTRM)
756                 return theFontNames[code - LM_TC_RM];
757         return 0;
758 }
759
760 string convertDelimToLatexName(string const & name)
761 {
762         if (name == "(")
763                 return name;
764         if (name == "[")
765                 return name;
766         if (name == ".")
767                 return name;
768         if (name == ")")
769                 return name;
770         if (name == "]")
771                 return name;
772         if (name == "/")
773                 return name;
774         if (name == "|")
775                 return name;
776         return "\\" + name + " ";
777 }