]> git.lyx.org Git - lyx.git/blob - src/mathed/math_cursor.C
fix the outstanding painter drawing problems, now tablelines, mathframe, specialchars...
[lyx.git] / src / mathed / math_cursor.C
1 /*
2  *  File:        math_cursor.C
3  *  Purpose:     Interaction for mathed
4  *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx> 
5  *  Created:     January 1996
6  *  Description: Math interaction for a WYSIWYG math editor.
7  *
8  *  Dependencies: Xlib, XForms
9  *
10  *  Copyright: (c) 1996, Alejandro Aguilar Sierra
11  *
12  *   Version: 0.8beta, Mathed & Lyx project.
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 #ifdef __GNUG__
19 #pragma implementation
20 #endif
21  
22 #include <config.h>
23 #include FORMS_H_LOCATION
24 #include "math_inset.h"
25 #include "math_parser.h"
26 #include "math_cursor.h"
27 #include "math_macro.h"
28 #include "math_root.h"
29 #include "support/lstrings.h"
30 #include "debug.h"
31 #include "LColor.h"
32 #include "Painter.h"
33
34 extern void mathed_set_font(short type, int style);
35
36 extern GC canvasGC, mathGC, latexGC, cursorGC, mathFrameGC;
37
38 static LyxArrayBase * selarray = 0;
39
40 inline bool IsAlpha(char c)
41 {
42    return ('A' <= c  && c <= 'Z' || 'a' <= c  && c <= 'z');
43 }
44
45 // This was very smaller, I'll change it later 
46 inline bool IsMacro(short tok, int id)
47 {
48    return (tok != LM_TK_STACK && tok != LM_TK_FRAC && tok != LM_TK_SQRT
49            && tok != LM_TK_WIDE
50            && tok != LM_TK_SPACE && tok != LM_TK_DOTS
51            && tok != LM_TK_FUNCLIM
52            && tok != LM_TK_BIGSYM && tok != LM_TK_ACCENT && 
53            !(tok == LM_TK_SYM && id < 255));
54 }
55
56
57 // Yes, mathed isn't using string yet.
58 inline char * strnew(char const * s)
59 {
60     char * s1 = new char[strlen(s)+1];
61     strcpy(s1, s);
62     return s1;
63 }
64
65
66
67 #define MAX_STACK_ITEMS 32
68
69 struct MathStackXIter {
70     
71     int i, imax;
72     MathedXIter * item;
73     
74     MathStackXIter(int n = MAX_STACK_ITEMS): imax(n) {
75         item = new MathedXIter[imax];
76         i = 0;
77     }
78     
79     MathStackXIter(MathStackXIter & stk);
80     
81     ~MathStackXIter() {
82         delete[] item;
83     }
84    
85     void push(MathedXIter ** a) {
86         *a = &item[i++];
87     }
88       
89     MathedXIter * pop() {
90         --i;
91         return &item[i - 1];
92     }
93       
94     MathedXIter * Item(int idx) {
95        return (idx + 1 <= i) ? &item[i - idx - 1] : 0;
96     }
97
98     void Reset() {
99         i = 0;
100     }
101    
102     bool Full() {
103         return i >= MAX_STACK_ITEMS;
104     }
105    
106     bool Empty() {
107         return i <= 1;
108     }
109
110     int Level() { return i; } 
111     
112 } mathstk, *selstk = 0;
113
114
115 MathStackXIter::MathStackXIter(MathStackXIter & stk) {
116     imax = stk.imax;
117     item = new MathedXIter[imax];
118     i = stk.i;
119     for (int k = 0; k < i; ++k) {
120         item[k].SetData(stk.item[k].getPar());
121         item[k].GoBegin();
122         item[k].goPosAbs(stk.item[k].getPos());
123     }
124 }
125
126
127 /***----------------  Mathed Cursor  ---------------------------***/
128   
129 MathedCursor::MathedCursor(MathParInset * p) // : par(p)
130 {
131     accent = 0;
132     anchor = 0;
133     lastcode = LM_TC_MIN;
134     SetPar(p);
135 //    selarray = 0;     
136     if (!MathMacroTable::built)
137         MathMacroTable::mathMTable.builtinMacros();
138 }
139
140
141 void MathedCursor::SetPar(MathParInset * p)
142 {
143    win = 0;
144    is_visible = False;
145    macro_mode = false;
146    selection = false; // not SelClear() ?
147    mathstk.Reset();
148    mathstk.push(&cursor);
149    par = p;
150    cursor->SetData(par);
151 }
152
153
154 #ifdef USE_PAINTER
155 void MathedCursor::draw(Painter & pain, int x, int y)
156 {
157         //    lyxerr << "Cursor[" << x << " " << y << "] ";
158         //win = pm;    // win = (mathedCanvas) ? mathedCanvas: pm;
159         par->Metrics();
160         int w = par->Width() + 2;
161         int a = par->Ascent() + 1;
162         int h = par->Height() + 1;
163         if (par->GetType() > LM_OT_PAR) { a += 4;  h += 8; }
164         
165         pain.rectangle(x - 1, y - a, w, h, LColor::mathframe);
166         
167         par->draw(pain, x, y);
168         cursor->Adjust();
169 }
170 #else
171 void MathedCursor::Draw(long unsigned pm, int x, int y)
172 {
173 //    lyxerr << "Cursor[" << x << " " << y << "] ";
174     win = pm;    // win = (mathedCanvas) ? mathedCanvas: pm;
175     par->Metrics();
176     int w = par->Width()+2, a = par->Ascent()+1, h = par->Height()+1;
177     if (par->GetType() > LM_OT_PAR) { a += 4;  h += 8; }
178     
179    if (!canvasGC) mathed_set_font(LM_TC_VAR, 1);
180     //   XFillRectangle(fl_display, pm, canvasGC, x, y-a, w, h);
181     XDrawRectangle(fl_display, pm, mathFrameGC, x - 1, y - a, w, h);
182     XFlush(fl_display);
183     MathParInset::pm = pm;
184     par->Draw(x, y);
185     cursor->Adjust();
186 }
187 #endif
188
189
190 #ifdef USE_PAINTER
191 void MathedCursor::Redraw(Painter & pain)
192 {  
193         lyxerr[Debug::MATHED] << "Mathed: Redrawing!" << endl;
194         par->Metrics();
195         int w = par->Width(), h = par->Height();
196         int x, y;
197         par->GetXY(x, y);
198         //mathed_set_font(LM_TC_VAR, 1);
199         pain.fillRectangle(x, y - par->Ascent(),
200                            x + w, y - par->Ascent() + h,
201                            LColor::mathbg);
202         par->draw(pain, x, y);
203 }
204 #else
205 void MathedCursor::Redraw()
206 {  
207         lyxerr[Debug::MATHED] << "Mathed: Redrawing!" << endl;
208    par->Metrics();
209    int w = par->Width(), h = par->Height();
210    int x, y;
211    par->GetXY(x, y);
212    mathed_set_font(LM_TC_VAR, 1);
213    XFillRectangle(fl_display, win, canvasGC, x, y-par->Ascent(), w, h);
214    XFlush(fl_display);
215     MathParInset::pm = win;
216    par->Draw(x, y);
217 }
218 #endif
219
220
221 bool MathedCursor::Left(bool sel)
222 {
223    if (macro_mode) {
224       MacroModeBack();
225       return true;
226    }
227     clearLastCode();
228    if (sel && !selection) SelStart();
229    if (!sel && selection) SelClear();
230    bool result = cursor->Prev();
231    if (!result && !mathstk.Empty()) {
232       cursor = mathstk.pop();
233       cursor->Adjust();
234       result = true;
235       if (selection) SelClear();
236    } else  
237      if (result && cursor->IsActive()) {
238         if (cursor->IsScript()) {
239            cursor->Prev();
240            if (!cursor->IsScript())
241              cursor->Next();
242            cursor->Adjust(); 
243            return true;
244         }
245         if (!selection) {
246             MathParInset * p = cursor->GetActiveInset();
247             if (!p)
248               return result;
249                 
250             p->setArgumentIdx(p->getMaxArgumentIdx());
251             mathstk.push(&cursor);
252             cursor->SetData(p);
253             cursor->GoLast();
254         }
255      } 
256    return result;  
257 }
258
259
260 // Leave the inset
261 bool MathedCursor::Pop()
262 {
263    if (!mathstk.Empty()) {
264       cursor = mathstk.pop();
265       cursor->Next(); 
266       return true;
267    }
268    return false;
269 }
270
271
272 // Go to the inset 
273 bool MathedCursor::Push()
274
275    if (cursor->IsActive()) {
276       MathParInset * p = cursor->GetActiveInset();
277        if (!p) return false;
278       mathstk.push(&cursor);
279       cursor->SetData(p);
280       return true;
281    }
282    return false;
283 }  
284
285
286 bool MathedCursor::Right(bool sel)
287 {  
288    if (macro_mode) {
289       MacroModeClose();
290       return true;
291    } 
292     clearLastCode();
293    if (sel && !selection) SelStart();
294    if (!sel && selection) SelClear();
295    bool result = false;
296  
297    if (cursor->IsActive()) {
298       if (cursor->IsScript()) {
299          cursor->Next();
300          // A script may be followed by another script
301          if (cursor->IsScript()) 
302            cursor->Next();
303          return true;
304       }
305       if (!selection) { 
306           MathParInset *p = cursor->GetActiveInset();
307           if (!p) {
308                   lyxerr << "Math error: Inset expected." << endl;
309               return cursor->Next();
310           }
311           p->setArgumentIdx(0);
312           mathstk.push(&cursor);
313           cursor->SetData(p);
314           result = true;
315       } else
316          result = cursor->Next();
317    } else {
318        if (cursor->GetChar()!= LM_TC_CR)
319          result = cursor->Next();
320      if (!result && !mathstk.Empty()) {
321         cursor = mathstk.pop();
322         cursor->Next();
323          cursor->Adjust();
324         result = true;
325         if (selection) SelClear();
326      }
327    }
328    return result;
329 }
330
331
332 void MathedCursor::SetPos(int x, int y)
333 {
334     int xp = 0;
335     
336     if (macro_mode) MacroModeClose();
337     lastcode = LM_TC_MIN;
338     mathstk.Reset();
339     mathstk.push(&cursor);
340     cursor->SetData(par);
341     cursor->fitCoord(x, y);
342     while (cursor->GetX()<x && cursor->OK()) {
343         if (cursor->IsActive()) {
344             MathParInset * p = cursor->GetActiveInset();
345             if (p->Inside(x, y)) {
346                 p->SetFocus(x, y);
347                 mathstk.push(&cursor);
348                 cursor->SetData(p);
349                 cursor->fitCoord(x, y);
350                 continue;
351             }
352         }
353         xp = cursor->GetX();
354         cursor->ipush();
355         if (!cursor->Next() && !Pop()) 
356           break;
357     }
358     if (x-xp < cursor->GetX()-x) cursor->ipop();
359     cursor->Adjust();
360 }
361    
362
363 void MathedCursor::Home()
364 {
365    if (macro_mode) MacroModeClose();
366     clearLastCode();
367    mathstk.Reset();
368    mathstk.push(&cursor);
369    cursor->GoBegin();
370 }
371
372
373 void MathedCursor::End()
374 {
375    if (macro_mode) MacroModeClose();
376     clearLastCode();
377    mathstk.Reset();
378    mathstk.push(&cursor);
379    cursor->GoLast();
380 }
381
382
383 void MathedCursor::Insert(byte c, MathedTextCodes t)
384 {  
385    if (selection) SelDel();
386    
387    if (t == LM_TC_MIN)
388       t = lastcode;
389     
390    if (macro_mode && !(MathIsAlphaFont(t) || t == LM_TC_MIN))
391       MacroModeClose();
392         
393    if (t == LM_TC_CR) {
394       MathParInset * p = cursor->p;
395       if (p == par && p->GetType()<LM_OT_MPAR && p->GetType()>LM_OT_MIN) {
396          MathMatrixInset * mt = new MathMatrixInset(3, 0);
397          mt->SetAlign(' ', "rcl");
398          mt->SetStyle(LM_ST_DISPLAY);
399          mt->SetType((p->GetType() == LM_OT_PARN) ? LM_OT_MPARN: LM_OT_MPAR);
400          mt->SetData(p->GetData());
401          p->SetData(0);//BUG duda
402          delete p;
403          par = mt;
404          p = mt;
405          p->Metrics();
406          int pos = cursor->getPos();
407          cursor->SetData(par);
408          cursor->goPosAbs(pos);
409       }      
410       if (p &&  p->Permit(LMPF_ALLOW_CR)) {
411           cursor->addRow();
412       }
413    } else
414    if (t == LM_TC_TAB) {
415       MathParInset * p = cursor->p;
416       if (p &&  p->Permit(LMPF_ALLOW_TAB)) {
417           if (c) {
418               cursor->Insert(c, t);
419               cursor->checkTabs();
420           } else
421             cursor->goNextColumn();
422       } else // Navigate between arguments
423          if (p && p->GetType() == LM_OT_MACRO) {
424              if (p->getArgumentIdx() < p->getMaxArgumentIdx()) {
425                  p->setArgumentIdx(p->getArgumentIdx()+1);
426                  cursor->SetData(p);
427                  return;
428              }
429          }       
430    } else {
431        if (macro_mode) {
432            if (MathIsAlphaFont(t) || t == LM_TC_MIN) {
433                MacroModeInsert(c);
434                return;
435            }
436        } 
437        if (accent) {
438                doAccent(c, t);
439        } else 
440          cursor->Insert(c, t);
441        lastcode = t;
442        
443        return;
444    }
445     clearLastCode();
446 }
447
448
449 void MathedCursor::Insert(MathedInset * p, int t)
450 {
451    if (macro_mode) MacroModeClose();
452    if (selection) {
453       if (MathIsActive(t)) {
454          SelCut();
455          static_cast<MathParInset*>(p)->SetData(selarray);
456       } else
457         SelDel();
458    }
459          
460    if (mathstk.i < MAX_STACK_ITEMS - 1) {
461        
462        if (accent && !MathIsActive(t)) {               
463                doAccent(p);
464        } else {
465            cursor->Insert(p, t);
466        
467            if (MathIsActive(t)) {
468                cursor->Prev();
469                Push();
470            }
471        }
472      
473    } else
474            lyxerr << "Math error: Full stack." << endl;
475 }
476
477
478 void MathedCursor::Delete() 
479 {   
480    if (macro_mode) return;
481    if (selection) {
482       SelDel();
483       return;
484    }
485    if (cursor->Empty() && !mathstk.Empty()) {
486       cursor = mathstk.pop();
487    } 
488 //   if (cursor->GetChar()!= LM_TC_TAB)
489     cursor->Delete();
490     cursor->checkTabs();
491 }
492
493
494 void MathedCursor::DelLine()
495 {  
496     if (macro_mode) MacroModeClose();
497     if (selection) {
498         SelDel();
499         return;
500     }
501     MathParInset *p= cursor->p;
502     if (p &&  (p->GetType()<= LM_OT_MATRIX && p->GetType()>= LM_OT_MPAR)) {
503         cursor->delRow();
504     }
505 }
506
507
508 bool MathedCursor::Up(bool sel)
509 {
510     bool result = false;
511    
512     if (macro_mode) MacroModeClose();
513     
514     if (sel && !selection) SelStart();
515     if (!sel && selection) SelClear();
516     
517
518     if (cursor->IsScript()) {
519         char cd = cursor->GetChar();
520         if (MathIsUp(cd)) {
521             Push();
522             return true;
523         } else {
524             // A subscript may be followed by a superscript
525             cursor->ipush();
526             cursor->Next();
527             if (MathIsUp(cursor->GetChar())) {
528                 Push();
529                 return true;
530             } else  // return to the previous state
531               cursor->ipop();
532       }
533    }    
534      
535     result = cursor->Up();
536     if (!result && cursor->p) {
537             MathParInset * p = cursor->p;   
538    
539         if (p->GetType() == LM_OT_SCRIPT) {
540             MathedXIter * cx = mathstk.Item(1);
541             bool is_down = (cx->GetChar() == LM_TC_DOWN);
542             cursor = mathstk.pop();
543             cursor->Next();
544             result =  (is_down) ? true: Up();
545         } else {
546             result = (p->getArgumentIdx() > 0);
547             if (result) {
548                 p->setArgumentIdx(p->getArgumentIdx()-1);
549                 cursor->SetData(p);
550             }
551         }
552         if (!result && !mathstk.Empty()) {
553             cursor = mathstk.pop();
554             return Up();
555         }     
556     }
557     return result;
558 }
559
560
561 bool MathedCursor::Down(bool sel)
562 {
563     bool result = false;
564    
565     if (macro_mode) MacroModeClose();
566     
567     if (sel && !selection) SelStart();
568     if (!sel && selection) SelClear();
569 //    if (selection) SelClear();
570
571     if (cursor->IsScript()) {
572         char cd = cursor->GetChar(); 
573         if (MathIsDown(cd)) {
574             Push();
575             return true;
576         } else {
577             // A superscript may be followed by a subscript
578             cursor->ipush();
579             cursor->Next();
580             if (MathIsDown(cursor->GetChar())) {
581                 Push();
582                 return true;
583             } else
584               cursor->ipop();
585       }
586    }
587      
588     result = cursor->Down();
589     if (!result && cursor->p) {
590         MathParInset * p= cursor->p;   
591         if (p->GetType() == LM_OT_SCRIPT) {
592             MathedXIter * cx = mathstk.Item(1);
593             bool is_up = (cx->GetChar() == LM_TC_UP);
594             cursor = mathstk.pop();
595             cursor->Next();
596             result = (is_up) ? true: Down();
597         } else {
598             result = (p->getArgumentIdx() < p->getMaxArgumentIdx());
599             if (result) {
600                 p->setArgumentIdx(p->getArgumentIdx()+1);
601                 cursor->SetData(p);
602             }
603         }
604         if (!result && !mathstk.Empty()) {
605             cursor = mathstk.pop();
606             return Down(sel);
607         }    
608     }
609     return result;
610 }
611
612
613 bool MathedCursor::Limits()
614 {
615    if (cursor->IsInset()) {
616       MathedInset * p = cursor->GetInset();
617       bool ol = p->GetLimits();
618       p->SetLimits(!ol);
619       return (ol!= p->GetLimits());
620    }
621    return false;
622 }
623
624
625 void MathedCursor::SetSize(short size)
626 {
627     MathParInset * p = cursor->p;
628     p->UserSetSize(size);
629     cursor->SetData(p);
630 }
631
632
633 void MathedCursor::setLabel(char const * label)
634 {  // ugly hack and possible bug
635     if (!cursor->setLabel(strnew(label)))
636             lyxerr << "MathErr: Bad place to set labels." << endl;
637 }
638
639
640 void MathedCursor::setNumbered()
641 {  // another ugly hack
642     MathedRowSt * crow = cursor->crow;
643     if (!crow) return;    
644     crow->setNumbered(!crow->isNumbered());
645 }
646
647
648 void MathedCursor::Interpret(char const * s)
649 {
650     MathedInset * p = 0;
651     latexkeys * l = 0;   
652     MathedTextCodes tcode = LM_TC_INSET;
653     
654     if (s[0] == '^' || s[0] == '_') {
655         char c = cursor->GetChar();
656         if (MathIsUp(c) && s[0] == '^' || MathIsDown(c) && s[0] == '_') {
657             Push();
658             return;
659         } else // A script may be followed by a script
660           if (MathIsUp(c)  || MathIsDown(c)) { 
661             cursor->ipush();
662             cursor->Next();
663             c = cursor->GetChar();
664             if (MathIsUp(c) && s[0] == '^' || MathIsDown(c) && s[0] == '_') {
665                 Push();
666                 return;
667             } else
668               cursor->ipop();
669         }
670         p = new MathParInset(LM_ST_SCRIPT, "", LM_OT_SCRIPT);
671         Insert (p, (s[0] == '_') ? LM_TC_DOWN: LM_TC_UP); 
672         return;
673     } else   
674       if (s[0] == '!' || s[0] == ','  || s[0] == ':' || s[0] == ';') {
675           int sp = ((s[0] == ',') ? 1:((s[0] == ':') ? 2:((s[0] == ';') ? 3: 0))); 
676           p = new MathSpaceInset(sp);
677           Insert(p);
678           return;
679       } else  
680       l = in_word_set (s, strlen(s));
681     
682     if (!l) {       
683         p = MathMacroTable::mathMTable.getMacro(s);
684         if (!p) {
685             lyxerr[Debug::MATHED] << "Macro2 " << s << ' ' << tcode << endl;
686             if (strcmp("root", s) == 0) {
687                 p = new MathRootInset();
688                 tcode = LM_TC_ACTIVE_INSET;
689             } else
690               p = new MathFuncInset(s, LM_OT_UNDEF);
691         } else {
692             tcode = static_cast<MathMacro*>(p)->getTCode();
693             lyxerr << "Macro2 " << s << ' ' << tcode << "  " ;
694         }
695     } else {
696         MathedInsetTypes fractype = LM_OT_FRAC;
697         switch (l->token) {
698          case LM_TK_BIGSYM:
699          {
700              p = new MathBigopInset(l->name, l->id);
701              break;
702          }
703          case LM_TK_SYM:
704          {                   
705              if (l->id<255) {
706                  Insert(static_cast<byte>(l->id), MathIsBOPS(l->id) ? 
707                         LM_TC_BOPS: LM_TC_SYMB);            
708              } else {
709                  p = new MathFuncInset(l->name);
710              }
711              break;
712          }  
713          case LM_TK_STACK:
714             fractype = LM_OT_STACKREL;
715             lyxerr[Debug::MATHED] << " i:stackrel " << endl;
716          case LM_TK_FRAC: 
717          {       
718              p = new MathFracInset(fractype);
719              tcode = LM_TC_ACTIVE_INSET;
720              break;
721          }
722          case LM_TK_SQRT: 
723          {       
724              p = new MathSqrtInset; 
725              tcode = LM_TC_ACTIVE_INSET;
726              break;
727          }
728          case LM_TK_WIDE: 
729          {       
730              p = new MathDecorationInset(l->id); 
731              tcode = LM_TC_ACTIVE_INSET;
732              break;
733          } 
734          case  LM_TK_FUNCLIM:
735          {
736              p = new MathFuncInset(l->name, LM_OT_FUNCLIM);
737              break;
738          }
739          case LM_TK_SPACE:
740          {
741              p = new MathSpaceInset(l->id);
742              break;
743          }         
744          case LM_TK_DOTS: 
745          {
746              p = new MathDotsInset(l->name, l->id);
747              break;
748          }         
749          case LM_TK_ACCENT:
750             setAccent(l->id);
751             break;
752          case LM_TK_MACRO:
753             p = MathMacroTable::mathMTable.getMacro(s);
754             tcode = static_cast<MathMacro*>(p)->getTCode();
755             lyxerr[Debug::MATHED] << "Macro " << s << ' ' << tcode << endl;
756             break;
757          default:
758          {
759              p = new MathFuncInset(l->name);
760              break;
761          }
762         }
763     }
764     if (p) {
765         Insert(p, tcode);
766         par->Metrics();
767     }
768 }
769
770
771 bool MathedCursor::pullArg()
772
773     if (cursor->IsActive()) {
774         MathParInset * p = cursor->GetActiveInset();
775         if (!p) { 
776             return false;
777         }
778         LyxArrayBase * a = p->GetData();
779         p->SetData(0);
780         Delete();
781         if (a) {
782             cursor->Merge(a);
783             cursor->Adjust();
784         }
785         
786         return true;
787     }
788     return false;
789 }  
790  
791
792 void MathedCursor::MacroModeOpen()
793 {
794    if (!macro_mode)  {
795       macroln = 0;
796       macrobf[0] = '\0';
797       imacro = new MathFuncInset(&macrobf[0]);
798       Insert (imacro);
799       macro_mode = true;
800    } else
801            lyxerr << "Mathed Warning: Already in macro mode" << endl;
802 }
803
804
805 void MathedCursor::MacroModeClose()
806 {
807    if (macro_mode)  {
808       macro_mode = false;
809       latexkeys * l = in_word_set(macrobf, macroln);
810       if (macroln > 0 && (!l || (l && IsMacro(l->token, l->id))) && 
811           !MathMacroTable::mathMTable.getMacro(macrobf)) {
812           if (!l) {
813             imacro->SetName(strnew(macrobf));
814               // This guarantees that the string will be removed by destructor
815             imacro->SetType(LM_OT_UNDEF);
816           } else 
817             imacro->SetName(l->name);
818       } else {
819          Left();
820          imacro->SetName(0);
821          if (cursor->GetInset()->GetType() == LM_OT_ACCENT) {
822              setAccent(static_cast<MathAccentInset*>(cursor->GetInset())->getAccentCode());
823          }
824          cursor->Delete();
825          if (l || MathMacroTable::mathMTable.getMacro(macrobf)) {
826             Interpret(macrobf);
827          }
828       }
829       imacro = 0;
830    }  
831 }
832
833
834 void MathedCursor::MacroModeBack()
835 {
836    if (macro_mode) {
837      if (macroln>0) {
838         macrobf[--macroln] = '\0';
839         imacro->Metrics();
840      } else 
841         MacroModeClose();
842    } else
843            lyxerr << "Mathed Warning: we are not in macro mode" << endl;
844 }
845
846
847 void MathedCursor::MacroModeInsert(char c)
848 {
849    if (macro_mode) {
850       macrobf[macroln + 1] = macrobf[macroln];
851       macrobf[macroln++] = c;
852       imacro->Metrics();
853    } else
854            lyxerr << "Mathed Warning: we are not in macro mode" << endl;
855 }
856
857
858 void MathedCursor::SelCopy()
859 {
860     if (selection) {
861         int p1 = (cursor->pos < selpos) ? cursor->pos: selpos;
862         int p2 = (cursor->pos > selpos) ? cursor->pos: selpos;
863         selarray = cursor->Copy(p1, p2);
864         cursor->Adjust();
865         SelClear();
866     }
867 }
868
869
870 void MathedCursor::SelCut()
871 {   
872     if (selection) {
873         if (cursor->pos == selpos) return;
874         
875         int p1 = (cursor->pos < selpos) ? cursor->pos: selpos;
876         int p2 = (cursor->pos > selpos) ? cursor->pos: selpos;
877         selarray = cursor->Copy(p1, p2);
878         cursor->Clean(selpos);
879         cursor->Adjust();
880         SelClear();
881     }
882 }
883
884
885 void MathedCursor::SelDel()
886 {
887 //    lyxerr << "Deleting sel "
888     if (selection) {    
889         if (cursor->pos == selpos) return;
890         cursor->Clean(selpos);
891         cursor->Adjust();
892         SelClear();
893     }
894 }
895
896
897 void MathedCursor::SelPaste()
898 {
899 //    lyxerr << "paste " << selarray << " " << curor->pos;
900     if (selection) SelDel();
901     if (selarray) {
902         cursor->Merge(selarray);
903         cursor->Adjust();
904     }
905 }
906
907
908 void MathedCursor::SelStart()
909 {
910         lyxerr[Debug::MATHED] << "Starting sel " << endl;
911     if (!anchor) {
912         selpos = cursor->pos;   
913         selstk = new MathStackXIter(mathstk); 
914         anchor = selstk->Item(-1); 
915         anchor->SetData(cursor->p);
916         anchor->GoBegin();
917         anchor->goPosAbs(selpos);
918         selection = true;
919         
920     }
921 }
922
923
924 void MathedCursor::SelClear()
925 {   
926         lyxerr[Debug::MATHED] << "Clearing sel " << endl;
927     selection = false;
928     delete selstk;
929     selstk = 0;
930     anchor = 0;
931 }
932
933
934
935 // Anchor position must be at the same level that stack.
936 void MathedCursor::SelBalance()
937 {
938     int d = mathstk.Level() - selstk->Level();
939
940     // If unbalanced, balance them
941     while (d != 0) {
942         if (d < 0) {
943 //            lyxerr << "b[" << mathstk.Level() << " " << selstk->Level << " " << anchor->GetX() << " " << cursor->GetX() << "]";
944             anchor = selstk->pop();
945             if (anchor->GetX() >= cursor->GetX()) 
946               anchor->Next();
947         } else {
948 //            lyxerr <<"a[" << mathstk.Level() << " " << selstk->Level() <<"]";
949             Pop();
950         }
951         d = mathstk.Level() - selstk->Level();
952     }
953
954     // Once balanced the levels, check that they are at the same paragraph
955     selpos = anchor->pos;
956
957
958
959 #ifdef USE_PAINTER
960 void MathedCursor::SelGetArea(int * xp, int * yp, int & np)
961 {   
962     if (!selection) {
963         np = 0;
964         return;
965     }
966
967     static int xpoint[10];
968     static int ypoint[10];
969     
970     // single row selection
971     int i = 0, x, y, a, d, xo, yo, x1, y1, a1, d1;
972
973     // Balance anchor and cursor
974     SelBalance();
975  
976     cursor->p->GetXY(xo, yo);
977     int w = cursor->p->Width();
978     cursor->GetPos(x1, y1);
979     cursor->getAD(a1, d1);
980     anchor->GetPos(x, y);
981     anchor->getAD(a, d);
982
983     xpoint[i] = x;
984     ypoint[i++] = y + d;
985     xpoint[i] = x;
986     ypoint[i++] = y - a;
987     
988     if (y != y1) {
989             xpoint[i] = xo + w;
990             ypoint[i++] = y - a;
991
992             if (x1 < xo + w) {
993                     xpoint[i] = xo + w;
994                     ypoint[i++] = y1 - a;
995             }
996     }
997
998     xpoint[i] = x1;
999     ypoint[i++] = y1 - a;
1000     xpoint[i] = x1;
1001     ypoint[i++] = y1 + d;
1002     
1003     if (y != y1) {
1004             xpoint[i] = xo;
1005             ypoint[i++] = y1 + d;
1006             if (x > xo) {
1007                     xpoint[i] = xo;
1008                     ypoint[i++] = y + d;
1009             }
1010     }
1011     xpoint[i] = xpoint[0];
1012     ypoint[i++] = ypoint[0];
1013
1014     xp = &xpoint[0];
1015     yp = &ypoint[0];
1016     np = i;
1017 //    lyxerr << "AN[" << x << " " << y << " " << x1 << " " << y1 << "] ";
1018 //    lyxerr << "MT[" << a << " " << d << " " << a1 << " " << d1 << "] ";
1019 //    for (i = 0; i < np; ++i)
1020 //      lyxerr << "XY[" << point[i].x << " " << point[i].y << "] ";
1021     
1022 }
1023 #else
1024 XPoint * MathedCursor::SelGetArea(int & np)
1025 {   
1026     if (!selection) {
1027         np = 0;
1028         return 0;
1029     }
1030     
1031     static XPoint point[10];
1032     
1033     // single row selection
1034     int i = 0, x, y, a, d, xo, yo, x1, y1, a1, d1; //, p1, p2;
1035
1036     // Balance anchor and cursor
1037     SelBalance();
1038  
1039     cursor->p->GetXY(xo, yo);
1040     int w = cursor->p->Width();
1041     cursor->GetPos(x1, y1);
1042     cursor->getAD(a1, d1);
1043     anchor->GetPos(x, y);
1044     anchor->getAD(a, d);
1045
1046     point[i].x = x;
1047     point[i++].y = y+d;
1048     point[i].x = x;
1049     point[i++].y = y-a;
1050     
1051     if (y != y1) {
1052         point[i].x = xo + w;
1053         point[i++].y = y - a;
1054         if (x1 < xo + w) {
1055             point[i].x = xo + w;
1056             point[i++].y = y1 - a;
1057         }
1058     }
1059         
1060     point[i].x = x1;
1061     point[i++].y = y1 - a;
1062     point[i].x = x1;
1063     point[i++].y = y1 + d;
1064     
1065     if (y != y1) {
1066         point[i].x = xo;
1067         point[i++].y = y1 + d;
1068         if (x > xo) {
1069             point[i].x = xo;
1070             point[i++].y = y + d;
1071         }
1072     }
1073     point[i].x = point[0].x;
1074     point[i++].y = point[0].y;
1075     np = i;
1076 //    lyxerr << "AN[" << x << " " << y << " " << x1 << " " << y1 << "] ";
1077 //    lyxerr << "MT[" << a << " " << d << " " << a1 << " " << d1 << "] ";
1078 //    for (i = 0; i < np; ++i)
1079 //      lyxerr << "XY[" << point[i].x << " " << point[i].y << "] ";
1080     
1081     return &point[0];
1082 }
1083 #endif
1084
1085
1086 void MathedCursor::setAccent(int ac)
1087 {
1088         if (ac > 0 && accent < 8) {
1089                 nestaccent[accent++] = ac;
1090         } else
1091           accent = 0;  // consumed!
1092 }
1093
1094  
1095 int MathedCursor::getAccent() const
1096 {
1097         return (accent > 0) ? nestaccent[accent - 1]: 0;
1098 }
1099
1100
1101 void MathedCursor::doAccent(byte c, MathedTextCodes t)
1102 {
1103         MathedInset * ac = 0;
1104         
1105         for (int i = accent - 1; i >= 0; --i) {
1106                 if (i == accent - 1)
1107                   ac = new MathAccentInset(c, t, nestaccent[i]);
1108                 else 
1109                   ac = new MathAccentInset(ac, nestaccent[i]);
1110         }
1111         if (ac) 
1112           cursor->Insert(ac);
1113         
1114         accent = 0;  // consumed!
1115 }
1116
1117
1118 void MathedCursor::doAccent(MathedInset * p)
1119 {
1120         MathedInset * ac = 0;
1121         
1122         for (int i = accent - 1; i >= 0; --i) {
1123                 if (i == accent - 1)
1124                   ac = new MathAccentInset(p, nestaccent[i]);
1125                 else 
1126                   ac = new MathAccentInset(ac, nestaccent[i]);
1127         }
1128         if (ac) 
1129           cursor->Insert(ac);
1130         
1131         accent = 0;  // consumed!
1132 }
1133