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