]> git.lyx.org Git - lyx.git/blob - src/mathed/math_cursor.C
LyX Drinkers United: patch 2
[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, Math & 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
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_grid.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 "math_sqrtinset.h"
46 #include "math_scriptinset.h"
47 #include "mathed/support.h"
48 #include "formulabase.h"
49
50
51 using std::endl;
52 using std::min;
53 using std::max;
54
55
56 namespace {
57
58 MathArray selarray;
59
60 bool IsMacro(short tok, int id)
61 {
62         return tok != LM_TK_STACK &&
63                tok != LM_TK_FRAC &&
64                tok != LM_TK_SQRT &&
65                tok != LM_TK_WIDE &&
66                tok != LM_TK_SPACE &&
67                tok != LM_TK_DOTS &&
68                tok != LM_TK_FUNCLIM &&
69                tok != LM_TK_BIGSYM &&
70                tok != LM_TK_ACCENT &&
71                !(tok == LM_TK_SYM && id < 255);
72 }
73
74 }
75
76 MathCursor::MathCursor(InsetFormulaBase * formula)
77         : formula_(formula)
78 {
79         accent     = 0;
80         lastcode   = LM_TC_MIN;
81         macro_mode = false;
82         first();
83 }
84
85
86 void MathCursor::push(MathInset * par, bool first)
87 {
88         path_.push_back(MathIter());
89         path_.back().par_    = par_;
90         path_.back().idx_    = idx_;
91         path_.back().cursor_ = cursor_;
92         dump("Pushed:");
93         par_ = par;
94         first ? par_->idxFirst(idx_, cursor_) : par_->idxLast(idx_, cursor_);
95 }
96
97
98 bool MathCursor::pop()
99 {
100         if (path_.empty())
101                 return false;
102         par_    = path_.back().par_;
103         idx_    = path_.back().idx_;
104         cursor_ = path_.back().cursor_;
105         dump("Popped:");
106         path_.pop_back();
107         return true;
108 }
109
110
111 MathInset * MathCursor::parInset(int i) const
112 {
113         return path_[i].par_;
114 }
115
116 void MathCursor::dump(char const * what) const
117 {
118         lyxerr << "MC: " << what
119                 << " cursor: " << cursor_
120                 << " anchor: " << anchor_
121                 << " idx: " << idx_
122                 << " par: " << par_
123                 << " sel: " << selection
124                 << " data: " << array()
125                 << "\n";
126 }
127
128 void MathCursor::seldump(char const * str) const
129 {
130         lyxerr << "SEL: " << str << ": '" << selarray << "'\n";
131         dump("   Pos");
132         return;
133
134         lyxerr << "\n\n\\n=================vvvvvvvvvvvvv=======================   "
135                 <<  str << "\nselarray: " << selarray;
136         for (unsigned int i = 0; i < path_.size(); ++i) 
137                 lyxerr << path_[i].par_ << "\n'" << path_[i].par_->cell(0) << "'\n";
138         lyxerr << "\ncursor: " << cursor_;
139         lyxerr << "\nanchor: " << anchor_;
140         lyxerr << "\n===================^^^^^^^^^^^^=====================\n\n\n";
141 }
142
143
144 bool MathCursor::isInside(MathInset * p) const
145 {
146         for (unsigned i = 0; i < path_.size(); ++i) 
147                 if (parInset(i) == p) 
148                         return true;
149         return par_ == p;
150 }
151
152
153 bool MathCursor::Left(bool sel)
154 {
155         dump("Left 1");
156         if (macro_mode) {
157                 // was MacroModeBack()
158                 if (!imacro->name().empty()) {
159                         imacro->SetName(imacro->name().substr(0, imacro->name().length()-1));
160                         imacro->Metrics(imacro->size());
161                 } else
162                         MacroModeClose();
163                 return true;
164         }
165         clearLastCode();
166         SelHandle(sel);
167
168         bool result = false;
169
170         if (selection) {
171                 result = array().prev(cursor_);
172                 if (!result && pop()) {
173                         anchor_ = cursor_;
174                         result = array().next(anchor_);
175                 }
176         } else {
177                 MathInset * p = prevActiveInset();
178                 if (p) {
179                         // We have to move deeper into the previous inset
180                         array().prev(cursor_);
181                         push(p, false);
182                         result = true;
183                 } else {
184                         // The common case, where we are not 
185                         // entering a deeper inset
186                         result = array().prev(cursor_);
187                         if (!result) {
188                                 if (par_->idxLeft(idx_, cursor_)) {
189                                         result = true;
190                                 } else if (pop()) {
191                                         result = true;
192                                 }
193                         }
194                 }
195         }
196         dump("Left 2");
197         return result;
198 }
199
200
201 bool MathCursor::plainRight()
202 {
203         return array().next(cursor_);
204 }
205
206
207 bool MathCursor::Right(bool sel)
208 {
209         dump("Right 1");
210         if (macro_mode) {
211                 MacroModeClose();
212                 return true;
213         }
214
215         clearLastCode();
216         SelHandle(sel);
217
218         bool result = false;
219
220         if (selection) {
221                 result = array().next(cursor_);
222                 if (!result && pop()) {
223                         anchor_ = cursor_;
224                         result = array().next(cursor_);
225                 }
226         } else {
227                 MathInset * p = nextActiveInset();
228                 if (p) {
229                         push(p, true);
230                         result = true;
231                 } else {
232                         result = array().next(cursor_);
233                         if (!result) {
234                                 if (par_->idxRight(idx_, cursor_)) {
235                                         result = true;
236                                 } else if (pop()) {
237                                         result = true;
238                                         array().next(cursor_);
239                                 }
240                         }
241                 }
242         }
243         dump("Right 2");
244         return result;
245 }
246
247
248 void MathCursor::first()
249 {
250         selection  = false;
251         par_       = formula_->par();
252         idx_       = 0;
253         cursor_    = 0;
254         anchor_    = 0;
255         par_->idxFirst(idx_, cursor_);
256 }
257
258
259 void MathCursor::last()
260 {
261         selection  = false;
262         par_       = formula_->par();
263         idx_       = 0;
264         cursor_    = 0;
265         anchor_    = 0;
266         par_->idxLast(idx_, cursor_);
267 }
268
269
270 void MathCursor::SetPos(int x, int y)
271 {
272         dump("SetPos 1");
273         lyxerr << "MathCursor::SetPos x: " << x << " y: " << y << "\n";
274
275         MacroModeClose();
276         lastcode = LM_TC_MIN;
277         path_.clear();
278
279         par_    = formula()->par();
280
281         while (1) {
282                 idx_    = -1;
283                 cursor_ = -1;
284                 int distmin = 1 << 30; // large enough
285                 for (int i = 0; i < par_->nargs(); ++i) {
286                         MathXArray const & ar = par_->xcell(i);
287                         int x1 = x - ar.xo();
288                         int y1 = y - ar.yo();
289                         int c  = ar.x2pos(x1);
290                         int xx = abs(x1 - ar.pos2x(c));
291                         int yy = abs(y1);
292                         //lyxerr << "idx: " << i << " xx: " << xx << " yy: " << yy
293                         //      << " c: " << c  << " xo: " << ar.xo() << "\n";
294                         if (yy + xx <= distmin) {
295                                 distmin = yy + xx;
296                                 idx_     = i;
297                                 cursor_  = c;
298                         }
299                 }
300                 lyxerr << "found idx: " << idx_ << " cursor: " << cursor_  << "\n";
301                 if (nextIsActive() && nextInset()->covers(x, y)) {
302                         MathInset * p = nextActiveInset();
303                         push(p, true);
304                 } else if (prevIsActive() && prevInset()->covers(x, y)) {
305                         MathInset * p = prevActiveInset();
306                         array().prev(cursor_);
307                         push(p, false);
308                 } else 
309                         break;
310         }
311         dump("SetPos 2");
312 }
313
314
315 void MathCursor::Home()
316 {
317         dump("Home 1");
318         if (macro_mode)
319                 MacroModeClose();
320         clearLastCode();
321         if (!par_->idxHome(idx_, cursor_)) {
322                 pop();
323         }
324         dump("Home 2");
325 }
326
327
328 void MathCursor::End()
329 {
330         dump("End 1");
331         if (macro_mode)
332                 MacroModeClose();
333         clearLastCode();
334         if (!par_->idxEnd(idx_, cursor_)) {
335                 pop();
336                 array().next(cursor_);
337         }
338         dump("End 2");
339 }
340
341
342
343 void MathCursor::insert(char c, MathTextCodes t)
344 {
345         lyxerr << "inserting '" << c << "'\n";
346         if (selection)
347                 SelDel();
348
349         if (t == LM_TC_MIN)
350                 t = lastcode;
351
352         if (macro_mode && !(MathIsAlphaFont(t) || t == LM_TC_MIN))
353                 MacroModeClose();
354
355         if (macro_mode) {
356                 if (MathIsAlphaFont(t) || t == LM_TC_MIN) {
357                         // was MacroModeinsert(c);
358                         imacro->SetName(imacro->name() + static_cast<char>(c));
359                         return;
360                 }
361         }
362
363         if (accent)
364                 doAccent(c, t);
365         else {
366                 array().insert(cursor_, c, t);
367                 array().next(cursor_);
368         }
369
370         lastcode = t;
371         return;
372 }
373
374
375 void MathCursor::insert(MathInset * p)
376 {
377         MacroModeClose();
378
379         if (selection) {
380                 if (p->nargs())
381                         SelCut();
382                 else
383                         SelDel();
384         }
385
386         if (accent && !p->nargs())
387                 doAccent(p);
388         else {
389                 array().insert(cursor_, p);
390                 array().next(cursor_);
391         }
392
393         //if (p->nargs()) 
394         //      push(p, true);
395 }
396
397
398 void MathCursor::Delete()
399 {
400         dump("Delete 1");
401         if (macro_mode)
402                 return;
403
404         if (selection) {
405                 SelDel();
406                 return;
407         }
408
409         if (cursor_ < array().size())
410                 array().erase(cursor_);
411
412         // delete empty cells parts if necessary
413         if (cursor_ == 0 && array().size() == 0) {
414                 bool removeit = par_->idxDelete(idx_);
415                 if (pop() && removeit)
416                                 Delete();
417         }
418
419 #ifdef WITH_WARNINGS
420 #warning pullArg disabled
421 #endif
422         //if (cursor_ == 0 && !path_.empty()) {
423         //      lyxerr << "Delete: popping...\n";
424         //      pop();
425         //}
426
427         dump("Delete 2");
428 }
429
430
431 void MathCursor::DelLine()
432 {
433         MacroModeClose();
434
435         if (selection) {
436                 SelDel();
437                 return;
438         }
439
440         if (par_->nrows() > 1)
441                 par_->delRow(row());
442 }
443
444
445 bool MathCursor::Up(bool sel)
446 {
447         dump("Up 1");
448         MacroModeClose();
449         SelHandle(sel);
450         SelClear();
451
452         // check whether we could move into an inset on the right or on the left
453         MathInset * p = nextInset();
454         if (p) {
455                 int idx, cursor;
456                 if (p->idxFirstUp(idx, cursor)) {
457                         push(p, true);
458                         par_ = p;
459                         idx_    = idx;
460                         cursor_ = cursor;
461                         dump("Up 3");
462                         return true;
463                 }
464         }
465
466         p = prevInset();
467         if (p) {
468                 int idx, cursor;
469                 if (p->idxLastUp(idx, cursor)) {
470                         array().prev(cursor_);
471                         push(p, false);
472                         par_ = p;
473                         idx_    = idx;
474                         cursor_ = cursor;
475                         dump("Up 4");
476                         return true;
477                 }
478         }
479
480
481         int x = xarray().pos2x(cursor_);
482         bool result = par_->idxUp(idx_, cursor_);
483         if (!result && pop()) {
484                 result = par_->idxUp(idx_, cursor_);
485         }
486         cursor_ = xarray().x2pos(x);
487
488         dump("Up 2");
489         return result;
490 }
491
492
493 bool MathCursor::Down(bool sel)
494 {
495         dump("Down 1");
496         MacroModeClose();
497         SelHandle(sel);
498         SelClear();
499
500         // check whether we could move into an inset on the right or on the left
501         MathInset * p = nextInset();
502         if (p) {
503                 int idx, cursor;
504                 if (p->idxFirstDown(idx, cursor)) {
505                         push(p, true);
506                         idx_    = idx;
507                         cursor_ = cursor;
508                         dump("Down 3");
509                         return true;
510                 }
511         }
512
513         p = prevInset();
514         if (p) {
515                 int idx, cursor;
516                 if (p->idxLastDown(idx, cursor)) {
517                         array().prev(cursor_);
518                         push(p, false);
519                         idx_    = idx;
520                         cursor_ = cursor;
521                         dump("Down 4");
522                         return true;
523                 }
524         }
525
526         int x = xarray().pos2x(cursor_);
527         bool result = par_->idxDown(idx_, cursor_);
528         if (!result && pop()) {
529                 result = par_->idxDown(idx_, cursor_);
530         }
531         cursor_ = xarray().x2pos(x);
532
533         dump("Down 2");
534         return result;
535 }
536
537
538 bool MathCursor::toggleLimits()
539 {
540         if (!prevIsInset())
541                 return false;
542         MathInset * p = prevInset();
543         int old = p->limits();
544         p->limits(old == -1 ? 1 : -1);
545         return old != p->limits();
546 }
547
548
549 void MathCursor::SetSize(MathStyles size)
550 {
551         par_->UserSetSize(size);
552 }
553
554
555
556 void MathCursor::Interpret(string const & s)
557 {
558         lyxerr << "Interpret: '" << s << "'\n";
559
560         if (s[0] == '^') {
561                 MathScriptInset * p = nearbyScriptInset();
562                 if (!p) {
563                         p = new MathScriptInset;
564                         insert(p);
565                         array().prev(cursor_);
566                 }
567                 push(p, true);
568                 if (!p->up())
569                         p->up(true);
570                 idx_ = 0;
571                 return;
572         }
573
574         if (s[0] == '_') {
575                 MathScriptInset * p = nearbyScriptInset();
576                 if (!p) {
577                         p = new MathScriptInset;
578                         insert(p);
579                         array().prev(cursor_);
580                 }
581                 push(p, true);
582                 if (!p->down())
583                         p->down(true);
584                 idx_ = 1;
585                 return;
586         }
587
588         if (s[0] == '!' || s[0] == ','  || s[0] == ':' || s[0] == ';') {
589                 int sp = (s[0] == ',') ? 1:((s[0] == ':') ? 2:((s[0] == ';') ? 3: 0));
590                 insert(new MathSpaceInset(sp));
591                 return;
592         }
593
594         MathInset * p = 0;
595         latexkeys const * l = in_word_set(s);
596
597         if (l == 0) {
598                 if (s == "root") 
599                         p = new MathRootInset;
600                 else if (MathMacroTable::hasTemplate(s))
601                         p = new MathMacro(MathMacroTable::provideTemplate(s));
602                 else
603                         p = new MathFuncInset(s, LM_OT_UNDEF);
604         } else {
605                 switch (l->token) {
606                         case LM_TK_BIGSYM: 
607                                         p = new MathBigopInset(l->name, l->id);
608                                         break;
609                                 
610                         case LM_TK_SYM: 
611                                 if (l->id < 255) {
612                                         insert(static_cast<byte>(l->id), 
613                                                MathIsBOPS(l->id) ?
614                                                 LM_TC_BOPS : LM_TC_SYMB);
615                                         
616                                 } else {
617                                         p = new MathFuncInset(l->name);
618                                 }
619                                 break;
620
621                         case LM_TK_STACK:
622                                 p = new MathFracInset(LM_OT_STACKREL);
623                                 break;
624
625                         case LM_TK_FRAC:
626                                 p = new MathFracInset(LM_OT_FRAC);
627                                 break;
628
629                         case LM_TK_SQRT:
630                                 p = new MathSqrtInset;
631                                 break;
632
633                         case LM_TK_WIDE:
634                                 p = new MathDecorationInset(l->id);
635                                 break;
636
637                         case  LM_TK_FUNCLIM:
638                                 p = new MathFuncInset(l->name, LM_OT_FUNCLIM);
639                                 break;
640
641                         case LM_TK_SPACE:
642                                 p = new MathSpaceInset(l->id);
643                                 break;
644
645                         case LM_TK_DOTS:
646                                 p = new MathDotsInset(l->name, l->id);
647                                 break;
648
649                         case LM_TK_ACCENT:
650                                 setAccent(l->id);
651                                 break;
652
653                         case LM_TK_MACRO:
654                                 p = new MathMacro(MathMacroTable::provideTemplate(s));
655                                 break;
656
657                         default:
658                                 p = new MathFuncInset(l->name);
659                                 break;
660                 }
661         }
662
663         if (p) {
664                 insert(p);
665                 if (p->nargs()) {
666                         array().prev(cursor_);
667                         push(p, true);
668                 }
669                 p->Metrics(p->size());
670         }
671 }
672
673
674 void MathCursor::MacroModeOpen()
675 {
676         if (!macro_mode) {
677                 imacro = new MathFuncInset("");
678                 insert(imacro);
679                 macro_mode = true;
680         } else
681                 lyxerr << "Math Warning: Already in macro mode" << endl;
682 }
683
684
685 void MathCursor::MacroModeClose()
686 {
687         if (macro_mode)  {
688                 macro_mode = false;
689                 latexkeys const * l = in_word_set(imacro->name());
690                 if (!imacro->name().empty()
691                                 && (!l || (l && IsMacro(l->token, l->id)))
692                                 && !MathMacroTable::hasTemplate(imacro->name()))
693                 {
694                         if (!l) {
695                                 //imacro->SetName(macrobf);
696                                 // This guarantees that the string will be removed by destructor
697                                 imacro->SetType(LM_OT_UNDEF);
698                         } else
699                                 imacro->SetName(l->name);
700                 } else {
701                         Left();
702                         if (nextInset()->GetType() == LM_OT_ACCENT) 
703                                 setAccent(
704                                         static_cast<MathAccentInset*>(nextInset())->getAccentCode());
705                         array().erase(cursor_);
706                         if (l || MathMacroTable::hasTemplate(imacro->name())) 
707                                 Interpret(imacro->name());
708                         imacro->SetName(string());
709                 }
710                 imacro = 0;
711         }
712 }
713
714
715 void MathCursor::SelCopy()
716 {
717         seldump("SelCopy");
718         if (selection) {
719                 int const p1 = min(cursor_, anchor_);
720                 int const p2 = max(cursor_, anchor_);
721                 selarray = array();
722                 selarray.erase(p2, selarray.size());
723                 selarray.erase(0, p1);
724                 SelClear();
725         }
726 }
727
728 void MathCursor::selArray(MathArray & ar) const
729 {
730         int const p1 = min(cursor_, anchor_);
731         int const p2 = max(cursor_, anchor_);
732         ar = array();
733         ar.erase(p2, ar.size());
734         ar.erase(0, p1);
735 }
736
737
738 void MathCursor::SelCut()
739 {
740         seldump("SelCut");
741         if (selection) {
742                 int const p1 = min(cursor_, anchor_);
743                 int const p2 = max(cursor_, anchor_);
744                 cursor_ = p1;  // move cursor to a same position
745                 selarray = array();
746                 selarray.erase(p2, selarray.size());
747                 selarray.erase(0, p1);
748                 array().erase(p1, p2);
749                 SelClear();
750         }
751 }
752
753
754 void MathCursor::SelDel()
755 {
756         seldump("SelDel");
757         if (selection) {
758                 int const p1 = min(cursor_, anchor_);
759                 int const p2 = max(cursor_, anchor_);
760                 array().erase(p1, p2);
761                 SelClear();
762         }
763 }
764
765
766 void MathCursor::SelPaste()
767 {
768         seldump("SelPaste");
769         array().insert(cursor_, selarray);
770         cursor_ += selarray.size();
771         SelClear();
772 }
773
774 void MathCursor::SelHandle(bool sel)
775 {
776         if (sel && !selection)
777                 SelStart();
778         if (!sel && selection)
779                 SelClear();
780 }
781
782
783 void MathCursor::SelStart()
784 {
785         seldump("SelStart");
786         if (selection)
787                 return;
788
789         anchor_   = cursor_;
790         selection = true;
791 }
792
793
794 void MathCursor::SelClear()
795 {
796         selection = false;
797 }
798
799
800
801 void MathCursor::SelGetArea(int * xpoint, int * ypoint, int & n)
802 {
803         if (!selection) {
804                 n = 0;
805                 xpoint[0] = 0;
806                 ypoint[0] = 0;
807                 return;
808         }
809
810         // Balance anchor and cursor
811         int xo;
812         int yo;
813         par()->GetXY(xo, yo);
814         int w = par()->width();
815         // cursor
816         int x1 = xarray().xo() + xarray().pos2x(cursor_);
817         int y1 = xarray().yo();
818         //int a1 = xarray().ascent();
819         //int d1 = xarray().descent();
820
821         // anchor
822         int x  = xarray().xo() + xarray().pos2x(anchor_);
823         int y  = xarray().yo();
824         int a  = xarray().ascent();
825         int d  = xarray().descent();
826
827         // single row selection
828         n = 0;
829         xpoint[n]   = x;
830         ypoint[n++] = y + d;
831         xpoint[n]   = x;
832         ypoint[n++] = y - a;
833
834         if (y != y1) {
835                 xpoint[n]   = xo + w;
836                 ypoint[n++] = y - a;
837
838                 if (x1 < xo + w) {
839                         xpoint[n]   = xo + w;
840                         ypoint[n++] = y1 - a;
841                 }
842         }
843
844         xpoint[n]   = x1;
845         ypoint[n++] = y1 - a;
846         xpoint[n]   = x1;
847         ypoint[n++] = y1 + d;
848
849         if (y != y1) {
850                 xpoint[n]   = xo;
851                 ypoint[n++] = y1 + d;
852                 if (x > xo) {
853                         xpoint[n]   = xo;
854                         ypoint[n++] = y + d;
855                 }
856         }
857         xpoint[n]   = xpoint[0];
858         ypoint[n++] = ypoint[0];
859
860         //lyxerr << "AN[" << x << " " << y << " " << x1 << " " << y1 << "]\n";
861         //lyxerr << "MT[" << a << " " << d << " " << a1 << " " << d1 << "]\n";
862         //for (i = 0; i < np; ++i)
863         //      lyxerr << "XY[" << xpoint[i] << " " << ypoint[i] << "]\n";
864 }
865
866
867 void MathCursor::setAccent(int ac)
868 {
869         if (ac > 0 && accent < 8)
870                 nestaccent[accent++] = ac;
871         else
872                 accent = 0;  // consumed!
873 }
874
875
876 int MathCursor::getAccent() const
877 {
878         return accent > 0 ? nestaccent[accent - 1] : 0;
879 }
880
881
882 void MathCursor::doAccent(char c, MathTextCodes t)
883 {
884         MathInset * ac = 0;
885
886         for (int i = accent - 1; i >= 0; --i) {
887                 if (i == accent - 1)
888                         ac = new MathAccentInset(c, t, nestaccent[i]);
889                 else
890                         ac = new MathAccentInset(ac, nestaccent[i]);
891         }
892         
893         if (ac)
894                 insert(ac);
895
896         accent = 0;  // consumed!
897 }
898
899
900 void MathCursor::doAccent(MathInset * p)
901 {
902         MathInset * ac = 0;
903
904         for (int i = accent - 1; i >= 0; --i) {
905                 if (i == accent - 1)
906                         ac = new MathAccentInset(p, nestaccent[i]);
907                 else
908                         ac = new MathAccentInset(ac, nestaccent[i]);
909         }
910
911         if (ac)
912                 insert(ac);
913
914         accent = 0;  // consumed!
915 }
916
917
918 void MathCursor::toggleLastCode(MathTextCodes t)
919 {
920         if (lastcode == t)
921                 lastcode = LM_TC_VAR;
922         else
923                 lastcode = t;
924 }
925
926
927 void MathCursor::GetPos(int & x, int & y)
928 {
929         x = xarray().xo() + xarray().pos2x(cursor_);
930         y = xarray().yo();
931 }
932
933
934 MathTextCodes MathCursor::nextCode() const
935 {
936         return array().GetCode(cursor_); 
937 }
938
939
940 MathTextCodes MathCursor::prevCode() const
941 {
942         return array().GetCode(cursor_ - 1); 
943 }
944
945
946 MathInset * MathCursor::par() const
947 {
948         return par_;
949 }
950
951
952 InsetFormulaBase const * MathCursor::formula()
953 {
954         return formula_;
955 }
956
957
958 int MathCursor::pos() const
959 {
960         return cursor_;
961 }
962
963
964 bool MathCursor::InMacroMode() const
965 {
966         return macro_mode;
967 }
968
969
970 bool MathCursor::Selection() const
971 {
972         return selection;
973 }
974
975
976 void MathCursor::clearLastCode()
977 {
978         lastcode = LM_TC_MIN;
979 }
980
981
982 void MathCursor::setLastCode(MathTextCodes t)
983 {
984         lastcode = t;
985 }
986
987
988 MathTextCodes MathCursor::getLastCode() const
989 {
990         return lastcode;
991 }
992
993
994 MathInset * MathCursor::enclosing(MathInsetTypes t, int & idx) const
995 {
996         if (par_->GetType() == t) {
997                 lyxerr << "enclosing par is current\n";
998                 idx = idx_;
999                 return par_;
1000         }
1001         for (int i = path_.size() - 1; i >= 0; --i) {
1002                 lyxerr << "checking level " << i << "\n";
1003                 if (path_[i].par_->GetType() == t) {
1004                         idx = path_[i].idx_;
1005                         return path_[i].par_;
1006                 }
1007         }
1008         return 0;
1009 }
1010
1011 void MathCursor::pullArg()
1012 {
1013         // pullArg
1014         MathArray a = array();
1015         if (!Left())
1016                 return;
1017         normalize();
1018         array().erase(cursor_);
1019         array().insert(cursor_, a);
1020 }
1021
1022
1023 MathStyles MathCursor::style() const
1024 {
1025         return xarray().style();
1026 }
1027
1028
1029 void MathCursor::normalize() const
1030 {
1031 #ifdef WITH_WARNINGS
1032 #warning This is evil!
1033 #endif
1034         MathCursor * it = const_cast<MathCursor *>(this);
1035
1036         if (idx_ < 0 || idx_ > par_->nargs())
1037                 lyxerr << "this should not really happen - 1\n";
1038         it->idx_    = max(idx_, 0);
1039         it->idx_    = min(idx_, par_->nargs());
1040
1041         if (cursor_ < 0 || cursor_ > array().size())
1042                 lyxerr << "this should not really happen - 2\n";
1043         it->cursor_ = max(cursor_, 0);
1044         it->cursor_ = min(cursor_, array().size());
1045 }
1046
1047
1048 int MathCursor::col() const
1049 {
1050         return par_->col(idx_);
1051 }
1052
1053
1054 int MathCursor::row() const
1055 {
1056         return par_->row(idx_);
1057 }
1058
1059
1060 /*
1061 char MathIter::GetChar() const
1062 {
1063         return array().GetChar(cursor_);
1064 }
1065
1066
1067 string MathIter::readString()
1068 {
1069         string s;
1070         int code = nextCode();
1071         for ( ; OK() && nextCode() == code; Next()) 
1072                 s += GetChar();
1073
1074         return s;
1075 }
1076 */
1077
1078 MathInset * MathCursor::prevInset() const
1079 {
1080         normalize();
1081         int c = cursor_;
1082         if (!array().prev(c))
1083                 return 0;
1084         return array().GetInset(c);
1085 }
1086
1087 MathInset * MathCursor::prevActiveInset() const
1088 {
1089         if (cursor_ <= 0 || !array().isInset(cursor_ - 1))
1090                 return 0;
1091         MathInset * inset = prevInset();
1092         return inset->isActive() ? inset : 0;
1093 }
1094
1095
1096 MathInset * MathCursor::nextInset() const
1097 {
1098         normalize();
1099         return array().GetInset(cursor_);
1100 }
1101
1102
1103 MathInset * MathCursor::nextActiveInset() const
1104 {
1105         if (!array().isInset(cursor_))
1106                 return 0;
1107         MathInset * inset = nextInset();
1108         return inset->isActive() ? inset : 0;
1109 }
1110
1111
1112 MathScriptInset * MathCursor::nearbyScriptInset() const
1113 {
1114         normalize();
1115         MathScriptInset * p = array().prevScriptInset(cursor_);
1116         if (p)
1117                 return p;
1118         return array().nextScriptInset(cursor_);
1119 }
1120
1121
1122
1123 MathArray & MathCursor::array() const
1124 {
1125         static MathArray dummy;
1126         if (!par_) {
1127                 lyxerr << "############  par_ not valid\n";
1128                 return dummy;
1129         }
1130
1131         if (idx_ < 0 || idx_ >= par_->nargs()) {
1132                 lyxerr << "############  idx_ " << idx_ << " not valid\n";
1133                 return dummy;
1134         }
1135
1136         return par_->cell(idx_);
1137 }
1138
1139
1140 MathXArray & MathCursor::xarray() const
1141 {
1142         return par_->xcell(idx_);
1143 }
1144
1145
1146
1147 bool MathCursor::nextIsInset() const
1148 {
1149         return cursor_ < array().size() && MathIsInset(nextCode());
1150 }
1151
1152
1153 bool MathCursor::nextIsActive() const
1154 {
1155         return nextIsInset() && nextInset()->isActive();
1156 }
1157
1158
1159 bool MathCursor::prevIsInset() const
1160 {
1161         return cursor_ > 0 && MathIsInset(prevCode());
1162 }
1163
1164
1165 bool MathCursor::prevIsActive() const
1166 {
1167         return prevIsInset() && prevInset()->isActive();
1168 }
1169
1170
1171 bool MathCursor::IsFont() const
1172 {
1173         return MathIsFont(nextCode());
1174 }
1175
1176
1177 bool MathCursor::IsScript() const
1178 {
1179         normalize();
1180         return MathIsScript(nextCode());
1181 }
1182
1183
1184 int MathCursor::xpos() const 
1185 {
1186         normalize();
1187         return xarray().pos2x(cursor_);
1188 }
1189
1190 void MathCursor::gotoX(int x)
1191 {
1192         cursor_ = xarray().x2pos(x);    
1193 }
1194
1195 void MathCursor::idxRight()
1196 {
1197         par_->idxRight(idx_, cursor_);
1198 }
1199
1200 char MathCursor::valign() const
1201 {
1202         int idx;
1203         MathGridInset * p =
1204                 static_cast<MathGridInset *>(enclosing(LM_OT_MATRIX, idx));
1205         return p ? p->valign() : 0;
1206 }
1207
1208 char MathCursor::halign() const
1209 {
1210         int idx;
1211         MathGridInset * p =
1212                 static_cast<MathGridInset *>(enclosing(LM_OT_MATRIX, idx));
1213         return p ? p->halign(idx % p->ncols()) : 0;
1214 }