]> git.lyx.org Git - lyx.git/blobdiff - src/Cursor.cpp
Embedding: saving inzip name to .lyx file so that embedded files can always be found...
[lyx.git] / src / Cursor.cpp
index 1f1ed772667cd8f4e32dc355836c5225a507f34f..eb23d79533094ea87ecf8ad64ba81515eabe79dc 100644 (file)
 
 #include "Bidi.h"
 #include "BufferView.h"
-#include "bufferview_funcs.h"
 #include "Buffer.h"
 #include "Cursor.h"
 #include "CoordCache.h"
 #include "CutAndPaste.h"
-#include "debug.h"
 #include "DispatchResult.h"
 #include "Encoding.h"
 #include "FuncRequest.h"
 #include "Paragraph.h"
 #include "paragraph_funcs.h"
 #include "ParIterator.h"
+#include "TextMetrics.h"
+
+#include "support/debug.h"
+#include "support/docstream.h"
 
 #include "insets/InsetTabular.h"
 #include "insets/InsetText.h"
 
-#include "mathed/MathData.h"
 #include "mathed/InsetMath.h"
 #include "mathed/InsetMathScript.h"
 #include "mathed/MacroTable.h"
-
-#include "support/limited_stack.h"
+#include "mathed/MathData.h"
+#include "mathed/MathMacro.h"
 
 #include <boost/assert.hpp>
 #include <boost/bind.hpp>
-#include <boost/current_function.hpp>
 
 #include <sstream>
 #include <limits>
 #include <map>
 
