]> git.lyx.org Git - lyx.git/blob - src/mathed/math_inset.C
several small and larger changes, read the 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 void MathMatrixInset::Draw(int x, int baseline)
420 {
421     MathParInset::Draw(x, baseline);
422 }                
423
424
425 void MathMatrixInset::Metrics()
426 {
427     int i, hl, h= 0;
428     MathedRowSt * cprow= 0, * cxrow;
429
430     if (!row) {
431 //      lyxerr << " MIDA ";
432         MathedXIter it(this);
433         row = it.adjustVerticalSt();
434     } 
435     
436     // Clean the arrays      
437     cxrow = row;
438     while (cxrow) {   
439         for (i = 0; i <= nc; ++i) cxrow->w[i] = 0;
440         cxrow = cxrow->next;
441     }
442     
443     // Basic metrics
444     MathParInset::Metrics();
445             
446     if (nc <= 1 && !row->next) {
447         row->asc = ascent;
448         row->desc = descent;
449     }
450     
451     // Vertical positions of each row
452     cxrow = row;     
453     while (cxrow) {
454         for (i = 0; i < nc; ++i) {
455             if (cxrow == row || ws[i]<cxrow->w[i]) ws[i]= cxrow->w[i];
456             if (cxrow->next == 0 && ws[i] == 0) ws[i] = df_width;
457         }
458         
459         cxrow->y = (cxrow == row) ? cxrow->asc:
460                    cxrow->asc + cprow->desc + MATH_ROWSEP + cprow->y;
461         h += cxrow->asc + cxrow->desc + MATH_ROWSEP;    
462         cprow = cxrow;
463         cxrow = cxrow->next;
464     }
465     
466     hl = Descent();
467     h -= MATH_ROWSEP;
468
469     //  Compute vertical align
470     switch (v_align) {
471      case 't': ascent = row->y; break;
472      case 'b': ascent = h - hl; break;
473      default:  ascent = (row->next) ? h / 2: h - hl; break;
474     }
475     descent = h - ascent + 2;
476     
477    
478    // Adjust local tabs
479     cxrow = row;
480     width = MATH_COLSEP;
481     while (cxrow) {   
482         int rg = MATH_COLSEP, ww, lf = 0, * w = cxrow->w;
483         for (i = 0; i < nc; ++i) {
484             bool isvoid = false;
485             if (w[i] <= 0) {
486                 w[i] = df_width;
487                 isvoid = true;
488             }
489             switch (h_align[i]) {
490              case 'l': lf = 0; break;
491              case 'c': lf = (ws[i] - w[i])/2; 
492                        break;
493              case 'r': lf = ws[i] - w[i]; break;
494             }
495             ww = (isvoid) ? lf: lf + w[i];
496             w[i] = lf + rg;
497             rg = ws[i] - ww + MATH_COLSEP;
498             if (cxrow == row) width += ws[i] + MATH_COLSEP;
499         }
500         cxrow->y -= ascent;
501         cxrow = cxrow->next;
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(char 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(char 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 }