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