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