]> git.lyx.org Git - lyx.git/blob - src/mathed/math_iter.C
More fixes to insettabular/text (and some missing features added).
[lyx.git] / src / mathed / math_iter.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, 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_iter.h"
22 #endif
23
24 #include "math_iter.h"
25 #include "math_inset.h"
26 #include "symbol_def.h"
27 #include "support/lstrings.h"
28 #include "debug.h"
29
30 using std::endl;
31
32 const int SizeInset = sizeof(char*) + 2;
33
34 extern int mathed_char_width(short type, int style, byte c);
35 extern int mathed_string_width(short type, int style, byte const * s, int ls);
36 extern int mathed_char_height(short, int, byte, int &, int &);
37
38 // the builtin memcpy() is broken in egcs and gcc 2.95.x on alpha
39 // stations. We provide a hand-made version instead. 
40 static inline
41 void my_memcpy( void * ps_in, void const * pt_in, size_t n )
42 {
43     char * ps = static_cast<char *>(ps_in);
44     char const * pt = static_cast<char const *>(pt_in);
45     /*
46     for (size_t i = n; i--;)
47         *ps++ = *pt++;
48         */
49     while (n--) *ps++ = *pt++;
50 }
51
52
53 void MathedIter::Reset()
54 {
55     if (array->last > 0 && MathIsFont(array->bf[0])) {
56         fcode = array->bf[0];
57         pos = 1;
58     } else {
59         fcode = -1;
60         pos = 0;
61     }
62     col = row = 0;
63 }
64
65
66 byte MathedIter::GetChar() const
67 {
68     if (IsFont()) { 
69         fcode = array->bf[pos];
70         ++pos;
71     }
72     return array->bf[pos];
73 }
74
75
76 byte * MathedIter::GetString(int & len) const
77 {
78     if (IsFont()) { 
79         fcode = array->bf[++pos];
80         ++pos;
81     }
82     byte * s = &array->bf[pos];
83     len = pos;
84     while (array->bf[pos] >= ' ' && pos < array->last) ++pos;
85     len = pos - len;
86    
87    return s;
88 }
89
90 string const MathedIter::GetString() const
91 {
92         int ls = 0;
93         byte const * s = GetString(ls);
94         return string(reinterpret_cast<char const *>(s), ls);
95 }
96
97         
98 MathedInset * MathedIter::GetInset() const
99 {
100    if (IsInset()) {
101       MathedInset * p;
102       my_memcpy(&p, &array->bf[pos + 1], sizeof(p));
103       return p;
104    } else {
105            lyxerr << "Math Error: This is not an inset["
106                   << array->bf[pos] << "]" << endl;
107      return 0;
108    }
109 }
110
111 // An active math inset MUST be derived from MathParInset because it 
112 // must have at least one paragraph to edit
113 MathParInset * MathedIter::GetActiveInset() const
114 {
115     if (IsActive()) {
116         return static_cast<MathParInset*>(GetInset());
117     } 
118     
119     lyxerr << "Math Error: This is not an active inset" << endl;
120     return 0;
121 }
122
123 bool MathedIter::Next()
124 {  
125     if (!OK()) return false;
126    
127     if (array->bf[pos] < ' ') {
128         fcode = -1;     
129         if (IsTab()) ++col;
130         if (IsCR())  {
131             col = 0;
132             ++row;
133         }
134     }
135         
136     if (IsInset())
137       pos += sizeof(char*) + 2;
138     else 
139       ++pos;
140     
141     if (IsFont()) {
142         fcode = array->bf[pos++];
143     }
144
145     return true;   
146 }
147
148
149 bool MathedIter::goNextCode(MathedTextCodes code)
150 {  
151     while (Next()) {
152         if (array->bf[pos] == code) 
153           return true;
154     }
155     
156     return false;
157 }
158
159
160 void MathedIter::goPosAbs(int p)
161 {  
162     Reset();
163     while (pos < p && Next());
164 }
165
166
167 void MathedIter::goPosRel(int dp)
168 {  
169     int const posx = pos + dp;
170  
171     // is posx a valid position?
172     if (dp < 0)
173       Reset();
174     while (pos < posx && Next());
175 }
176
177
178 void MathedIter::Insert(byte c, MathedTextCodes t)
179 {
180     if (c < ' ') return;
181     
182     if (t == LM_TC_TAB && col >= ncols - 1) 
183       return;
184     
185     // Never more than one space // array->bf[pos-1] gives error from purify:
186     //       Reading 1 byte from 0x47b857 in the heap.
187     //  Address 0x47b857 is 1 byte before start of malloc'd block at 0x47b858 of 16 bytes.
188     if (c == ' ' && (array->bf[pos] == ' ' || array->bf[pos - 1] == ' ')) 
189       return;
190         
191     if (IsFont() && array->bf[pos] == t) {
192         fcode = t;
193         ++pos;
194     } else
195       if (t != fcode && pos > 0 && MathIsFont(array->bf[pos - 1])) {
196           --pos;
197           int k = pos - 1;
198           for (; k >= 0 && array->bf[k] >= ' '; --k);
199           fcode = (k >= 0 && MathIsFont(array->bf[k])) ? array->bf[k] : -1;
200       }
201     short const f = (array->bf[pos] < ' ') ? 0 : fcode;
202     int shift = (t == fcode) ? 1 : ((f) ? 3 : 2);
203     
204     if (t == LM_TC_TAB || t == LM_TC_CR) {
205         --shift;
206         c = t;
207         if (t == LM_TC_CR) {
208             ++row;
209             col = 0;
210         } else
211           ++col;
212     }
213  
214     if (pos < array->last)
215         array->Move(pos, shift);
216     else {
217         if (array->last+shift >= array->maxsize) {
218             array->Resize(array->last+shift);
219         }
220         array->last += shift;
221         array->bf[array->last] = '\0';
222     }
223     if (t != fcode) {
224         if (f)  
225           array->bf[pos + shift - 1] = fcode;
226         if (c >= ' ') {
227             array->bf[pos++] = t;
228             fcode = t;
229         } else {
230             fcode = 0;
231         }
232     }      
233     array->bf[pos++] = c;
234 }
235
236
237 // Prepare to insert a non-char object
238 void MathedIter::split(int shift)
239 {
240    if (pos < array->last) {
241       bool fg = false;
242       if (array->bf[pos] >= ' ') {
243          if (pos> 0 && MathIsFont(array->bf[pos - 1]))
244            --pos;
245          else { 
246             fg = true; 
247             ++shift;
248          }
249       }      
250       array->Move(pos, shift);
251       if (fg) array->bf[pos + shift - 1] = fcode;
252    } else {
253       if (array->last + shift >= array->maxsize) {
254           array->Resize(array->last + shift);
255       }
256       array->last += shift;
257    }
258    array->bf[array->last] = '\0';
259 }
260
261
262 // I assume that both pos and pos2 are legal positions
263 void MathedIter::join(int pos2)
264 {   
265     if (!OK() || pos2<= pos)
266       return;    
267
268     short f = fcode;
269     if (pos > 0 && array->bf[pos] >= ' ' && MathIsFont(array->bf[pos - 1]))
270       --pos;    
271             
272     if (MathIsFont(array->bf[pos2 - 1]))
273       --pos2;
274     
275     if (array->bf[pos2] >= ' ') {
276         for (int p = pos2; p > 0; --p) 
277           if (MathIsFont(array->bf[p])) {
278               f = array->bf[p];
279               break;
280           }
281         array->bf[pos++] = f;
282     }    
283
284     array->Move(pos2, pos - pos2);
285 }
286
287 void MathedIter::Insert(MathedInset * p, int type)
288 {
289     int const shift = SizeInset;
290     if (!MathIsInset(type))
291       type = LM_TC_INSET;
292     split(shift);
293     array->bf[pos] = type;
294     my_memcpy(&array->bf[pos + 1], &p, sizeof(p));
295     pos += SizeInset;
296     array->bf[pos - 1] = type;
297     array->bf[array->last] = '\0';
298     fcode = -1;
299 }
300
301
302 bool MathedIter::Delete()
303 {   
304    if (!OK())
305      return false;
306    
307    int shift = 0;
308    byte c = GetChar();
309    if (c >= ' ') { 
310       if (MathIsFont(array->bf[pos - 1]) && array->bf[pos + 1] < ' ') {
311          shift = 2;
312          pos--;
313          int i = pos - 1;
314          for (; i > 0 && !MathIsFont(array->bf[i]); --i);
315          if (i > 0 && MathIsFont(array->bf[i]))
316            fcode = array->bf[i];
317       } else
318         shift = 1;      
319    } else {
320       if (MathIsInset(array->bf[pos]))
321         shift = sizeof(char*) + 2;
322      else if (c == LM_TC_TAB || c == LM_TC_CR) {
323          ++shift;
324 //       lyxerr <<"Es un tab.";
325       } else {
326              lyxerr << "Math Warning: expected inset." << endl;
327      }
328    } 
329     
330    if (shift != 0) {
331       array->Move(pos + shift, -shift);
332       if (pos >= array->last) 
333          pos = (array->last > 0) ? array->last : 0;
334        return true;
335    } else
336      return false;
337 }
338
339
340 LyxArrayBase * MathedIter::Copy(int pos1, int pos2)
341 {
342    if (!array) {
343 //      lyxerr << "Math error: Attempting to copy a void array." << endl;
344       return 0;
345    }
346       
347 //   int posx = pos;
348    ipush(); 
349    LyxArrayBase * t = array, * a;
350     
351    if (pos1 > 0 || pos2 <= array->last) {       
352        short fc = 0;
353        if (pos1 > 0 && array->bf[pos1] > ' ') {
354            for (int p = pos1; p >= 0; --p) 
355              if (MathIsFont(array->bf[p])) {
356                  if (p != pos1 - 1)
357                    fc = array->bf[p];
358                  else
359                    --pos1;
360                  break;
361              }
362        }
363
364        if (pos2 > 0 && array->bf[pos2] >= ' '
365            && MathIsFont(array->bf[pos2 - 1])) 
366          --pos2;
367
368        int dx = pos2 - pos1;
369        a = new LyxArrayBase(dx + LyxArrayBase::ARRAY_MIN_SIZE);
370 //       lyxerr << "VA " << pos2 << " " << pos2 << " " << dx << endl;
371        my_memcpy(&a->bf[(fc) ? 1 : 0], &array->bf[pos1], dx);
372        if (fc) {
373            a->bf[0] = fc;
374            ++dx;
375        }
376        a->last = dx;
377        a->bf[dx] = '\0';
378    }  else   
379       a = new LyxArrayBase(*array);
380    SetData(a);
381    while (OK()) {
382       if (IsInset()) {
383          MathedInset * inset = GetInset();
384          inset = inset->Clone();
385          my_memcpy(&array->bf[pos + 1], &inset, sizeof(inset));
386       }
387       Next();
388    }
389 //   pos = posx;
390    array = t;
391    ipop(); 
392    return a;
393 }
394
395
396 void MathedIter::Clear()
397 {
398    if (!array) {
399            lyxerr << "Math error: Attempting to clean a void array." << endl;
400       return;
401    }   
402    Reset();  
403    while (OK()) {
404       if (IsInset()) {
405          MathedInset * inset = GetInset();
406           if (inset->GetType()!= LM_OT_MACRO_ARG)
407             delete inset;
408           Delete();
409       } else
410         Next();
411    }
412 }
413
414
415 // Check consistency of tabs and crs
416 void MathedIter::checkTabs()
417 {
418     ipush();
419     
420 //    MathedIter:Reset();
421     while (OK()) {
422         if ((IsTab() && col >= ncols - 1) || (IsCR() && !(MthIF_CR & flags))) {
423             Delete();
424             continue;
425         }
426         if (IsCR() && col < ncols - 2) {
427             Insert(' ', LM_TC_TAB);
428         }
429         MathedIter::Next();
430     }
431     if (col < ncols - 2) {
432         Insert(' ', LM_TC_TAB);
433     }
434     ipop();
435 }         
436
437
438 //  Try to adjust tabs in the expected place, as used in eqnarrays
439 //  Rules:
440 //   - If there are a relation operator, put tabs around it
441 //   - If tehre are not a relation operator, put everything in the
442 //     3rd column.
443 void MathedIter::adjustTabs()
444 {
445
446 }         
447
448
449 void MathedXIter::Clean(int pos2)
450 {
451     if (!array) {
452             lyxerr << "Math error: Attempting to clean a void array." << endl;
453         return;
454     } 
455     
456     int pos1 = pos;
457     
458     if (pos2 < pos1) {
459         GoBegin();
460         while (pos < pos2 && OK()) {
461                 Next();
462         }
463         pos2 = pos1;
464         pos1 = pos;
465     }
466
467     ipush();
468     while (OK() && pos < pos2) {
469         if (IsInset()) {
470             MathedInset * inset = GetInset();
471             Next();
472             if (inset->GetType()!= LM_OT_MACRO_ARG)
473               delete inset;
474             continue;
475         } 
476         if (IsCR()) {
477             if (crow) {
478                 MathedRowSt * r = crow->getNext();
479                 if (r) {
480                     crow->setNext(r->getNext());
481                     delete r;
482                 }          
483             }
484         }
485         Next();
486     }    
487     ipop();
488     
489     if (pos2 <= array->Last()) {
490         pos = pos1;
491         join(pos2);
492         checkTabs();
493     } 
494 }
495
496
497 void MathedXIter::Merge(LyxArrayBase * a0)
498 {
499     if (!a0) {
500             lyxerr[Debug::MATHED]
501                     << "Math error: Attempting to merge a void array." << endl;
502
503         return;
504     }
505     // All insets must be clonned
506     MathedIter it(a0);
507     LyxArrayBase * a = it.Copy();
508     
509     // make room for the data 
510     split(a->Last());
511     array->MergeF(a, pos, a->Last());
512
513     int pos1 = pos;
514     int pos2 = pos + a->Last();
515     // int pos3 = 0;
516
517     goPosAbs(pos1);
518     
519     // Complete rows
520     while (pos < pos2 && OK()) {
521         if (IsCR()) {
522             if (p && p->Permit(LMPF_ALLOW_CR)) {
523                 MathedRowSt * r = new MathedRowSt(ncols+1);
524                 if (crow) {
525                     r->setNext(crow->getNext());
526                     crow->setNext(r);
527                   } else {
528                       r->setNext(0);
529                   }
530                 crow = r;
531             } else {
532                 Delete();
533                 --pos2;
534             }
535         }
536         Next();    
537     }
538     pos2 = getPos();
539     goPosAbs(pos1);
540     checkTabs();
541     goPosAbs(pos2);
542     
543     delete a;
544 }
545
546
547 //-----------  XIter
548
549
550 MathedXIter::MathedXIter(MathParInset * pp)
551         : p(pp) 
552
553     x = y = 0;
554     sx = sw = 0;   
555     limits = false;
556     s_type = 0;  
557     if (p) 
558       SetData(p);
559     else {
560         crow = 0;
561         size = 0;
562     }
563 }
564
565 void MathedXIter::SetData(MathParInset * pp)
566 {
567     p = pp;
568     x = y = 0;
569     array = p->GetData();
570     ncols = p->GetColumns();
571     crow = p->getRowSt();
572     if (p->Permit(LMPF_ALLOW_CR))
573       flags |= MthIF_CR;
574     if (p->Permit(LMPF_ALLOW_TAB))
575       flags |= MthIF_Tabs;
576     
577     if (crow) {
578         x = crow->getTab(0);
579         y = crow->getBaseline();
580     } 
581     if (!array) {
582             array = new LyxArrayBase; // this leaks
583         p->SetData(array);
584     }
585     size = p->GetStyle();
586     Reset();
587 }
588
589
590 byte * MathedXIter::GetString(int & ls) const
591 {  
592    static byte s[255];
593    byte const * sxs =  MathedIter::GetString(ls);
594    if (ls > 0) {
595        strncpy(reinterpret_cast<char*>(s),
596                reinterpret_cast<char const *>(sxs), ls);
597        x += mathed_string_width(fcode, size, s, ls);
598        return &s[0];
599    }        
600     return 0;
601 }
602
603
604 string const MathedXIter::GetString() const
605 {
606         int ls;
607         byte const * s = GetString(ls);
608         return string(reinterpret_cast<char const *>(s), ls);
609 }
610
611
612 bool MathedXIter::Next()
613 {  
614 //    lyxerr << "Ne[" << pos << "]";
615    if (!OK()) return false;
616    int w = 0;
617 //   lyxerr << "xt ";
618    if (IsInset()) {
619       MathedInset * px = GetInset();
620       w = px->Width();
621       if (px->GetType() == LM_OT_SCRIPT) {
622          if (w > sw) sw = w;
623          w = 0;
624       } else
625         sx = (px->GetLimits()) ? w : 0;
626    } else {  
627       byte c = GetChar();
628       if (c >= ' ') {
629 //        lyxerr << "WD[" << fcode << " " << size << " " << c << endl;
630           w = mathed_char_width(fcode, size, c);
631       } else
632       if (c == LM_TC_TAB && p) {
633 //       w = p->GetTab(col + 1);
634           w = (crow) ? crow->getTab(col + 1) : 0;
635          //lyxerr << "WW[" << w << "]";
636       } else
637       if (c == LM_TC_CR && p) {
638           x = 0;
639           if (crow && crow->getNext()) {
640               crow = crow->getNext();
641               y = crow->getBaseline();
642               w = crow->getTab(0);
643           }
644 //        lyxerr << "WW[" << col " " << row << "|" << w << "]";
645       } else 
646               lyxerr << "No hubo w[" << c << "]!";
647    }
648    if (MathedIter::Next()) {
649 //       lyxerr <<"LNX " << pos << endl;
650 //       if (sw>0 && GetChar()!= LM_TC_UP && GetChar()!= LM_TC_DOWN) {
651 //         w = (sx>sw) ? 0: sw-sx;
652       if ((sw > 0 || sx > 0)
653           && GetChar() != LM_TC_UP && GetChar() != LM_TC_DOWN) {
654           if (sw > 0)
655             w = (sx > sw) ? 0 : sw - sx;
656           sx = sw = 0;
657       }
658       x += w;
659       return true;
660    } else
661      return false;
662 }
663
664
665 void MathedXIter::GoBegin()
666 {
667    Reset();
668    x = y = 0;   
669    sw = sx = 0;
670    if (p) {
671        crow = p->getRowSt();
672        if (crow) {
673            x = crow->getTab(0);
674            y = crow->getBaseline();
675        }
676    }
677 }
678
679 void MathedXIter::GoLast()
680 {
681    while (Next());
682 }
683
684
685 void MathedXIter::Adjust()
686 {
687    int posx = pos;
688    GoBegin();
689    while (posx > pos && OK()) Next();  
690 }
691
692
693 bool MathedXIter::Prev()
694 {  
695     if (pos == 0 || (pos == 1 && GetChar() >= ' '))
696       return false;
697     
698     int pos2 = pos; // pos1
699     GoBegin();
700     do {
701         ipush();
702         Next();
703     } while (pos<pos2);
704     ipop();
705     
706     return (!IsCR());
707 }
708
709
710 bool MathedXIter::goNextColumn()
711 {  
712     int rowp = row;
713     int colp = col;
714     while (Next() && col == colp);
715     
716     return (col != colp + 1 || rowp != row);
717 }
718
719
720 bool MathedXIter::Up()
721 {
722     if (row == 0) return false;
723     int xp = x;
724     int rowp = row;
725     int colp= col;
726     GoBegin();
727     while (row < rowp - 1) Next();
728     while (x < xp && OK() && !IsCR()) {
729         ipush();
730         Next();
731     }
732     if (col > colp) // || (stck.col == colp && stck.x<= xp && x>xp))
733       ipop();
734     
735     return true;
736 }
737
738
739 bool MathedXIter::Down()
740 {
741     int xp = x;
742     int colp= col;
743     // int rowp = row
744     
745     bool res = (IsCR()) ? true : goNextCode(LM_TC_CR);
746     if (res) {
747         Next();
748         ipush();
749         while (x < xp && OK()) {
750             ipush();
751             Next();
752         }
753         if (col > colp || (stck.col == colp && stck.x <= xp && x > xp))
754           ipop();
755         return true;
756     }
757     return false;
758 }
759
760
761 void MathedXIter::addRow()
762 {
763     if (!crow) {
764         lyxerr[Debug::MATHED] << "MathErr: Attempt to insert new"
765                 " line in a subparagraph. " << this << endl;
766
767         return;
768     }
769     // Create new item for the structure    
770     MathedRowSt * r = new MathedRowSt(ncols + 1);
771     if (crow) {
772         r->setNext(crow->getNext());
773         crow->setNext(r);
774     } else {
775         crow = r;
776         r->setNext(0);
777     }    
778     // Fill missed tabs in current row
779     while (col < ncols - 1) 
780       Insert('T', LM_TC_TAB); 
781     //newline
782     Insert('K', LM_TC_CR);
783     
784     ipush();
785     if (!IsCR())
786       goNextCode(LM_TC_CR);
787     
788     // Fill missed tabs in new row
789     while (col < ncols - 1) 
790       Insert('T', LM_TC_TAB);
791     ipop();
792 }
793
794
795 void MathedXIter::delRow()
796 {
797     if (!crow) {
798             lyxerr[Debug::MATHED] << "MathErr: Attempt to delete a line in a subparagraph." << endl;
799         return;
800     }
801     bool line_empty = true;
802     ipush();
803 //    while (Next()) {
804     do {
805         if (IsCR()) {
806             break;
807         } else if (!IsTab()) {
808             line_empty = false;
809         }
810     } while (Next());
811     int const p1 = getPos();
812     ipop();
813     
814     if (line_empty) {
815         
816         MathedRowSt * r = crow->getNext();
817         if (r) {
818             crow->setNext(r->getNext());
819             delete r;
820         }
821         join(p1);
822         Delete();
823     } else
824       Clean(p1);
825     
826     checkTabs();    
827 }
828
829 void MathedXIter::ipush()
830
831     MathedIter::ipush();
832     stck.x = x;
833     stck.y = y;
834 }
835
836
837 void MathedXIter::ipop()
838
839     MathedIter::ipop();
840     x = stck.x;
841     y = stck.y;
842     if (p) {
843         crow = p->getRowSt();
844         if (crow)
845           for (int i = 0; i < row; ++i)
846             crow = crow->getNext();
847     }
848 }
849
850
851 void MathedXIter::fitCoord(int /*xx*/, int yy)
852 {
853     int xo = 0;
854     int yo = 0;
855     
856     GoBegin();
857     if (p)
858       p->GetXY(xo, yo);
859     // first fit vertically
860     while (crow && OK()) {
861         if (yy >= yo + y - crow->ascent() && yy <= yo + y + crow->descent()) 
862           break;
863         goNextCode(LM_TC_CR);
864         Next();
865     }
866     // now horizontally
867 //    while (x<xx && Next());
868 }
869
870
871 void MathedXIter::setTab(int tx, int tab)
872 {
873         if (crow && tab <= ncols) {
874                 crow->setTab(tab, tx);
875         } else
876                 lyxerr << "MathErr: No tabs allowed here" << endl;
877 }
878
879
880 void MathedXIter::subMetrics(int a, int d)
881 {
882     if (!crow) {
883             lyxerr[Debug::MATHED]
884                     << "MathErr: Attempt to submetric a subparagraph." << endl;
885         return;
886     }
887     crow->ascent(a);
888     crow->descent(d);
889 }
890
891
892 // This function is not recursive, as MathPar::Metrics is
893 void MathedXIter::IMetrics(int pos2, int & width, int & ascent, int & descent)
894 {  
895     byte cx;
896     int x1; // ls;
897     int asc = 0;
898     int des = 0;
899     bool limit = false;
900   
901     descent = ascent = width = 0;
902     if (!array) return;
903     if (array->empty()) return;
904 //    if  (pos2 > array->last) return;
905     x1 = x; 
906     while (pos < pos2) {
907         cx = GetChar();
908         if (cx >= ' ') {
909             mathed_char_height(FCode(), size, cx, asc, des);
910             if (asc > ascent) ascent = asc;
911             if (des > descent) descent = des;
912             limit = false;
913         } else
914         if (MathIsInset(cx)) {
915             MathedInset * pp = GetInset();
916             if (cx == LM_TC_UP) {
917                 if (!asc && p) {
918                     int xx;
919                     int yy;
920                     p->GetXY(xx, yy);
921                     static_cast<MathParInset*>(pp)->GetXY(xx, asc);
922                     asc = yy - asc;
923                 }
924                 asc += ((limits) ? pp->Height() + 4 : pp->Ascent());
925             } else if (cx == LM_TC_DOWN) {
926                   if (!des && p) {
927                       int xx;
928                       int yy;
929                       p->GetXY(xx, yy);
930                       static_cast<MathParInset*>(pp)->GetXY(xx, des);
931                       if (des - pp->Height() < yy && !asc)
932                         asc = yy - (des - pp->Height());
933                       des -= yy;
934                   }
935                   des += (limit ? pp->Height()+4: pp->Height()-pp->Ascent()/2);
936             } else {
937                 asc = pp->Ascent();
938                 des = pp->Descent();
939             }
940             if (asc > ascent) ascent = asc;
941             if (des > descent) descent = des;
942             if (cx != LM_TC_UP && cx != LM_TC_DOWN)
943               limit = pp->GetLimits();
944         } else if (cx == LM_TC_TAB) {
945             limit = false;                   
946         } else {
947             lyxerr[Debug::MATHED]
948                 << "Mathed Sel-Error: Unrecognized code["
949                 << cx << ']' << endl;
950             break;
951         }
952         if (pos < pos2)  Next();
953    }
954     width = x - x1;
955 }
956
957
958 bool MathedXIter::setNumbered(bool numb)
959 {  
960     if (crow) {
961         crow->setNumbered(numb);
962         return true;
963     }
964     
965     return false;
966 }
967
968
969 bool MathedXIter::setLabel(string const & label)
970 {  
971     if (crow) {
972         crow->setLabel(label);
973         return true;
974     }
975     
976     return false;
977 }
978
979
980 MathedRowSt * MathedXIter::adjustVerticalSt()
981 {
982     GoBegin();
983     if (!crow) {
984 //      lyxerr << " CRW" << ncols << " ";
985             crow = new MathedRowSt(ncols + 1); // this leaks
986     }
987 //    lyxerr<< " CRW[" << crow << "] ";
988     MathedRowSt * mrow = crow;
989     while (OK()) {
990         if (IsCR()) {
991             if (col >= ncols) ncols = col + 1; 
992             MathedRowSt * r = new MathedRowSt(ncols + 1); // this leaks
993 //          r->next = crow->next;
994             crow->setNext(r);
995             crow = r;
996 //          lyxerr << " CX[" << crow << "]";
997         }   
998         Next(); 
999     }
1000     return mrow;
1001 }