]> git.lyx.org Git - lyx.git/blob - src/mathed/support.C
LyX Drinkers Union: patch 1
[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         if (type == LM_TC_TEX) {
368                 f.setLatex(LyXFont::ON);
369         }
370         return f;
371 }
372
373
374 void mathed_draw_deco(Painter & pain, int x, int y, int w, int h, int code)
375 {
376         Matriz mt;
377         Matriz sqmt;
378         float xx;
379         float yy;
380         float x2;
381         float y2;
382         int i = 0;
383         
384 #if USE_EXCEPTIONS
385         math_deco_struct mds;
386         try {
387                 mds = search_deco(code);
388         }
389         catch (deco_not_found) {
390                 // Should this ever happen?
391                 lyxerr << "Deco was not found. Programming error?" << endl;
392                 return;
393         }
394         
395         int const r = mds.angle;
396         float const * d = mds.data;
397         
398         if (h > 70 && (mds.code == int('(')
399                        || mds.code == int(')')))
400                 d = parenthHigh;
401 #else
402         math_deco_struct const * mds = search_deco(code);
403         if (!mds) {
404                 // Should this ever happen?
405                 lyxerr << "Deco was not found. Programming error?" << endl;
406                 return;
407         }
408         
409         
410         int const r = mds->angle;
411         float const * d = mds->data;
412         
413         if (h > 70 && (mds->code == int('(')
414                        || mds->code == int(')')))
415                 d = parenthHigh;
416 #endif
417         
418         mt.rota(r);
419         mt.escala(w, h);
420         
421         int const n = (w < h) ? w : h;
422         sqmt.rota(r);
423         sqmt.escala(n, n);
424         if (r > 0 && r < 3) y += h;   
425         if (r >= 2) x += w;   
426         do {
427                 code = int(d[i++]);
428                 switch (code) {
429                 case 0: break;
430                 case 1: 
431                 case 3:
432                 {
433                         xx = d[i++]; yy = d[i++];
434                         x2 = d[i++]; y2 = d[i++];
435                         if (code == 3) 
436                                 sqmt.transf(xx, yy, xx, yy);
437                         else
438                                 mt.transf(xx, yy, xx, yy);
439                         mt.transf(x2, y2, x2, y2);
440                         pain.line(x + int(xx), y + int(yy),
441                                   x + int(x2), y + int(y2),
442                                   LColor::mathline);
443                         break;
444                 }        
445                 case 2: 
446                 case 4:
447                 {
448                         int xp[32];
449                         int yp[32];
450                         int const n = int(d[i++]);
451                         for (int j = 0; j < n; ++j) {
452                                 xx = d[i++]; yy = d[i++];
453 //           lyxerr << " " << xx << " " << yy << " ";
454                                 if (code == 4) 
455                                         sqmt.transf(xx, yy, xx, yy);
456                                 else
457                                         mt.transf(xx, yy, xx, yy);
458                                 xp[j] = x + int(xx);
459                                 yp[j] = y + int(yy);
460                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
461                         }
462                         pain.lines(xp, yp, n, LColor::mathline);
463                 }
464                 }
465         } while (code);
466 }
467
468
469 #define USE_EXCEPTIONS 0
470 #if USE_EXCEPTIONS
471 struct deco_not_found {};
472
473
474 math_deco_struct const & search_deco(int code)
475 {
476         math_deco_struct const * res =
477                 lower_bound(math_deco_table,
478                             math_deco_table + math_deco_table_size,
479                             code, math_deco_compare());
480         if (res != math_deco_table + math_deco_table_size &&
481             res->code == code)
482                 return *res;
483         throw deco_not_found();
484 }
485
486 #else
487
488
489 math_deco_struct const * search_deco(int code)
490 {
491         math_deco_struct search_elem = { code, 0, 0 };
492         
493         math_deco_struct const * res =
494                 lower_bound(math_deco_table,
495                             math_deco_table + math_deco_table_size,
496                             search_elem, math_deco_compare());
497         if (res != math_deco_table + math_deco_table_size &&
498             res->code == code)
499                 return res;
500         return 0;
501 }
502 #endif
503
504
505 bool MathIsInset(short x)
506 {
507         return LM_TC_INSET <= x && x <= LM_TC_ACTIVE_INSET;
508 }
509
510
511 bool MathIsFont(short x)
512 {
513         return LM_TC_CONST <= x && x <= LM_TC_BSYM;
514 }
515
516
517 bool MathIsAlphaFont(short x)
518 {
519         return LM_TC_VAR <= x && x <= LM_TC_TEXTRM;
520 }
521
522
523 bool MathIsUp(short x)
524 {
525         return x == LM_TC_UP;
526 }
527
528
529 bool MathIsDown(short x)
530 {
531         return x == LM_TC_DOWN;
532 }
533
534
535 bool MathIsScript(short x)
536 {
537         return x == LM_TC_DOWN || x == LM_TC_UP;
538 }
539
540
541 bool MathIsBOPS(short x)
542 {
543         return MathLookupBOP(x) > LMB_NONE;
544 }
545
546
547 bool MathIsBinary(short x)
548 {
549         return x == LM_TC_BOP || x == LM_TC_BOPS;
550 }
551
552
553 bool MathIsSymbol(short x)
554 {
555         return LM_TC_SYMB <= x && x <= LM_TC_BSYM;
556 }
557      
558
559 bool is_matrix_type(short int type)
560 {
561         return type == LM_OT_MATRIX;
562 }
563
564 // In a near future maybe we use a better fonts renderer
565 void drawStr(Painter & pain, short type, int siz,
566         int x, int y, string const & s)
567 {
568         string st;
569         if (MathIsBinary(type))
570                 for (string::const_iterator it = s.begin();
571                      it != s.end(); ++it) {
572                         st += ' ';
573                         st += *it;
574                         st += ' ';
575                 }
576         else
577                 st = s;
578         
579         LyXFont const mf = mathed_get_font(type, siz);
580         pain.text(x, y, st, mf);
581 }
582
583 void drawChar(Painter & pain, short type, int siz, int x, int y, char c)
584 {
585         string s;
586         s += c;
587         drawStr(pain, type, siz, x, y, s);
588 }