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