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