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