]> git.lyx.org Git - lyx.git/blob - src/mathed/support.C
more 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 deco_struct {
391         int code;
392         float const * data;
393         int angle;
394 };
395
396 deco_struct 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 deco_compare {
453         /// for use by sort and lower_bound
454         int operator()(deco_struct const & a, deco_struct const & b) const
455         {
456                 return a.code < b.code;
457         }
458 };
459
460
461 int const deco_table_size =
462         sizeof(deco_table) / sizeof(deco_struct);
463
464
465 // sort the table on startup
466 struct init_deco_table {
467         init_deco_table() {
468                         std::sort(deco_table,
469                              deco_table + deco_table_size,
470                              deco_compare());
471         }
472 };
473
474 static init_deco_table dummy;
475
476
477 deco_struct const * search_deco(int code)
478 {
479         const deco_struct search_elem = { code, 0, 0 };
480         
481         deco_struct const * res =
482                 lower_bound(deco_table, deco_table + deco_table_size, search_elem,
483                         deco_compare());
484         if (res != deco_table + deco_table_size &&
485             res->code == code)
486                 return res;
487         return 0;
488 }
489
490
491 } // namespace anon
492
493
494 void mathed_char_dim(MathTextCodes type, MathStyles size, unsigned char c,
495         int & asc, int & des, int & wid)
496 {
497         LyXFont const font = WhichFont(type, size);
498         des = lyxfont::descent(c, font);
499         asc = lyxfont::ascent(c, font);
500         wid = mathed_char_width(type, size, c);
501 }
502
503
504 int mathed_char_height(MathTextCodes type, MathStyles size, unsigned char c,
505         int & asc, int & des)
506 {
507         LyXFont const font = WhichFont(type, size);
508         des = lyxfont::descent(c, font);
509         asc = lyxfont::ascent(c, font);
510         return asc + des;
511 }
512
513
514 int mathed_char_height(MathTextCodes type, MathStyles size, unsigned char c)
515 {
516         int asc;
517         int des;
518         return mathed_char_height(type, size, c, asc, des);
519 }
520
521 int mathed_char_ascent(MathTextCodes type, MathStyles size, unsigned char c)
522 {
523         LyXFont const font = WhichFont(type, size);
524         return lyxfont::ascent(c, font);
525 }
526
527 int mathed_char_descent(MathTextCodes type, MathStyles size, unsigned char c)
528 {
529         LyXFont const font = WhichFont(type, size);
530         return lyxfont::descent(c, font);
531 }
532
533 int mathed_char_width(MathTextCodes type, MathStyles size, unsigned char c)
534 {
535         LyXFont const font = WhichFont(type, size);
536         if (type == LM_TC_BOP)
537                 return lyxfont::width(c, font) + 2 * lyxfont::width(' ', font);
538         else
539                 return lyxfont::width(c, font);
540 }
541
542
543 void mathed_string_dim(MathTextCodes type, MathStyles size, string const & s,
544                          int & asc, int & des, int & wid)
545 {
546         mathed_string_height(type, size, s, asc, des);
547         wid = mathed_string_width(type, size, s);
548 }
549
550 int mathed_string_height(MathTextCodes type, MathStyles size, string const & s,
551                          int & asc, int & des)
552 {
553         LyXFont const font = WhichFont(type, size);
554         asc = des = 0;
555         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
556                 des = max(des, lyxfont::descent(*it, font));
557                 asc = max(asc, lyxfont::ascent(*it, font));
558         }
559         return asc + des;
560 }
561
562 int mathed_string_width(MathTextCodes type, MathStyles size, string const & s)
563 {
564         return lyxfont::width(s, WhichFont(type, size));
565 }
566
567
568 void mathed_draw_deco(Painter & pain, int x, int y, int w, int h,
569         latexkeys const * l)
570 {
571         Matrix mt;
572         Matrix sqmt;
573         int i = 0;
574         string name = l->name;
575         int code = (name.size() > 1) ? l->id : name[0];
576
577         if (name == ".") {
578                 pain.line(x + w/2, y, x + w/2, y + h,
579                           LColor::mathcursor, Painter::line_onoffdash);
580                 return;
581         }       
582         
583         deco_struct const * mds = search_deco(code);
584         if (!mds) {
585                 lyxerr << "Deco was not found. Programming error?\n";
586                 lyxerr << "name: '" << l->name << "', code: " << code << "\n";
587                 return;
588         }
589         
590         int const r = mds->angle;
591         float const * d = mds->data;
592         
593         if (h > 70 && (mds->code == int('(') || mds->code == int(')')))
594                 d = parenthHigh;
595         
596         mt.rotate(r);
597         mt.escalate(w, h);
598         
599         int const n = (w < h) ? w : h;
600
601         sqmt.rotate(r);
602         sqmt.escalate(n, n);
603
604         if (r > 0 && r < 3)
605                 y += h;
606
607         if (r >= 2)
608                 x += w;   
609
610         do {
611                 float xx;
612                 float yy;
613                 float x2;
614                 float y2;
615
616                 code = int(d[i++]);
617                 switch (code) {
618                 case 0: break;
619                 case 1: 
620                 case 3:
621                 {
622                         xx = d[i++]; yy = d[i++];
623                         x2 = d[i++]; y2 = d[i++];
624                         if (code == 3) 
625                                 sqmt.transform(xx, yy, xx, yy);
626                         else
627                                 mt.transform(xx, yy, xx, yy);
628                         mt.transform(x2, y2, x2, y2);
629                         pain.line(x + int(xx), y + int(yy),
630                                   x + int(x2), y + int(y2),
631                                   LColor::mathline);
632                         break;
633                 }        
634                 case 2: 
635                 case 4:
636                 {
637                         int xp[32];
638                         int yp[32];
639                         int const n = int(d[i++]);
640                         for (int j = 0; j < n; ++j) {
641                                 xx = d[i++]; yy = d[i++];
642 //           lyxerr << " " << xx << " " << yy << " ";
643                                 if (code == 4) 
644                                         sqmt.transform(xx, yy, xx, yy);
645                                 else
646                                         mt.transform(xx, yy, 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         } while (code);
655 }
656
657
658 bool isBinaryOp(char c)
659 {
660         return true; 
661 }
662
663
664 // In a near future maybe we use a better fonts renderer
665 void drawStr(Painter & pain, MathTextCodes type, MathStyles siz,
666         int x, int y, string const & s)
667 {
668         pain.text(x, y, s, WhichFont(type, siz));
669 }
670
671
672 void drawChar
673         (Painter & pain, MathTextCodes type, MathStyles siz, int x, int y, char c)
674 {
675         string s;
676         if (type == LM_TC_BOP)
677                 s += ' ';
678         s += c;
679         if (type == LM_TC_BOP)
680                 s += ' ';
681         drawStr(pain, type, siz, x, y, s);
682 }
683
684 // decrease math size for super- and subscripts
685 MathStyles smallerStyleScript(MathStyles st)
686 {
687         switch (st) {
688                 case LM_ST_DISPLAY:
689                 case LM_ST_TEXT:    st = LM_ST_SCRIPT; break;
690                 default:            st = LM_ST_SCRIPTSCRIPT;
691         }
692         return st;
693 }
694
695 // decrease math size for fractions
696 MathStyles smallerStyleFrac(MathStyles st)
697 {
698         switch (st) {
699                 case LM_ST_DISPLAY: st = LM_ST_TEXT; break;
700                 case LM_ST_TEXT:    st = LM_ST_SCRIPT; break;
701                 default:            st = LM_ST_SCRIPTSCRIPT;
702         }
703         return st;
704 }
705
706
707 void math_font_max_dim(MathTextCodes code, MathStyles siz, int & asc, int & des)
708 {
709         LyXFont font = WhichFont(code, siz);
710         asc = lyxfont::maxAscent(font);
711         des = lyxfont::maxDescent(font);
712 }
713
714 char const * latex_mathspace[] = {
715         "!", ",", ":", ";", "quad", "qquad"
716 };