]> git.lyx.org Git - lyx.git/blob - src/cursor.C
a bit of selection is back
[lyx.git] / src / cursor.C
1 /**
2  * \file cursor.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  * \author Alfredo Braunstein
8  * \author André Pönitz
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "buffer.h"
16 #include "BufferView.h"
17 #include "cursor.h"
18 #include "debug.h"
19 #include "dispatchresult.h"
20 #include "funcrequest.h"
21 #include "iterators.h"
22 #include "lfuns.h"
23 #include "lyxfunc.h" // only for setMessage()
24 #include "lyxrc.h"
25 #include "lyxrow.h"
26 #include "lyxtext.h"
27 #include "paragraph.h"
28
29 #include "insets/updatableinset.h"
30 #include "insets/insettabular.h"
31 #include "insets/insettext.h"
32
33 #include "mathed/math_data.h"
34 #include "mathed/math_hullinset.h"
35 #include "mathed/math_support.h"
36
37 #include "support/limited_stack.h"
38 #include "frontends/LyXView.h"
39
40 #include <boost/assert.hpp>
41
42 using std::string;
43 using std::vector;
44 using std::endl;
45 #ifndef CXX_GLOBAL_CSTD
46 using std::isalpha;
47 #endif
48 using std::min;
49 using std::swap;
50
51
52
53 // our own cut buffer
54 limited_stack<string> theCutBuffer;
55
56
57 LCursor::LCursor(BufferView & bv)
58         : cursor_(1), anchor_(1), bv_(&bv), current_(0),
59           cached_y_(0), x_target_(-1),
60           selection_(false), mark_(false)
61 {}
62
63
64 void LCursor::reset()
65 {
66         cursor_.clear();
67         anchor_.clear();
68         cursor_.push_back(CursorSlice());
69         anchor_.push_back(CursorSlice());
70         current_ = 0;
71         cached_y_ = 0;
72         clearTargetX();
73         selection_ = false;
74         mark_ = false;
75 }
76
77
78 DispatchResult LCursor::dispatch(FuncRequest const & cmd0)
79 {
80         lyxerr << "\nLCursor::dispatch: cmd: " << cmd0 << endl << *this << endl;
81         FuncRequest cmd = cmd0;
82         for (current_ = cursor_.size() - 1; current_ >= 1; --current_) {
83                 DispatchResult res = inset()->dispatch(*this, cmd);
84                 if (res.dispatched())
85                         return DispatchResult(true, true);
86
87                 // "Mutate" the request for semi-handled requests that need
88                 // additional handling in outer levels.
89                 switch (res.val()) {
90                         case FINISHED:
91                                 cmd = FuncRequest(LFUN_FINISHED_LEFT);
92                                 break;
93                         case FINISHED_RIGHT:
94                                 cmd = FuncRequest(LFUN_FINISHED_RIGHT);
95                                 break;
96                         case FINISHED_UP:
97                                 cmd = FuncRequest(LFUN_FINISHED_UP);
98                                 break;
99                         case FINISHED_DOWN:
100                                 cmd = FuncRequest(LFUN_FINISHED_DOWN);
101                                 break;
102                         default:
103                                 //lyxerr << "not handled on level " << current_
104                                 //      << " val: " << res.val() << endl;
105                                 break;
106                 }
107         }
108         BOOST_ASSERT(current_ == 0);
109         DispatchResult res = bv_->text()->dispatch(*this, cmd);
110         //lyxerr << "   result: " << res.val() << endl;
111         return res;
112 }
113
114
115 void LCursor::push(InsetBase * inset)
116 {
117         lyxerr << "LCursor::push()  inset: " << inset << endl;
118         cursor_.push_back(CursorSlice(inset));
119         anchor_.push_back(CursorSlice(inset));
120         ++current_;
121         updatePos();
122 }
123
124
125 void LCursor::pop(int depth)
126 {
127         while (int(cursor_.size()) > depth + 1)
128                 pop();
129         lyxerr << "LCursor::pop() result: " << *this << endl;
130 }
131
132
133 void LCursor::pop()
134 {
135         BOOST_ASSERT(cursor_.size() >= 1);
136         cursor_.pop_back();
137         anchor_.pop_back();
138         current_ = cursor_.size() - 1;
139 }
140
141
142 void LCursor::pushLeft(InsetBase * p)
143 {
144         BOOST_ASSERT(!cursor_.empty());
145         //lyxerr << "Entering inset " << t << " left" << endl;
146         push(p);
147         p->idxFirst(*this);
148 }
149
150
151 bool LCursor::popLeft()
152 {
153         BOOST_ASSERT(!cursor_.empty());
154         //lyxerr << "Leaving inset to the left" << endl;
155         if (depth() <= 1) {
156                 if (depth() == 1)
157                         inset()->notifyCursorLeaves(idx());
158                 return false;
159         }
160         inset()->notifyCursorLeaves(idx());
161         pop();
162         return true;
163 }
164
165
166 bool LCursor::popRight()
167 {
168         BOOST_ASSERT(!cursor_.empty());
169         //lyxerr << "Leaving inset to the right" << endl;
170         if (depth() <= 1) {
171                 if (depth() == 1)
172                         inset()->notifyCursorLeaves(idx());
173                 return false;
174         }
175         inset()->notifyCursorLeaves(idx());
176         pop();
177         posRight();
178         return true;
179 }
180
181
182 CursorSlice & LCursor::current()
183 {
184         BOOST_ASSERT(!cursor_.empty());
185         //lyxerr << "accessing cursor slice " << current_
186         //      << ": " << cursor_[current_] << endl;
187         return cursor_[current_];
188 }
189
190
191 CursorSlice const & LCursor::current() const
192 {
193         //lyxerr << "accessing cursor slice " << current_
194         //      << ": " << cursor_[current_] << endl;
195         return cursor_[current_];
196 }
197
198
199 int LCursor::currentMode()
200 {
201         BOOST_ASSERT(!cursor_.empty());
202         for (int i = cursor_.size() - 1; i >= 1; --i) {
203                 int res = cursor_[i].inset()->currentMode();
204                 if (res != MathInset::UNDECIDED_MODE)
205                         return res;
206         }
207         return MathInset::TEXT_MODE;
208 }
209
210
211 LyXText * LCursor::innerText() const
212 {
213         BOOST_ASSERT(!cursor_.empty());
214         if (cursor_.size() > 1) {
215                 // go up until first non-0 text is hit
216                 // (innermost text is 0 in mathed)
217                 for (int i = cursor_.size() - 1; i >= 1; --i)
218                         if (cursor_[i].text())
219                                 return cursor_[i].text();
220         }
221         return bv_->text();
222 }
223
224
225 CursorSlice const & LCursor::innerTextSlice() const
226 {
227         BOOST_ASSERT(!cursor_.empty());
228         if (cursor_.size() > 1) {
229                 // go up until first non-0 text is hit
230                 // (innermost text is 0 in mathed)
231                 for (int i = cursor_.size() - 1; i >= 1; --i)
232                         if (cursor_[i].text())
233                                 return cursor_[i];
234         }
235         return cursor_[0];
236 }
237
238
239 void LCursor::updatePos()
240 {
241         BOOST_ASSERT(!cursor_.empty());
242         if (cursor_.size() > 1)
243                 cached_y_ = bv_->top_y() + cursor_.back().inset()->yo();
244                 //cached_y_ = cursor_.back().inset()->yo();
245 }
246
247
248 void LCursor::getDim(int & asc, int & des) const
249 {
250         BOOST_ASSERT(!cursor_.empty());
251         if (inMathed()) {
252                 BOOST_ASSERT(inset());
253                 BOOST_ASSERT(inset()->asMathInset());
254                 //inset()->asMathInset()->getCursorDim(asc, des);
255                 asc = 10;
256                 des = 10;
257         } else {
258                 Row const & row = *text()->cursorRow();
259                 asc = row.baseline();
260                 des = row.height() - asc;
261         }
262 }
263
264
265 void LCursor::getPos(int & x, int & y) const
266 {
267         BOOST_ASSERT(!cursor_.empty());
268         x = 0;
269         y = 0;
270         if (cursor_.size() == 1) {
271                 x = bv_->text()->cursorX(cursor_.front());
272                 y = bv_->text()->cursorY(cursor_.front());
273         } else {
274                 if (!inset()) {
275                         lyxerr << "#### LCursor::getPos: " << *this << endl;
276                         BOOST_ASSERT(inset());
277                 }
278                 inset()->getCursorPos(cursor_.back(), x, y);
279                 // getCursorPos gives _screen_ coordinates. We need to add
280                 // top_y to get document coordinates. This is hidden in cached_y_.
281                 //y += cached_y_ - inset()->yo();
282                 // The rest is non-obvious. The reason we have to have these
283                 // extra computation is that the getCursorPos() calls rely
284                 // on the inset's own knowledge of its screen position.
285                 // If we scroll up or down in a big enough increment,
286                 // inset->draw() is not called: this doesn't update
287                 // inset.yo_, so getCursor() returns an old value.
288                 // Ugly as you like.
289         }
290         //lyxerr << "#### LCursor::getPos: " << *this 
291         // << " x: " << x << " y: " << y << endl;
292 }
293
294
295 void LCursor::paste(string const & data)
296 {
297         dispatch(FuncRequest(LFUN_PASTE, data));
298 }
299
300
301 InsetBase * LCursor::innerInsetOfType(int code) const
302 {
303         for (int i = cursor_.size() - 1; i >= 1; --i)
304                 if (cursor_[i].inset_->lyxCode() == code)
305                         return cursor_[i].inset_;
306         return 0;
307 }
308
309
310 InsetTabular * LCursor::innerInsetTabular() const
311 {
312         return static_cast<InsetTabular *>(innerInsetOfType(InsetBase::TABULAR_CODE));
313 }
314
315
316 void LCursor::resetAnchor()
317 {
318         anchor_ = cursor_;
319 }
320
321
322 BufferView & LCursor::bv() const
323 {
324         return *bv_;
325 }
326
327
328 MathAtom const & LCursor::prevAtom() const
329 {
330         BOOST_ASSERT(pos() > 0);
331         return cell()[pos() - 1];
332 }
333
334
335 MathAtom & LCursor::prevAtom()
336 {
337         BOOST_ASSERT(pos() > 0);
338         return cell()[pos() - 1];
339 }
340
341
342 MathAtom const & LCursor::nextAtom() const
343 {
344         BOOST_ASSERT(pos() < lastpos());
345         return cell()[pos()];
346 }
347
348
349 MathAtom & LCursor::nextAtom()
350 {
351         BOOST_ASSERT(pos() < lastpos());
352         return cell()[pos()];
353 }
354
355
356 bool LCursor::posLeft()
357 {
358         if (pos() == 0)
359                 return false;
360         --pos();
361         return true;
362 }
363
364
365 bool LCursor::posRight()
366 {
367         if (pos() == lastpos())
368                 return false;
369         ++pos();
370         return true;
371 }
372
373
374 CursorSlice & LCursor::anchor()
375 {
376         return anchor_.back();
377 }
378
379
380 CursorSlice const & LCursor::anchor() const
381 {
382         return anchor_.back();
383 }
384
385
386 CursorSlice const & LCursor::selBegin() const
387 {
388         if (!selection())
389                 return cursor_.back();
390         // can't use std::min as this creates a new object
391         return anchor() < cursor_.back() ? anchor() : cursor_.back();
392 }
393
394
395 CursorSlice & LCursor::selBegin()
396 {
397         if (!selection())
398                 return cursor_.back();
399         return anchor() < cursor_.back() ? anchor() : cursor_.back();
400 }
401
402
403 CursorSlice const & LCursor::selEnd() const
404 {
405         if (!selection())
406                 return cursor_.back();
407         return anchor() > cursor_.back() ? anchor() : cursor_.back();
408 }
409
410
411 CursorSlice & LCursor::selEnd()
412 {
413         if (selection())
414                 return cursor_.back();
415         return anchor() > cursor_.back() ? anchor() : cursor_.back();
416 }
417
418
419 void LCursor::setSelection()
420 {
421         selection() = true;
422         // a selection with no contents is not a selection
423         if (par() == anchor().par() && pos() == anchor().pos())
424                 selection() = false;
425 }
426
427
428 void LCursor::setSelection(CursorBase const & where, size_t n)
429 {
430         selection() = true;
431         cursor_ = where;
432         anchor_ = where;
433         pos() += n;
434 }
435
436
437 void LCursor::clearSelection()
438 {
439         selection() = false;
440         mark() = false;
441         resetAnchor();
442         bv().unsetXSel();
443 }
444
445
446 int & LCursor::x_target()
447 {
448         return x_target_;
449 }
450
451
452 int LCursor::x_target() const
453 {
454         return x_target_;
455 }
456
457
458 void LCursor::clearTargetX()
459 {
460         x_target_ = -1;
461 }
462
463
464 LyXText * LCursor::text() const
465 {
466         return current_ ? current().text() : bv_->text();
467 }
468
469
470 Paragraph & LCursor::paragraph()
471 {
472         BOOST_ASSERT(inTexted());
473         return current_ ? current().paragraph() : *bv_->text()->getPar(par());
474 }
475
476
477 Paragraph const & LCursor::paragraph() const
478 {
479         BOOST_ASSERT(inTexted());
480         return current_ ? current().paragraph() : *bv_->text()->getPar(par());
481 }
482
483
484 LCursor::par_type LCursor::lastpar() const
485 {
486         return inMathed() ? 0 : text()->paragraphs().size() - 1;
487 }
488
489
490 LCursor::pos_type LCursor::lastpos() const
491 {
492         InsetBase * inset = current().inset();
493         return inset && inset->asMathInset() ? cell().size() : paragraph().size();
494 }
495
496
497 LCursor::row_type LCursor::crow() const
498 {
499         return paragraph().row(pos());
500 }
501
502
503 LCursor::row_type LCursor::lastcrow() const
504 {
505         return paragraph().rows.size();
506 }
507
508
509 size_t LCursor::nargs() const
510 {
511         // assume 1x1 grid for 'plain text'
512         return current_ ? current().nargs() : 1;
513 }
514
515
516 size_t LCursor::ncols() const
517 {
518         // assume 1x1 grid for 'plain text'
519         return current_ ? current().ncols() : 1;
520 }
521
522
523 size_t LCursor::nrows() const
524 {
525         // assume 1x1 grid for 'plain text'
526         return current_ ? current().nrows() : 1;
527 }
528
529
530 LCursor::row_type LCursor::row() const
531 {
532         BOOST_ASSERT(current_ > 0);
533         return current().row();
534 }
535
536
537 LCursor::col_type LCursor::col() const
538 {
539         BOOST_ASSERT(current_ > 0);
540         return current().col();
541 }
542
543
544 MathArray const & LCursor::cell() const
545 {
546         BOOST_ASSERT(current_ > 0);
547         return current().cell();
548 }
549
550
551 MathArray & LCursor::cell()
552 {
553         BOOST_ASSERT(current_ > 0);
554         return current().cell();
555 }
556
557
558 void LCursor::info(std::ostream & os)
559 {
560         for (int i = 1, n = depth(); i < n; ++i) {
561                 cursor_[i].inset()->infoize(os);
562                 os << "  ";
563         }
564         if (pos() != 0)
565                 prevInset()->infoize2(os);
566         // overwite old message
567         os << "                    ";
568 }
569
570
571 namespace {
572
573 void region(CursorSlice const & i1, CursorSlice const & i2,
574         LCursor::row_type & r1, LCursor::row_type & r2,
575         LCursor::col_type & c1, LCursor::col_type & c2)
576 {
577         InsetBase * p = i1.inset();
578         c1 = p->col(i1.idx_);
579         c2 = p->col(i2.idx_);
580         if (c1 > c2)
581                 swap(c1, c2);
582         r1 = p->row(i1.idx_);
583         r2 = p->row(i2.idx_);
584         if (r1 > r2)
585                 swap(r1, r2);
586 }
587
588 }
589
590
591 string LCursor::grabSelection()
592 {
593         if (!selection())
594                 return string();
595
596         CursorSlice i1 = selBegin();
597         CursorSlice i2 = selEnd();
598
599         if (i1.idx_ == i2.idx_) {
600                 if (i1.inset()->asMathInset()) {
601                         MathArray::const_iterator it = i1.cell().begin();
602                         return asString(MathArray(it + i1.pos_, it + i2.pos_));
603                 } else {
604                         return "unknown selection 1";
605                 }
606         }
607
608         row_type r1, r2;
609         col_type c1, c2;
610         region(i1, i2, r1, r2, c1, c2);
611
612         string data;
613         if (i1.inset()->asMathInset()) {
614                 for (row_type row = r1; row <= r2; ++row) {
615                         if (row > r1)
616                                 data += "\\\\";
617                         for (col_type col = c1; col <= c2; ++col) {
618                                 if (col > c1)
619                                         data += '&';
620                                 data += asString(i1.asMathInset()->cell(i1.asMathInset()->index(row, col)));
621                         }
622                 }
623         } else {
624                 data = "unknown selection 2";
625         }
626         return data;
627 }
628
629
630 void LCursor::eraseSelection()
631 {
632         CursorSlice i1 = selBegin();
633         CursorSlice i2 = selEnd();
634 #warning FIXME
635         if (i1.inset()->asMathInset()) {
636                 if (i1.idx_ == i2.idx_) {
637                         i1.cell().erase(i1.pos_, i2.pos_);
638                 } else {
639                         MathInset * p = i1.asMathInset();
640                         row_type r1, r2;
641                         col_type c1, c2;
642                         region(i1, i2, r1, r2, c1, c2);
643                         for (row_type row = r1; row <= r2; ++row)
644                                 for (col_type col = c1; col <= c2; ++col)
645                                         p->cell(p->index(row, col)).clear();
646                 }
647                 current() = i1;
648         } else {
649                 lyxerr << "can't erase this selection 1" << endl;
650         }
651 }
652
653
654 string LCursor::grabAndEraseSelection()
655 {
656         if (!selection())
657                 return string();
658         string res = grabSelection();
659         eraseSelection();
660         selection() = false;
661         return res;
662 }
663
664
665 void LCursor::selClear()
666 {
667         resetAnchor();
668         clearSelection();
669 }
670
671
672 void LCursor::selCopy()
673 {
674         if (selection()) {
675                 theCutBuffer.push(grabSelection());
676                 selection() = false;
677         } else {
678                 //theCutBuffer.erase();
679         }
680 }
681
682
683 void LCursor::selCut()
684 {
685         theCutBuffer.push(grabAndEraseSelection());
686 }
687
688
689 void LCursor::selDel()
690 {
691         if (selection()) {
692                 eraseSelection();
693                 selection() = false;
694         }
695 }
696
697
698 void LCursor::selPaste(size_t n)
699 {
700         selClearOrDel();
701         if (n < theCutBuffer.size())
702                 paste(theCutBuffer[n]);
703         //grabSelection();
704         selection() = false;
705 }
706
707
708 void LCursor::selHandle(bool sel)
709 {
710         if (sel == selection())
711                 return;
712         resetAnchor();
713         selection() = sel;
714 }
715
716
717 void LCursor::selStart()
718 {
719         resetAnchor();
720         selection() = true;
721 }
722
723
724 void LCursor::selClearOrDel()
725 {
726         if (lyxrc.auto_region_delete)
727                 selDel();
728         else
729                 selection() = false;
730 }
731
732
733 std::ostream & operator<<(std::ostream & os, LCursor const & cur)
734 {
735         for (size_t i = 0, n = cur.cursor_.size(); i != n; ++i)
736                 os << "  (" << cur.cursor_[i] << " | " << cur.anchor_[i] << "\n";
737         os << "  current: " << cur.current_ << endl;
738         os << "  selection: " << cur.selection_ << endl;
739         return os;
740 }
741
742
743
744
745 //
746 // CursorBase
747 //
748
749
750 void increment(CursorBase & it)
751 {
752         CursorSlice & top = it.back();
753         MathArray & ar = top.asMathInset()->cell(top.idx_);
754
755         // move into the current inset if possible
756         // it is impossible for pos() == size()!
757         MathInset * n = 0;
758         if (top.pos() != top.lastpos())
759                 n = (ar.begin() + top.pos_)->nucleus();
760         if (n && n->isActive()) {
761                 it.push_back(CursorSlice(n));
762                 return;
763         }
764
765         // otherwise move on one cell back if possible
766         if (top.pos() < top.lastpos()) {
767                 // pos() == lastpos() is valid!
768                 ++top.pos_;
769                 return;
770         }
771
772         // otherwise try to move on one cell if possible
773         while (top.idx() < top.lastidx()) {
774                 ++top.idx_;
775                 if (top.asMathInset()->validCell(top.idx_)) {
776                         top.pos_ = 0;
777                         return;
778                 }
779         }
780
781         // otherwise leave array, move on one back
782         // this might yield pos() == size(), but that's a ok.
783         it.pop_back();
784         // it certainly invalidates top
785         ++it.back().pos_;
786 }
787
788
789 CursorBase ibegin(InsetBase * p)
790 {
791         CursorBase it;
792         it.push_back(CursorSlice(p));
793         return it;
794 }
795
796
797 CursorBase iend(InsetBase * p)
798 {
799         CursorBase it;
800         it.push_back(CursorSlice(p));
801         CursorSlice & cur = it.back();
802         cur.idx() = cur.lastidx();
803         cur.pos() = cur.lastpos();
804         return it;
805 }
806
807
808
809
810 ///////////////////////////////////////////////////////////////////
811 //
812 // The part below is the non-integrated rest of the original math
813 // cursor. This should be either generalized for texted or moved
814 // back to the math insets.
815 //
816 ///////////////////////////////////////////////////////////////////
817
818 #include "mathed/math_braceinset.h"
819 #include "mathed/math_charinset.h"
820 #include "mathed/math_commentinset.h"
821 #include "mathed/math_factory.h"
822 #include "mathed/math_gridinset.h"
823 #include "mathed/math_macroarg.h"
824 #include "mathed/math_macrotemplate.h"
825 #include "mathed/math_mathmlstream.h"
826 #include "mathed/math_scriptinset.h"
827 #include "mathed/math_spaceinset.h"
828 #include "mathed/math_support.h"
829 #include "mathed/math_unknowninset.h"
830
831 //#define FILEDEBUG 1
832
833
834 bool LCursor::isInside(InsetBase const * p)
835 {
836         for (unsigned i = 0; i < depth(); ++i)
837                 if (cursor_[i].inset() == p)
838                         return true;
839         return false;
840 }
841
842
843 bool LCursor::openable(MathAtom const & t)
844 {
845         if (!t->isActive())
846                 return false;
847
848         if (t->lock())
849                 return false;
850
851         if (!selection())
852                 return true;
853
854         // we can't move into anything new during selection
855         if (depth() == anchor_.size())
856                 return false;
857         if (!ptr_cmp(t.nucleus(), anchor_[depth()].inset()))
858                 return false;
859
860         return true;
861 }
862
863
864 bool LCursor::inNucleus()
865 {
866         return inset()->asMathInset()->asScriptInset() && idx() == 2;
867 }
868
869
870 bool LCursor::left()
871 {
872         autocorrect() = false;
873         clearTargetX();
874         if (inMacroMode()) {
875                 macroModeClose();
876                 return true;
877         }
878
879         if (pos() != 0 && openable(prevAtom())) {
880                 posLeft();
881                 push(nextAtom().nucleus());
882                 inset()->idxLast(*this);
883                 return true;
884         }
885
886         return posLeft() || idxLeft() || popLeft() || selection();
887 }
888
889
890 bool LCursor::right()
891 {
892         autocorrect() = false;
893         clearTargetX();
894         if (inMacroMode()) {
895                 macroModeClose();
896                 return true;
897         }
898
899         if (pos() != lastpos() && openable(nextAtom())) {
900                 pushLeft(nextAtom().nucleus());
901                 inset()->idxFirst(*this);
902                 return true;
903         }
904
905         return posRight() || idxRight() || popRight() || selection();
906 }
907
908
909 bool positionable(CursorBase const & cursor, CursorBase const & anchor)
910 {
911         // avoid deeper nested insets when selecting
912         if (cursor.size() > anchor.size())
913                 return false;
914
915         // anchor might be deeper, should have same path then
916         for (size_t i = 0; i < cursor.size(); ++i)
917                 if (cursor[i].inset() != anchor[i].inset())
918                         return false;
919
920         // position should be ok.
921         return true;
922 }
923
924
925 void LCursor::setScreenPos(int x, int y)
926 {
927         bool res = bruteFind(x, y, formula()->xlow(), formula()->xhigh(),
928                 formula()->ylow(), formula()->yhigh());
929         if (!res) {
930                 // this can happen on creation of "math-display"
931                 idx() = 0;
932                 pos() = 0;
933         }
934         clearTargetX();
935 }
936
937
938
939 bool LCursor::home()
940 {
941         autocorrect() = false;
942         macroModeClose();
943         if (!inset()->idxHome(*this))
944                 return popLeft();
945         clearTargetX();
946         return true;
947 }
948
949
950 bool LCursor::end()
951 {
952         autocorrect() = false;
953         macroModeClose();
954         if (!inset()->idxEnd(*this))
955                 return popRight();
956         clearTargetX();
957         return true;
958 }
959
960
961 void LCursor::plainErase()
962 {
963         cell().erase(pos());
964 }
965
966
967 void LCursor::markInsert()
968 {
969         cell().insert(pos(), MathAtom(new MathCharInset(0)));
970 }
971
972
973 void LCursor::markErase()
974 {
975         cell().erase(pos());
976 }
977
978
979 void LCursor::plainInsert(MathAtom const & t)
980 {
981         cell().insert(pos(), t);
982         ++pos();
983 }
984
985
986 void LCursor::insert2(string const & str)
987 {
988         MathArray ar;
989         asArray(str, ar);
990         insert(ar);
991 }
992
993
994 void LCursor::insert(string const & str)
995 {
996         lyxerr << "inserting '" << str << "'" << endl;
997         selClearOrDel();
998         for (string::const_iterator it = str.begin(); it != str.end(); ++it)
999                 plainInsert(MathAtom(new MathCharInset(*it)));
1000 }
1001
1002
1003 void LCursor::insert(char c)
1004 {
1005         lyxerr << "inserting '" << c << "'" << endl;
1006         selClearOrDel();
1007         plainInsert(MathAtom(new MathCharInset(c)));
1008 }
1009
1010
1011 void LCursor::insert(MathAtom const & t)
1012 {
1013         macroModeClose();
1014         selClearOrDel();
1015         plainInsert(t);
1016 }
1017
1018
1019 void LCursor::niceInsert(string const & t)
1020 {
1021         lyxerr << "*** LCursor::niceInsert 1: " << t << endl;
1022         MathArray ar;
1023         asArray(t, ar);
1024         if (ar.size() == 1)
1025                 niceInsert(ar[0]);
1026         else
1027                 insert(ar);
1028 }
1029
1030
1031 void LCursor::niceInsert(MathAtom const & t)
1032 {
1033         lyxerr << "*** LCursor::niceInsert 2: " << t << endl;
1034         macroModeClose();
1035         string safe = grabAndEraseSelection();
1036         plainInsert(t);
1037         // enter the new inset and move the contents of the selection if possible
1038         if (t->isActive()) {
1039                 posLeft();
1040                 pushLeft(nextAtom().nucleus());
1041                 paste(safe);
1042         }
1043         lyxerr << "*** LCursor::niceInsert 3: " << t << endl;
1044 }
1045
1046
1047 void LCursor::insert(MathArray const & ar)
1048 {
1049         macroModeClose();
1050         if (selection())
1051                 eraseSelection();
1052         cell().insert(pos(), ar);
1053         pos() += ar.size();
1054 }
1055
1056
1057 bool LCursor::backspace()
1058 {
1059         autocorrect() = false;
1060
1061         if (selection()) {
1062                 selDel();
1063                 return true;
1064         }
1065
1066         if (pos() == 0) {
1067                 if (inset()->nargs() == 1 && depth() == 1 && lastpos() == 0)
1068                         return false;
1069                 pullArg();
1070                 return true;
1071         }
1072
1073         if (inMacroMode()) {
1074                 MathUnknownInset * p = activeMacro();
1075                 if (p->name().size() > 1) {
1076                         p->setName(p->name().substr(0, p->name().size() - 1));
1077                         return true;
1078                 }
1079         }
1080
1081         if (pos() != 0 && prevAtom()->nargs() > 0) {
1082                 // let's require two backspaces for 'big stuff' and
1083                 // highlight on the first
1084                 selection() = true;
1085                 left();
1086         } else {
1087                 --pos();
1088                 plainErase();
1089         }
1090         return true;
1091 }
1092
1093
1094 bool LCursor::erase()
1095 {
1096         autocorrect() = false;
1097         if (inMacroMode())
1098                 return true;
1099
1100         if (selection()) {
1101                 selDel();
1102                 return true;
1103         }
1104
1105         // delete empty cells if possible
1106         if (pos() == lastpos() && inset()->idxDelete(idx()))
1107                 return true;
1108
1109         // special behaviour when in last position of cell
1110         if (pos() == lastpos()) {
1111                 bool one_cell = inset()->nargs() == 1;
1112                 if (one_cell && depth() == 1 && lastpos() == 0)
1113                         return false;
1114                 // remove markup
1115                 if (one_cell)
1116                         pullArg();
1117                 else
1118                         inset()->idxGlue(idx());
1119                 return true;
1120         }
1121
1122         if (pos() != lastpos() && inset()->nargs() > 0) {
1123                 selection() = true;
1124                 right();
1125         } else {
1126                 plainErase();
1127         }
1128
1129         return true;
1130 }
1131
1132
1133 bool LCursor::up()
1134 {
1135         macroModeClose();
1136         CursorBase save = cursor_;
1137         if (goUpDown(true))
1138                 return true;
1139         cursor_ = save;
1140         autocorrect() = false;
1141         return selection();
1142 }
1143
1144
1145 bool LCursor::down()
1146 {
1147         macroModeClose();
1148         CursorBase save = cursor_;
1149         if (goUpDown(false))
1150                 return true;
1151         cursor_ = save;
1152         autocorrect() = false;
1153         return selection();
1154 }
1155
1156
1157 void LCursor::macroModeClose()
1158 {
1159         if (!inMacroMode())
1160                 return;
1161         MathUnknownInset * p = activeMacro();
1162         p->finalize();
1163         string s = p->name();
1164         --pos();
1165         cell().erase(pos());
1166
1167         // do nothing if the macro name is empty
1168         if (s == "\\")
1169                 return;
1170
1171         string const name = s.substr(1);
1172
1173         // prevent entering of recursive macros
1174         if (formula()->lyxCode() == InsetOld::MATHMACRO_CODE
1175                         && formula()->getInsetName() == name)
1176                 lyxerr << "can't enter recursive macro" << endl;
1177
1178         niceInsert(createMathInset(name));
1179 }
1180
1181
1182 string LCursor::macroName()
1183 {
1184         return inMacroMode() ? activeMacro()->name() : string();
1185 }
1186
1187
1188 void LCursor::handleNest(MathAtom const & a, int c)
1189 {
1190         MathAtom t = a;
1191         asArray(grabAndEraseSelection(), t.nucleus()->cell(c));
1192         insert(t);
1193         posLeft();
1194         pushLeft(t.nucleus());
1195 }
1196
1197
1198 int LCursor::targetX() const
1199 {
1200         if (x_target() != -1)
1201                 return x_target();
1202         int x = 0;
1203         int y = 0;
1204         getPos(x, y);
1205         return x;
1206 }
1207
1208
1209 MathHullInset * LCursor::formula() const
1210 {
1211         for (int i = cursor_.size() - 1; i >= 1; --i) {
1212                 MathInset * inset = cursor_[i].inset()->asMathInset();
1213                 if (inset && inset->asHullInset())
1214                         return static_cast<MathHullInset *>(inset);
1215         }
1216         return 0;
1217 }
1218
1219
1220 void LCursor::adjust(pos_type from, int diff)
1221 {
1222         if (pos() > from)
1223                 pos() += diff;
1224         if (anchor().pos_ > from)
1225                 anchor().pos_ += diff;
1226         // just to be on the safe side
1227         // theoretically unecessary
1228         normalize();
1229 }
1230
1231
1232 bool LCursor::inMacroMode() const
1233 {
1234         if (!pos() != 0)
1235                 return false;
1236         MathUnknownInset const * p = prevAtom()->asUnknownInset();
1237         return p && !p->final();
1238 }
1239
1240
1241 MathUnknownInset * LCursor::activeMacro()
1242 {
1243         return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : 0;
1244 }
1245
1246
1247 bool LCursor::inMacroArgMode() const
1248 {
1249         return pos() > 0 && prevAtom()->getChar() == '#';
1250 }
1251
1252
1253 MathGridInset * LCursor::enclosingGrid(idx_type & idx) const
1254 {
1255         for (MathInset::difference_type i = depth() - 1; i >= 0; --i) {
1256                 MathInset * m = cursor_[i].inset()->asMathInset();
1257                 if (!m)
1258                         return 0;
1259                 MathGridInset * p = m->asGridInset();
1260                 if (p) {
1261                         idx = cursor_[i].idx_;
1262                         return p;
1263                 }
1264         }
1265         return 0;
1266 }
1267
1268
1269 void LCursor::pullArg()
1270 {
1271 #warning look here
1272 #if 0
1273         MathArray ar = cell();
1274         if (popLeft()) {
1275                 plainErase();
1276                 cell().insert(pos(), ar);
1277                 resetAnchor();
1278         } else {
1279                 formula()->mutateToText();
1280         }
1281 #endif
1282 }
1283
1284
1285 void LCursor::touch()
1286 {
1287 #warning look here
1288 #if 0
1289         CursorBase::const_iterator it = cursor_.begin();
1290         CursorBase::const_iterator et = cursor_.end();
1291         for ( ; it != et; ++it)
1292                 it->cell().touch();
1293 #endif
1294 }
1295
1296
1297 void LCursor::normalize()
1298 {
1299         if (idx() >= nargs()) {
1300                 lyxerr << "this should not really happen - 1: "
1301                        << idx() << ' ' << nargs()
1302                        << " in: " << inset() << endl;
1303         }
1304         idx() = min(idx(), lastidx());
1305
1306         if (pos() > lastpos()) {
1307                 lyxerr << "this should not really happen - 2: "
1308                         << pos() << ' ' << lastpos() <<  " in idx: " << idx()
1309                        << " in atom: '";
1310                 WriteStream wi(lyxerr, false, true);
1311                 inset()->asMathInset()->write(wi);
1312                 lyxerr << endl;
1313         }
1314         pos() = min(pos(), lastpos());
1315 }
1316
1317
1318 char LCursor::valign()
1319 {
1320         idx_type idx;
1321         MathGridInset * p = enclosingGrid(idx);
1322         return p ? p->valign() : '\0';
1323 }
1324
1325
1326 char LCursor::halign()
1327 {
1328         idx_type idx;
1329         MathGridInset * p = enclosingGrid(idx);
1330         return p ? p->halign(idx % p->ncols()) : '\0';
1331 }
1332
1333
1334 bool LCursor::goUpDown(bool up)
1335 {
1336         // Be warned: The 'logic' implemented in this function is highly fragile.
1337         // A distance of one pixel or a '<' vs '<=' _really_ matters.
1338         // So fiddle around with it only if you know what you are doing!
1339   int xo = 0;
1340         int yo = 0;
1341         getPos(xo, yo);
1342
1343         // check if we had something else in mind, if not, this is the future goal
1344         if (x_target() == -1)
1345                 x_target() = xo;
1346         else
1347                 xo = x_target();
1348
1349         // try neigbouring script insets
1350         if (!selection()) {
1351                 // try left
1352                 if (pos() != 0) {
1353                         MathScriptInset const * p = prevAtom()->asScriptInset();
1354                         if (p && p->has(up)) {
1355                                 --pos();
1356                                 push(inset());
1357                                 idx() = up; // the superscript has index 1
1358                                 pos() = lastpos();
1359                                 //lyxerr << "updown: handled by scriptinset to the left" << endl;
1360                                 return true;
1361                         }
1362                 }
1363
1364                 // try right
1365                 if (pos() != lastpos()) {
1366                         MathScriptInset const * p = nextAtom()->asScriptInset();
1367                         if (p && p->has(up)) {
1368                                 push(inset());
1369                                 idx() = up;
1370                                 pos() = 0;
1371                                 //lyxerr << "updown: handled by scriptinset to the right" << endl;
1372                                 return true;
1373                         }
1374                 }
1375         }
1376
1377         // try current cell for e.g. text insets
1378         if (inset()->idxUpDown2(*this, up))
1379                 return true;
1380
1381         //xarray().boundingBox(xlow, xhigh, ylow, yhigh);
1382         //if (up)
1383         //      yhigh = yo - 4;
1384         //else
1385         //      ylow = yo + 4;
1386         //if (bruteFind(xo, yo, xlow, xhigh, ylow, yhigh)) {
1387         //      lyxerr << "updown: handled by brute find in the same cell" << endl;
1388         //      return true;
1389         //}
1390
1391         // try to find an inset that knows better then we
1392         while (1) {
1393                 //lyxerr << "updown: We are in " << inset() << " idx: " << idx() << endl;
1394                 // ask inset first
1395                 if (inset()->idxUpDown(*this, up)) {
1396                         // try to find best position within this inset
1397                         if (!selection())
1398                                 bruteFind2(xo, yo);
1399                         return true;
1400                 }
1401
1402                 // no such inset found, just take something "above"
1403                 //lyxerr << "updown: handled by strange case" << endl;
1404                 if (!popLeft()) {
1405                         return
1406                                 bruteFind(xo, yo,
1407                                         formula()->xlow(),
1408                                         formula()->xhigh(),
1409                                         up ? formula()->ylow() : yo + 4,
1410                                         up ? yo - 4 : formula()->yhigh()
1411                                 );
1412                 }
1413
1414                 // any improvement so far?
1415                 int xnew, ynew;
1416                 getPos(xnew, ynew);
1417                 if (up ? ynew < yo : ynew > yo)
1418                         return true;
1419         }
1420 }
1421
1422
1423 bool LCursor::bruteFind(int x, int y, int xlow, int xhigh, int ylow, int yhigh)
1424 {
1425         CursorBase best_cursor;
1426         double best_dist = 1e10;
1427
1428         CursorBase it = ibegin(formula());
1429         CursorBase et = iend(formula());
1430         while (1) {
1431                 // avoid invalid nesting when selecting
1432                 if (!selection() || positionable(it, anchor_)) {
1433                         int xo, yo;
1434                         CursorSlice & cur = it.back();
1435                         cur.inset()->getCursorPos(cur, xo, yo);
1436                         if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
1437                                 double d = (x - xo) * (x - xo) + (y - yo) * (y - yo);
1438                                 //lyxerr << "x: " << x << " y: " << y << " d: " << endl;
1439                                 // '<=' in order to take the last possible position
1440                                 // this is important for clicking behind \sum in e.g. '\sum_i a'
1441                                 if (d <= best_dist) {
1442                                         best_dist   = d;
1443                                         best_cursor = it;
1444                                 }
1445                         }
1446                 }
1447
1448                 if (it == et)
1449                         break;
1450                 increment(it);
1451         }
1452
1453         if (best_dist < 1e10)
1454                 cursor_ = best_cursor;
1455         return best_dist < 1e10;
1456 }
1457
1458
1459 void LCursor::bruteFind2(int x, int y)
1460 {
1461         double best_dist = 1e10;
1462
1463         CursorBase it = cursor_;
1464         it.back().pos(0);
1465         CursorBase et = cursor_;
1466         int n = et.back().asMathInset()->cell(et.back().idx_).size();
1467         et.back().pos(n);
1468         for (int i = 0; ; ++i) {
1469                 int xo, yo;
1470                 CursorSlice & cur = it.back();
1471                 cur.inset()->getCursorPos(cur, xo, yo);
1472                 double d = (x - xo) * (x - xo) + (y - yo) * (y - yo);
1473                 // '<=' in order to take the last possible position
1474                 // this is important for clicking behind \sum in e.g. '\sum_i a'
1475                 lyxerr << "i: " << i << " d: " << d << " best: " << best_dist << endl;
1476                 if (d <= best_dist) {
1477                         best_dist = d;
1478                         cursor_ = it;
1479                 }
1480                 if (it == et)
1481                         break;
1482                 increment(it);
1483         }
1484 }
1485
1486
1487 bool LCursor::idxLineLast()
1488 {
1489         idx() -= idx() % ncols();
1490         idx() += ncols() - 1;
1491         pos() = lastpos();
1492         return true;
1493 }
1494
1495
1496 bool LCursor::idxLeft()
1497 {
1498         return inset()->idxLeft(*this);
1499 }
1500
1501
1502 bool LCursor::idxRight()
1503 {
1504         return inset()->idxRight(*this);
1505 }
1506
1507
1508 bool LCursor::script(bool up)
1509 {
1510         // Hack to get \\^ and \\_ working
1511         lyxerr << "handling script: up: " << up << endl;
1512         if (inMacroMode() && macroName() == "\\") {
1513                 if (up)
1514                         niceInsert(createMathInset("mathcircumflex"));
1515                 else
1516                         interpret('_');
1517                 return true;
1518         }
1519
1520         macroModeClose();
1521         string safe = grabAndEraseSelection();
1522         if (inNucleus()) {
1523                 // we are in a nucleus of a script inset, move to _our_ script
1524                 inset()->asMathInset()->asScriptInset()->ensure(up);
1525                 idx() = up;
1526                 pos() = 0;
1527         } else if (pos() != 0 && prevAtom()->asScriptInset()) {
1528                 --pos();
1529                 nextAtom().nucleus()->asScriptInset()->ensure(up);
1530                 push(nextInset());
1531                 idx() = up;
1532                 pos() = lastpos();
1533         } else if (pos() != 0) {
1534                 --pos();
1535                 cell()[pos()] = MathAtom(new MathScriptInset(nextAtom(), up));
1536                 push(nextInset());
1537                 idx() = up;
1538                 pos() = 0;
1539         } else {
1540                 plainInsert(MathAtom(new MathScriptInset(up)));
1541                 --pos();
1542                 nextAtom().nucleus()->asScriptInset()->ensure(up);
1543                 push(nextInset());
1544                 idx() = up;
1545                 pos() = 0;
1546         }
1547         paste(safe);
1548         return true;
1549 }
1550
1551
1552 bool LCursor::interpret(char c)
1553 {
1554         //lyxerr << "interpret 2: '" << c << "'" << endl;
1555         clearTargetX();
1556         if (inMacroArgMode()) {
1557                 posLeft();
1558                 plainErase();
1559 #warning FIXME
1560 #if 0
1561                 int n = c - '0';
1562                 MathMacroTemplate const * p = formula()->asMacroTemplate();
1563                 if (p && 1 <= n && n <= p->numargs())
1564                         insert(MathAtom(new MathMacroArgument(c - '0')));
1565                 else {
1566                         insert(createMathInset("#"));
1567                         interpret(c); // try again
1568                 }
1569 #endif
1570                 return true;
1571         }
1572
1573         // handle macroMode
1574         if (inMacroMode()) {
1575                 string name = macroName();
1576                 //lyxerr << "interpret name: '" << name << "'" << endl;
1577
1578                 if (isalpha(c)) {
1579                         activeMacro()->setName(activeMacro()->name() + c);
1580                         return true;
1581                 }
1582
1583                 // handle 'special char' macros
1584                 if (name == "\\") {
1585                         // remove the '\\'
1586                         backspace();
1587                         if (c == '\\') {
1588                                 if (currentMode() == MathInset::TEXT_MODE)
1589                                         niceInsert(createMathInset("textbackslash"));
1590                                 else
1591                                         niceInsert(createMathInset("backslash"));
1592                         } else if (c == '{') {
1593                                 niceInsert(MathAtom(new MathBraceInset));
1594                         } else {
1595                                 niceInsert(createMathInset(string(1, c)));
1596                         }
1597                         return true;
1598                 }
1599
1600                 // leave macro mode and try again if necessary
1601                 macroModeClose();
1602                 if (c == '{')
1603                         niceInsert(MathAtom(new MathBraceInset));
1604                 else if (c != ' ')
1605                         interpret(c);
1606                 return true;
1607         }
1608
1609         // This is annoying as one has to press <space> far too often.
1610         // Disable it.
1611
1612         if (0) {
1613                 // leave autocorrect mode if necessary
1614                 if (autocorrect() && c == ' ') {
1615                         autocorrect() = false;
1616                         return true;
1617                 }
1618         }
1619
1620         // just clear selection on pressing the space bar
1621         if (selection() && c == ' ') {
1622                 selection() = false;
1623                 return true;
1624         }
1625
1626         selClearOrDel();
1627
1628         if (c == '\\') {
1629                 //lyxerr << "starting with macro" << endl;
1630                 insert(MathAtom(new MathUnknownInset("\\", false)));
1631                 return true;
1632         }
1633
1634         if (c == '\n') {
1635                 if (currentMode() == MathInset::TEXT_MODE)
1636                         insert(c);
1637                 return true;
1638         }
1639
1640         if (c == ' ') {
1641                 if (currentMode() == MathInset::TEXT_MODE) {
1642                         // insert spaces in text mode,
1643                         // but suppress direct insertion of two spaces in a row
1644                         // the still allows typing  '<space>a<space>' and deleting the 'a', but
1645                         // it is better than nothing...
1646                         if (!pos() != 0 || prevAtom()->getChar() != ' ')
1647                                 insert(c);
1648                         return true;
1649                 }
1650                 if (pos() != 0 && prevAtom()->asSpaceInset()) {
1651                         prevAtom().nucleus()->asSpaceInset()->incSpace();
1652                         return true;
1653                 }
1654                 if (popRight())
1655                         return true;
1656                 // if are at the very end, leave the formula
1657                 return pos() != lastpos();
1658         }
1659
1660         if (c == '_') {
1661                 script(false);
1662                 return true;
1663         }
1664
1665         if (c == '^') {
1666                 script(true);
1667                 return true;
1668         }
1669
1670         if (c == '{' || c == '}' || c == '#' || c == '&' || c == '$') {
1671                 niceInsert(createMathInset(string(1, c)));
1672                 return true;
1673         }
1674
1675         if (c == '%') {
1676                 niceInsert(MathAtom(new MathCommentInset));
1677                 return true;
1678         }
1679
1680         // try auto-correction
1681         //if (autocorrect() && hasPrevAtom() && math_autocorrect(prevAtom(), c))
1682         //      return true;
1683
1684         // no special circumstances, so insert the character without any fuss
1685         insert(c);
1686         autocorrect() = true;
1687         return true;
1688 }
1689
1690
1691 void LCursor::lockToggle()
1692 {
1693         if (pos() != lastpos()) {
1694                 // toggle previous inset ...
1695                 nextAtom().nucleus()->lock(!nextAtom()->lock());
1696         } else if (popLeft() && pos() != lastpos()) {
1697                 // ... or enclosing inset if we are in the last inset position
1698                 nextAtom().nucleus()->lock(!nextAtom()->lock());
1699                 posRight();
1700         }
1701 }
1702
1703
1704 CursorSlice LCursor::normalAnchor()
1705 {
1706         if (anchor_.size() < depth()) {
1707                 resetAnchor();
1708                 lyxerr << "unusual Anchor size" << endl;
1709         }
1710         //lyx::BOOST_ASSERT(Anchor_.size() >= cursor.depth());
1711         // use Anchor on the same level as Cursor
1712         CursorSlice normal = anchor_[current_];
1713 #if 0
1714         if (depth() < anchor_.size() && !(normal < xx())) {
1715                 // anchor is behind cursor -> move anchor behind the inset
1716                 ++normal.pos_;
1717         }
1718 #endif
1719         return normal;
1720 }
1721
1722
1723 /*
1724 DispatchResult dispatch(LCursor & cur, FuncRequest const & cmd)
1725 {
1726         // mouse clicks are somewhat special
1727         // check
1728         switch (cmd.action) {
1729         case LFUN_MOUSE_PRESS:
1730         case LFUN_MOUSE_MOTION:
1731         case LFUN_MOUSE_RELEASE:
1732         case LFUN_MOUSE_DOUBLE: {
1733                 CursorSlice & pos = cursor_.back();
1734                 int x = 0;
1735                 int y = 0;
1736                 getPos(x, y);
1737                 if (x < cmd.x && pos() != 0) {
1738                         DispatchResult const res = prevAtom().nucleus()->dispatch(cmd);
1739                         if (res.dispatched())
1740                                 return res;
1741                 }
1742                 if (x > cmd.x && pos() != lastpos()) {
1743                         DispatchResult const res = inset()->dispatch(cmd);
1744                         if (res.dispatched())
1745                                 return res;
1746                 }
1747         }
1748         default:
1749         break;
1750         }
1751 }
1752 */
1753
1754
1755 void LCursor::handleFont(string const & font)
1756 {
1757         string safe;
1758         if (selection()) {
1759                 macroModeClose();
1760                 safe = grabAndEraseSelection();
1761         }
1762
1763         if (lastpos() != 0) {
1764                 // something left in the cell
1765                 if (pos() == 0) {
1766                         // cursor in first position
1767                         popLeft();
1768                 } else if (pos() == lastpos()) {
1769                         // cursor in last position
1770                         popRight();
1771                 } else {
1772                         // cursor in between. split cell
1773                         MathArray::iterator bt = cell().begin();
1774                         MathAtom at = createMathInset(font);
1775                         at.nucleus()->cell(0) = MathArray(bt, bt + pos());
1776                         cell().erase(bt, bt + pos());
1777                         popLeft();
1778                         plainInsert(at);
1779                 }
1780         } else {
1781                 // nothing left in the cell
1782                 pullArg();
1783                 plainErase();
1784         }
1785         insert(safe);
1786 }
1787
1788
1789 void LCursor::releaseMathCursor()
1790 {
1791         if (inMathed())
1792                 formula()->insetUnlock(bv());
1793 }
1794
1795
1796 bool LCursor::inMathed() const
1797 {
1798         return formula();
1799 }
1800
1801
1802 bool LCursor::inTexted() const
1803 {
1804         return !formula();
1805 }
1806
1807
1808 InsetBase * LCursor::nextInset()
1809 {
1810         if (pos() == lastpos())
1811                 return 0;
1812         if (inMathed()) 
1813                 return nextAtom().nucleus();
1814         Paragraph & par = paragraph();
1815         return par.isInset(pos()) ? par.getInset(pos()) : 0;
1816 }
1817
1818
1819 InsetBase * LCursor::prevInset()
1820 {
1821         if (pos() == 0)
1822                 return 0;
1823         if (inMathed()) 
1824                 return prevAtom().nucleus();
1825         Paragraph & par = paragraph();
1826         return par.isInset(pos() - 1) ? par.getInset(pos() - 1) : 0;
1827 }
1828
1829
1830 void LCursor::message(string const & msg) const
1831 {
1832         bv().owner()->getLyXFunc().setMessage(msg);
1833 }
1834
1835
1836 void LCursor::errorMessage(string const & msg) const
1837 {
1838         bv().owner()->getLyXFunc().setErrorMessage(msg);
1839 }