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