]> git.lyx.org Git - lyx.git/blob - src/mathed/math_xiter.C
mathed17.diff + some iterator methods
[lyx.git] / src / mathed / math_xiter.C
1 #include <config.h>
2
3 #include "math_xiter.h"
4 #include "math_parinset.h"
5 #include "math_rowst.h"
6 #include "array.h"
7 #include "mathed/support.h"
8 #include "debug.h"
9
10 using std::endl;
11
12 MathedXIter::MathedXIter()
13         : MathedIter(), sx(0), sw(0)
14 {
15         x = y = size = 0;
16         p = 0;
17         crow = 0;
18 }
19
20
21 MathParInset * MathedXIter::getPar() const
22 {
23         return p;
24 }
25
26
27 void MathedXIter::GetPos(int & xx, int & yy) const
28
29         if (p) 
30                 p->GetXY(xx, yy);
31         else {
32                 xx = 0;
33                 yy = 0;
34         }        
35         xx += x;
36         yy += y;
37 }
38
39
40 int MathedXIter::GetX() const
41
42         int xx;
43         int dummy_y;
44         GetPos(xx, dummy_y);
45         return xx; 
46 }
47
48
49 int MathedXIter::GetY() const
50
51         int dummy_x;
52         int yy;
53         GetPos(dummy_x, yy);
54         return yy; 
55 }
56
57
58 void MathedXIter::GetIncPos(int & xx, int & yy) const
59
60         xx = x;
61         yy = y; 
62 }
63
64
65 void MathedXIter::getAD(int & a, int & d) const
66
67         if (crow) {
68                 a = crow->ascent();
69                 d = crow->descent();
70         } else 
71                 if (p) {
72                         a = p->Ascent();
73                         d = p->Descent();
74                 } else {
75                         a = d = 0;
76                 }
77 }
78
79
80
81 void MathedXIter::Clean(int pos2)
82 {
83         if (!array) {
84                 lyxerr << "Math error: Attempting to clean a void array." << endl;
85                 return;
86         } 
87         
88         int pos1 = pos;
89         
90         if (pos2 < pos1) {
91                 GoBegin();
92                 while (pos < pos2 && OK()) {
93                         Next();
94                 }
95                 pos2 = pos1;
96                 pos1 = pos;
97         }
98         
99         ipush();
100         while (OK() && pos < pos2) {
101                 if (IsInset()) {
102                         MathedInset * inset = GetInset();
103                         Next();
104                         if (inset->GetType()!= LM_OT_MACRO_ARG)
105                                 delete inset;
106                         continue;
107                 } 
108                 if (IsCR()) {
109                         if (crow) {
110                                 MathedRowSt * r = crow->getNext();
111                                 if (r) {
112                                         crow->setNext(r->getNext());
113                                         delete r;
114                                 }          
115                         }
116                 }
117                 Next();
118         }    
119         ipop();
120         
121         if (pos2 <= array->last()) {
122                 pos = pos1;
123                 join(pos2);
124                 checkTabs();
125         } 
126 }
127
128
129 void MathedXIter::Merge(MathedArray * a0)
130 {
131         if (!a0) {
132                 lyxerr[Debug::MATHED]
133                         << "Math error: Attempting to merge a void array." << endl;
134                 
135                 return;
136         }
137         // All insets must be clonned
138         MathedIter it(a0);
139         MathedArray * a = it.Copy();
140
141 #if 0
142         array->insert(array->begin() + pos,
143                       a->begin(), a->end());
144 #else
145         // make room for the data 
146         split(a->last());
147         array->mergeF(a, pos, a->last());
148 #endif
149         int pos1 = pos;
150         int pos2 = pos + a->last();
151         
152         goPosAbs(pos1);
153         
154         // Complete rows
155         while (pos < pos2 && OK()) {
156                 if (IsCR()) {
157                         if (p && p->Permit(LMPF_ALLOW_CR)) {
158                                 MathedRowSt * r = new MathedRowSt(ncols+1);
159                                 if (crow) {
160                                         r->setNext(crow->getNext());
161                                         crow->setNext(r);
162                                 } else {
163                                         r->setNext(0);
164                                 }
165                                 crow = r;
166                         } else {
167                                 Delete();
168                                 --pos2;
169                         }
170                 }
171                 Next();    
172         }
173         pos2 = getPos();
174         goPosAbs(pos1);
175         checkTabs();
176         goPosAbs(pos2);
177         
178         delete a;
179 }
180
181
182
183
184 MathedXIter::MathedXIter(MathParInset * pp)
185         : p(pp) 
186
187         x = y = 0;
188         sx = sw = 0;   
189         limits = false;
190         s_type = 0;  
191         if (p) 
192                 SetData(p);
193         else {
194                 crow = 0;
195                 size = 0;
196         }
197 }
198
199
200 void MathedXIter::SetData(MathParInset * pp)
201 {
202         p = pp;
203         x = y = 0;
204         array = p->GetData();
205         ncols = p->GetColumns();
206         crow = p->getRowSt();
207         if (p->Permit(LMPF_ALLOW_CR))
208                 flags |= MthIF_CR;
209         if (p->Permit(LMPF_ALLOW_TAB))
210                 flags |= MthIF_Tabs;
211         
212         if (crow) {
213                 x = crow->getTab(0);
214                 y = crow->getBaseline();
215         } 
216         if (!array) {
217                 array = new MathedArray; // this leaks
218                 p->SetData(array);
219         }
220         size = p->GetStyle();
221         Reset();
222 }
223
224
225 string const MathedXIter::GetString() const
226 {
227         string s = MathedIter::GetString();
228         x += mathed_string_width(fcode, size, s);
229         return s;
230 }
231
232
233 bool MathedXIter::Next()
234 {  
235 //    lyxerr << "Ne[" << pos << "]";
236         if (!OK()) return false;
237         int w = 0;
238 //   lyxerr << "xt ";
239         if (IsInset()) {
240                 MathedInset * px = GetInset();
241                 w = px->Width();
242                 if (px->GetType() == LM_OT_SCRIPT) {
243                         if (w > sw) sw = w;
244                         w = 0;
245                 } else
246                         sx = (px->GetLimits()) ? w : 0;
247         } else {  
248                 byte c = GetChar();
249                 if (c >= ' ') {
250 //        lyxerr << "WD[" << fcode << " " << size << " " << c << endl;
251                         w = mathed_char_width(fcode, size, c);
252                 } else
253                         if (c == LM_TC_TAB && p) {
254 //       w = p->GetTab(col + 1);
255                                 w = (crow) ? crow->getTab(col + 1) : 0;
256                                 //lyxerr << "WW[" << w << "]";
257                         } else
258                                 if (c == LM_TC_CR && p) {
259                                         x = 0;
260                                         if (crow && crow->getNext()) {
261                                                 crow = crow->getNext();
262                                                 y = crow->getBaseline();
263                                                 w = crow->getTab(0);
264                                         }
265 //        lyxerr << "WW[" << col " " << row << "|" << w << "]";
266                                 } else 
267                                         lyxerr << "No hubo w[" << c << "]!";
268         }
269         if (MathedIter::Next()) {
270 //       lyxerr <<"LNX " << pos << endl;
271 //       if (sw>0 && GetChar()!= LM_TC_UP && GetChar()!= LM_TC_DOWN) {
272 //         w = (sx>sw) ? 0: sw-sx;
273                 if ((sw > 0 || sx > 0)
274                     && GetChar() != LM_TC_UP && GetChar() != LM_TC_DOWN) {
275                         if (sw > 0)
276                                 w = (sx > sw) ? 0 : sw - sx;
277                         sx = sw = 0;
278                 }
279                 x += w;
280                 return true;
281         } else
282                 return false;
283 }
284
285
286 void MathedXIter::GoBegin()
287 {
288         Reset();
289         x = y = 0;   
290         sw = sx = 0;
291         if (p) {
292                 crow = p->getRowSt();
293                 if (crow) {
294                         x = crow->getTab(0);
295                         y = crow->getBaseline();
296                 }
297         }
298 }
299
300
301 void MathedXIter::GoLast()
302 {
303         while (Next());
304 }
305
306
307 void MathedXIter::Adjust()
308 {
309         int posx = pos;
310         GoBegin();
311         while (posx > pos && OK()) Next();  
312 }
313
314
315 bool MathedXIter::Prev()
316 {  
317         if (pos == 0 || (pos == 1 && GetChar() >= ' '))
318                 return false;
319         
320         int pos2 = pos; // pos1
321         GoBegin();
322         do {
323                 ipush();
324                 Next();
325         } while (pos<pos2);
326         ipop();
327         
328         return (!IsCR());
329 }
330
331
332 bool MathedXIter::goNextColumn()
333 {  
334         int rowp = row;
335         int colp = col;
336         while (Next() && col == colp);
337         
338         return (col != colp + 1 || rowp != row);
339 }
340
341
342 bool MathedXIter::Up()
343 {
344         if (row == 0) return false;
345         int xp = x;
346         int rowp = row;
347         int colp = col;
348         GoBegin();
349         while (row < rowp - 1) Next();
350         while (x < xp && OK() && !IsCR()) {
351                 ipush();
352                 Next();
353         }
354         if (col > colp) // || (stck.col == colp && stck.x<= xp && x>xp))
355                 ipop();
356         
357         return true;
358 }
359
360
361 bool MathedXIter::Down()
362 {
363         int xp = x;
364         int colp= col;
365         // int rowp = row
366         
367         bool res = (IsCR()) ? true : goNextCode(LM_TC_CR);
368         if (res) {
369                 Next();
370                 ipush();
371                 while (x < xp && OK()) {
372                         ipush();
373                         Next();
374                 }
375                 if (col > colp || (stck.col == colp && stck.x <= xp && x > xp))
376                         ipop();
377                 return true;
378         }
379         return false;
380 }
381
382
383
384 void MathedXIter::addRow()
385 {
386         if (!crow) {
387                 lyxerr[Debug::MATHED] << "MathErr: Attempt to insert new"
388                         " line in a subparagraph. " << this << endl;
389                 
390                 return;
391         }
392         // Create new item for the structure    
393         MathedRowSt * r = new MathedRowSt(ncols + 1);
394         if (crow) {
395                 r->setNext(crow->getNext());
396                 crow->setNext(r);
397         } else {
398                 crow = r;
399                 r->setNext(0);
400         }    
401         // Fill missed tabs in current row
402         while (col < ncols - 1) 
403                 Insert('T', LM_TC_TAB); 
404         //newline
405         Insert('K', LM_TC_CR);
406         
407         ipush();
408         if (!IsCR())
409                 goNextCode(LM_TC_CR);
410         
411         // Fill missed tabs in new row
412         while (col < ncols - 1) 
413                 Insert('T', LM_TC_TAB);
414         ipop();
415 }
416
417
418 void MathedXIter::delRow()
419 {
420         if (!crow) {
421                 lyxerr[Debug::MATHED] << "MathErr: Attempt to delete a line in a subparagraph." << endl;
422                 return;
423         }
424         bool line_empty = true;
425         ipush();
426 //    while (Next()) {
427         do {
428                 if (IsCR()) {
429                         break;
430                 } else if (!IsTab()) {
431                         line_empty = false;
432                 }
433         } while (Next());
434         int const p1 = getPos();
435         ipop();
436         
437         if (line_empty) {
438                 
439                 MathedRowSt * r = crow->getNext();
440                 if (r) {
441                         crow->setNext(r->getNext());
442                         delete r;
443                 }
444                 join(p1);
445                 Delete();
446         } else
447                 Clean(p1);
448         
449         checkTabs();    
450 }
451
452
453 void MathedXIter::ipush()
454
455         MathedIter::ipush();
456         stck.x = x;
457         stck.y = y;
458 }
459
460
461 void MathedXIter::ipop()
462
463         MathedIter::ipop();
464         x = stck.x;
465         y = stck.y;
466         if (p) {
467                 crow = p->getRowSt();
468                 if (crow)
469                         for (int i = 0; i < row; ++i)
470                                 crow = crow->getNext();
471         }
472 }
473
474
475 void MathedXIter::fitCoord(int /*xx*/, int yy)
476 {
477         int xo = 0;
478         int yo = 0;
479         
480         GoBegin();
481         if (p)
482                 p->GetXY(xo, yo);
483         // first fit vertically
484         while (crow && OK()) {
485                 if (yy >= yo + y - crow->ascent() && yy <= yo + y + crow->descent()) 
486                         break;
487                 goNextCode(LM_TC_CR);
488                 Next();
489         }
490         // now horizontally
491 //    while (x<xx && Next());
492 }
493
494
495 void MathedXIter::setTab(int tx, int tab)
496 {
497         if (crow && tab <= ncols) {
498                 crow->setTab(tab, tx);
499         } else
500                 lyxerr << "MathErr: No tabs allowed here" << endl;
501 }
502
503
504 void MathedXIter::subMetrics(int a, int d)
505 {
506         if (!crow) {
507                 lyxerr[Debug::MATHED]
508                         << "MathErr: Attempt to submetric a subparagraph." << endl;
509                 return;
510         }
511         crow->ascent(a);
512         crow->descent(d);
513 }
514
515
516 // This function is not recursive, as MathPar::Metrics is
517 void MathedXIter::IMetrics(int pos2, int & width, int & ascent, int & descent)
518 {  
519         byte cx;
520         int x1; // ls;
521         int asc = 0;
522         int des = 0;
523         bool limit = false;
524         
525         descent = ascent = width = 0;
526         if (!array) return;
527         if (array->empty()) return;
528 //    if  (pos2 > array->last) return;
529         x1 = x; 
530         while (pos < pos2) {
531                 cx = GetChar();
532                 if (cx >= ' ') {
533                         mathed_char_height(FCode(), size, cx, asc, des);
534                         if (asc > ascent) ascent = asc;
535                         if (des > descent) descent = des;
536                         limit = false;
537                 } else
538                         if (MathIsInset(cx)) {
539                                 MathedInset * pp = GetInset();
540                                 if (cx == LM_TC_UP) {
541                                         if (!asc && p) {
542                                                 int xx;
543                                                 int yy;
544                                                 p->GetXY(xx, yy);
545                                                 static_cast<MathParInset*>(pp)->GetXY(xx, asc);
546                                                 asc = yy - asc;
547                                         }
548                                         asc += ((limits) ? pp->Height() + 4 : pp->Ascent());
549                                 } else if (cx == LM_TC_DOWN) {
550                                         if (!des && p) {
551                                                 int xx;
552                                                 int yy;
553                                                 p->GetXY(xx, yy);
554                                                 static_cast<MathParInset*>(pp)->GetXY(xx, des);
555                                                 if (des - pp->Height() < yy && !asc)
556                                                         asc = yy - (des - pp->Height());
557                                                 des -= yy;
558                                         }
559                                         des += (limit ? pp->Height()+4: pp->Height()-pp->Ascent()/2);
560                                 } else {
561                                         asc = pp->Ascent();
562                                         des = pp->Descent();
563                                 }
564                                 if (asc > ascent) ascent = asc;
565                                 if (des > descent) descent = des;
566                                 if (cx != LM_TC_UP && cx != LM_TC_DOWN)
567                                         limit = pp->GetLimits();
568                         } else if (cx == LM_TC_TAB) {
569                                 limit = false;                   
570                         } else {
571                                 lyxerr[Debug::MATHED]
572                                         << "Mathed Sel-Error: Unrecognized code["
573                                         << cx << ']' << endl;
574                                 break;
575                         }
576                 if (pos < pos2)  Next();
577         }
578         width = x - x1;
579 }
580
581
582 bool MathedXIter::setNumbered(bool numb)
583 {  
584         if (crow) {
585                 crow->setNumbered(numb);
586                 return true;
587         }
588         
589         return false;
590 }
591
592
593 bool MathedXIter::setLabel(string const & label)
594 {  
595         if (crow) {
596                 crow->setLabel(label);
597                 return true;
598         }
599         
600         return false;
601 }
602
603
604 MathedRowSt * MathedXIter::adjustVerticalSt()
605 {
606         GoBegin();
607         if (!crow) {
608 //      lyxerr << " CRW" << ncols << " ";
609                 crow = new MathedRowSt(ncols + 1); // this leaks
610         }
611 //    lyxerr<< " CRW[" << crow << "] ";
612         MathedRowSt * mrow = crow;
613         while (OK()) {
614                 if (IsCR()) {
615                         if (col >= ncols) ncols = col + 1; 
616                         MathedRowSt * r = new MathedRowSt(ncols + 1); // this leaks
617 //          r->next = crow->next;
618                         crow->setNext(r);
619                         crow = r;
620 //          lyxerr << " CX[" << crow << "]";
621                 }   
622                 Next(); 
623         }
624         return mrow;
625 }
626
627
628 string const &  MathedXIter::getLabel() const
629 {
630         return crow ? crow->getLabel() : error_label;
631 }
632
633
634 string MathedXIter::error_label = "$mathed-error$";