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