]> git.lyx.org Git - features.git/blob - src/mathed/math_draw.C
new painter,workarea and lcolor. Read the diff/sources and ChangeLog...
[features.git] / src / mathed / math_draw.C
1 /*
2  *  File:        math_draw.C
3  *  Purpose:     Interaction and drawing for mathed
4  *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx> 
5  *  Created:     January 1996
6  *  Description: Math drawing and interaction for a WYSIWYG math editor.
7  *
8  *  Dependencies: Xlib, XForms
9  *
10  *  Copyright: (c) 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 #include FORMS_H_LOCATION
20 #include "math_cursor.h"
21 #include "math_parser.h"
22 #include "debug.h"
23 #include "lyxfont.h"
24 #include "Painter.h"
25
26 #ifdef USE_PAINTER
27 extern LyXFont mathed_get_font(short type, int size);
28 #else
29 extern void mathed_set_font(short type, int style);
30 #endif
31 extern int mathed_char_width(short type, int style, byte c);
32 extern int mathed_string_width(short type, int style, byte const* s, int ls);
33 extern int mathed_string_height(short, int, byte const*, int, int&, int&);
34 extern int mathed_char_height(short, int, byte, int&, int&);
35    
36 GC canvasGC= 0, mathGC= 0, mathLineGC= 0, latexGC= 0, cursorGC= 0, mathFrameGC= 0;
37
38
39 #ifndef USE_PAINTER
40 unsigned long MathedInset::pm;
41 #endif
42
43 #ifdef USE_PAINTER
44 void
45 MathSpaceInset::draw(Painter & pain, int x, int y)
46
47
48 // XPoint p[4] = {{++x, y-3}, {x, y}, {x+width-2, y}, {x+width-2, y-3}};
49
50 // Sadly, HP-UX CC can't handle that kind of initialization.
51
52    int xp[4];
53    int yp[4];
54    
55    xp[0] = ++x;            yp[0] = y - 3;
56    xp[1] = x;              yp[1] = y;
57    xp[2] = x + width - 2;  yp[2] = y;
58    xp[3] = x + width - 2;  yp[3] = y - 3;
59
60    pain.lines(xp, yp, 4, (space) ? LColor::latex : LColor::math);
61 }
62 #else
63 void
64 MathSpaceInset::Draw(int x, int y)
65
66
67 // XPoint p[4] = {{++x, y-3}, {x, y}, {x+width-2, y}, {x+width-2, y-3}};
68
69 // Sadly, HP-UX CC can't handle that kind of initialization.
70
71    XPoint p[4];
72    p[0].x = ++x;        p[0].y = y-3;
73    p[1].x = x;          p[1].y = y;
74    p[2].x = x+width-2;  p[2].y = y;
75    p[3].x = x+width-2;  p[3].y = y-3;
76
77    XDrawLines(fl_display, pm,(space) ? latexGC: mathGC, p, 4, CoordModeOrigin);
78    XFlush(fl_display);
79 }
80 #endif
81
82
83 #ifdef USE_PAINTER
84 void 
85 MathParInset::draw(Painter & pain, int x, int y)
86 {
87    byte cx, cxp = 0;
88    int xp = 0, ls;
89    int asc = df_asc, des = 0;
90    bool limits = false;
91     
92    xo = x;  yo = y; 
93    if (!array || array->empty()) {
94        if (array) {
95            MathedXIter data(this);
96            data.GetPos(x, y);
97        }
98        pain.rectangle(x, y - df_asc, df_width, df_asc, LColor::mathline);
99       return;
100    }  
101    MathedXIter data(this);
102    data.GoBegin();
103    while (data.OK()) {
104       data.GetPos(x, y);
105       cx = data.GetChar();
106       if (cx >= ' ') {
107          byte * s = data.GetString(ls);
108           drawStr(pain, data.FCode(), size, x, y, s, ls);
109           mathed_char_height(LM_TC_CONST, size, 'y', asc, des);
110           limits = false;
111       } else {
112           if (cx == 0) break;
113          if (MathIsInset(cx)) {
114             int yy = y;
115             MathedInset * p = data.GetInset();
116             if (cx == LM_TC_UP) {
117                if (limits) {
118                   x -= (xp>p->Width()) ? p->Width()+(xp-p->Width())/2: xp;  
119                   yy -= (asc + p->Descent()+4);
120                } else
121                   yy -= (p->Descent()>asc) ? p->Descent()+4: asc;
122             } else
123             if (cx == LM_TC_DOWN) {
124                if (limits) {
125                   x -= (xp>p->Width()) ? p->Width()+(xp-p->Width())/2: xp;
126                   yy += des + p->Ascent() + 2;
127                } else
128                  yy += des + p->Ascent()/2;
129             } else {
130                asc = p->Ascent();
131                des = p->Descent();
132             }
133             p->draw(pain, x, yy);
134             if (cx!= LM_TC_UP && cx!= LM_TC_DOWN) {
135                limits = p->GetLimits();
136                if (limits) xp = p->Width();
137             }
138             data.Next();
139          } else 
140            if (cx == LM_TC_TAB) {
141                if ((cxp == cx || cxp == LM_TC_CR || data.IsFirst())) { // && objtype == L
142                        pain.rectangle(x, y - df_asc, df_width, df_asc,
143                                       LColor::mathline);
144                }
145               data.Next();
146               limits = false;
147            } else
148             if (cx == LM_TC_CR) {
149                 if (cxp == LM_TC_TAB || cxp == LM_TC_CR || data.IsFirst()) { //  && objtype == LM_OT_MATRIX) {
150                         pain.rectangle(x, y - df_asc, df_width, df_asc,
151                                        LColor::mathline);
152                 }
153                 data.Next();
154                 limits = false;
155             }
156          else {  
157                  lyxerr << "GMathed Error: Unrecognized code[" << cx
158                         << "]" << endl;
159             break;
160          }
161       }
162       cxp = cx;
163    }
164    if (cxp == LM_TC_TAB || cxp == LM_TC_CR) { // && objtype == LM_OT_MATRIX) {
165       data.GetPos(x, y);
166       pain.rectangle(x, y - df_asc, df_width, df_asc, LColor::mathline);
167    }
168 }
169 #else
170 void 
171 MathParInset::Draw(int x, int y)
172 {
173    byte cx, cxp= 0;
174    int xp= 0, ls;
175    int asc= df_asc, des= 0;
176    bool limits = false;
177     
178    xo = x;  yo = y; 
179    if (!array || array->empty()) {
180       mathed_set_font(LM_TC_VAR, 1);
181        if (array) {
182            MathedXIter data(this);
183            data.GetPos(x, y);
184        }
185       XDrawRectangle(fl_display, pm, mathLineGC, x, y-df_asc, df_width, df_asc);
186       XFlush(fl_display);
187       return;
188    }  
189    MathedXIter data(this);
190    data.GoBegin();
191    while (data.OK()) {
192       data.GetPos(x, y);
193       cx = data.GetChar();
194       if (cx >= ' ') {
195          byte *s = data.GetString(ls);
196           drawStr(data.FCode(), size, x, y, s, ls);
197           mathed_char_height(LM_TC_CONST, size, 'y', asc, des);
198           limits = false;
199       } else {
200           if (cx == 0) break;
201          if (MathIsInset(cx)) {
202             int yy = y;
203             MathedInset *p = data.GetInset();
204             if (cx == LM_TC_UP) {
205                if (limits) {
206                   x -= (xp>p->Width()) ? p->Width()+(xp-p->Width())/2: xp;  
207                   yy -= (asc + p->Descent()+4);
208                } else
209                   yy -= (p->Descent()>asc) ? p->Descent()+4: asc;
210             } else
211             if (cx == LM_TC_DOWN) {
212                if (limits) {
213                   x -= (xp>p->Width()) ? p->Width()+(xp-p->Width())/2: xp;
214                   yy += des + p->Ascent() + 2;
215                } else
216                  yy += des + p->Ascent()/2;
217             } else {
218                asc = p->Ascent();
219                des = p->Descent();
220             }
221             p->Draw(x, yy);
222             if (cx!= LM_TC_UP && cx!= LM_TC_DOWN) {
223                limits = p->GetLimits();
224                if (limits) xp = p->Width();
225             }
226             data.Next();
227          } else 
228            if (cx == LM_TC_TAB) {
229                if ((cxp == cx || cxp == LM_TC_CR || data.IsFirst())) { // && objtype == L
230                    XDrawRectangle(fl_display, pm, mathLineGC,
231                                   x, y-df_asc, df_width, df_asc);
232                }
233            
234               XFlush(fl_display);
235               data.Next();
236               limits = false;
237            } else
238             if (cx == LM_TC_CR) {
239                 if (cxp == LM_TC_TAB || cxp == LM_TC_CR || data.IsFirst()) { //  && objtype == LM_OT_MATRIX) {
240                   XDrawRectangle(fl_display, pm, mathLineGC, x, y-df_asc, df_width, df_asc);
241                 }
242                 data.Next();
243                 limits = false;
244             }
245          else {  
246                  lyxerr << "GMathed Error: Unrecognized code[" << cx
247                         << "]" << endl;
248             break;
249          }
250       }
251       cxp = cx;
252    }
253    if (cxp == LM_TC_TAB || cxp == LM_TC_CR) { // && objtype == LM_OT_MATRIX) {
254       data.GetPos(x, y);
255       XDrawRectangle(fl_display, pm, mathLineGC, x, y-df_asc, df_width, df_asc);
256       XFlush(fl_display);
257    }
258 }
259 #endif
260
261
262 void 
263 MathParInset::Metrics()
264 {
265     byte cx, cxp= 0, *s;
266     int ls;
267     int asc= df_asc, des= 0;
268     int tb = 0, tab= 0;
269
270     bool limits = false;
271     
272     ascent = df_asc;//mathed_char_height(LM_TC_VAR, size, 'I', asc, des); 
273     width = df_width;
274     descent = 0;
275     if (!array) return;
276     if (array->empty()) return;
277     
278     ascent = 0;
279     MathedXIter data(this);
280     data.GoBegin();
281     while (data.OK()) {
282         cx = data.GetChar();      
283         if (cx >= ' ') {
284             s = data.GetString(ls);
285             mathed_string_height(data.FCode(), size, s, ls, asc, des);
286             if (asc > ascent) ascent = asc;
287             if (des > descent) descent = des;
288             limits = false;
289             mathed_char_height(LM_TC_CONST, size, 'y', asc, des);
290         } else
291           if (MathIsInset(cx)) {
292               MathedInset *p = data.GetInset();
293               p->SetStyle(size);   
294               p->Metrics();
295               if (cx == LM_TC_UP) {
296                   asc += (limits) ? p->Height()+4: p->Ascent() + 
297                     ((p->Descent()>asc) ? p->Descent()-asc+4: 0);
298               } else
299                 if (cx == LM_TC_DOWN) {
300                     des += ((limits) ? p->Height()+4: p->Height()-p->Ascent()/2);
301                 } else {
302                     asc = p->Ascent();
303                     des = p->Descent();
304                 }
305               if (asc > ascent) ascent = asc;
306               if (des > descent) descent = des;
307               if (cx!= LM_TC_UP && cx!= LM_TC_DOWN)
308                 limits = p->GetLimits();
309               data.Next();
310           } else 
311           if (cx == LM_TC_TAB) {
312               int x, y;
313               data.GetIncPos(x, y);
314               if (data.IsFirst() || cxp == LM_TC_TAB || cxp == LM_TC_CR) {
315                   if (ascent<df_asc) ascent = df_asc;
316                   tb = x;
317               }
318               data.setTab(x-tb, tab);
319               tb = x;
320               ++tab;
321               limits = false;                   
322               data.Next();
323           } else
324           if (cx == LM_TC_CR) {
325               if (tb>0) {
326                   int x, y;
327                   data.GetIncPos(x, y);
328                   if (data.IsFirst() || cxp == LM_TC_TAB || cxp == LM_TC_CR) {
329                       if (ascent<df_asc) ascent = df_asc;
330                       tb = x;
331                   } 
332                   data.setTab(x-tb, tab);
333               } else //if (GetColumns() == 1) 
334                     {
335                   int x, y;
336                   data.GetIncPos(x, y);
337                   data.setTab(x, tab);
338                   if (ascent<df_asc) ascent = df_asc;
339               } 
340               tb= tab= 0;
341               data.subMetrics(ascent, descent);
342               ascent = df_asc;   
343               descent = 0;
344               data.Next();
345           }      
346         else {
347                 lyxerr << "Mathed Error: Unrecognized code[" << cx
348                        << "]" << endl;
349             break;
350         }       
351         cxp = cx;
352     }
353     data.GetIncPos(width, ls);
354     
355     // No matter how simple is a matrix, it is NOT a subparagraph
356     if (isMatrix()) {
357         if (cxp == LM_TC_TAB) {
358             if (ascent<df_asc) ascent = df_asc;
359             data.setTab(0, tab);
360         } else {
361           data.setTab(width-tb, tab);
362         }
363     }
364           
365     data.subMetrics(ascent, descent);
366 }
367
368
369 #ifdef USE_PAINTER
370 void
371 MathSqrtInset::draw(Painter & pain, int x, int y)
372
373    MathParInset::draw(pain, x + hmax + 2, y); 
374    int h = ascent;
375    int d = descent;
376    int h2 = Height() / 2;
377    int w2 = (Height() > 4 * hmax) ? hmax : hmax / 2; 
378    int xp[4], yp[4];
379    xp[0] = x + hmax + wbody; yp[0] = y - h;
380    xp[1] = x + hmax;         yp[1] = y - h;
381    xp[2] = x + w2;           yp[2] = y + d;
382    xp[3] = x;                yp[3] = y + d - h2;
383    pain.lines(xp, yp, 4, LColor::mathline);
384 }
385 #else
386 void
387 MathSqrtInset::Draw(int x, int y)
388
389    MathParInset::Draw(x+hmax+2, y); 
390    int h = ascent;
391    int d = descent;
392    int h2 = Height() / 2;
393    int w2 = (Height() > 4 * hmax) ? hmax : hmax / 2; 
394    XPoint p[4];
395    p[0].x = x + hmax + wbody; p[0].y = y - h;
396    p[1].x = x + hmax;    p[1].y = y - h;
397    p[2].x = x + w2;      p[2].y = y + d;
398    p[3].x = x;         p[3].y = y + d - h2;
399    XDrawLines(fl_display, pm, mathLineGC, p, 4, CoordModeOrigin);
400    XFlush(fl_display);
401 }
402 #endif
403
404
405 void
406 MathSqrtInset::Metrics()
407 {
408    MathParInset::Metrics();
409    ascent += 4;
410    descent += 2;
411    int a, b;
412    hmax = mathed_char_height(LM_TC_VAR, size, 'I', a, b);
413    if (hmax < 10) hmax = 10;
414    wbody = width + 4;
415    width += hmax + 4;
416 }
417
418
419 #ifdef USE_PAINTER
420 void
421 MathFracInset::draw(Painter & pain, int x, int y)
422
423     short idxp = idx;
424     short sizex = size;
425     
426     idx = 0;
427     if (size == LM_ST_DISPLAY) ++size;
428     MathParInset::draw(pain, x + (width - w0) / 2, y - des0);
429     den->draw(pain, x + (width - w1) / 2, y + den->Ascent() + 2 - dh);
430     size = sizex;
431     if (objtype == LM_OT_FRAC)
432             pain.line(x + 2, y - dh, x + width - 4, y - dh, LColor::mathline);
433     idx = idxp;
434 }
435 #else
436 void
437 MathFracInset::Draw(int x, int y)
438
439     short idxp = idx;
440     short sizex = size;
441     
442     idx = 0;
443     if (size == LM_ST_DISPLAY) ++size;
444     MathParInset::Draw(x + (width - w0) / 2, y - des0);
445     den->Draw(x + (width - w1) / 2, y + den->Ascent() + 2 - dh);
446     size = sizex;
447     if (objtype == LM_OT_FRAC)
448       XDrawLine(fl_display, pm, mathLineGC,
449                 x + 2, y - dh, x + width - 4, y - dh);
450     XFlush(fl_display);
451     idx = idxp;
452 }
453 #endif
454
455
456 void
457 MathFracInset::Metrics()
458 {
459     if (!dh) {
460         int a, b;
461         dh = mathed_char_height(LM_TC_CONST, size, 'I', a, b)/2;
462     }
463     short idxp = idx;
464     short sizex = size; 
465     idx = 0;
466     if (size == LM_ST_DISPLAY) ++size; 
467     MathParInset::Metrics();
468     size = sizex;
469     w0 = width;
470     int as = Height() + 2 + dh;
471     des0 = Descent() + 2 + dh;
472     den->Metrics();  
473     w1 = den->Width();   
474     width = ((w0 > w1) ? w0: w1) + 12;
475     ascent = as; 
476     descent = den->Height()+ 2 - dh;
477     idx = idxp;
478 }
479
480
481 #ifdef USE_PAINTER
482 void
483 MathBigopInset::draw(Painter & pain, int x, int y)
484 {
485    int ls;
486    char c;
487    char const *s;
488    short t;
489    
490    if (sym < 256 || sym == LM_oint) {
491       ls = 1;
492       c = (sym == LM_oint) ? LM_int : sym;
493       s = &c;
494       t = LM_TC_BSYM;
495    } else {
496       s = name;
497       ls = strlen(name);
498       t = LM_TC_TEXTRM;
499    }
500    if (sym == LM_oint) {
501            pain.arc(x, y - 5 * width / 4, width, width, 0, 360*64,
502                     LColor::mathline);
503            ++x;
504    }
505    pain.text(x, y, s, ls, mathed_get_font(t, size));
506 }
507 #else
508 void
509 MathBigopInset::Draw(int x, int y)
510 {
511    int ls;
512    char c;
513    char const *s;
514    short t;
515    
516    if (sym<256 || sym == LM_oint) {
517       ls = 1;
518       c = (sym == LM_oint) ? LM_int: sym;
519       s = &c;
520       t = LM_TC_BSYM;
521    } else {
522       s = name;
523       ls = strlen(name);
524       t = LM_TC_TEXTRM;
525    }
526    mathed_set_font(t, size);
527    if (sym == LM_oint) {
528       XDrawArc(fl_display, pm, mathLineGC, x, y-5*width/4, width, width, 0, 23040);
529       XFlush(fl_display);
530       ++x;
531    }
532    XDrawString(fl_display, pm, mathGC, x, y, s, ls);
533    XFlush(fl_display);
534 }
535 #endif
536
537
538 #ifdef USE_PAINTER
539 void
540 MathBigopInset::Metrics()
541 {   
542         int ls;
543         char c;
544         char const *s;
545         short t;
546         
547         if (sym < 256 || sym == LM_oint) {
548                 ls = 1;
549                 c = (sym == LM_oint) ? LM_int: sym;
550                 s = &c;
551                 t = LM_TC_BSYM;
552         } else {
553                 s = name;
554                 ls = strlen(name);
555                 t = LM_TC_TEXTRM;
556         }
557         mathed_string_height(t, size,
558                              reinterpret_cast<const unsigned char*>(s),
559                              ls, ascent, descent);
560         width = mathed_string_width(t, size,
561                                     reinterpret_cast<const unsigned char*>(s),
562                                     ls);
563         if (sym == LM_oint) width += 2;
564 }
565 #else
566 void
567 MathBigopInset::Metrics()
568 {   
569    int ls;
570    char c;
571    char const *s;
572    short t;
573
574    if (sym<256 || sym == LM_oint) {
575       ls = 1;
576       c = (sym == LM_oint) ? LM_int: sym;
577       s = &c;
578       t = LM_TC_BSYM;
579    } else {
580       s = name;
581       ls = strlen(name);
582       t = LM_TC_TEXTRM;
583    }
584    mathed_set_font(t, size);
585    mathed_string_height(t, size, reinterpret_cast<const unsigned char*>(s), ls, ascent, descent);
586    width = mathed_string_width(t, size, reinterpret_cast<const unsigned char*>(s), ls);
587    if (sym == LM_oint) width += 2;
588 }
589 #endif
590