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