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