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