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