]> git.lyx.org Git - lyx.git/blob - src/mathed/math_inset.C
mathed14.diff
[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), nr(0), ws_(m),
291         v_align(0), h_align(nc, 'c')
292 {
293     row = 0;
294     flag = 15;
295     if (n > 0) {
296             row = new MathedRowSt(nc+1);
297         MathedXIter it(this);
298         for (int j = 1; j < n; ++j) it.addRow();
299         nr = n;
300         if (nr == 1 && nc > 1) {
301             for (int j = 0; j < nc - 1; ++j) 
302               it.Insert('T', LM_TC_TAB);
303         }
304     } else if (n < 0) {
305             row = new MathedRowSt(nc + 1);
306         nr = 1;
307     }
308 }
309
310
311 MathMatrixInset::MathMatrixInset(MathMatrixInset * mt)
312         : MathParInset(mt->GetStyle(), mt->GetName(), mt->GetType()),
313           nc(mt->nc), nr(0), ws_(mt->nc), v_align(mt->v_align), h_align(mt->h_align)
314 {
315     MathedIter it;
316     it.SetData(mt->GetData());
317     array = it.Copy();
318     if (mt->row != 0) {
319         MathedRowSt * r, * ro= 0, * mrow = mt->row;
320         //mrow = mt->row; // This must be redundant...
321         while (mrow) {
322             r = new MathedRowSt(nc + 1);
323             r->setNumbered(mrow->isNumbered());
324             //if (mrow->label) 
325               r->setLabel(mrow->getLabel());
326             if (!ro) 
327               row = r;
328             else
329               ro->setNext(r);
330             mrow = mrow->getNext();
331             ro = r;
332             ++nr;
333         } 
334     } else         
335       row = 0;
336     flag = mt->flag;
337 }
338
339
340 MathMatrixInset::~MathMatrixInset()
341 {
342     MathedRowSt * r = row;
343     while (r) {
344         MathedRowSt * q = r->getNext();
345         delete r;
346         r = q;
347     }
348 }
349
350
351 MathedInset * MathMatrixInset::Clone()
352 {
353     return new MathMatrixInset(this);
354 }
355
356
357 void MathMatrixInset::SetAlign(char vv, string const & hh)
358 {
359    v_align = vv;
360    h_align = hh.substr(0, nc); // usr just h_align = hh; perhaps
361 }
362
363
364 // Check the number of tabs and crs
365 void MathMatrixInset::SetData(MathedArray * a)
366 {
367     if (!a) return;
368     MathedIter it(a);
369     int nn = nc - 1;
370     nr = 1;
371     // count tabs per row
372     while (it.OK()) {
373         if (it.IsTab()) {
374             if (nn < 0) { 
375                 it.Delete();
376                 continue;
377             } else {
378 //            it.Next();
379                 --nn;
380             }
381         }
382         if (it.IsCR()) {
383             while (nn > 0) {
384                 it.Insert(' ', LM_TC_TAB);
385                 --nn;
386             }
387             nn = nc - 1;
388             ++nr;
389         }
390         it.Next();
391     }
392     it.Reset();
393
394     // Automatically inserts tabs around bops
395     // DISABLED because it's very easy to insert tabs 
396     array = a;
397 }
398
399
400 void MathMatrixInset::draw(Painter & pain, int x, int baseline)
401 {
402     MathParInset::draw(pain, x, baseline);
403 }
404
405
406 void MathMatrixInset::Metrics()
407 {
408     int i, hl, h = 0;
409     MathedRowSt * cprow= 0;
410
411     if (!row) {
412 //      lyxerr << " MIDA ";
413         MathedXIter it(this);
414         row = it.adjustVerticalSt();
415     } 
416     
417     // Clean the arrays      
418     MathedRowSt * cxrow = row;
419     while (cxrow) {   
420         for (i = 0; i <= nc; ++i) cxrow->setTab(i, 0);
421         cxrow = cxrow->getNext();
422     }
423     
424     // Basic metrics
425     MathParInset::Metrics();
426             
427     if (nc <= 1 && !row->getNext()) {
428         row->ascent(ascent);
429         row->descent(descent);
430     }
431     
432     // Vertical positions of each row
433     cxrow = row;     
434     while (cxrow) {
435         for (i = 0; i < nc; ++i) {
436             if (cxrow == row || ws_[i] < cxrow->getTab(i))
437                     ws_[i] = cxrow->getTab(i);
438             if (cxrow->getNext() == 0 && ws_[i] == 0) ws_[i] = df_width;
439         }
440         
441         cxrow->setBaseline((cxrow == row) ?
442                            cxrow->ascent() :
443                    cxrow->ascent() + cprow->descent()
444                            + MATH_ROWSEP + cprow->getBaseline());
445         h += cxrow->ascent() + cxrow->descent() + MATH_ROWSEP;  
446         cprow = cxrow;
447         cxrow = cxrow->getNext();
448     }
449     
450     hl = Descent();
451     h -= MATH_ROWSEP;
452
453     //  Compute vertical align
454     switch (v_align) {
455      case 't': ascent = row->getBaseline(); break;
456      case 'b': ascent = h - hl; break;
457      default:  ascent = (row->getNext()) ? h / 2: h - hl; break;
458     }
459     descent = h - ascent + 2;
460     
461     // Increase ws_[i] for 'R' columns (except the first one)
462     for (i = 1; i < nc; ++i)
463         if (h_align[i] == 'R')
464             ws_[i] += 10*df_width;
465     // Increase ws_[i] for 'C' column
466     if (h_align[0] == 'C')
467         if (ws_[0] < 7*workWidth/8)
468             ws_[0] = 7*workWidth/8;
469
470    // Adjust local tabs
471     cxrow = row;
472     width = MATH_COLSEP;
473     while (cxrow) {   
474             int rg = MATH_COLSEP, ww, lf = 0; //, * w = cxrow->w;
475         for (i = 0; i < nc; ++i) {
476             bool isvoid = false;
477             if (cxrow->getTab(i) <= 0) {
478                 cxrow->setTab(i, df_width);
479                 isvoid = true;
480             }
481             switch (h_align[i]) {
482             case 'l':
483                 lf = 0;
484                 break;
485             case 'c':
486                 lf = (ws_[i] - cxrow->getTab(i))/2; 
487                 break;
488             case 'r':
489             case 'R':
490                 lf = ws_[i] - cxrow->getTab(i);
491                 break;
492             case 'C':
493                 if (cxrow == row)
494                     lf = 0;
495                 else if (!cxrow->getNext())
496                      lf = ws_[i] - cxrow->getTab(i);
497                 else
498                     lf = (ws_[i] - cxrow->getTab(i))/2; 
499                 break;
500             }
501             ww = (isvoid) ? lf : lf + cxrow->getTab(i);
502             cxrow->setTab(i, lf + rg);
503             rg = ws_[i] - ww + MATH_COLSEP;
504             if (cxrow == row) width += ws_[i] + MATH_COLSEP;
505         }
506         cxrow->setBaseline(cxrow->getBaseline() - ascent);
507         cxrow = cxrow->getNext();
508     }
509 }
510
511
512 MathAccentInset::MathAccentInset(byte cx, MathedTextCodes f, int cd, short st)
513         : MathedInset("", LM_OT_ACCENT, st), c(cx), fn(f), code(cd)
514 {
515     inset = 0;
516 }
517
518
519 MathAccentInset::MathAccentInset(MathedInset *ins, int cd, short st)
520         : MathedInset("", LM_OT_ACCENT, st),
521           c(0), fn(LM_TC_MIN), code(cd), inset(ins) {}
522
523
524 MathAccentInset::~MathAccentInset()
525 {
526         delete inset;
527 }
528
529
530 MathedInset * MathAccentInset::Clone()
531 {   
532     MathAccentInset * p;
533     
534     if (inset) 
535       p = new MathAccentInset(inset->Clone(), code, GetStyle());
536     else
537       p = new MathAccentInset(c, fn, code, GetStyle());
538     
539     return p;
540 }
541
542
543 MathBigopInset::MathBigopInset(string const & nam, int id, short st)
544         : MathedInset(nam, LM_OT_BIGOP, st), sym(id)
545 {
546    lims = -1;
547 }
548
549
550 MathedInset * MathBigopInset::Clone()
551 {
552    return new MathBigopInset(name, sym, GetStyle());
553 }
554
555
556 MathDotsInset::MathDotsInset(string const & nam, int id, short st)
557         : MathedInset(nam, LM_OT_DOTS, st), code(id) {}
558
559
560 MathedInset * MathDotsInset::Clone()
561 {
562    return new MathDotsInset(name, code, GetStyle());
563 }