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