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