]> git.lyx.org Git - features.git/blob - src/mathed/math_iter.C
cf72b48bd59654bb9aa7af92643649996346abc8
[features.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, const void * 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 * s = GetString(ls);
94         return string(reinterpret_cast<char *>(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 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;
198           for (k= pos-1; k>= 0 && array->bf[k]>= ' '; k--);
199           fcode = (k >= 0 && MathIsFont(array->bf[k])) ? array->bf[k]: -1;
200       }
201     short 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 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          int i;
312          shift = 2;
313          pos--;
314          for (i= pos-1; 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 
323       if (c == LM_TC_TAB || c == LM_TC_CR) {
324          shift++;
325 //       lyxerr <<"Es un tab.";
326       }
327      else {
328              lyxerr << "Math Warning: expected inset." << endl;
329      }
330    } 
331     
332    if (shift!= 0) {
333       array->Move(pos+shift, -shift);
334       if (pos>= array->last) 
335          pos = (array->last>0) ? array->last: 0;
336        return true;
337    } else
338      return false;
339 }
340
341
342 LyxArrayBase *MathedIter::Copy(int pos1, int pos2)
343 {
344    if (!array) {
345 //      lyxerr << "Math error: Attempting to copy a void array." << endl;
346       return 0;
347    }
348       
349 //   int posx = pos;
350    ipush(); 
351    LyxArrayBase *t= array, *a;
352     
353    if (pos1>0 || pos2<= array->last) {       
354        short fc= 0;
355        if (pos1>0 && array->bf[pos1]>' ') {
356            for (int p= pos1; p>= 0; p--) 
357              if (MathIsFont(array->bf[p])) {
358                  if (p!= pos1-1)
359                    fc = array->bf[p];
360                  else
361                    pos1--;
362                  break;
363              }
364        }
365
366        if (pos2>0 && array->bf[pos2]>= ' ' && MathIsFont(array->bf[pos2-1])) 
367          pos2--;
368
369        int dx = pos2 - pos1;
370        a = new LyxArrayBase(dx+LyxArrayBase::ARRAY_MIN_SIZE);
371 //       lyxerr << "VA " << pos2 << " " << pos2 << " " << dx << endl;
372        my_memcpy(&a->bf[(fc) ? 1: 0], &array->bf[pos1], dx);
373        if (fc) {
374            a->bf[0] = fc;
375            dx++;
376        }
377        a->last = dx;
378        a->bf[dx] = '\0';
379    }  else   
380       a = new LyxArrayBase(*array);
381    SetData(a);
382    while (OK()) {
383       if (IsInset()) {
384          MathedInset* inset = GetInset();
385          inset = inset->Clone();
386          my_memcpy(&array->bf[pos+1], &inset, sizeof(inset));
387       }
388       Next();
389    }
390 //   pos = posx;
391    array = t;
392    ipop(); 
393    return a;
394 }
395
396
397 void MathedIter::Clear()
398 {
399    if (!array) {
400            lyxerr << "Math error: Attempting to clean a void array." << endl;
401       return;
402    }   
403    Reset();  
404    while (OK()) {
405       if (IsInset()) {
406          MathedInset* inset = GetInset();
407           if (inset->GetType()!= LM_OT_MACRO_ARG)
408             delete inset;
409           Delete();
410       } else
411         Next();
412    }
413 }
414
415
416 // Check consistency of tabs and crs
417 void MathedIter::checkTabs()
418 {
419     ipush();
420     
421 //    MathedIter:Reset();
422     while (OK()) {
423         if ((IsTab() && col>= ncols-1) || (IsCR() && !(MthIF_CR&flags))) {
424             Delete();
425             continue;
426         }
427         if (IsCR() && col<ncols-2) {
428             Insert(' ', LM_TC_TAB);
429         }
430         MathedIter::Next();
431     }
432     if (col<ncols-2) {
433         Insert(' ', LM_TC_TAB);
434     }
435     ipop();
436 }         
437
438
439 //  Try to adjust tabs in the expected place, as used in eqnarrays
440 //  Rules:
441 //   - If there are a relation operator, put tabs around it
442 //   - If tehre are not a relation operator, put everything in the
443 //     3rd column.
444 void MathedIter::adjustTabs()
445 {
446
447 }         
448
449
450 void MathedXIter::Clean(int pos2)
451 {
452     if (!array) {
453             lyxerr << "Math error: Attempting to clean a void array." << endl;
454         return;
455     } 
456     
457     int pos1 = pos;
458     
459     if (pos2<pos1) {  
460         GoBegin();
461         while (pos<pos2 && OK()) { 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->next;
479                 if (r) {
480                     crow->next = r->next;
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 rom for the data 
510     split(a->Last());
511     array->MergeF(a, pos, a->Last());
512
513     int pos1= pos, pos2 = pos + a->Last(); // pos3= 0;
514
515     goPosAbs(pos1);
516     
517     // Complete rows
518     while (pos<pos2 && OK()) {
519         if (IsCR()) {
520             if (p && p->Permit(LMPF_ALLOW_CR)) {
521                 MathedRowSt *r = new MathedRowSt(ncols+1);
522                 if (crow) {
523                     r->next = crow->next;
524                     crow->next = r;
525                   } else {
526                       r->next = 0;
527                   }
528                 crow = r;
529             } else {
530                 Delete();
531                 pos2--;
532             }
533         }
534         Next();    
535     }
536     pos2 = getPos();
537     goPosAbs(pos1);
538     checkTabs();
539     goPosAbs(pos2);
540     
541     delete a;
542 }
543
544
545 //-----------  XIter
546
547
548 MathedXIter::MathedXIter(MathParInset * pp)
549         : p(pp) 
550
551     x = y = 0;
552     sx = sw = 0;   
553     limits = false;
554     s_type = 0;  
555     if (p) 
556       SetData(p);
557     else {
558         crow = 0;
559         size = 0;
560     }
561 }
562
563 void MathedXIter::SetData(MathParInset * pp)
564 {
565     p = pp;
566     x = y = 0;
567     array = p->GetData();
568     ncols = p->GetColumns();
569     crow = p->getRowSt();
570     if (p->Permit(LMPF_ALLOW_CR))
571       flags |= MthIF_CR;
572     if (p->Permit(LMPF_ALLOW_TAB))
573       flags |= MthIF_Tabs;
574     
575     if (crow) {
576         x = crow->getTab(0);
577         y = crow->getBaseline();
578     } 
579     if (!array) {
580             array = new LyxArrayBase; // this leaks
581         p->SetData(array);
582     }
583     size = p->GetStyle();
584     Reset();
585 }
586
587
588 byte * MathedXIter::GetString(int & ls) const
589 {  
590    static byte s[255];
591    byte const * sxs =  MathedIter::GetString(ls);
592    if (ls > 0) {
593        strncpy(reinterpret_cast<char*>(s),
594                reinterpret_cast<const char*>(sxs), ls);
595        x += mathed_string_width(fcode, size, s, ls);
596        return &s[0];
597    }        
598     return 0;
599 }
600
601
602 string const MathedXIter::GetString() const
603 {
604         int ls;
605         byte * s = GetString(ls);
606         return string(reinterpret_cast<char*>(s), ls);
607 }
608
609
610 bool MathedXIter::Next()
611 {  
612 //    lyxerr << "Ne[" << pos << "]";
613    if (!OK()) return false;
614    int w = 0;
615 //   lyxerr << "xt ";
616    if (IsInset()) {
617       MathedInset * px = GetInset();
618       w = px->Width();
619       if (px->GetType() == LM_OT_SCRIPT) {
620          if (w > sw) sw = w;
621          w = 0;
622       } else
623         sx = (px->GetLimits()) ? w : 0;
624    } else {  
625       byte c = GetChar();
626       if (c >= ' ') {
627 //        lyxerr << "WD[" << fcode << " " << size << " " << c << endl;
628           w = mathed_char_width(fcode, size, c);
629       } else
630       if (c == LM_TC_TAB && p) {
631 //       w = p->GetTab(col+1);
632           w = (crow) ? crow->getTab(col + 1) : 0;
633          //lyxerr << "WW[" << w << "]";
634       } else
635       if (c == LM_TC_CR && p) {
636           x = 0;
637           if (crow && crow->next) {
638               crow = crow->next;
639               y = crow->getBaseline();
640               w = crow->getTab(0);
641           }
642 //        lyxerr << "WW[" << col " " << row << "|" << w << "]";
643       } else 
644               lyxerr << "No hubo w[" << c << "]!";
645    }
646    if (MathedIter::Next()) {
647 //       lyxerr <<"LNX " << pos << endl;
648 //       if (sw>0 && GetChar()!= LM_TC_UP && GetChar()!= LM_TC_DOWN) {
649 //         w = (sx>sw) ? 0: sw-sx;
650       if ((sw > 0 || sx > 0)
651           && GetChar() != LM_TC_UP && GetChar() != LM_TC_DOWN) {
652           if (sw > 0)
653             w = (sx > sw) ? 0 : sw - sx;
654           sx = sw = 0;
655       }
656       x += w;
657       return true;
658    } else
659      return false;
660 }
661
662
663 void MathedXIter::GoBegin()
664 {
665    Reset();
666    x = y = 0;   
667    sw = sx = 0;
668    if (p) {
669        crow = p->getRowSt();
670        if (crow) {
671            x = crow->getTab(0);
672            y = crow->getBaseline();
673        }
674    }
675 }
676
677 void MathedXIter::GoLast()
678 {
679    while (Next());
680 }
681
682
683 void MathedXIter::Adjust()
684 {
685    int posx = pos;
686    GoBegin();
687    while (posx>pos && OK()) Next();  
688 }
689
690
691 bool MathedXIter::Prev()
692 {  
693     if (pos == 0 || (pos == 1 && GetChar()>= ' '))
694       return false;
695     
696     int pos2 = pos; // pos1
697     GoBegin();
698     do {
699         ipush();
700         Next();
701     } while (pos<pos2);
702     ipop();
703     
704     return (!IsCR());
705 }
706
707
708 bool MathedXIter::goNextColumn()
709 {  
710     int rowp = row, colp= col;
711     while (Next() && col == colp);
712     
713     return (col!= colp+1 || rowp!= row);
714 }
715
716
717 bool MathedXIter::Up()
718 {
719     if (row == 0) return false;
720     int xp = x, rowp = row, colp= col;
721     GoBegin();
722     while (row<rowp-1) Next();
723     while (x<xp && OK() && !IsCR()) {
724         ipush();
725         Next();
726     }
727     if (col>colp) // || (stck.col == colp && stck.x<= xp && x>xp))
728       ipop();
729     
730     return true;
731 }
732
733
734 bool MathedXIter::Down()
735 {
736         int xp = x, colp= col; // , rowp = row
737     
738     bool res = (IsCR()) ? true: goNextCode(LM_TC_CR);
739     if (res) {
740         Next();
741         ipush();
742         while (x<xp && OK()) {
743             ipush();
744             Next();
745         }
746         if (col>colp || (stck.col == colp && stck.x<= xp && x>xp)) 
747           ipop();         
748         return true;
749     }
750     return false;
751 }
752
753
754 void MathedXIter::addRow()
755 {
756     if (!crow) {
757         lyxerr[Debug::MATHED] << "MathErr: Attempt to insert new"
758                 " line in a subparagraph. " << this << endl;
759
760         return;
761     }    
762     // Create new item for the structure    
763     MathedRowSt *r = new MathedRowSt(ncols+1);
764     if (crow) {
765         r->next = crow->next;
766         crow->next = r;
767     } else {
768         crow = r;
769         r->next = 0;
770     }    
771     // Fill missed tabs in current row
772     while (col<ncols-1) 
773       Insert('T', LM_TC_TAB); 
774     //newline
775     Insert('K', LM_TC_CR);
776     
777     ipush();
778     if (!IsCR())
779       goNextCode(LM_TC_CR);
780     
781     // Fill missed tabs in new row
782     while (col<ncols-1) 
783       Insert('T', LM_TC_TAB);
784     ipop();
785 }
786
787
788 void MathedXIter::delRow()
789 {
790     if (!crow) {
791             lyxerr[Debug::MATHED] << "MathErr: Attempt to delete a line in a subparagraph." << endl;
792         return;
793     }
794     bool line_empty = true;
795     ipush();
796 //    while (Next()) {
797     do {
798         if (IsCR()){
799             break;
800         } else if (!IsTab()) {
801             line_empty = false;
802         }
803     } while (Next());
804     int p1 = getPos();
805     ipop();
806     
807     if (line_empty) {
808         
809         MathedRowSt *r = crow->next;
810         if (r) {
811             crow->next = r->next;
812             delete r;
813         }
814         join(p1);
815         Delete();
816     } else
817       Clean(p1);
818     
819     checkTabs();    
820 }
821
822 void MathedXIter::ipush()
823
824     MathedIter::ipush();
825     stck.x = x;
826     stck.y = y;
827 }
828
829
830 void MathedXIter::ipop()
831
832     MathedIter::ipop();
833     x = stck.x;
834     y = stck.y;
835     if (p) {
836         crow = p->getRowSt();
837         if (crow)
838           for (int i= 0; i<row; i++) 
839             crow = crow->next;
840     }
841 }
842
843
844 void MathedXIter::fitCoord(int /*xx*/, int yy)
845 {
846     int xo = 0;
847     int yo = 0;
848     
849     GoBegin();
850     if (p) 
851       p->GetXY(xo, yo);
852     // first fit vertically
853     while (crow && OK()) {
854         if (yy >= yo + y - crow->asc && yy <= yo + y + crow->desc) 
855           break;
856         goNextCode(LM_TC_CR);
857         Next();
858     }
859     // now horizontally
860 //    while (x<xx && Next());
861 }
862
863
864 void MathedXIter::setTab(int tx, int tab)
865 {
866     if (crow && tab<= ncols) {
867         crow->w[tab] = tx;
868     }
869     else 
870             lyxerr << "MathErr: No tabs allowed here" << endl;
871 }
872
873
874 void MathedXIter::subMetrics(int a, int d)
875 {
876     if (!crow) {
877 //      lyxerr << "MathErr: Attempt to submetric a subparagraph." << endl;
878         return;
879     }    
880     crow->asc = a;
881     crow->desc = d;
882 }
883
884
885 // This function is not recursive, as MathPar::Metrics is
886 void MathedXIter::IMetrics(int pos2, int & width, int & ascent, int & descent)
887 {  
888     byte cx;
889     int x1; // ls;
890     int asc = 0;
891     int des = 0;
892     bool limit = false;
893   
894     descent = ascent = width = 0;
895     if (!array) return;
896     if (array->empty()) return;
897 //    if  (pos2 > array->last) return;
898     x1 = x; 
899     while (pos<pos2) {
900         cx = GetChar();
901         if (cx >= ' ') {
902             mathed_char_height(FCode(), size, cx, asc, des);
903             if (asc > ascent) ascent = asc;
904             if (des > descent) descent = des;
905             limit = false;
906         } else
907         if (MathIsInset(cx)) {
908             MathedInset *pp = GetInset();
909             if (cx == LM_TC_UP) {
910                 if (!asc && p) {
911                     int xx;
912                     int yy;
913                     p->GetXY(xx, yy);
914                     static_cast<MathParInset*>(pp)->GetXY(xx, asc);
915                     asc = yy - asc;
916                 }
917                 asc += ((limits) ? pp->Height() + 4 : pp->Ascent());
918             } else
919               if (cx == LM_TC_DOWN) {
920                   if (!des && p) {
921                       int xx;
922                       int yy;
923                       p->GetXY(xx, yy);
924                       static_cast<MathParInset*>(pp)->GetXY(xx, des);
925                       if (des - pp->Height() < yy && !asc)
926                         asc = yy - (des - pp->Height());
927                       des -= yy;
928                   }
929                   des += (limit ? pp->Height()+4: pp->Height()-pp->Ascent()/2);
930               } else {
931                   asc = pp->Ascent();
932                   des = pp->Descent();
933               }
934             if (asc > ascent) ascent = asc;
935             if (des > descent) descent = des;
936             if (cx!= LM_TC_UP && cx!= LM_TC_DOWN)
937               limit = pp->GetLimits();
938         } else 
939         if (cx == LM_TC_TAB) {
940             limit = false;                   
941         }      
942         else {
943                 lyxerr[Debug::MATHED]
944                         << "Mathed Sel-Error: Unrecognized code["
945                         << cx << ']' << endl;
946             break;
947         }       
948         if (pos < pos2)  Next();
949    }
950     width = x - x1;
951 }
952
953
954 bool MathedXIter::setNumbered(bool numb)
955 {  
956     if (crow) {
957         crow->setNumbered(numb);
958         return true;
959     }
960     
961     return false;
962 }
963
964
965 bool MathedXIter::setLabel(string const & label)
966 {  
967     if (!label.empty() && crow) {
968         crow->setLabel(label);
969         return true;
970     }
971     
972     return false;
973 }
974
975
976 MathedRowSt * MathedXIter::adjustVerticalSt()
977 {
978     GoBegin();
979     if (!crow) {
980 //      lyxerr << " CRW" << ncols << " ";
981             crow = new MathedRowSt(ncols + 1); // this leaks
982     }
983 //    lyxerr<< " CRW[" << crow << "] ";
984     MathedRowSt * mrow = crow;
985     while (OK()) {
986         if (IsCR()) {
987             if (col >= ncols) ncols = col + 1; 
988             MathedRowSt * r = new MathedRowSt(ncols + 1); // this leaks
989 //          r->next = crow->next;
990             crow->next = r;
991             crow = r;
992 //          lyxerr << " CX[" << crow << "]";
993         }   
994         Next(); 
995     }
996     return mrow;
997 }
998