X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fcursor.C;h=85b7956e56855f7edfe0334a812d4911d623278c;hb=b634b3eb3b5cc1c47fd3bc63294e16536d4f7664;hp=1902a16f231ab8cc2424f889a6588912820bfaa0;hpb=2288d1724715307a71e888faa4bec1f5de1242aa;p=lyx.git diff --git a/src/cursor.C b/src/cursor.C index 1902a16f23..85b7956e56 100644 --- a/src/cursor.C +++ b/src/cursor.C @@ -12,19 +12,23 @@ #include -#include "buffer.h" #include "BufferView.h" +#include "buffer.h" #include "cursor.h" #include "debug.h" #include "dispatchresult.h" +#include "encoding.h" #include "funcrequest.h" #include "iterators.h" +#include "language.h" #include "lfuns.h" +#include "lyxfont.h" #include "lyxfunc.h" // only for setMessage() #include "lyxrc.h" #include "lyxrow.h" #include "lyxtext.h" #include "paragraph.h" +#include "paragraph_funcs.h" #include "insets/updatableinset.h" #include "insets/insettabular.h" @@ -57,19 +61,17 @@ limited_stack theCutBuffer; LCursor::LCursor(BufferView & bv) - : cursor_(1), anchor_(1), bv_(&bv), current_(0), - cached_y_(0), x_target_(-1), - selection_(false), mark_(false) + : DocumentIterator(), bv_(&bv), anchor_(), + cached_y_(0), x_target_(-1), selection_(false), mark_(false) {} void LCursor::reset() { - cursor_.clear(); + clear(); + push_back(CursorSlice()); anchor_.clear(); - cursor_.push_back(CursorSlice()); anchor_.push_back(CursorSlice()); - current_ = 0; cached_y_ = 0; clearTargetX(); selection_ = false; @@ -77,93 +79,107 @@ void LCursor::reset() } +void LCursor::setCursor(DocumentIterator const & cur, bool sel) +{ + // this (intentionally) does not touch the anchor + DocumentIterator::operator=(cur); + selection() = sel; +} + + DispatchResult LCursor::dispatch(FuncRequest const & cmd0) { - lyxerr << "\nLCursor::dispatch: cmd: " << cmd0 << endl << *this << endl; + if (empty()) + return DispatchResult(); + + //lyxerr << "\nLCursor::dispatch: cmd: " << cmd0 << endl << *this << endl; FuncRequest cmd = cmd0; - for (current_ = cursor_.size() - 1; current_ >= 1; --current_) { - DispatchResult res = inset()->dispatch(*this, cmd); - if (res.dispatched()) { - current_ = cursor_.size() - 1; - return DispatchResult(true, true); - } - - - // "Mutate" the request for semi-handled requests that need - // additional handling in outer levels. - switch (res.val()) { - case FINISHED: - cmd = FuncRequest(LFUN_FINISHED_LEFT); - break; - case FINISHED_RIGHT: - cmd = FuncRequest(LFUN_FINISHED_RIGHT); - break; - case FINISHED_UP: - cmd = FuncRequest(LFUN_FINISHED_UP); - break; - case FINISHED_DOWN: - cmd = FuncRequest(LFUN_FINISHED_DOWN); - break; - default: - //lyxerr << "not handled on level " << current_ - // << " val: " << res.val() << endl; - break; - } + nopop_ = false; + LCursor safe = *this; + + for ( ; size(); pop()) { + lyxerr << "\nLCursor::dispatch: cmd: " << cmd0 << endl << *this << endl; + BOOST_ASSERT(pos() <= lastpos()); + BOOST_ASSERT(idx() <= lastidx()); + BOOST_ASSERT(par() <= lastpar()); + + // The common case is 'LFUN handled, need update', so make the + // LFUN handler's life easier by assuming this as default value. + // The handler can reset the update and val flags if necessary. + disp_.update(true); + disp_.dispatched(true); + inset().dispatch(*this, cmd); + if (disp_.dispatched()) + break; } - BOOST_ASSERT(current_ == 0); - DispatchResult res = bv_->text()->dispatch(*this, cmd); - //lyxerr << " result: " << res.val() << endl; - current_ = cursor_.size() - 1; - return res; + // it completely to get a 'bomb early' behaviour in case this + // object will be used again. + if (nopop_ || !disp_.dispatched()) + operator=(safe); + return disp_; } -void LCursor::push(InsetBase * inset) +bool LCursor::getStatus(FuncRequest const & cmd, FuncStatus & status) { - lyxerr << "LCursor::push() inset: " << inset << endl; - cursor_.push_back(CursorSlice(inset)); - anchor_.push_back(CursorSlice(inset)); - ++current_; - updatePos(); + LCursor safe = *this; + for ( ; size(); pop()) { + //lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl; + BOOST_ASSERT(pos() <= lastpos()); + BOOST_ASSERT(idx() <= lastidx()); + BOOST_ASSERT(par() <= lastpar()); + + // The inset's getStatus() will return 'true' if it made + // a definitive decision on whether it want to handle the + // request or not. The result of this decision is put into + // the 'status' parameter. + if (inset().getStatus(*this, cmd, status)) + break; + } + operator=(safe); + return true; } -void LCursor::pop(int depth) +BufferView & LCursor::bv() const { - while (int(cursor_.size()) > depth + 1) - pop(); - lyxerr << "LCursor::pop() result: " << *this << endl; + return *bv_; } void LCursor::pop() { - BOOST_ASSERT(cursor_.size() >= 1); - cursor_.pop_back(); + BOOST_ASSERT(size() >= 1); + pop_back(); anchor_.pop_back(); - current_ = cursor_.size() - 1; } -void LCursor::pushLeft(InsetBase * p) +void LCursor::push(InsetBase & p) +{ + push_back(CursorSlice(p)); +} + + +void LCursor::pushLeft(InsetBase & p) { - BOOST_ASSERT(!cursor_.empty()); + BOOST_ASSERT(!empty()); //lyxerr << "Entering inset " << t << " left" << endl; push(p); - p->idxFirst(*this); + p.idxFirst(*this); } bool LCursor::popLeft() { - BOOST_ASSERT(!cursor_.empty()); + BOOST_ASSERT(!empty()); //lyxerr << "Leaving inset to the left" << endl; if (depth() <= 1) { if (depth() == 1) - inset()->notifyCursorLeaves(idx()); + inset().notifyCursorLeaves(idx()); return false; } - inset()->notifyCursorLeaves(idx()); + inset().notifyCursorLeaves(idx()); pop(); return true; } @@ -171,42 +187,25 @@ bool LCursor::popLeft() bool LCursor::popRight() { - BOOST_ASSERT(!cursor_.empty()); + BOOST_ASSERT(!empty()); //lyxerr << "Leaving inset to the right" << endl; if (depth() <= 1) { if (depth() == 1) - inset()->notifyCursorLeaves(idx()); + inset().notifyCursorLeaves(idx()); return false; } - inset()->notifyCursorLeaves(idx()); + inset().notifyCursorLeaves(idx()); pop(); ++pos(); return true; } -CursorSlice & LCursor::current() -{ - BOOST_ASSERT(!cursor_.empty()); - //lyxerr << "accessing cursor slice " << current_ - // << ": " << cursor_[current_] << endl; - return cursor_[current_]; -} - - -CursorSlice const & LCursor::current() const -{ - //lyxerr << "accessing cursor slice " << current_ - // << ": " << cursor_[current_] << endl; - return cursor_[current_]; -} - - int LCursor::currentMode() { - BOOST_ASSERT(!cursor_.empty()); - for (int i = cursor_.size() - 1; i >= 1; --i) { - int res = cursor_[i].inset()->currentMode(); + BOOST_ASSERT(!empty()); + for (int i = size() - 1; i >= 1; --i) { + int res = operator[](i).inset().currentMode(); if (res != MathInset::UNDECIDED_MODE) return res; } @@ -214,87 +213,50 @@ int LCursor::currentMode() } -LyXText * LCursor::innerText() const -{ - BOOST_ASSERT(!cursor_.empty()); - if (cursor_.size() > 1) { - // go up until first non-0 text is hit - // (innermost text is 0 in mathed) - for (int i = cursor_.size() - 1; i >= 1; --i) - if (cursor_[i].text()) - return cursor_[i].text(); - } - return bv_->text(); -} - - -CursorSlice const & LCursor::innerTextSlice() const -{ - BOOST_ASSERT(!cursor_.empty()); - if (cursor_.size() > 1) { - // go up until first non-0 text is hit - // (innermost text is 0 in mathed) - for (int i = cursor_.size() - 1; i >= 1; --i) - if (cursor_[i].text()) - return cursor_[i]; - } - return cursor_[0]; -} - - void LCursor::updatePos() { - BOOST_ASSERT(!cursor_.empty()); - if (cursor_.size() > 1) - cached_y_ = bv_->top_y() + cursor_.back().inset()->yo(); - //cached_y_ = cursor_.back().inset()->yo(); + BOOST_ASSERT(!empty()); + if (size() > 1) + cached_y_ = bv().top_y() + back().inset().yo(); + //cached_y_ = back().inset().yo(); } void LCursor::getDim(int & asc, int & des) const { - BOOST_ASSERT(!cursor_.empty()); if (inMathed()) { - BOOST_ASSERT(inset()); - BOOST_ASSERT(inset()->asMathInset()); - //inset()->asMathInset()->getCursorDim(asc, des); + BOOST_ASSERT(inset().asMathInset()); + //inset().asMathInset()->getCursorDim(asc, des); asc = 10; des = 10; - } else { + } else if (inTexted()) { Row const & row = textRow(); asc = row.baseline(); des = row.height() - asc; + } else { + lyxerr << "should this happen?" << endl; + asc = 10; + des = 10; } } void LCursor::getPos(int & x, int & y) const { - BOOST_ASSERT(!cursor_.empty()); x = 0; y = 0; - if (cursor_.size() == 1) { - x = bv_->text()->cursorX(cursor_.front()); - y = bv_->text()->cursorY(cursor_.front()); - } else { - if (!inset()) { - lyxerr << "#### LCursor::getPos: " << *this << endl; - BOOST_ASSERT(inset()); - } - inset()->getCursorPos(cursor_.back(), x, y); - // getCursorPos gives _screen_ coordinates. We need to add - // top_y to get document coordinates. This is hidden in cached_y_. - //y += cached_y_ - inset()->yo(); - // The rest is non-obvious. The reason we have to have these - // extra computation is that the getCursorPos() calls rely - // on the inset's own knowledge of its screen position. - // If we scroll up or down in a big enough increment, - // inset->draw() is not called: this doesn't update - // inset.yo_, so getCursor() returns an old value. - // Ugly as you like. - } - //lyxerr << "#### LCursor::getPos: " << *this - // << " x: " << x << " y: " << y << endl; + if (!empty()) + inset().getCursorPos(back(), x, y); + // getCursorPos gives _screen_ coordinates. We need to add + // top_y to get document coordinates. This is hidden in cached_y_. + //y += cached_y_ - inset().yo(); + // The rest is non-obvious. The reason we have to have these + // extra computation is that the getCursorPos() calls rely + // on the inset's own knowledge of its screen position. + // If we scroll up or down in a big enough increment, + // inset->draw() is not called: this doesn't update + // inset.yo_, so getCursor() returns an old value. + // Ugly as you like. } @@ -304,60 +266,12 @@ void LCursor::paste(string const & data) } -InsetBase * LCursor::innerInsetOfType(int code) const -{ - for (int i = cursor_.size() - 1; i >= 1; --i) - if (cursor_[i].inset_->lyxCode() == code) - return cursor_[i].inset_; - return 0; -} - - -InsetTabular * LCursor::innerInsetTabular() const -{ - return static_cast(innerInsetOfType(InsetBase::TABULAR_CODE)); -} - - void LCursor::resetAnchor() { - anchor_ = cursor_; + anchor_ = *this; } -BufferView & LCursor::bv() const -{ - return *bv_; -} - - -MathAtom const & LCursor::prevAtom() const -{ - BOOST_ASSERT(pos() > 0); - return cell()[pos() - 1]; -} - - -MathAtom & LCursor::prevAtom() -{ - BOOST_ASSERT(pos() > 0); - return cell()[pos() - 1]; -} - - -MathAtom const & LCursor::nextAtom() const -{ - BOOST_ASSERT(pos() < lastpos()); - return cell()[pos()]; -} - - -MathAtom & LCursor::nextAtom() -{ - BOOST_ASSERT(pos() < lastpos()); - return cell()[pos()]; -} - bool LCursor::posLeft() { @@ -392,34 +306,34 @@ CursorSlice const & LCursor::anchor() const CursorSlice const & LCursor::selBegin() const { if (!selection()) - return cursor_.back(); - return anchor() < cursor_.back() ? anchor() : cursor_.back(); + return back(); + return anchor() < back() ? anchor() : back(); } CursorSlice & LCursor::selBegin() { if (!selection()) - return cursor_.back(); + return back(); // can't use std::min as this returns a const ref - return anchor() < cursor_.back() ? anchor() : cursor_.back(); + return anchor() < back() ? anchor() : back(); } CursorSlice const & LCursor::selEnd() const { if (!selection()) - return cursor_.back(); - return anchor() > cursor_.back() ? anchor() : cursor_.back(); + return back(); + return anchor() > back() ? anchor() : back(); } CursorSlice & LCursor::selEnd() { if (!selection()) - return cursor_.back(); + return back(); // can't use std::min as this returns a const ref - return anchor() > cursor_.back() ? anchor() : cursor_.back(); + return anchor() > back() ? anchor() : back(); } @@ -432,10 +346,10 @@ void LCursor::setSelection() } -void LCursor::setSelection(CursorBase const & where, size_t n) +void LCursor::setSelection(DocumentIterator const & where, size_t n) { selection() = true; - cursor_ = where; + setCursor(where, false); anchor_ = where; pos() += n; } @@ -468,116 +382,11 @@ void LCursor::clearTargetX() } -LyXText * LCursor::text() const -{ - return current_ ? current().text() : bv_->text(); -} - - -Paragraph & LCursor::paragraph() -{ - BOOST_ASSERT(inTexted()); - return current_ ? current().paragraph() : *bv_->text()->getPar(par()); -} - - -Paragraph const & LCursor::paragraph() const -{ - BOOST_ASSERT(inTexted()); - return current_ ? current().paragraph() : *bv_->text()->getPar(par()); -} - - -Row & LCursor::textRow() -{ - return *paragraph().getRow(pos()); -} - - -Row const & LCursor::textRow() const -{ - return *paragraph().getRow(pos()); -} - - -LCursor::par_type LCursor::lastpar() const -{ - return inMathed() ? 0 : text()->paragraphs().size() - 1; -} - - -LCursor::pos_type LCursor::lastpos() const -{ - InsetBase * inset = current().inset(); - return inset && inset->asMathInset() ? cell().size() : paragraph().size(); -} - - -LCursor::row_type LCursor::crow() const -{ - return paragraph().row(pos()); -} - - -LCursor::row_type LCursor::lastcrow() const -{ - return paragraph().rows.size(); -} - - -size_t LCursor::nargs() const -{ - // assume 1x1 grid for 'plain text' - return current_ ? current().nargs() : 1; -} - - -size_t LCursor::ncols() const -{ - // assume 1x1 grid for 'plain text' - return current_ ? current().ncols() : 1; -} - - -size_t LCursor::nrows() const -{ - // assume 1x1 grid for 'plain text' - return current_ ? current().nrows() : 1; -} - - -LCursor::row_type LCursor::row() const -{ - BOOST_ASSERT(current_ > 0); - return current().row(); -} - - -LCursor::col_type LCursor::col() const -{ - BOOST_ASSERT(current_ > 0); - return current().col(); -} - - -MathArray const & LCursor::cell() const -{ - BOOST_ASSERT(current_ > 0); - return current().cell(); -} - - -MathArray & LCursor::cell() -{ - BOOST_ASSERT(current_ > 0); - return current().cell(); -} - void LCursor::info(std::ostream & os) const { for (int i = 1, n = depth(); i < n; ++i) { - cursor_[i].inset()->infoize(os); + operator[](i).inset().infoize(os); os << " "; } if (pos() != 0) @@ -593,13 +402,13 @@ void region(CursorSlice const & i1, CursorSlice const & i2, LCursor::row_type & r1, LCursor::row_type & r2, LCursor::col_type & c1, LCursor::col_type & c2) { - InsetBase * p = i1.inset(); - c1 = p->col(i1.idx_); - c2 = p->col(i2.idx_); + InsetBase & p = i1.inset(); + c1 = p.col(i1.idx_); + c2 = p.col(i2.idx_); if (c1 > c2) swap(c1, c2); - r1 = p->row(i1.idx_); - r2 = p->row(i2.idx_); + r1 = p.row(i1.idx_); + r2 = p.row(i2.idx_); if (r1 > r2) swap(r1, r2); } @@ -616,7 +425,7 @@ string LCursor::grabSelection() CursorSlice i2 = selEnd(); if (i1.idx_ == i2.idx_) { - if (i1.inset()->asMathInset()) { + if (i1.inset().asMathInset()) { MathArray::const_iterator it = i1.cell().begin(); return asString(MathArray(it + i1.pos_, it + i2.pos_)); } else { @@ -629,7 +438,7 @@ string LCursor::grabSelection() region(i1, i2, r1, r2, c1, c2); string data; - if (i1.inset()->asMathInset()) { + if (i1.inset().asMathInset()) { for (row_type row = r1; row <= r2; ++row) { if (row > r1) data += "\\\\"; @@ -652,7 +461,7 @@ void LCursor::eraseSelection() CursorSlice const & i1 = selBegin(); CursorSlice const & i2 = selEnd(); #warning FIXME - if (i1.inset()->asMathInset()) { + if (i1.inset().asMathInset()) { if (i1.idx_ == i2.idx_) { i1.cell().erase(i1.pos_, i2.pos_); } else { @@ -664,7 +473,7 @@ void LCursor::eraseSelection() for (col_type col = c1; col <= c2; ++col) p->cell(p->index(row, col)).clear(); } - current() = i1; + back() = i1; } else { lyxerr << "can't erase this selection 1" << endl; } @@ -749,9 +558,8 @@ void LCursor::selClearOrDel() std::ostream & operator<<(std::ostream & os, LCursor const & cur) { - for (size_t i = 0, n = cur.cursor_.size(); i != n; ++i) - os << " " << cur.cursor_[i] << " | " << cur.anchor_[i] << "\n"; - os << " current: " << cur.current_ << endl; + for (size_t i = 0, n = cur.size(); i != n; ++i) + os << " " << cur.operator[](i) << " | " << cur.anchor_[i] << "\n"; os << " selection: " << cur.selection_ << endl; return os; } @@ -759,89 +567,21 @@ std::ostream & operator<<(std::ostream & os, LCursor const & cur) -// -// CursorBase -// - - -void increment(CursorBase & it) -{ - CursorSlice & top = it.back(); - MathArray & ar = top.asMathInset()->cell(top.idx_); - - // move into the current inset if possible - // it is impossible for pos() == size()! - MathInset * n = 0; - if (top.pos() != top.lastpos()) - n = (ar.begin() + top.pos_)->nucleus(); - if (n && n->isActive()) { - it.push_back(CursorSlice(n)); - return; - } - - // otherwise move on one cell back if possible - if (top.pos() < top.lastpos()) { - // pos() == lastpos() is valid! - ++top.pos_; - return; - } - - // otherwise try to move on one cell if possible - while (top.idx() < top.lastidx()) { - ++top.idx_; - if (top.asMathInset()->validCell(top.idx_)) { - top.pos_ = 0; - return; - } - } - - // otherwise leave array, move on one back - // this might yield pos() == size(), but that's a ok. - it.pop_back(); - // it certainly invalidates top - ++it.back().pos_; -} - - -CursorBase ibegin(InsetBase * p) -{ - CursorBase it; - it.push_back(CursorSlice(p)); - return it; -} - - -CursorBase iend(InsetBase * p) -{ - CursorBase it; - it.push_back(CursorSlice(p)); - CursorSlice & cur = it.back(); - cur.idx() = cur.lastidx(); - cur.pos() = cur.lastpos(); - return it; -} - - - - /////////////////////////////////////////////////////////////////// // // The part below is the non-integrated rest of the original math // cursor. This should be either generalized for texted or moved -// back to the math insets. +// back to mathed (in most cases to MathNestInset). // /////////////////////////////////////////////////////////////////// -#include "mathed/math_braceinset.h" #include "mathed/math_charinset.h" -#include "mathed/math_commentinset.h" #include "mathed/math_factory.h" #include "mathed/math_gridinset.h" #include "mathed/math_macroarg.h" #include "mathed/math_macrotemplate.h" #include "mathed/math_mathmlstream.h" #include "mathed/math_scriptinset.h" -#include "mathed/math_spaceinset.h" #include "mathed/math_support.h" #include "mathed/math_unknowninset.h" @@ -851,13 +591,13 @@ CursorBase iend(InsetBase * p) bool LCursor::isInside(InsetBase const * p) { for (unsigned i = 0; i < depth(); ++i) - if (cursor_[i].inset() == p) + if (&operator[](i).inset() == p) return true; return false; } -bool LCursor::openable(MathAtom const & t) +bool LCursor::openable(MathAtom const & t) const { if (!t->isActive()) return false; @@ -871,59 +611,15 @@ bool LCursor::openable(MathAtom const & t) // we can't move into anything new during selection if (depth() == anchor_.size()) return false; - if (!ptr_cmp(t.nucleus(), anchor_[depth()].inset())) + if (!ptr_cmp(t.nucleus(), &anchor_[depth()].inset())) return false; return true; } -bool LCursor::inNucleus() -{ - return inset()->asMathInset()->asScriptInset() && idx() == 2; -} - - -bool LCursor::left() -{ - autocorrect() = false; - clearTargetX(); - if (inMacroMode()) { - macroModeClose(); - return true; - } - - if (pos() != 0 && openable(prevAtom())) { - posLeft(); - push(nextAtom().nucleus()); - inset()->idxLast(*this); - return true; - } - - return posLeft() || idxLeft() || popLeft() || selection(); -} - - -bool LCursor::right() -{ - autocorrect() = false; - clearTargetX(); - if (inMacroMode()) { - macroModeClose(); - return true; - } - - if (pos() != lastpos() && openable(nextAtom())) { - pushLeft(nextAtom().nucleus()); - inset()->idxFirst(*this); - return true; - } - - return posRight() || idxRight() || popRight() || selection(); -} - - -bool positionable(CursorBase const & cursor, CursorBase const & anchor) +bool positionable(DocumentIterator const & cursor, + DocumentIterator const & anchor) { // avoid deeper nested insets when selecting if (cursor.size() > anchor.size()) @@ -931,7 +627,7 @@ bool positionable(CursorBase const & cursor, CursorBase const & anchor) // anchor might be deeper, should have same path then for (size_t i = 0; i < cursor.size(); ++i) - if (cursor[i].inset() != anchor[i].inset()) + if (&cursor[i].inset() != &anchor[i].inset()) return false; // position should be ok. @@ -953,28 +649,6 @@ void LCursor::setScreenPos(int x, int y) -bool LCursor::home() -{ - autocorrect() = false; - macroModeClose(); - if (!inset()->idxHome(*this)) - return popLeft(); - clearTargetX(); - return true; -} - - -bool LCursor::end() -{ - autocorrect() = false; - macroModeClose(); - if (!inset()->idxEnd(*this)) - return popRight(); - clearTargetX(); - return true; -} - - void LCursor::plainErase() { cell().erase(pos()); @@ -1003,23 +677,21 @@ void LCursor::plainInsert(MathAtom const & t) void LCursor::insert(string const & str) { lyxerr << "LCursor::insert str '" << str << "'" << endl; - selClearOrDel(); -#if 0 for (string::const_iterator it = str.begin(); it != str.end(); ++it) - plainInsert(MathAtom(new MathCharInset(*it))); -#else - MathArray ar; - asArray(str, ar); - insert(ar); -#endif + insert(*it); } void LCursor::insert(char c) { //lyxerr << "LCursor::insert char '" << c << "'" << endl; - selClearOrDel(); - plainInsert(MathAtom(new MathCharInset(c))); + BOOST_ASSERT(!empty()); + if (inMathed()) { + selClearOrDel(); + plainInsert(MathAtom(new MathCharInset(c))); + } else { + text()->insertChar(*this, c); + } } @@ -1062,7 +734,7 @@ void LCursor::niceInsert(MathAtom const & t) posLeft(); // be careful here: don't use 'pushLeft(t)' as this we need to // push the clone, not the original - pushLeft(nextAtom().nucleus()); + pushLeft(*nextInset()); paste(safe); } } @@ -1088,7 +760,7 @@ bool LCursor::backspace() } if (pos() == 0) { - if (inset()->nargs() == 1 && depth() == 1 && lastpos() == 0) + if (inset().nargs() == 1 && depth() == 1 && lastpos() == 0) return false; pullArg(); return true; @@ -1106,7 +778,7 @@ bool LCursor::backspace() // let's require two backspaces for 'big stuff' and // highlight on the first selection() = true; - left(); + --pos(); } else { --pos(); plainErase(); @@ -1127,25 +799,25 @@ bool LCursor::erase() } // delete empty cells if possible - if (pos() == lastpos() && inset()->idxDelete(idx())) + if (pos() == lastpos() && inset().idxDelete(idx())) return true; // special behaviour when in last position of cell if (pos() == lastpos()) { - bool one_cell = inset()->nargs() == 1; + bool one_cell = inset().nargs() == 1; if (one_cell && depth() == 1 && lastpos() == 0) return false; // remove markup if (one_cell) pullArg(); else - inset()->idxGlue(idx()); + inset().idxGlue(idx()); return true; } - if (pos() != lastpos() && inset()->nargs() > 0) { + if (pos() != lastpos() && inset().nargs() > 0) { selection() = true; - right(); + ++pos(); } else { plainErase(); } @@ -1157,10 +829,10 @@ bool LCursor::erase() bool LCursor::up() { macroModeClose(); - CursorBase save = cursor_; + DocumentIterator save = *this; if (goUpDown(true)) return true; - cursor_ = save; + setCursor(save, false); autocorrect() = false; return selection(); } @@ -1169,10 +841,10 @@ bool LCursor::up() bool LCursor::down() { macroModeClose(); - CursorBase save = cursor_; + DocumentIterator save = *this; if (goUpDown(false)) return true; - cursor_ = save; + setCursor(save, false); autocorrect() = false; return selection(); } @@ -1195,8 +867,8 @@ void LCursor::macroModeClose() string const name = s.substr(1); // prevent entering of recursive macros - if (formula()->lyxCode() == InsetOld::MATHMACRO_CODE - && formula()->getInsetName() == name) + InsetBase const * macro = innerInsetOfType(InsetBase::MATHMACRO_CODE); + if (macro && macro->getInsetName() == name) lyxerr << "can't enter recursive macro" << endl; niceInsert(createMathInset(name)); @@ -1216,7 +888,7 @@ void LCursor::handleNest(MathAtom const & a, int c) asArray(grabAndEraseSelection(), t.nucleus()->cell(c)); insert(t); posLeft(); - pushLeft(nextAtom().nucleus()); + pushLeft(*nextInset()); } @@ -1233,8 +905,8 @@ int LCursor::targetX() const MathHullInset * LCursor::formula() const { - for (int i = cursor_.size() - 1; i >= 1; --i) { - MathInset * inset = cursor_[i].inset()->asMathInset(); + for (int i = size() - 1; i >= 1; --i) { + MathInset * inset = operator[](i).inset().asMathInset(); if (inset && inset->asHullInset()) return static_cast(inset); } @@ -1278,12 +950,12 @@ bool LCursor::inMacroArgMode() const MathGridInset * LCursor::enclosingGrid(idx_type & idx) const { for (MathInset::difference_type i = depth() - 1; i >= 0; --i) { - MathInset * m = cursor_[i].inset()->asMathInset(); + MathInset * m = operator[](i).inset().asMathInset(); if (!m) return 0; MathGridInset * p = m->asGridInset(); if (p) { - idx = cursor_[i].idx_; + idx = operator[](i).idx_; return p; } } @@ -1309,8 +981,8 @@ void LCursor::touch() { #warning look here #if 0 - CursorBase::const_iterator it = cursor_.begin(); - CursorBase::const_iterator et = cursor_.end(); + DocumentIterator::const_iterator it = begin(); + DocumentIterator::const_iterator et = end(); for ( ; it != et; ++it) it->cell().touch(); #endif @@ -1322,7 +994,7 @@ void LCursor::normalize() if (idx() >= nargs()) { lyxerr << "this should not really happen - 1: " << idx() << ' ' << nargs() - << " in: " << inset() << endl; + << " in: " << &inset() << endl; } idx() = min(idx(), lastidx()); @@ -1331,7 +1003,7 @@ void LCursor::normalize() << pos() << ' ' << lastpos() << " in idx: " << idx() << " in atom: '"; WriteStream wi(lyxerr, false, true); - inset()->asMathInset()->write(wi); + inset().asMathInset()->write(wi); lyxerr << endl; } pos() = min(pos(), lastpos()); @@ -1356,9 +1028,10 @@ char LCursor::halign() bool LCursor::goUpDown(bool up) { - // Be warned: The 'logic' implemented in this function is highly fragile. - // A distance of one pixel or a '<' vs '<=' _really_ matters. - // So fiddle around with it only if you know what you are doing! + // Be warned: The 'logic' implemented in this function is highly + // fragile. A distance of one pixel or a '<' vs '<=' _really + // matters. So fiddle around with it only if you think you know + // what you are doing! int xo = 0; int yo = 0; getPos(xo, yo); @@ -1398,7 +1071,7 @@ bool LCursor::goUpDown(bool up) } // try current cell for e.g. text insets - if (inset()->idxUpDown2(*this, up)) + if (inset().idxUpDown2(*this, up)) return true; //xarray().boundingBox(xlow, xhigh, ylow, yhigh); @@ -1413,9 +1086,9 @@ bool LCursor::goUpDown(bool up) // try to find an inset that knows better then we while (1) { - //lyxerr << "updown: We are in " << inset() << " idx: " << idx() << endl; + //lyxerr << "updown: We are in " << &inset() << " idx: " << idx() << endl; // ask inset first - if (inset()->idxUpDown(*this, up)) { + if (inset().idxUpDown(*this, up)) { // try to find best position within this inset if (!selection()) bruteFind2(xo, yo); @@ -1445,17 +1118,17 @@ bool LCursor::goUpDown(bool up) bool LCursor::bruteFind(int x, int y, int xlow, int xhigh, int ylow, int yhigh) { - CursorBase best_cursor; + DocumentIterator best_cursor; double best_dist = 1e10; - CursorBase it = ibegin(formula()); - CursorBase et = iend(formula()); + DocumentIterator it = insetBegin(bv().buffer()->inset()); + DocumentIterator et = insetEnd(); while (1) { // avoid invalid nesting when selecting if (!selection() || positionable(it, anchor_)) { int xo, yo; CursorSlice & cur = it.back(); - cur.inset()->getCursorPos(cur, xo, yo); + cur.inset().getCursorPos(cur, xo, yo); if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) { double d = (x - xo) * (x - xo) + (y - yo) * (y - yo); //lyxerr << "x: " << x << " y: " << y << " d: " << endl; @@ -1470,11 +1143,11 @@ bool LCursor::bruteFind(int x, int y, int xlow, int xhigh, int ylow, int yhigh) if (it == et) break; - increment(it); + it.forwardPos(); } if (best_dist < 1e10) - cursor_ = best_cursor; + setCursor(best_cursor, false); return best_dist < 1e10; } @@ -1483,243 +1156,25 @@ void LCursor::bruteFind2(int x, int y) { double best_dist = 1e10; - CursorBase it = cursor_; - it.back().pos(0); - CursorBase et = cursor_; - int n = et.back().asMathInset()->cell(et.back().idx_).size(); - et.back().pos(n); + DocumentIterator it = *this; + it.back().pos() = 0; + DocumentIterator et = *this; + et.back().pos() = et.back().asMathInset()->cell(et.back().idx_).size(); for (int i = 0; ; ++i) { int xo, yo; CursorSlice & cur = it.back(); - cur.inset()->getCursorPos(cur, xo, yo); + cur.inset().getCursorPos(cur, xo, yo); double d = (x - xo) * (x - xo) + (y - yo) * (y - yo); // '<=' in order to take the last possible position // this is important for clicking behind \sum in e.g. '\sum_i a' lyxerr << "i: " << i << " d: " << d << " best: " << best_dist << endl; if (d <= best_dist) { best_dist = d; - cursor_ = it; + setCursor(it, false); } if (it == et) break; - increment(it); - } -} - - -bool LCursor::idxLineLast() -{ - idx() -= idx() % ncols(); - idx() += ncols() - 1; - pos() = lastpos(); - return true; -} - - -bool LCursor::idxLeft() -{ - return inset()->idxLeft(*this); -} - - -bool LCursor::idxRight() -{ - return inset()->idxRight(*this); -} - - -bool LCursor::script(bool up) -{ - // Hack to get \\^ and \\_ working - lyxerr << "handling script: up: " << up << endl; - if (inMacroMode() && macroName() == "\\") { - if (up) - niceInsert(createMathInset("mathcircumflex")); - else - interpret('_'); - return true; - } - - macroModeClose(); - string safe = grabAndEraseSelection(); - if (inNucleus()) { - // we are in a nucleus of a script inset, move to _our_ script - inset()->asMathInset()->asScriptInset()->ensure(up); - idx() = up; - pos() = 0; - } else if (pos() != 0 && prevAtom()->asScriptInset()) { - --pos(); - nextAtom().nucleus()->asScriptInset()->ensure(up); - push(nextInset()); - idx() = up; - pos() = lastpos(); - } else if (pos() != 0) { - --pos(); - cell()[pos()] = MathAtom(new MathScriptInset(nextAtom(), up)); - push(nextInset()); - idx() = up; - pos() = 0; - } else { - plainInsert(MathAtom(new MathScriptInset(up))); - --pos(); - nextAtom().nucleus()->asScriptInset()->ensure(up); - push(nextInset()); - idx() = up; - pos() = 0; - } - paste(safe); - return true; -} - - -bool LCursor::interpret(char c) -{ - //lyxerr << "interpret 2: '" << c << "'" << endl; - clearTargetX(); - if (inMacroArgMode()) { - posLeft(); - plainErase(); -#warning FIXME -#if 0 - int n = c - '0'; - MathMacroTemplate const * p = formula()->asMacroTemplate(); - if (p && 1 <= n && n <= p->numargs()) - insert(MathAtom(new MathMacroArgument(c - '0'))); - else { - insert(createMathInset("#")); - interpret(c); // try again - } -#endif - return true; - } - - // handle macroMode - if (inMacroMode()) { - string name = macroName(); - //lyxerr << "interpret name: '" << name << "'" << endl; - - if (isalpha(c)) { - activeMacro()->setName(activeMacro()->name() + c); - return true; - } - - // handle 'special char' macros - if (name == "\\") { - // remove the '\\' - backspace(); - if (c == '\\') { - if (currentMode() == MathInset::TEXT_MODE) - niceInsert(createMathInset("textbackslash")); - else - niceInsert(createMathInset("backslash")); - } else if (c == '{') { - niceInsert(MathAtom(new MathBraceInset)); - } else { - niceInsert(createMathInset(string(1, c))); - } - return true; - } - - // leave macro mode and try again if necessary - macroModeClose(); - if (c == '{') - niceInsert(MathAtom(new MathBraceInset)); - else if (c != ' ') - interpret(c); - return true; - } - - // This is annoying as one has to press far too often. - // Disable it. - - if (0) { - // leave autocorrect mode if necessary - if (autocorrect() && c == ' ') { - autocorrect() = false; - return true; - } - } - - // just clear selection on pressing the space bar - if (selection() && c == ' ') { - selection() = false; - return true; - } - - selClearOrDel(); - - if (c == '\\') { - //lyxerr << "starting with macro" << endl; - insert(MathAtom(new MathUnknownInset("\\", false))); - return true; - } - - if (c == '\n') { - if (currentMode() == MathInset::TEXT_MODE) - insert(c); - return true; - } - - if (c == ' ') { - if (currentMode() == MathInset::TEXT_MODE) { - // insert spaces in text mode, - // but suppress direct insertion of two spaces in a row - // the still allows typing 'a' and deleting the 'a', but - // it is better than nothing... - if (!pos() != 0 || prevAtom()->getChar() != ' ') - insert(c); - return true; - } - if (pos() != 0 && prevAtom()->asSpaceInset()) { - prevAtom().nucleus()->asSpaceInset()->incSpace(); - return true; - } - if (popRight()) - return true; - // if are at the very end, leave the formula - return pos() != lastpos(); - } - - if (c == '_') { - script(false); - return true; - } - - if (c == '^') { - script(true); - return true; - } - - if (c == '{' || c == '}' || c == '#' || c == '&' || c == '$') { - niceInsert(createMathInset(string(1, c))); - return true; - } - - if (c == '%') { - niceInsert(MathAtom(new MathCommentInset)); - return true; - } - - // try auto-correction - //if (autocorrect() && hasPrevAtom() && math_autocorrect(prevAtom(), c)) - // return true; - - // no special circumstances, so insert the character without any fuss - insert(c); - autocorrect() = true; - return true; -} - - -void LCursor::lockToggle() -{ - if (pos() != lastpos()) { - // toggle previous inset ... - nextAtom().nucleus()->lock(!nextAtom()->lock()); - } else if (popLeft() && pos() != lastpos()) { - // ... or enclosing inset if we are in the last inset position - nextAtom().nucleus()->lock(!nextAtom()->lock()); - ++pos(); + it.forwardPos(); } } @@ -1732,7 +1187,7 @@ CursorSlice LCursor::normalAnchor() } //lyx::BOOST_ASSERT(Anchor_.size() >= cursor.depth()); // use Anchor on the same level as Cursor - CursorSlice normal = anchor_[current_]; + CursorSlice normal = anchor_[size() - 1]; #if 0 if (depth() < anchor_.size() && !(normal < xx())) { // anchor is behind cursor -> move anchor behind the inset @@ -1743,38 +1198,6 @@ CursorSlice LCursor::normalAnchor() } -/* -DispatchResult dispatch(LCursor & cur, FuncRequest const & cmd) -{ - // mouse clicks are somewhat special - // check - switch (cmd.action) { - case LFUN_MOUSE_PRESS: - case LFUN_MOUSE_MOTION: - case LFUN_MOUSE_RELEASE: - case LFUN_MOUSE_DOUBLE: { - CursorSlice & pos = cursor_.back(); - int x = 0; - int y = 0; - getPos(x, y); - if (x < cmd.x && pos() != 0) { - DispatchResult const res = prevAtom().nucleus()->dispatch(cmd); - if (res.dispatched()) - return res; - } - if (x > cmd.x && pos() != lastpos()) { - DispatchResult const res = inset()->dispatch(cmd); - if (res.dispatched()) - return res; - } - } - default: - break; - } -} -*/ - - void LCursor::handleFont(string const & font) { lyxerr << "LCursor::handleFont: " << font << endl; @@ -1810,55 +1233,6 @@ void LCursor::handleFont(string const & font) } -void LCursor::releaseMathCursor() -{ - if (inMathed()) - formula()->insetUnlock(bv()); -} - - -bool LCursor::inMathed() const -{ - return formula(); -} - - -bool LCursor::inTexted() const -{ - return !formula(); -} - - -InsetBase * LCursor::nextInset() -{ - if (pos() == lastpos()) - return 0; - if (inMathed()) - return nextAtom().nucleus(); - return paragraph().isInset(pos()) ? paragraph().getInset(pos()) : 0; -} - - -InsetBase * LCursor::prevInset() -{ - if (pos() == 0) - return 0; - if (inMathed()) - return prevAtom().nucleus(); - return paragraph().isInset(pos() - 1) ? paragraph().getInset(pos() - 1) : 0; -} - - -InsetBase const * LCursor::prevInset() const -{ - if (pos() == 0) - return 0; - if (inMathed()) - return prevAtom().nucleus(); - return paragraph().isInset(pos() - 1) ? paragraph().getInset(pos() - 1) : 0; -} - - void LCursor::message(string const & msg) const { bv().owner()->getLyXFunc().setMessage(msg); @@ -1903,7 +1277,7 @@ string LCursor::selectionAsString(bool label) const return result; } -#warning an mathed? +#warning and mathed? return string(); } @@ -1915,7 +1289,11 @@ string LCursor::currentState() info(os); return os.str(); } - return text()->currentState(*this); + + if (inTexted()) + return text()->currentState(*this); + + return string(); } @@ -1923,13 +1301,14 @@ string LCursor::currentState() void LCursor::replaceWord(string const & replacestring) { LyXText * t = text(); + BOOST_ASSERT(t); t->replaceSelectionWithString(*this, replacestring); t->setSelectionRange(*this, replacestring.length()); // Go back so that replacement string is also spellchecked for (string::size_type i = 0; i < replacestring.length() + 1; ++i) - t->cursorLeft(*this, true); + t->cursorLeft(*this); } @@ -1937,3 +1316,42 @@ void LCursor::update() { bv().update(); } + + +string LCursor::getPossibleLabel() +{ + return inMathed() ? "eq:" : text()->getPossibleLabel(*this); +} + + +Encoding const * LCursor::getEncoding() const +{ + if (empty()) + return 0; + if (!bv().buffer()) + return 0; + int s = 0; + // go up until first non-0 text is hit + // (innermost text is 0 in mathed) + for (s = size() - 1; s >= 0; --s) + if (operator[](s).text()) + break; + CursorSlice const & sl = operator[](s); + LyXText & text = *sl.text(); + ParagraphList::iterator pit = text.getPar(sl.par()); + LyXFont font = pit->getFont( + bv().buffer()->params(), sl.pos(), outerFont(pit, text.paragraphs())); + return font.language()->encoding(); +} + + +void LCursor::undispatched() +{ + disp_.dispatched(false); +} + + +void LCursor::noUpdate() +{ + disp_.update(false); +}