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