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