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