+
+
+MathInset * MathCursor::enclosing(MathInsetTypes t, int & idx) const
+{
+ for (int i = Cursor_.size() - 1; i >= 0; --i) {
+ //lyxerr << "checking level " << i << "\n";
+ if (Cursor_[i].par_->GetType() == t) {
+ idx = Cursor_[i].idx_;
+ return Cursor_[i].par_;
+ }
+ }
+ return 0;
+}
+
+
+void MathCursor::pullArg()
+{
+ // pullArg
+ dump("pullarg");
+ MathArray a = array();
+ if (pop()) {
+ array().erase(cursor().pos_);
+ array().insert(cursor().pos_, a);
+ }
+}
+
+
+MathStyles MathCursor::style() const
+{
+ return xarray().style();
+}
+
+
+void MathCursor::normalize() const
+{
+#ifdef WITH_WARNINGS
+#warning This is evil!
+#endif
+ MathCursor * it = const_cast<MathCursor *>(this);
+
+ if (cursor().idx_ < 0 || cursor().idx_ > cursor().par_->nargs())
+ lyxerr << "this should not really happen - 1\n";
+ it->cursor().idx_ = max(cursor().idx_, 0);
+ it->cursor().idx_ = min(cursor().idx_, cursor().par_->nargs());
+
+ if (cursor().pos_ < 0 || cursor().pos_ > array().size())
+ lyxerr << "this should not really happen - 2\n";
+ it->cursor().pos_ = max(cursor().pos_, 0);
+ it->cursor().pos_ = min(cursor().pos_, array().size());
+}
+
+
+int MathCursor::col() const
+{
+ return par()->col(cursor().idx_);
+}
+
+
+int MathCursor::row() const
+{
+ return par()->row(cursor().idx_);
+}
+
+
+/*
+char MathCursorPos::GetChar() const
+{
+ return array().GetChar(cursor().pos_);
+}
+
+
+string MathCursorPos::readString()
+{
+ string s;
+ int code = nextCode();
+ for ( ; OK() && nextCode() == code; Next())
+ s += GetChar();
+
+ return s;
+}
+*/
+
+
+MathInset * MathCursor::prevInset() const
+{
+ normalize();
+ int c = cursor().pos_;
+ if (!array().prev(c))
+ return 0;
+ return array().nextInset(c);
+}
+
+
+MathInset * MathCursor::nextInset() const
+{
+ normalize();
+ return array().nextInset(cursor().pos_);
+}
+
+
+MathUpDownInset * MathCursor::nearbyUpDownInset() const
+{
+ normalize();
+ MathInset * p = array().prevInset(cursor().pos_);
+ if (p && p->isUpDownInset())
+ return static_cast<MathUpDownInset *>(p);
+ p = array().nextInset(cursor().pos_);
+ if (p && p->isUpDownInset())
+ return static_cast<MathUpDownInset *>(p);
+ return 0;
+}
+
+
+MathArray & MathCursor::array() const
+{
+ static MathArray dummy;
+ if (!cursor().par_) {
+ lyxerr << "############ par_ not valid\n";
+ return dummy;
+ }
+
+ if (cursor().idx_ < 0 || cursor().idx_ >= cursor().par_->nargs()) {
+ lyxerr << "############ idx_ " << cursor().idx_ << " not valid\n";
+ return dummy;
+ }
+
+ return cursor().cell();
+}
+
+
+MathXArray & MathCursor::xarray() const
+{
+ return cursor().xcell();
+}
+
+
+bool MathCursor::nextIsInset() const
+{
+ return cursor().pos_ < array().size() && MathIsInset(nextCode());
+}
+
+
+bool MathCursor::prevIsInset() const
+{
+ return cursor().pos_ > 0 && MathIsInset(prevCode());
+}
+
+
+int MathCursor::xpos() const
+{
+ normalize();
+ return xarray().pos2x(cursor().pos_);
+}
+
+
+void MathCursor::gotoX(int x)
+{
+ cursor().pos_ = xarray().x2pos(x);
+}
+
+
+void MathCursor::idxNext()
+{
+ cursor().par_->idxNext(cursor().idx_, cursor().pos_);
+}
+
+
+void MathCursor::idxPrev()
+{
+ cursor().par_->idxPrev(cursor().idx_, cursor().pos_);
+}
+
+
+void MathCursor::splitCell()
+{
+ if (cursor().idx_ == cursor().par_->nargs() - 1)
+ return;
+ MathArray ar = array();
+ ar.erase(0, cursor().pos_);
+ array().erase(cursor().pos_, array().size());
+ ++cursor().idx_;
+ cursor().pos_ = 0;
+ array().insert(0, ar);
+}
+
+
+void MathCursor::breakLine()
+{
+ MathMatrixInset * p = static_cast<MathMatrixInset *>(formula()->par());
+ if (p->GetType() == LM_OT_SIMPLE || p->GetType() == LM_OT_EQUATION) {
+ p->mutate(LM_OT_EQNARRAY);
+ p->addRow(0);
+ cursor().idx_ = p->nrows();
+ cursor().pos_ = 0;
+ } else {
+ p->addRow(row());
+
+ // split line
+ const int r = row();
+ for (int c = col() + 1; c < p->ncols(); ++c) {
+ const int i1 = p->index(r, c);
+ const int i2 = p->index(r + 1, c);
+ lyxerr << "swapping cells " << i1 << " and " << i2 << "\n";
+ p->cell(i1).swap(p->cell(i2));
+ }
+
+ // split cell
+ splitCell();
+ p->cell(cursor().idx_).swap(p->cell(cursor().idx_ + p->ncols() - 1));
+ }
+}
+
+
+char MathCursor::valign() const
+{
+ int idx;
+ MathGridInset * p =
+ static_cast<MathGridInset *>(enclosing(LM_OT_MATRIX, idx));
+ return p ? p->valign() : 0;
+}
+
+
+char MathCursor::halign() const
+{
+ int idx;
+ MathGridInset * p =
+ static_cast<MathGridInset *>(enclosing(LM_OT_MATRIX, idx));
+ return p ? p->halign(idx % p->ncols()) : 0;
+}
+
+
+MathCursorPos MathCursor::firstSelectionPos() const
+{
+ MathCursorPos anc = normalAnchor();
+ return anc < cursor() ? anc : cursor();
+}
+
+
+MathCursorPos MathCursor::lastSelectionPos() const
+{
+ MathCursorPos anc = normalAnchor();
+ return anc < cursor() ? cursor() : anc;
+}
+
+
+void MathCursor::getSelection(MathCursorPos & i1, MathCursorPos & i2) const
+{
+ MathCursorPos anc = normalAnchor();
+ if (anc < cursor()) {
+ i1 = anc;
+ i2 = cursor();
+ } else {
+ i1 = cursor();
+ i2 = anc;
+ }
+}
+
+
+MathCursorPos & MathCursor::cursor()
+{
+ return Cursor_.back();
+}
+
+
+MathCursorPos const & MathCursor::cursor() const
+{
+ return Cursor_.back();
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+
+
+bool operator==(MathCursorPos const & ti, MathCursorPos const & it)
+{
+ return ti.par_ == it.par_ && ti.idx_ == it.idx_ && ti.pos_ == it.pos_;
+}
+
+
+bool operator<(MathCursorPos const & ti, MathCursorPos const & it)
+{
+ if (ti.par_ != it.par_) {
+ lyxerr << "can't compare cursor and anchor in different insets\n";
+ return true;
+ }
+ if (ti.idx_ != it.idx_)
+ return ti.idx_ < it.idx_;
+ return ti.pos_ < it.pos_;
+}
+
+
+MathArray & MathCursorPos::cell(int idx) const
+{
+ return par_->cell(idx);
+}
+
+MathArray & MathCursorPos::cell() const
+{
+ return par_->cell(idx_);
+}
+
+
+MathXArray & MathCursorPos::xcell(int idx) const
+{
+ return par_->xcell(idx);
+}
+
+
+MathXArray & MathCursorPos::xcell() const
+{
+ return par_->xcell(idx_);
+}
+
+
+MathCursorPos MathCursor::normalAnchor() const
+{
+ // use Anchor on the same level as Cursor
+ MathCursorPos normal = Anchor_[Cursor_.size() - 1];
+ if (Cursor_.size() < Anchor_.size() && !(normal < cursor())) {
+ // anchor is behind cursor -> move anchor behind the inset
+ normal.cell().next(normal.pos_);
+ }
+ //lyxerr << "normalizing: from " << Anchor_[Anchor_.size() - 1] << " to "
+ // << normal << "\n";
+ return normal;
+}
+
+
+bool MathCursorPos::idxUp()
+{
+ return par_->idxUp(idx_, pos_);
+}
+
+
+bool MathCursorPos::idxDown()
+{
+ return par_->idxDown(idx_, pos_);
+}
+
+
+bool MathCursorPos::idxLeft()
+{
+ return par_->idxLeft(idx_, pos_);
+}
+
+
+bool MathCursorPos::idxRight()
+{
+ return par_->idxRight(idx_, pos_);
+}