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