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