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