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