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