]> git.lyx.org Git - lyx.git/blob - src/mathed/math_delim.C
some using changes small changes in lyxfont and some other things, read the Changelog
[lyx.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
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         /// for use by lower_bound
308         inline
309         int operator()(math_deco_struct const & a, int b) const {
310                 return a.code < b;
311         }
312 };
313
314
315 static
316 int const math_deco_table_size = sizeof(math_deco_table) /sizeof(math_deco_struct);
317
318 class init_deco_table {
319 public:
320         init_deco_table() {
321                 if (!init) {
322                         sort(math_deco_table,
323                              math_deco_table + math_deco_table_size,
324                              math_deco_compare());
325                         init_deco_table::init = true;
326                 }
327         }
328 private:
329         static bool init;
330 };
331
332 bool init_deco_table::init = false;
333 static init_deco_table idt;
334
335 // If we had exceptions we could return a reference in stead and not
336 // have to check for a null pointer in mathed_draw_deco
337
338 #define USE_EXCEPTIONS 0
339 #if USE_EXCEPTIONS
340 struct deco_not_found {};
341
342 static
343 math_deco_struct const & search_deco(int code)
344 {
345         math_deco_struct * res =
346                 lower_bound(math_deco_table,
347                             math_deco_table + math_deco_table_size,
348                             code, math_deco_compare());
349         if (res != math_deco_table + math_deco_table_size &&
350             res->code == code)
351                 return *res;
352         throw deco_not_found();
353 }
354
355 #else
356
357 static
358 math_deco_struct const * search_deco(int code)
359 {
360         math_deco_struct * res =
361                 lower_bound(math_deco_table,
362                             math_deco_table + math_deco_table_size,
363                             code, math_deco_compare());
364         if (res != math_deco_table + math_deco_table_size &&
365             res->code == code)
366                 return res;
367         return 0;
368 }
369 #endif
370
371 void mathed_draw_deco(Painter & pain, int x, int y, int w, int h, int code)
372 {
373         Matriz mt, sqmt;
374         float xx, yy, x2, y2;
375         int i = 0;
376
377 #if USE_EXCEPTIONS
378         math_deco_struct mds;
379         try {
380                 mds = search_deco(code);
381         }
382         catch (deco_not_found) {
383                 // Should this ever happen?
384                 lyxerr << "Deco was not found. Programming error?" << endl;
385                 return;
386         }
387    
388         int r = mds.angle;
389         float * d = mds.data;
390         
391         if (h > 70 && (mds.code == int('(')
392                        || mds.code == int(')')))
393                 d = parenthHigh;
394 #else
395         math_deco_struct const * mds = search_deco(code);
396         if (!mds) {
397                 // Should this ever happen?
398                 lyxerr << "Deco was not found. Programming error?" << endl;
399                 return;
400         }
401         
402    
403         int r = mds->angle;
404         float * d = mds->data;
405         
406         if (h > 70 && (mds->code == int('(')
407                        || mds->code == int(')')))
408                 d = parenthHigh;
409 #endif
410         
411         mt.rota(r);
412         mt.escala(w, h);
413    
414         int n = (w < h) ? w: h;
415         sqmt.rota(r);
416         sqmt.escala(n, n);
417         if (r > 0 && r < 3) y += h;   
418         if (r >= 2) x += w;   
419         do {
420                 code = int(d[i++]);
421                 switch (code) {
422                 case 0: break;
423                 case 1: 
424                 case 3:
425                 {
426                         xx = d[i++]; yy = d[i++];
427                         x2 = d[i++]; y2 = d[i++];
428                         if (code == 3) 
429                                 sqmt.transf(xx, yy, xx, yy);
430                         else
431                                 mt.transf(xx, yy, xx, yy);
432                         mt.transf(x2, y2, x2, y2);
433                         pain.line(x + int(xx), y + int(yy),
434                                   x + int(x2), y + int(y2),
435                                   LColor::mathline);
436                         break;
437                 }        
438                 case 2: 
439                 case 4:
440                 {
441                         int xp[32], yp[32];
442                         n = int(d[i++]);
443                         for (int j = 0; j < n; ++j) {
444                                 xx = d[i++]; yy = d[i++];
445 //           lyxerr << " " << xx << " " << yy << " ";
446                                 if (code == 4) 
447                                         sqmt.transf(xx, yy, xx, yy);
448                                 else
449                                         mt.transf(xx, yy, xx, yy);
450                                 xp[j] = x + int(xx);
451                                 yp[j] = y + int(yy);
452                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
453                         }
454                         pain.lines(xp, yp, n, LColor::mathline);
455                 }
456                 }
457         } while (code);
458 }
459
460
461 void
462 MathDelimInset::draw(Painter & pain, int x, int y)
463
464         xo = x;  yo = y; 
465         MathParInset::draw(pain, x + dw + 2, y - dh); 
466         
467         if (left == '.') {
468                 pain.line(x + 4, yo - ascent,
469                           x + 4, yo + descent,
470                           LColor::mathcursor, Painter::line_onoffdash);
471         } else
472                 mathed_draw_deco(pain, x, y - ascent, dw, Height(), left);
473         x += Width() - dw - 2;
474         if (right == '.') {
475                 pain.line(x + 4, yo - ascent,
476                           x + 4, yo + descent,
477                           LColor::mathcursor, Painter::line_onoffdash);
478         } else
479                 mathed_draw_deco(pain, x, y-ascent, dw, Height(), right);
480 }
481
482
483 void
484 MathDelimInset::Metrics()
485 {
486    MathParInset::Metrics();
487    int d;
488    
489    mathed_char_height(LM_TC_CONST, size, 'I', d, dh);
490    dh /= 2;
491    ascent += 2 + dh;
492    descent += 2 - dh;
493    dw = Height()/5;
494    if (dw > 15) dw = 15;
495    if (dw<6) dw = 6;
496    width += 2*dw+4;
497 }
498
499
500 void
501 MathDecorationInset::draw(Painter & pain, int x, int y)
502
503    MathParInset::draw(pain, x + (width - dw) / 2, y);
504    mathed_draw_deco(pain, x, y + dy, width, dh, deco);
505 }
506
507
508 void
509 MathDecorationInset::Metrics()
510 {
511    int h = 2*mathed_char_height(LM_TC_VAR, size, 'I', ascent, descent);  
512    MathParInset::Metrics();
513    int w = Width()+4;
514    if (w<16) w = 16;
515    dh = w/5;
516    if (dh>h) dh = h;
517
518    if (upper) {
519       ascent += dh+2;
520       dy = -ascent;
521    } else {
522       dy = descent+2;
523       descent += dh+4;
524    }
525    dw = width;
526    width = w;
527 }
528
529
530 void
531 MathAccentInset::draw(Painter & pain, int x, int y)
532 {
533     int dw = width - 2;
534
535     if (inset) {
536         inset->draw(pain, x, y);
537     } else {
538         drawStr(pain, fn, size, x, y, &c, 1);
539     }
540     x += (code == LM_not) ? (width-dw) / 2 : 2;
541     mathed_draw_deco(pain, x, y - dy, dw, dh, code);
542 }
543
544
545 void
546 MathAccentInset::Metrics()
547 {
548     
549     if (inset) {
550         inset->Metrics();
551         ascent = inset->Ascent();
552         descent = inset->Descent();
553         width = inset->Width();
554         dh = ascent;
555     } else {
556         mathed_char_height(fn, size, c, ascent, descent);
557         width = mathed_char_width(fn, size, c);
558         dh = (width-2)/2; 
559     }
560     if (code == LM_not) {
561         ascent += dh;
562         descent += dh;
563         dh = Height();
564     } else 
565       ascent += dh+2;
566             
567     dy = ascent;
568 //    if (MathIsBinary(fn))
569 //      width += 2*mathed_char_width(fn, size, ' ');    
570 }
571
572
573 void
574 MathDotsInset::draw(Painter & pain, int x, int y)
575 {
576    mathed_draw_deco(pain, x + 2, y - dh, width - 2, ascent, code);
577    if (code == LM_vdots || code == LM_ddots) ++x; 
578    if (code != LM_vdots) --y;
579    mathed_draw_deco(pain, x + 2, y - dh, width - 2, ascent, code);
580 }
581
582
583 void
584 MathDotsInset::Metrics()
585 {
586    mathed_char_height(LM_TC_VAR, size, 'M', ascent, descent);
587    width = mathed_char_width(LM_TC_VAR, size, 'M');   
588    switch (code) {
589     case LM_ldots: dh = 0; break;
590     case LM_cdots: dh = ascent/2; break;
591     case LM_vdots: width /= 2;
592     case LM_ddots: dh = ascent; break;
593    }
594
595