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