-using std::string;
-using std::vector;
-using std::endl;
-using std::min;
-using std::for_each;
-
+using namespace std;
 
 namespace lyx {
 
 namespace {
 
-       bool
-       positionable(DocIterator const & cursor, DocIterator const & anchor)
-       {
-               // avoid deeper nested insets when selecting
-               if (cursor.depth() > anchor.depth())
+bool positionable(DocIterator const & cursor, DocIterator const & anchor)
+{
+       // avoid deeper nested insets when selecting
+       if (cursor.depth() > anchor.depth())
+               return false;
+
+       // anchor might be deeper, should have same path then
+       for (size_t i = 0; i < cursor.depth(); ++i)
+               if (&cursor[i].inset() != &anchor[i].inset())
                        return false;
 
-               // anchor might be deeper, should have same path then
-               for (size_t i = 0; i < cursor.depth(); ++i)
-                       if (&cursor[i].inset() != &anchor[i].inset())
-                               return false;
+       // position should be ok.
+       return true;
+}
+
 
-               // position should be ok.
-               return true;
-       }
+// Find position closest to (x, y) in cell given by iter.
+// Used only in mathed
+DocIterator bruteFind2(Cursor const & c, int x, int y)
+{
+       double best_dist = numeric_limits<double>::max();
 
+       DocIterator result;
 
-       // Find position closest to (x, y) in cell given by iter.
-       // Used only in mathed
-       DocIterator bruteFind2(Cursor const & c, int x, int y)
-       {
-               double best_dist = std::numeric_limits<double>::max();
-
-               DocIterator result;
-
-               DocIterator it = c;
-               it.top().pos() = 0;
-               DocIterator et = c;
-               et.top().pos() = et.top().asInsetMath()->cell(et.top().idx()).size();
-               for (size_t i = 0;; ++i) {
-                       int xo;
-                       int yo;
-                       Inset const * inset = &it.inset();
-                       std::map<Inset const *, Geometry> const & data =
-                               c.bv().coordCache().getInsets().getData();
-                       std::map<Inset const *, Geometry>::const_iterator I = data.find(inset);
-
-                       // FIXME: in the case where the inset is not in the cache, this
-                       // means that no part of it is visible on screen. In this case
-                       // we don't do elaborate search and we just return the forwarded
-                       // DocIterator at its beginning.
-                       if (I == data.end()) {
-                               it.top().pos() = 0;
-                               return it;
-                       }
+       DocIterator it = c;
+       it.top().pos() = 0;
+       DocIterator et = c;
+       et.top().pos() = et.top().asInsetMath()->cell(et.top().idx()).size();
+       for (size_t i = 0;; ++i) {
+               int xo;
+               int yo;
+               Inset const * inset = &it.inset();
+               map<Inset const *, Geometry> const & data =
+                       c.bv().coordCache().getInsets().getData();
+               map<Inset const *, Geometry>::const_iterator I = data.find(inset);
 
-                       Point o = I->second.pos;
-                       inset->cursorPos(c.bv(), it.top(), c.boundary(), xo, yo);
-                       // Convert to absolute
-                       xo += o.x_;
-                       yo += o.y_;
-                       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(Debug::DEBUG) << "i: " << i << " d: " << d
-                               << " best: " << best_dist << endl;
-                       if (d <= best_dist) {
-                               best_dist = d;
-                               result = it;
-                       }
-                       if (it == et)
-                               break;
-                       it.forwardPos();
+               // FIXME: in the case where the inset is not in the cache, this
+               // means that no part of it is visible on screen. In this case
+               // we don't do elaborate search and we just return the forwarded
+               // DocIterator at its beginning.
+               if (I == data.end()) {
+                       it.top().pos() = 0;
+                       return it;
                }
-               return result;
-       }
-
 
-       /*
-       /// moves position closest to (x, y) in given box
-       bool bruteFind(Cursor & cursor,
-               int x, int y, int xlow, int xhigh, int ylow, int yhigh)
-       {
-               BOOST_ASSERT(!cursor.empty());
-               Inset & inset = cursor[0].inset();
-               BufferView & bv = cursor.bv();
-
-               CoordCache::InnerParPosCache const & cache =
-                       bv.coordCache().getParPos().find(cursor.bottom().text())->second;
-               // Get an iterator on the first paragraph in the cache
-               DocIterator it(inset);
-               it.push_back(CursorSlice(inset));
-               it.pit() = cache.begin()->first;
-               // Get an iterator after the last paragraph in the cache
-               DocIterator et(inset);
-               et.push_back(CursorSlice(inset));
-               et.pit() = boost::prior(cache.end())->first;
-               if (et.pit() >= et.lastpit())
-                       et = doc_iterator_end(inset);
-               else
-                       ++et.pit();
-
-               double best_dist = std::numeric_limits<double>::max();;
-               DocIterator best_cursor = et;
-
-               for ( ; it != et; it.forwardPos(true)) {
-                       // avoid invalid nesting when selecting
-                       if (!cursor.selection() || positionable(it, cursor.anchor_)) {
-                               Point p = bv.getPos(it, false);
-                               int xo = p.x_;
-                               int yo = p.y_;
-                               if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
-                                       double const dx = xo - x;
-                                       double const dy = yo - y;
-                                       double const d = dx * dx + dy * dy;
-                                       // '<=' in order to take the last possible position
-                                       // this is important for clicking behind \sum in e.g. '\sum_i a'
-                                       if (d <= best_dist) {
-                                               //      lyxerr << "*" << endl;
-                                               best_dist   = d;
-                                               best_cursor = it;
-                                       }
+               Point o = I->second.pos;
+               inset->cursorPos(c.bv(), it.top(), c.boundary(), xo, yo);
+               // Convert to absolute
+               xo += o.x_;
+               yo += o.y_;
+               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(Debug::DEBUG, "i: " << i << " d: " << d
+                       << " best: " << best_dist);
+               if (d <= best_dist) {
+                       best_dist = d;
+                       result = it;
+               }
+               if (it == et)
+                       break;
+               it.forwardPos();
+       }
+       return result;
+}
+
+
+/*
+/// moves position closest to (x, y) in given box
+bool bruteFind(Cursor & cursor,
+       int x, int y, int xlow, int xhigh, int ylow, int yhigh)
+{
+       BOOST_ASSERT(!cursor.empty());
+       Inset & inset = cursor[0].inset();
+       BufferView & bv = cursor.bv();
+
+       CoordCache::InnerParPosCache const & cache =
+               bv.coordCache().getParPos().find(cursor.bottom().text())->second;
+       // Get an iterator on the first paragraph in the cache
+       DocIterator it(inset);
+       it.push_back(CursorSlice(inset));
+       it.pit() = cache.begin()->first;
+       // Get an iterator after the last paragraph in the cache
+       DocIterator et(inset);
+       et.push_back(CursorSlice(inset));
+       et.pit() = boost::prior(cache.end())->first;
+       if (et.pit() >= et.lastpit())
+               et = doc_iterator_end(inset);
+       else
+               ++et.pit();
+
+       double best_dist = numeric_limits<double>::max();;
+       DocIterator best_cursor = et;
+
+       for ( ; it != et; it.forwardPos(true)) {
+               // avoid invalid nesting when selecting
+               if (!cursor.selection() || positionable(it, cursor.anchor_)) {
+                       Point p = bv.getPos(it, false);
+                       int xo = p.x_;
+                       int yo = p.y_;
+                       if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
+                               double const dx = xo - x;
+                               double const dy = yo - y;
+                               double const d = dx * dx + dy * dy;
+                               // '<=' in order to take the last possible position
+                               // this is important for clicking behind \sum in e.g. '\sum_i a'
+                               if (d <= best_dist) {
+                                       //      lyxerr << "*" << endl;
+                                       best_dist   = d;
+                                       best_cursor = it;
                                }
                        }
                }
+       }
 
-               if (best_cursor != et) {
-                       cursor.setCursor(best_cursor);
-                       return true;
-               }
-
-               return false;
+       if (best_cursor != et) {
+               cursor.setCursor(best_cursor);
+               return true;
        }
-       */
 
+       return false;
+}
+*/
 
-       /// moves position closest to (x, y) in given box
-       bool bruteFind3(Cursor & cur, int x, int y, bool up)
-       {
-               BufferView & bv = cur.bv();
-               int ylow  = up ? 0 : y + 1;
-               int yhigh = up ? y - 1 : bv.workHeight();
-               int xlow = 0;
-               int xhigh = bv.workWidth();
+
+/// moves position closest to (x, y) in given box
+bool bruteFind3(Cursor & cur, int x, int y, bool up)
+{
+       BufferView & bv = cur.bv();
+       int ylow  = up ? 0 : y + 1;
+       int yhigh = up ? y - 1 : bv.workHeight();
+       int xlow = 0;
+       int xhigh = bv.workWidth();
 
 // FIXME: bit more work needed to get 'from' and 'to' right.
-               pit_type from = cur.bottom().pit();
-               //pit_type to = cur.bottom().pit();
-               //lyxerr << "Pit start: " << from << endl;
-
-               //lyxerr << "bruteFind3: x: " << x << " y: " << y
-               //      << " xlow: " << xlow << " xhigh: " << xhigh
-               //      << " ylow: " << ylow << " yhigh: " << yhigh
-               //      << endl;
-               Inset & inset = bv.buffer().inset();
-               DocIterator it = doc_iterator_begin(inset);
-               it.pit() = from;
-               DocIterator et = doc_iterator_end(inset);
-
-               double best_dist = std::numeric_limits<double>::max();
-               DocIterator best_cursor = et;
-
-               for ( ; it != et; it.forwardPos()) {
-                       // avoid invalid nesting when selecting
-                       if (bv.cursorStatus(it) == CUR_INSIDE
-                           && (!cur.selection() || positionable(it, cur.anchor_))) {
-                               Point p = bv.getPos(it, false);
-                               int xo = p.x_;
-                               int yo = p.y_;
-                               if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
-                                       double const dx = xo - x;
-                                       double const dy = yo - y;
-                                       double const d = dx * dx + dy * dy;
-                                       //lyxerr << "itx: " << xo << " ity: " << yo << " d: " << d
-                                       //      << " dx: " << dx << " dy: " << dy
-                                       //      << " idx: " << it.idx() << " pos: " << it.pos()
-                                       //      << " it:\n" << it
-                                       //      << endl;
-                                       // '<=' in order to take the last possible position
-                                       // this is important for clicking behind \sum in e.g. '\sum_i a'
-                                       if (d <= best_dist) {
-                                               //lyxerr << "*" << endl;
-                                               best_dist   = d;
-                                               best_cursor = it;
-                                       }
+       pit_type from = cur.bottom().pit();
+       //pit_type to = cur.bottom().pit();
+       //lyxerr << "Pit start: " << from << endl;
+
+       //lyxerr << "bruteFind3: x: " << x << " y: " << y
+       //      << " xlow: " << xlow << " xhigh: " << xhigh
+       //      << " ylow: " << ylow << " yhigh: " << yhigh
+       //      << endl;
+       Inset & inset = bv.buffer().inset();
+       DocIterator it = doc_iterator_begin(inset);
+       it.pit() = from;
+       DocIterator et = doc_iterator_end(inset);
+
+       double best_dist = numeric_limits<double>::max();
+       DocIterator best_cursor = et;
+
+       for ( ; it != et; it.forwardPos()) {
+               // avoid invalid nesting when selecting
+               if (bv.cursorStatus(it) == CUR_INSIDE
+                               && (!cur.selection() || positionable(it, cur.anchor_))) {
+                       Point p = bv.getPos(it, false);
+                       int xo = p.x_;
+                       int yo = p.y_;
+                       if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
+                               double const dx = xo - x;
+                               double const dy = yo - y;
+                               double const d = dx * dx + dy * dy;
+                               //lyxerr << "itx: " << xo << " ity: " << yo << " d: " << d
+                               //      << " dx: " << dx << " dy: " << dy
+                               //      << " idx: " << it.idx() << " pos: " << it.pos()
+                               //      << " it:\n" << it
+                               //      << endl;
+                               // '<=' in order to take the last possible position
+                               // this is important for clicking behind \sum in e.g. '\sum_i a'
+                               if (d <= best_dist) {
+                                       //lyxerr << "*" << endl;
+                                       best_dist   = d;
+                                       best_cursor = it;
                                }
                        }
                }
-
-               //lyxerr << "best_dist: " << best_dist << " cur:\n" << best_cursor << endl;
-               if (best_cursor == et)
-                       return false;
-               cur.setCursor(best_cursor);
-               return true;
        }
 
-       docstring parbreak(Paragraph const & par)
-       {
-               odocstringstream ods;
+       //lyxerr << "best_dist: " << best_dist << " cur:\n" << best_cursor << endl;
+       if (best_cursor == et)
+               return false;
+       cur.setCursor(best_cursor);
+       return true;
+}
+
+docstring parbreak(Paragraph const & par)
+{
+       odocstringstream ods;
+       ods << '\n';
+       // only add blank line if we're not in an ERT or Listings inset
+       if (par.ownerCode() != ERT_CODE
+                       && par.ownerCode() != LISTINGS_CODE)
                ods << '\n';
-               // only add blank line if we're not in an ERT or Listings inset
-               if (par.ownerCode() != Inset::ERT_CODE
-                   && par.ownerCode() != Inset::LISTINGS_CODE)
-                       ods << '\n';
-               return ods.str();
-       }
+       return ods.str();
+}
 
 } // namespace anon
 
@@ -268,7 +262,8 @@ namespace {
 // bv functions are not yet available!
 Cursor::Cursor(BufferView & bv)
        : DocIterator(), bv_(&bv), anchor_(), x_target_(-1), textTargetOffset_(0),
-         selection_(false), mark_(false), logicalpos_(false), current_font(Font::ALL_INHERIT)
+         selection_(false), mark_(false), logicalpos_(false),
+         current_font(inherit_font)
 {}
 
 
@@ -292,9 +287,7 @@ void Cursor::setCursor(DocIterator const & cur)
 
 void Cursor::dispatch(FuncRequest const & cmd0)
 {
-       LYXERR(Debug::DEBUG) << BOOST_CURRENT_FUNCTION
-                            << " cmd: " << cmd0 << '\n'
-                            << *this << endl;
+       LYXERR(Debug::DEBUG, "cmd: " << cmd0 << '\n' << *this);
        if (empty())
                return;
 
@@ -303,11 +296,10 @@ void Cursor::dispatch(FuncRequest const & cmd0)
        Cursor safe = *this;
        
        // store some values to be used inside of the handlers
-       getPos(beforeDispX_, beforeDispY_);
        beforeDispatchCursor_ = *this;
        for (; depth(); pop()) {
-               LYXERR(Debug::DEBUG) << "Cursor::dispatch: cmd: "
-                       << cmd0 << endl << *this << endl;
+               LYXERR(Debug::DEBUG, "Cursor::dispatch: cmd: "
+                       << cmd0 << endl << *this);
                BOOST_ASSERT(pos() <= lastpos());
                BOOST_ASSERT(idx() <= lastidx());
                BOOST_ASSERT(pit() <= lastpit());
@@ -325,7 +317,7 @@ void Cursor::dispatch(FuncRequest const & cmd0)
        // it completely to get a 'bomb early' behaviour in case this
        // object will be used again.
        if (!disp_.dispatched()) {
-               LYXERR(Debug::DEBUG) << "RESTORING OLD CURSOR!" << endl;
+               LYXERR(Debug::DEBUG, "RESTORING OLD CURSOR!");
                operator=(safe);
                disp_.update(Update::None);
                disp_.dispatched(false);
@@ -370,19 +362,19 @@ void Cursor::push(Inset & p)
 }
 
 
-void Cursor::pushLeft(Inset & p)
+void Cursor::pushBackward(Inset & p)
 {
        BOOST_ASSERT(!empty());
-       //lyxerr << "Entering inset " << t << " left" << endl;
+       //lyxerr << "Entering inset " << t << " front" << endl;
        push(p);
        p.idxFirst(*this);
 }
 
 
-bool Cursor::popLeft()
+bool Cursor::popBackward()
 {
        BOOST_ASSERT(!empty());
-       //lyxerr << "Leaving inset to the left" << endl;
+       //lyxerr << "Leaving inset from in front" << endl;
        inset().notifyCursorLeaves(*this);
        if (depth() == 1)
                return false;
@@ -391,10 +383,10 @@ bool Cursor::popLeft()
 }
 
 
-bool Cursor::popRight()
+bool Cursor::popForward()
 {
        BOOST_ASSERT(!empty());
-       //lyxerr << "Leaving inset to the right" << endl;
+       //lyxerr << "Leaving inset from in back" << endl;
        const pos_type lp = (depth() > 1) ? (*this)[depth() - 2].lastpos() : 0;
        inset().notifyCursorLeaves(*this);
        if (depth() == 1)
@@ -427,7 +419,8 @@ void Cursor::getPos(int & x, int & y) const
 
 Row const & Cursor::textRow() const
 {
-       ParagraphMetrics const & pm = bv().parMetrics(text(), pit());
+       CursorSlice const & cs = innerTextSlice();
+       ParagraphMetrics const & pm = bv().parMetrics(cs.text(), cs.pit());
        BOOST_ASSERT(!pm.rows().empty());
        return pm.getRow(pos(), boundary());
 }
@@ -440,7 +433,7 @@ void Cursor::resetAnchor()
 
 
 
-bool Cursor::posLeft()
+bool Cursor::posBackward()
 {
        if (pos() == 0)
                return false;
@@ -449,7 +442,7 @@ bool Cursor::posLeft()
 }
 
 
-bool Cursor::posRight()
+bool Cursor::posForward()
 {
        if (pos() == lastpos())
                return false;
@@ -585,6 +578,8 @@ void Cursor::info(odocstream & os) const
 bool Cursor::selHandle(bool sel)
 {
        //lyxerr << "Cursor::selHandle" << endl;
+       if (mark())
+               sel = true;
        if (sel == selection())
                return false;
 
@@ -597,7 +592,7 @@ bool Cursor::selHandle(bool sel)
 }
 
 
-std::ostream & operator<<(std::ostream & os, Cursor const & cur)
+ostream & operator<<(ostream & os, Cursor const & cur)
 {
        os << "\n cursor:                                | anchor:\n";
        for (size_t i = 0, n = cur.depth(); i != n; ++i) {
@@ -616,11 +611,20 @@ std::ostream & operator<<(std::ostream & os, Cursor const & cur)
        return os;
 }
 
+
+LyXErr & operator<<(LyXErr & os, Cursor const & cur)
+{
+       os.stream() << cur;
+       return os;
+}
+
+
 } // namespace lyx
 
 
 ///////////////////////////////////////////////////////////////////
 //
+// FIXME: Look here
 // The part below is the non-integrated rest of the original math
 // cursor. This should be either generalized for texted or moved
 // back to mathed (in most cases to InsetMathNest).
@@ -641,7 +645,7 @@ namespace lyx {
 //#define FILEDEBUG 1
 
 
-bool Cursor::isInside(Inset const * p)
+bool Cursor::isInside(Inset const * p) const
 {
        for (size_t i = 0; i != depth(); ++i)
                if (&operator[](i).inset() == p)
@@ -675,7 +679,7 @@ bool Cursor::openable(MathAtom const & t) const
        // we can't move into anything new during selection
        if (depth() >= anchor_.depth())
                return false;
-       if (!ptr_cmp(t.nucleus(), &anchor_[depth()].inset()))
+       if (t.nucleus() != &anchor_[depth()].inset())
                return false;
 
        return true;
@@ -772,10 +776,10 @@ void Cursor::niceInsert(MathAtom const & t)
        plainInsert(t);
        // enter the new inset and move the contents of the selection if possible
        if (t->isActive()) {
-               posLeft();
-               // be careful here: don't use 'pushLeft(t)' as this we need to
+               posBackward();
+               // be careful here: don't use 'pushBackward(t)' as this we need to
                // push the clone, not the original
-               pushLeft(*nextInset());
+               pushBackward(*nextInset());
                // We may not use niceInsert here (recursion)
                MathData ar;
                asArray(safe, ar);
@@ -806,7 +810,7 @@ bool Cursor::backspace()
        if (pos() == 0) {
                // If empty cell, and not part of a big cell
                if (lastpos() == 0 && inset().nargs() == 1) {
-                       popLeft();
+                       popBackward();
                        // Directly delete empty cell: [|[]] => [|]
                        if (inMathed()) {
                                plainErase();
@@ -819,7 +823,7 @@ bool Cursor::backspace()
                        if (inMathed())
                                pullArg();
                        else
-                               popLeft();
+                               popBackward();
                        return true;
                }
        }
@@ -865,7 +869,7 @@ bool Cursor::erase()
        if (pos() == lastpos()) {
                bool one_cell = inset().nargs() == 1;
                if (one_cell && lastpos() == 0) {
-                       popLeft();
+                       popBackward();
                        // Directly delete empty cell: [|[]] => [|]
                        if (inMathed()) {
                                plainErase();
@@ -944,7 +948,13 @@ bool Cursor::macroModeClose()
        InsetMathNest * const in = inset().asInsetMath()->asNestInset();
        if (in && in->interpretString(*this, s))
                return true;
-       plainInsert(createInsetMath(name));
+       MathAtom atom = createInsetMath(name);
+       MathMacro * atomAsMacro = atom.nucleus()->asMacro();
+       if (atomAsMacro) {
+               // make non-greedy, i.e. don't eat parameters from the right
+               atomAsMacro->setDisplayMode(MathMacro::DISPLAY_INTERACTIVE_INIT);
+       }
+       plainInsert(atom);
        return true;
 }
 
@@ -961,8 +971,8 @@ void Cursor::handleNest(MathAtom const & a, int c)
        MathAtom t = a;
        asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(c));
        insert(t);
-       posLeft();
-       pushLeft(*nextInset());
+       posBackward();
+       pushBackward(*nextInset());
 }
 
 
@@ -1013,7 +1023,7 @@ void Cursor::pullArg()
 {
        // FIXME: Look here
        MathData ar = cell();
-       if (popLeft() && inMathed()) {
+       if (popBackward() && inMathed()) {
                plainErase();
                cell().insert(pos(), ar);
                resetAnchor();
@@ -1066,13 +1076,13 @@ bool Cursor::upDownInMath(bool up)
        int xo = 0;
        int yo = 0;
        getPos(xo, yo);
-       xo = beforeDispX_;
-
+       xo = theLyXFunc().cursorBeforeDispatchX();
+       
        // check if we had something else in mind, if not, this is the future
        // target
        if (x_target_ == -1)
                setTargetX(xo);
-       else if (inset().asTextInset() && xo - textTargetOffset() != x_target()) {
+       else if (inset().asInsetText() && xo - textTargetOffset() != x_target()) {
                // In text mode inside the line (not left or right) possibly set a new target_x,
                // but only if we are somewhere else than the previous target-offset.
                
@@ -1116,8 +1126,9 @@ bool Cursor::upDownInMath(bool up)
                                int x;
                                int y;
                                getPos(x, y);
-                               if ((!up && y <= beforeDispY_) ||
-                                               (up && y >= beforeDispY_))
+                               int oy = theLyXFunc().cursorBeforeDispatchY();
+                               if ((!up && y <= oy) ||
+                                               (up && y >= oy))
                                        operator=(old);
                                else
                                        return true;
@@ -1136,8 +1147,9 @@ bool Cursor::upDownInMath(bool up)
                                int x;
                                int y;
                                getPos(x, y);
-                               if ((!up && y <= beforeDispY_) ||
-                                               (up && y >= beforeDispY_))
+                               int oy = theLyXFunc().cursorBeforeDispatchY();
+                               if ((!up && y <= oy) ||
+                                               (up && y >= oy))
                                        operator=(old);
                                else
                                        return true;
@@ -1155,12 +1167,13 @@ bool Cursor::upDownInMath(bool up)
        }
        
        // any improvement going just out of inset?
-       if (popLeft() && inMathed()) {
-               //lyxerr << "updown: popLeft succeeded" << endl;
+       if (popBackward() && inMathed()) {
+               //lyxerr << "updown: popBackward succeeded" << endl;
                int xnew;
                int ynew;
+               int yold = theLyXFunc().cursorBeforeDispatchY();
                getPos(xnew, ynew);
-               if (up ? ynew < beforeDispY_ : ynew > beforeDispY_)
+               if (up ? ynew < yold : ynew > yold)
                        return true;
        }
        
@@ -1178,8 +1191,8 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded)
        int xo = 0;
        int yo = 0;
        getPos(xo, yo);
-       xo = beforeDispX_;
-       
+       xo = theLyXFunc().cursorBeforeDispatchX();
+
        // update the targetX - this is here before the "return false"
        // to set a new target which can be used by InsetTexts above
        // if we cannot move up/down inside this inset anymore
@@ -1261,18 +1274,18 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded)
                Cursor old = *this;
                if (up) {
                        if (row > 0) {
-                               top().pos() = std::min(tm.x2pos(pit(), row - 1, xo), top().lastpos());
+                               top().pos() = min(tm.x2pos(pit(), row - 1, xo), top().lastpos());
                        } else if (pit() > 0) {
                                --pit();
                                ParagraphMetrics const & pmcur = bv_->parMetrics(text(), pit());
-                               top().pos() = std::min(tm.x2pos(pit(), pmcur.rows().size() - 1, xo), top().lastpos());
+                               top().pos() = min(tm.x2pos(pit(), pmcur.rows().size() - 1, xo), top().lastpos());
                        }
                } else {
                        if (row + 1 < int(pm.rows().size())) {
-                               top().pos() = std::min(tm.x2pos(pit(), row + 1, xo), top().lastpos());
+                               top().pos() = min(tm.x2pos(pit(), row + 1, xo), top().lastpos());
                        } else if (pit() + 1 < int(text()->paragraphs().size())) {
                                ++pit();
-                               top().pos() = std::min(tm.x2pos(pit(), 0, xo), top().lastpos());
+                               top().pos() = min(tm.x2pos(pit(), 0, xo), top().lastpos());
                        }
                }
 
@@ -1286,7 +1299,7 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded)
 
 void Cursor::handleFont(string const & font)
 {
-       LYXERR(Debug::DEBUG) << BOOST_CURRENT_FUNCTION << ": " << font << endl;
+       LYXERR(Debug::DEBUG, font);
        docstring safe;
        if (selection()) {
                macroModeClose();
@@ -1297,17 +1310,17 @@ void Cursor::handleFont(string const & font)
                // something left in the cell
                if (pos() == 0) {
                        // cursor in first position
-                       popLeft();
+                       popBackward();
                } else if (pos() == lastpos()) {
                        // cursor in last position
-                       popRight();
+                       popForward();
                } else {
                        // cursor in between. split cell
                        MathData::iterator bt = cell().begin();
                        MathAtom at = createInsetMath(from_utf8(font));
                        at.nucleus()->cell(0) = MathData(bt, bt + pos());
                        cell().erase(bt, bt + pos());
-                       popLeft();
+                       popBackward();
                        plainInsert(at);
                }
        } else {
@@ -1546,10 +1559,84 @@ void Cursor::setCurrentFont()
            && !boundary()) {
                Language const * lang = par.getParLanguage(bufparams);
                current_font.setLanguage(lang);
-               current_font.setNumber(Font::OFF);
+               current_font.fontInfo().setNumber(FONT_OFF);
                real_current_font.setLanguage(lang);
-               real_current_font.setNumber(Font::OFF);
+               real_current_font.fontInfo().setNumber(FONT_OFF);
        }
 }
 
+
+bool Cursor::textUndo()
+{
+       DocIterator dit = *this;
+       // Undo::textUndo() will modify dit.
+       if (!bv_->buffer().undo().textUndo(dit))
+               return false;
+       // Set cursor
+       setCursor(dit);
+       selection() = false;
+       resetAnchor();
+       fixIfBroken();
+       return true;
+}
+
+
+bool Cursor::textRedo()
+{
+       DocIterator dit = *this;
+       // Undo::textRedo() will modify dit.
+       if (!bv_->buffer().undo().textRedo(dit))
+               return false;
+       // Set cursor
+       setCursor(dit);
+       selection() = false;
+       resetAnchor();
+       fixIfBroken();
+       return true;
+}
+
+
+void Cursor::finishUndo()
+{
+       bv_->buffer().undo().finishUndo();
+}
+
+
+void Cursor::recordUndo(UndoKind kind, pit_type from, pit_type to)
+{
+       bv_->buffer().undo().recordUndo(*this, kind, from, to);
+}
+
+
+void Cursor::recordUndo(UndoKind kind, pit_type from)
+{
+       bv_->buffer().undo().recordUndo(*this, kind, from);
+}
+
+
+void Cursor::recordUndo(UndoKind kind)
+{
+       bv_->buffer().undo().recordUndo(*this, kind);
+}
+
+
+void Cursor::recordUndoInset(UndoKind kind)
+{
+       bv_->buffer().undo().recordUndoInset(*this, kind);
+}
+
+
+void Cursor::recordUndoFullDocument()
+{
+       bv_->buffer().undo().recordUndoFullDocument(*this);
+}
+
+
+void Cursor::recordUndoSelection()
+{
+       bv_->buffer().undo().recordUndo(*this, ATOMIC_UNDO,
+               selBegin().pit(), selEnd().pit());
+}
+
+
 } // namespace lyx