]> git.lyx.org Git - lyx.git/blob - src/mathed/math_xiter.C
more mathed cleanup
[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         // make room for the data 
142         split(a->last());
143         array->mergeF(a, pos, a->last());
144         
145         int pos1 = pos;
146         int pos2 = pos + a->last();
147         
148         goPosAbs(pos1);
149         
150         // Complete rows
151         while (pos < pos2 && OK()) {
152                 if (IsCR()) {
153                         if (p && p->Permit(LMPF_ALLOW_CR)) {
154                                 MathedRowSt * r = new MathedRowSt(ncols+1);
155                                 if (crow) {
156                                         r->setNext(crow->getNext());
157                                         crow->setNext(r);
158                                 } else {
159                                         r->setNext(0);
160                                 }
161                                 crow = r;
162                         } else {
163                                 Delete();
164                                 --pos2;
165                         }
166                 }
167                 Next();    
168         }
169         pos2 = getPos();
170         goPosAbs(pos1);
171         checkTabs();
172         goPosAbs(pos2);
173         
174         delete a;
175 }
176
177
178
179
180 MathedXIter::MathedXIter(MathParInset * pp)
181         : p(pp) 
182
183         x = y = 0;
184         sx = sw = 0;   
185         limits = false;
186         s_type = 0;  
187         if (p) 
188                 SetData(p);
189         else {
190                 crow = 0;
191                 size = 0;
192         }
193 }
194
195
196 void MathedXIter::SetData(MathParInset * pp)
197 {
198         p = pp;
199         x = y = 0;
200         array = p->GetData();
201         ncols = p->GetColumns();
202         crow = p->getRowSt();
203         if (p->Permit(LMPF_ALLOW_CR))
204                 flags |= MthIF_CR;
205         if (p->Permit(LMPF_ALLOW_TAB))
206                 flags |= MthIF_Tabs;
207         
208         if (crow) {
209                 x = crow->getTab(0);
210                 y = crow->getBaseline();
211         } 
212         if (!array) {
213                 array = new MathedArray; // this leaks
214                 p->SetData(array);
215         }
216         size = p->GetStyle();
217         Reset();
218 }
219
220
221 string const MathedXIter::GetString() const
222 {
223         string s = MathedIter::GetString();
224         x += mathed_string_width(fcode, size, s);
225         return s;
226 }
227
228
229 bool MathedXIter::Next()
230 {  
231 //    lyxerr << "Ne[" << pos << "]";
232         if (!OK()) return false;
233         int w = 0;
234 //   lyxerr << "xt ";
235         if (IsInset()) {
236                 MathedInset * px = GetInset();
237                 w = px->Width();
238                 if (px->GetType() == LM_OT_SCRIPT) {
239                         if (w > sw) sw = w;
240                         w = 0;
241                 } else
242                         sx = (px->GetLimits()) ? w : 0;
243         } else {  
244                 byte c = GetChar();
245                 if (c >= ' ') {
246 //        lyxerr << "WD[" << fcode << " " << size << " " << c << endl;
247                         w = mathed_char_width(fcode, size, c);
248                 } else
249                         if (c == LM_TC_TAB && p) {
250 //       w = p->GetTab(col + 1);
251                                 w = (crow) ? crow->getTab(col + 1) : 0;
252                                 //lyxerr << "WW[" << w << "]";
253                         } else
254                                 if (c == LM_TC_CR && p) {
255                                         x = 0;
256                                         if (crow && crow->getNext()) {
257                                                 crow = crow->getNext();
258                                                 y = crow->getBaseline();
259                                                 w = crow->getTab(0);
260                                         }
261 //        lyxerr << "WW[" << col " " << row << "|" << w << "]";
262                                 } else 
263                                         lyxerr << "No hubo w[" << c << "]!";
264         }
265         if (MathedIter::Next()) {
266 //       lyxerr <<"LNX " << pos << endl;
267 //       if (sw>0 && GetChar()!= LM_TC_UP && GetChar()!= LM_TC_DOWN) {
268 //         w = (sx>sw) ? 0: sw-sx;
269                 if ((sw > 0 || sx > 0)
270                     && GetChar() != LM_TC_UP && GetChar() != LM_TC_DOWN) {
271                         if (sw > 0)
272                                 w = (sx > sw) ? 0 : sw - sx;
273                         sx = sw = 0;
274                 }
275                 x += w;
276                 return true;
277         } else
278                 return false;
279 }
280
281
282 void MathedXIter::GoBegin()
283 {
284         Reset();
285         x = y = 0;   
286         sw = sx = 0;
287         if (p) {
288                 crow = p->getRowSt();
289                 if (crow) {
290                         x = crow->getTab(0);
291                         y = crow->getBaseline();
292                 }
293         }
294 }
295
296
297 void MathedXIter::GoLast()
298 {
299         while (Next());
300 }
301
302
303 void MathedXIter::Adjust()
304 {
305         int posx = pos;
306         GoBegin();
307         while (posx > pos && OK()) Next();  
308 }
309
310
311 bool MathedXIter::Prev()
312 {  
313         if (pos == 0 || (pos == 1 && GetChar() >= ' '))
314                 return false;
315         
316         int pos2 = pos; // pos1
317         GoBegin();
318         do {
319                 ipush();
320                 Next();
321         } while (pos<pos2);
322         ipop();
323         
324         return (!IsCR());
325 }
326
327
328 bool MathedXIter::goNextColumn()
329 {  
330         int rowp = row;
331         int colp = col;
332         while (Next() && col == colp);
333         
334         return (col != colp + 1 || rowp != row);
335 }
336
337
338 bool MathedXIter::Up()
339 {
340         if (row == 0) return false;
341         int xp = x;
342         int rowp = row;
343         int colp = col;
344         GoBegin();
345         while (row < rowp - 1) Next();
346         while (x < xp && OK() && !IsCR()) {
347                 ipush();
348                 Next();
349         }
350         if (col > colp) // || (stck.col == colp && stck.x<= xp && x>xp))
351                 ipop();
352         
353         return true;
354 }
355
356
357 bool MathedXIter::Down()
358 {
359         int xp = x;
360         int colp= col;
361         // int rowp = row
362         
363         bool res = (IsCR()) ? true : goNextCode(LM_TC_CR);
364         if (res) {
365                 Next();
366                 ipush();
367                 while (x < xp && OK()) {
368                         ipush();
369                         Next();
370                 }
371                 if (col > colp || (stck.col == colp && stck.x <= xp && x > xp))
372                         ipop();
373                 return true;
374         }
375         return false;
376 }
377
378
379
380 void MathedXIter::addRow()
381 {
382         if (!crow) {
383                 lyxerr[Debug::MATHED] << "MathErr: Attempt to insert new"
384                         " line in a subparagraph. " << this << endl;
385                 
386                 return;
387         }
388         // Create new item for the structure    
389         MathedRowSt * r = new MathedRowSt(ncols + 1);
390         if (crow) {
391                 r->setNext(crow->getNext());
392                 crow->setNext(r);
393         } else {
394                 crow = r;
395                 r->setNext(0);
396         }    
397         // Fill missed tabs in current row
398         while (col < ncols - 1) 
399                 Insert('T', LM_TC_TAB); 
400         //newline
401         Insert('K', LM_TC_CR);
402         
403         ipush();
404         if (!IsCR())
405                 goNextCode(LM_TC_CR);
406         
407         // Fill missed tabs in new row
408         while (col < ncols - 1) 
409                 Insert('T', LM_TC_TAB);
410         ipop();
411 }
412
413
414 void MathedXIter::delRow()
415 {
416         if (!crow) {
417                 lyxerr[Debug::MATHED] << "MathErr: Attempt to delete a line in a subparagraph." << endl;
418                 return;
419         }
420         bool line_empty = true;
421         ipush();
422 //    while (Next()) {
423         do {
424                 if (IsCR()) {
425                         break;
426                 } else if (!IsTab()) {
427                         line_empty = false;
428                 }
429         } while (Next());
430         int const p1 = getPos();
431         ipop();
432         
433         if (line_empty) {
434                 
435                 MathedRowSt * r = crow->getNext();
436                 if (r) {
437                         crow->setNext(r->getNext());
438                         delete r;
439                 }
440                 join(p1);
441                 Delete();
442         } else
443                 Clean(p1);
444         
445         checkTabs();    
446 }
447
448
449 void MathedXIter::ipush()
450
451         MathedIter::ipush();
452         stck.x = x;
453         stck.y = y;
454 }
455
456
457 void MathedXIter::ipop()
458
459         MathedIter::ipop();
460         x = stck.x;
461         y = stck.y;
462         if (p) {
463                 crow = p->getRowSt();
464                 if (crow)
465                         for (int i = 0; i < row; ++i)
466                                 crow = crow->getNext();
467         }
468 }
469
470
471 void MathedXIter::fitCoord(int /*xx*/, int yy)
472 {
473         int xo = 0;
474         int yo = 0;
475         
476         GoBegin();
477         if (p)
478                 p->GetXY(xo, yo);
479         // first fit vertically
480         while (crow && OK()) {
481                 if (yy >= yo + y - crow->ascent() && yy <= yo + y + crow->descent()) 
482                         break;
483                 goNextCode(LM_TC_CR);
484                 Next();
485         }
486         // now horizontally
487 //    while (x<xx && Next());
488 }
489
490
491 void MathedXIter::setTab(int tx, int tab)
492 {
493         if (crow && tab <= ncols) {
494                 crow->setTab(tab, tx);
495         } else
496                 lyxerr << "MathErr: No tabs allowed here" << endl;
497 }
498
499
500 void MathedXIter::subMetrics(int a, int d)
501 {
502         if (!crow) {
503                 lyxerr[Debug::MATHED]
504                         << "MathErr: Attempt to submetric a subparagraph." << endl;
505                 return;
506         }
507         crow->ascent(a);
508         crow->descent(d);
509 }
510
511
512 // This function is not recursive, as MathPar::Metrics is
513 void MathedXIter::IMetrics(int pos2, int & width, int & ascent, int & descent)
514 {  
515         byte cx;
516         int x1; // ls;
517         int asc = 0;
518         int des = 0;
519         bool limit = false;
520         
521         descent = ascent = width = 0;
522         if (!array) return;
523         if (array->empty()) return;
524 //    if  (pos2 > array->last) return;
525         x1 = x; 
526         while (pos < pos2) {
527                 cx = GetChar();
528                 if (cx >= ' ') {
529                         mathed_char_height(FCode(), size, cx, asc, des);
530                         if (asc > ascent) ascent = asc;
531                         if (des > descent) descent = des;
532                         limit = false;
533                 } else
534                         if (MathIsInset(cx)) {
535                                 MathedInset * pp = GetInset();
536                                 if (cx == LM_TC_UP) {
537                                         if (!asc && p) {
538                                                 int xx;
539                                                 int yy;
540                                                 p->GetXY(xx, yy);
541                                                 static_cast<MathParInset*>(pp)->GetXY(xx, asc);
542                                                 asc = yy - asc;
543                                         }
544                                         asc += ((limits) ? pp->Height() + 4 : pp->Ascent());
545                                 } else if (cx == LM_TC_DOWN) {
546                                         if (!des && p) {
547                                                 int xx;
548                                                 int yy;
549                                                 p->GetXY(xx, yy);
550                                                 static_cast<MathParInset*>(pp)->GetXY(xx, des);
551                                                 if (des - pp->Height() < yy && !asc)
552                                                         asc = yy - (des - pp->Height());
553                                                 des -= yy;
554                                         }
555                                         des += (limit ? pp->Height()+4: pp->Height()-pp->Ascent()/2);
556                                 } else {
557                                         asc = pp->Ascent();
558                                         des = pp->Descent();
559                                 }
560                                 if (asc > ascent) ascent = asc;
561                                 if (des > descent) descent = des;
562                                 if (cx != LM_TC_UP && cx != LM_TC_DOWN)
563                                         limit = pp->GetLimits();
564                         } else if (cx == LM_TC_TAB) {
565                                 limit = false;                   
566                         } else {
567                                 lyxerr[Debug::MATHED]
568                                         << "Mathed Sel-Error: Unrecognized code["
569                                         << cx << ']' << endl;
570                                 break;
571                         }
572                 if (pos < pos2)  Next();
573         }
574         width = x - x1;
575 }
576
577
578 bool MathedXIter::setNumbered(bool numb)
579 {  
580         if (crow) {
581                 crow->setNumbered(numb);
582                 return true;
583         }
584         
585         return false;
586 }
587
588
589 bool MathedXIter::setLabel(string const & label)
590 {  
591         if (crow) {
592                 crow->setLabel(label);
593                 return true;
594         }
595         
596         return false;
597 }
598
599
600 MathedRowSt * MathedXIter::adjustVerticalSt()
601 {
602         GoBegin();
603         if (!crow) {
604 //      lyxerr << " CRW" << ncols << " ";
605                 crow = new MathedRowSt(ncols + 1); // this leaks
606         }
607 //    lyxerr<< " CRW[" << crow << "] ";
608         MathedRowSt * mrow = crow;
609         while (OK()) {
610                 if (IsCR()) {
611                         if (col >= ncols) ncols = col + 1; 
612                         MathedRowSt * r = new MathedRowSt(ncols + 1); // this leaks
613 //          r->next = crow->next;
614                         crow->setNext(r);
615                         crow = r;
616 //          lyxerr << " CX[" << crow << "]";
617                 }   
618                 Next(); 
619         }
620         return mrow;
621 }
622
623
624 string const &  MathedXIter::getLabel() const
625 {
626         return crow ? crow->getLabel() : error_label;
627 }
628
629
630 string MathedXIter::error_label = "$mathed-error$";