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