]> git.lyx.org Git - lyx.git/blob - src/mathed/math_delim.C
A bit of cxx warniong hunting; update to rpm spec file.
[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 static
335 int search_deco(int code)
336 {
337         math_deco_struct * res =
338                 lower_bound(math_deco_table,
339                             math_deco_table + math_deco_table_size,
340                             code, math_deco_compare());
341         if (res != math_deco_table + math_deco_table_size &&
342             res->code == code)
343                 return res - math_deco_table;
344         return -1;
345 }
346
347
348 void mathed_draw_deco(Painter & pain, int x, int y, int w, int h, int code)
349 {
350         Matriz mt, sqmt;
351         float xx, yy, x2, y2;
352         int i = 0;
353    
354         int j = search_deco(code);   
355         if (j < 0) return;
356    
357         int r = math_deco_table[j].angle;
358         float * d = math_deco_table[j].data;
359         
360         if (h > 70 && (math_deco_table[j].code == int('(')
361                        || math_deco_table[j].code == int(')')))
362                 d = parenthHigh;
363         
364         mt.rota(r);
365         mt.escala(w, h);
366    
367         int n = (w < h) ? w: h;
368         sqmt.rota(r);
369         sqmt.escala(n, n);
370         if (r > 0 && r < 3) y += h;   
371         if (r >= 2) x += w;   
372         do {
373                 code = int(d[i++]);
374                 switch (code) {
375                 case 0: break;
376                 case 1: 
377                 case 3:
378                 {
379                         xx = d[i++]; yy = d[i++];
380                         x2 = d[i++]; y2 = d[i++];
381                         if (code == 3) 
382                                 sqmt.transf(xx, yy, xx, yy);
383                         else
384                                 mt.transf(xx, yy, xx, yy);
385                         mt.transf(x2, y2, x2, y2);
386                         pain.line(x + int(xx), y + int(yy),
387                                   x + int(x2), y + int(y2),
388                                   LColor::mathline);
389                         break;
390                 }        
391                 case 2: 
392                 case 4:
393                 {
394                         int xp[32], yp[32];
395                         n = int(d[i++]);
396                         for (j = 0; j < n; ++j) {
397                                 xx = d[i++]; yy = d[i++];
398 //           lyxerr << " " << xx << " " << yy << " ";
399                                 if (code == 4) 
400                                         sqmt.transf(xx, yy, xx, yy);
401                                 else
402                                         mt.transf(xx, yy, xx, yy);
403                                 xp[j] = x + int(xx);
404                                 yp[j] = y + int(yy);
405                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
406                         }
407                         pain.lines(xp, yp, n, LColor::mathline);
408                 }
409                 }
410         } while (code);
411 }
412
413
414 void
415 MathDelimInset::draw(Painter & pain, int x, int y)
416
417         xo = x;  yo = y; 
418         MathParInset::draw(pain, x + dw + 2, y - dh); 
419         
420         if (left == '.') {
421                 pain.line(x + 4, yo - ascent,
422                           x + 4, yo + descent,
423                           LColor::mathcursor, Painter::line_onoffdash);
424         } else
425                 mathed_draw_deco(pain, x, y - ascent, dw, Height(), left);
426         x += Width() - dw - 2;
427         if (right == '.') {
428                 pain.line(x + 4, yo - ascent,
429                           x + 4, yo + descent,
430                           LColor::mathcursor, Painter::line_onoffdash);
431         } else
432                 mathed_draw_deco(pain, x, y-ascent, dw, Height(), right);
433 }
434
435
436 void
437 MathDelimInset::Metrics()
438 {
439    MathParInset::Metrics();
440    int d;
441    
442    mathed_char_height(LM_TC_CONST, size, 'I', d, dh);
443    dh /= 2;
444    ascent += 2 + dh;
445    descent += 2 - dh;
446    dw = Height()/5;
447    if (dw > 15) dw = 15;
448    if (dw<6) dw = 6;
449    width += 2*dw+4;
450 }
451
452
453 void
454 MathDecorationInset::draw(Painter & pain, int x, int y)
455
456    MathParInset::draw(pain, x + (width - dw) / 2, y);
457    mathed_draw_deco(pain, x, y + dy, width, dh, deco);
458 }
459
460
461 void
462 MathDecorationInset::Metrics()
463 {
464    int h = 2*mathed_char_height(LM_TC_VAR, size, 'I', ascent, descent);  
465    MathParInset::Metrics();
466    int w = Width()+4;
467    if (w<16) w = 16;
468    dh = w/5;
469    if (dh>h) dh = h;
470
471    if (upper) {
472       ascent += dh+2;
473       dy = -ascent;
474    } else {
475       dy = descent+2;
476       descent += dh+4;
477    }
478    dw = width;
479    width = w;
480 }
481
482
483 void
484 MathAccentInset::draw(Painter & pain, int x, int y)
485 {
486     int dw = width - 2;
487
488     if (inset) {
489         inset->draw(pain, x, y);
490     } else {
491         drawStr(pain, fn, size, x, y, &c, 1);
492     }
493     x += (code == LM_not) ? (width-dw) / 2 : 2;
494     mathed_draw_deco(pain, x, y - dy, dw, dh, code);
495 }
496
497
498 void
499 MathAccentInset::Metrics()
500 {
501     
502     if (inset) {
503         inset->Metrics();
504         ascent = inset->Ascent();
505         descent = inset->Descent();
506         width = inset->Width();
507         dh = ascent;
508     } else {
509         mathed_char_height(fn, size, c, ascent, descent);
510         width = mathed_char_width(fn, size, c);
511         dh = (width-2)/2; 
512     }
513     if (code == LM_not) {
514         ascent += dh;
515         descent += dh;
516         dh = Height();
517     } else 
518       ascent += dh+2;
519             
520     dy = ascent;
521 //    if (MathIsBinary(fn))
522 //      width += 2*mathed_char_width(fn, size, ' ');    
523 }
524
525
526 void
527 MathDotsInset::draw(Painter & pain, int x, int y)
528 {
529    mathed_draw_deco(pain, x + 2, y - dh, width - 2, ascent, code);
530    if (code == LM_vdots || code == LM_ddots) ++x; 
531    if (code != LM_vdots) --y;
532    mathed_draw_deco(pain, x + 2, y - dh, width - 2, ascent, code);
533 }
534
535
536 void
537 MathDotsInset::Metrics()
538 {
539    mathed_char_height(LM_TC_VAR, size, 'M', ascent, descent);
540    width = mathed_char_width(LM_TC_VAR, size, 'M');   
541    switch (code) {
542     case LM_ldots: dh = 0; break;
543     case LM_cdots: dh = ascent/2; break;
544     case LM_vdots: width /= 2;
545     case LM_ddots: dh = ascent; break;
546    }
547
548