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