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