]> git.lyx.org Git - lyx.git/blob - src/mathed/math_inset.C
new painter,workarea and lcolor. Read the diff/sources and ChangeLog...
[lyx.git] / src / mathed / math_inset.C
1 /*
2  *  File:        math_inset.C
3  *  Purpose:     Implementation of insets for mathed
4  *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx> 
5  *  Created:     January 1996
6  *  Description: 
7  *
8  *  Dependencies: Xlib, XForms
9  *
10  *  Copyright: (c) 1996, 1997 Alejandro Aguilar Sierra
11  *
12  *   Version: 0.8beta.
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 #ifdef __GNUG__
21 #pragma implementation "math_inset.h"
22 #endif
23
24 #include "math_iter.h"
25 #include "math_inset.h"
26 #include "symbol_def.h"
27
28
29 inline
30 char * strnew(char const * s)
31 {
32    char * s1 = new char[strlen(s)+1];
33    return strcpy(s1, s);
34 }
35
36
37 MathedInset::MathedInset(MathedInset * inset) 
38 {
39    if (inset) {
40       name = inset->GetName();
41       objtype = inset->GetType();
42       size = inset->GetStyle();
43       width = inset->Width();
44       ascent = inset->Ascent();
45       descent = inset->Descent();
46    } else {
47       objtype = LM_OT_UNDEF;
48       size = LM_ST_TEXT;
49       width = ascent = descent = 0;
50       name = 0;
51    }
52 }
53
54
55 MathFuncInset::MathFuncInset(char const * nm, short ot, short st)
56         : MathedInset("", ot, st)
57 {
58    ln = 0;
59    lims = (GetType() == LM_OT_FUNCLIM);
60     if (GetType() == LM_OT_UNDEF) {
61         fname = strnew(nm);
62         SetName(fname);
63     } else {
64         fname = 0;
65         SetName(nm);
66     }
67 }
68
69
70 MathedInset * MathFuncInset::Clone()
71 {
72    return new MathFuncInset(name, GetType(), GetStyle());
73 }
74
75
76 MathSpaceInset::MathSpaceInset(int sp, short ot, short st)
77         : MathedInset("", ot, st), space(sp)
78 {}
79
80
81 MathedInset * MathSpaceInset::Clone()
82 {
83    return new MathSpaceInset(space, GetType(), GetStyle());
84 }
85
86
87 MathParInset::MathParInset(short st, char const * nm, short ot)
88         : MathedInset(nm, ot, st)
89 {
90     array = 0;
91     ascent = 8;
92     width = 4;
93     descent = 0;
94     flag = 1;
95     if (objtype == LM_OT_SCRIPT)
96       flag |= LMPF_SCRIPT;
97 }
98
99
100 MathParInset::MathParInset(MathParInset * p)
101         : MathedInset(p)
102 {
103     flag = p->flag;
104     p->setArgumentIdx(0);
105     MathedIter it(p->GetData());
106     SetData(it.Copy());
107 }
108
109
110 MathParInset::~MathParInset()
111 {
112    if (array) {
113       MathedIter it(array);
114       it.Clear();
115       delete array;
116    }
117 }
118
119
120 MathedInset * MathParInset::Clone()
121 {
122    return new MathParInset(this);
123 }
124
125
126 void MathParInset::SetData(LyxArrayBase * a)
127 {
128     array = a;
129    
130     // A standard paragraph shouldn't have any tabs nor CRs.
131     if (array) {
132         MathedIter it(array);
133         while (it.OK()) {
134             char c = it.GetChar();
135             if (c == LM_TC_TAB || c == LM_TC_CR) 
136               it.Delete();
137             else
138               it.Next();
139         }
140    }
141 }
142
143
144 MathSqrtInset::MathSqrtInset(short st)
145         : MathParInset(st, "sqrt", LM_OT_SQRT) {}
146
147
148 MathedInset * MathSqrtInset::Clone()
149 {   
150    MathSqrtInset * p = new MathSqrtInset(GetStyle());
151    MathedIter it(array);
152    p->SetData(it.Copy());
153    return p;
154 }
155
156
157 bool MathSqrtInset::Inside(int x, int y) 
158 {
159         return x >= xo - hmax
160                 && x <= xo + width - hmax
161                 && y <= yo + descent
162                 && y >= yo - ascent;
163 }
164
165
166 MathDelimInset::MathDelimInset(int l, int r, short st)
167         : MathParInset(st, "", LM_OT_DELIM), left(l), right(r) {}
168
169
170 MathedInset * MathDelimInset::Clone()
171 {   
172    MathDelimInset * p = new MathDelimInset(left, right, GetStyle());
173    MathedIter it(array);
174    p->SetData(it.Copy());
175    return p;
176 }
177
178
179 MathDecorationInset::MathDecorationInset(int d, short st)
180         : MathParInset(st, "", LM_OT_DECO), deco(d)
181 {
182    upper = (deco!= LM_underline && deco!= LM_underbrace);
183 }
184
185
186 MathedInset * MathDecorationInset::Clone()
187 {   
188    MathDecorationInset * p = new MathDecorationInset(deco, GetStyle());
189    MathedIter it(array);
190    p->SetData(it.Copy());
191    return p;
192 }
193
194
195 MathFracInset::MathFracInset(short ot)
196         : MathParInset(LM_ST_TEXT, "frac", ot)
197 {
198         
199     den = new MathParInset(LM_ST_TEXT); // this leaks
200     dh = 0;
201     idx = 0;
202     if (objtype == LM_OT_STACKREL) {
203         flag |= LMPF_SCRIPT;
204         SetName("stackrel");
205     }
206 }
207
208
209 MathFracInset::~MathFracInset()
210 {
211     delete den;
212 }
213
214
215 MathedInset * MathFracInset::Clone()
216 {   
217     MathFracInset * p = new MathFracInset(GetType());
218     MathedIter itn(array);
219     MathedIter itd(den->GetData());
220     p->SetData(itn.Copy(), itd.Copy());
221     p->idx = idx;
222     p->dh = dh;
223    return p;
224 }
225
226
227 bool MathFracInset::setArgumentIdx(int i)
228 {
229    if (i == 0 || i == 1) {
230        idx = i;
231        return true;
232    } else 
233       return false;
234 }
235
236
237 void MathFracInset::SetStyle(short st)
238 {
239     MathParInset::SetStyle(st);
240     dh = 0;
241     den->SetStyle((size == LM_ST_DISPLAY) ?
242                   static_cast<short>(LM_ST_TEXT)
243                   : size);
244 }
245
246
247 void MathFracInset::SetData(LyxArrayBase * n, LyxArrayBase * d)
248 {
249    den->SetData(d);
250    MathParInset::SetData(n);
251 }
252
253
254 void MathFracInset::SetData(LyxArrayBase * d)
255 {
256    if (idx == 0)
257      MathParInset::SetData(d);
258    else {
259       den->SetData(d);
260    }
261 }
262
263
264 void MathFracInset::GetXY(int & x, int & y) const
265 {  
266    if (idx == 0)
267      MathParInset::GetXY(x, y);
268    else
269      den->GetXY(x, y);
270 }
271
272
273 LyxArrayBase * MathFracInset::GetData()
274 {
275    if (idx == 0)
276      return array;
277    else
278      return den->GetData();
279 }
280
281
282 bool MathFracInset::Inside(int x, int y) 
283 {
284     int xx = xo - (width - w0) / 2;
285     
286     return x >= xx && x <= xx + width && y <= yo + descent && y >= yo - ascent;
287 }
288
289
290 void MathFracInset::SetFocus(int /*x*/, int y)
291 {  
292 //    lyxerr << "y " << y << " " << yo << " " << den->yo << " ";
293     idx = (y > yo) ? 1: 0;
294 }
295
296
297 MathMatrixInset::MathMatrixInset(int m, int n, short st)
298         : MathParInset(st, "array", LM_OT_MATRIX), nc(m)
299 {
300     ws = new int[nc]; 
301     v_align = 0;
302     h_align = new char[nc + 1];
303     for (int i = 0; i < nc; ++i) h_align[i] = 'c'; 
304     h_align[nc] = '\0';
305     nr = 0;
306     row = 0;
307     flag = 15;
308     if (n > 0) {
309             row = new MathedRowSt(nc+1);
310         MathedXIter it(this);
311         for (int j = 1; j < n; ++j) it.addRow();
312         nr = n;
313         if (nr == 1 && nc > 1) {
314             for (int j = 0; j < nc - 1; ++j) 
315               it.Insert('T', LM_TC_TAB);
316         }
317     } else if (n < 0) {
318             row = new MathedRowSt(nc + 1);
319         nr = 1;
320     }
321 }
322
323
324 MathMatrixInset::MathMatrixInset(MathMatrixInset * mt)
325         : MathParInset(mt->GetStyle(), mt->GetName(), mt->GetType())
326 {
327         nr = 0;
328     nc = mt->nc;
329     ws = new int[nc];
330     h_align = new char[nc + 1];
331     strcpy(h_align, mt->GetAlign(&v_align));
332     MathedIter it;
333     it.SetData(mt->GetData());
334     array = it.Copy();
335     if (mt->row != 0) {
336         MathedRowSt * r, * ro= 0, * mrow = mt->row;
337         //mrow = mt->row; // This must be redundant...
338         while (mrow) {
339             r = new MathedRowSt(nc + 1);
340             r->numbered = mrow->numbered;
341             if (mrow->label) 
342               r->label = strnew(mrow->label);
343             if (!ro) 
344               row = r;
345             else
346               ro->next = r;
347             mrow = mrow->next;
348             ro = r;
349             ++nr;
350         } 
351     } else         
352       row = 0;
353     flag = mt->flag;
354 }
355
356
357 MathMatrixInset::~MathMatrixInset()
358 {
359     delete[] ws;
360     
361     MathedRowSt * r = row;
362     while (r) {
363         MathedRowSt * q = r->next;
364         delete r;
365         r = q;
366     }
367 }
368
369
370 MathedInset * MathMatrixInset::Clone()
371 {
372     return new MathMatrixInset(this);
373 }
374
375
376 void MathMatrixInset::SetAlign(char vv, char const * hh)
377 {
378    v_align = vv;
379    strncpy(h_align, hh, nc);
380 }
381
382
383 // Check the number of tabs and crs
384 void MathMatrixInset::SetData(LyxArrayBase * a)
385 {
386     if (!a) return;
387     MathedIter it(a);
388     int nn = nc - 1;
389     nr = 1;
390     // count tabs per row
391     while (it.OK()) {
392         if (it.IsTab()) {
393             if (nn < 0) { 
394                 it.Delete();
395                 continue;
396             } else {
397 //            it.Next();
398                 --nn;
399             }
400         }
401         if (it.IsCR()) {
402             while (nn > 0) {
403                 it.Insert(' ', LM_TC_TAB);
404                 --nn;
405             }
406             nn = nc - 1;
407             ++nr;
408         }
409         it.Next();
410     }
411     it.Reset();
412
413     // Automatically inserts tabs around bops
414     // DISABLED because it's very easy to insert tabs 
415     array = a;
416 }
417
418
419 #ifdef USE_PAINTER
420 void MathMatrixInset::draw(Painter & pain, int x, int baseline)
421 {
422     MathParInset::draw(pain, x, baseline);
423 }
424 #else
425 void MathMatrixInset::Draw(int x, int baseline)
426 {
427     MathParInset::Draw(x, baseline);
428 }
429 #endif
430
431
432 void MathMatrixInset::Metrics()
433 {
434     int i, hl, h= 0;
435     MathedRowSt * cprow= 0, * cxrow;
436
437     if (!row) {
438 //      lyxerr << " MIDA ";
439         MathedXIter it(this);
440         row = it.adjustVerticalSt();
441     } 
442     
443     // Clean the arrays      
444     cxrow = row;
445     while (cxrow) {   
446         for (i = 0; i <= nc; ++i) cxrow->w[i] = 0;
447         cxrow = cxrow->next;
448     }
449     
450     // Basic metrics
451     MathParInset::Metrics();
452             
453     if (nc <= 1 && !row->next) {
454         row->asc = ascent;
455         row->desc = descent;
456     }
457     
458     // Vertical positions of each row
459     cxrow = row;     
460     while (cxrow) {
461         for (i = 0; i < nc; ++i) {
462             if (cxrow == row || ws[i]<cxrow->w[i]) ws[i]= cxrow->w[i];
463             if (cxrow->next == 0 && ws[i] == 0) ws[i] = df_width;
464         }
465         
466         cxrow->y = (cxrow == row) ? cxrow->asc:
467                    cxrow->asc + cprow->desc + MATH_ROWSEP + cprow->y;
468         h += cxrow->asc + cxrow->desc + MATH_ROWSEP;    
469         cprow = cxrow;
470         cxrow = cxrow->next;
471     }
472     
473     hl = Descent();
474     h -= MATH_ROWSEP;
475
476     //  Compute vertical align
477     switch (v_align) {
478      case 't': ascent = row->y; break;
479      case 'b': ascent = h - hl; break;
480      default:  ascent = (row->next) ? h / 2: h - hl; break;
481     }
482     descent = h - ascent + 2;
483     
484    
485    // Adjust local tabs
486     cxrow = row;
487     width = MATH_COLSEP;
488     while (cxrow) {   
489         int rg = MATH_COLSEP, ww, lf = 0, * w = cxrow->w;
490         for (i = 0; i < nc; ++i) {
491             bool isvoid = false;
492             if (w[i] <= 0) {
493                 w[i] = df_width;
494                 isvoid = true;
495             }
496             switch (h_align[i]) {
497              case 'l': lf = 0; break;
498              case 'c': lf = (ws[i] - w[i])/2; 
499                        break;
500              case 'r': lf = ws[i] - w[i]; break;
501             }
502             ww = (isvoid) ? lf: lf + w[i];
503             w[i] = lf + rg;
504             rg = ws[i] - ww + MATH_COLSEP;
505             if (cxrow == row) width += ws[i] + MATH_COLSEP;
506         }
507         cxrow->y -= ascent;
508         cxrow = cxrow->next;
509     }
510 }
511
512
513 MathAccentInset::MathAccentInset(byte cx, MathedTextCodes f, int cd, short st)
514         : MathedInset("", LM_OT_ACCENT, st), c(cx), fn(f), code(cd)
515 {
516     inset = 0;
517 }
518
519
520 MathAccentInset::MathAccentInset(MathedInset *ins, int cd, short st)
521         : MathedInset("", LM_OT_ACCENT, st),
522           c(0), fn(LM_TC_MIN), code(cd), inset(ins) {}
523
524
525 MathAccentInset::~MathAccentInset()
526 {
527         delete inset;
528 }
529
530
531 MathedInset * MathAccentInset::Clone()
532 {   
533     MathAccentInset * p;
534     
535     if (inset) 
536       p = new MathAccentInset(inset->Clone(), code, GetStyle());
537     else
538       p = new MathAccentInset(c, fn, code, GetStyle());
539     
540     return p;
541 }
542
543
544 MathBigopInset::MathBigopInset(char const* nam, int id, short st)
545         : MathedInset(nam, LM_OT_BIGOP, st), sym(id)
546 {
547    lims = -1;
548 }
549
550
551 MathedInset * MathBigopInset::Clone()
552 {
553    return new MathBigopInset(name, sym, GetStyle());
554 }
555
556
557 MathDotsInset::MathDotsInset(char const * nam, int id, short st)
558         : MathedInset(nam, LM_OT_DOTS, st), code(id) {}
559
560
561 MathedInset * MathDotsInset::Clone()
562 {
563    return new MathDotsInset(name, code, GetStyle());
564 }