]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/math_cursor.C
small up/down tweaking
[lyx.git] / src / mathed / math_cursor.C
index aebf2fa50415d33fd36b46966f2a773a43291b13..44b0136ce6075e99e6c4f33a7c6a8e5c961fbd8c 100644 (file)
 
 #include "support/lstrings.h"
 #include "support/LAssert.h"
-#include "BufferView.h"
 #include "debug.h"
-#include "LColor.h"
 #include "frontends/Painter.h"
 #include "math_cursor.h"
 #include "formulabase.h"
+#include "funcrequest.h"
 #include "math_autocorrect.h"
-#include "math_arrayinset.h"
 #include "math_braceinset.h"
-#include "math_casesinset.h"
+#include "math_commentinset.h"
 #include "math_charinset.h"
 #include "math_extern.h"
 #include "math_factory.h"
-#include "math_hullinset.h"
+#include "math_fontinset.h"
+#include "math_gridinset.h"
 #include "math_iterator.h"
 #include "math_macroarg.h"
 #include "math_macrotemplate.h"
 #include "math_mathmlstream.h"
-#include "math_parser.h"
-#include "math_replace.h"
 #include "math_scriptinset.h"
 #include "math_spaceinset.h"
 #include "math_support.h"
@@ -64,11 +61,11 @@ using std::isalpha;
 
 
 // matheds own cut buffer
-MathGridInset theCutBuffer = MathGridInset(1, 1);
+string theCutBuffer;
 
 
 MathCursor::MathCursor(InsetFormulaBase * formula, bool front)
-       :       formula_(formula), autocorrect_(false), selection_(false)
+       :       formula_(formula), autocorrect_(false), selection_(false), targetx_(-1)
 {
        front ? first() : last();
        Anchor_ = Cursor_;
@@ -77,9 +74,9 @@ MathCursor::MathCursor(InsetFormulaBase * formula, bool front)
 
 MathCursor::~MathCursor()
 {
-  // ensure that 'notifyCursorLeave' is called
-  while (popLeft())
-    ;
+       // ensure that 'notifyCursorLeave' is called
+       while (popLeft())
+               ;
 }
 
 
@@ -91,7 +88,7 @@ void MathCursor::push(MathAtom & t)
 
 void MathCursor::pushLeft(MathAtom & t)
 {
-       //cerr << "Entering atom "; t->write(cerr, false); cerr << " left\n";
+       //lyxerr << "Entering atom " << t << " left\n";
        push(t);
        t->idxFirst(idx(), pos());
 }
@@ -99,7 +96,7 @@ void MathCursor::pushLeft(MathAtom & t)
 
 void MathCursor::pushRight(MathAtom & t)
 {
-       //cerr << "Entering atom "; t->write(cerr, false); cerr << " right\n";
+       //lyxerr << "Entering atom " << t << " right\n";
        posLeft();
        push(t);
        t->idxLast(idx(), pos());
@@ -111,10 +108,10 @@ bool MathCursor::popLeft()
        //cerr << "Leaving atom to the left\n";
        if (depth() <= 1) {
                if (depth() == 1)
-                       par()->notifyCursorLeaves();
+                       par()->notifyCursorLeaves(idx());
                return false;
        }
-       par()->notifyCursorLeaves();
+       par()->notifyCursorLeaves(idx());
        Cursor_.pop_back();
        return true;
 }
@@ -125,10 +122,10 @@ bool MathCursor::popRight()
        //cerr << "Leaving atom "; par()->write(cerr, false); cerr << " right\n";
        if (depth() <= 1) {
                if (depth() == 1)
-                       par()->notifyCursorLeaves();
+                       par()->notifyCursorLeaves(idx());
                return false;
        }
-       par()->notifyCursorLeaves();
+       par()->notifyCursorLeaves(idx());
        Cursor_.pop_back();
        posRight();
        return true;
@@ -139,14 +136,14 @@ bool MathCursor::popRight()
 #if FILEDEBUG
        void MathCursor::dump(char const * what) const
        {
-               lyxerr << "MC: " << what << "\n";
-               lyxerr << " Cursor: " << depth() << "\n";
+               lyxerr << "MC: " << what << endl;
+               lyxerr << " Cursor: " << depth() << endl;
                for (unsigned i = 0; i < depth(); ++i)
-                       lyxerr << "    i: " << i << " " << Cursor_[i] << "\n";
-               lyxerr << " Anchor: " << Anchor_.size() << "\n";
+                       lyxerr << "    i: " << i << ' ' << Cursor_[i] << endl;
+               lyxerr << " Anchor: " << Anchor_.size() << endl;
                for (unsigned i = 0; i < Anchor_.size(); ++i)
-                       lyxerr << "    i: " << i << " " << Anchor_[i] << "\n";
-               lyxerr  << " sel: " << selection_ << "\n";
+                       lyxerr << "    i: " << i << ' ' << Anchor_[i] << endl;
+               lyxerr  << " sel: " << selection_ << endl;
        }
 #else
        void MathCursor::dump(char const *) const {}
@@ -174,7 +171,7 @@ bool MathCursor::openable(MathAtom const & t, bool sel) const
                // we can't move into anything new during selection
                if (depth() == Anchor_.size())
                        return false;
-               if (t.nucleus() != Anchor_[depth()].par_)
+               if (t.operator->() != Anchor_[depth()].par_)
                        return false;
        }
        return true;
@@ -189,8 +186,6 @@ bool MathCursor::inNucleus() const
 
 bool MathCursor::posLeft()
 {
-       if (inNucleus())
-               return false;
        if (pos() == 0)
                return false;
        --pos();
@@ -263,7 +258,8 @@ void MathCursor::last()
 }
 
 
-bool positionable(MathIterator const & cursor, MathIterator const & anchor)
+bool positionable
+       (MathIterator const & cursor, MathIterator const & anchor)
 {
        // avoid deeper nested insets when selecting
        if (cursor.size() > anchor.size())
@@ -377,10 +373,20 @@ void MathCursor::insert(MathAtom const & t)
 }
 
 
+void MathCursor::niceInsert(string const & t)
+{
+       MathArray ar = asArray(t);
+       if (ar.size() == 1)
+               niceInsert(ar[0]);
+       else
+               insert(ar);
+}
+
+
 void MathCursor::niceInsert(MathAtom const & t)
 {
        macroModeClose();
-       MathGridInset safe = grabAndEraseSelection();
+       string safe = grabAndEraseSelection();
        plainInsert(t);
        // enter the new inset and move the contents of the selection if possible
        if (t->isActive()) {
@@ -396,73 +402,36 @@ void MathCursor::insert(MathArray const & ar)
        macroModeClose();
        if (selection_)
                eraseSelection();
-
        array().insert(pos(), ar);
        pos() += ar.size();
 }
 
 
-void MathCursor::paste(MathArray const & ar)
+void MathCursor::paste(string const & data)
 {
-       Anchor_ = Cursor_;
-       selection_ = true;
-       array().insert(pos(), ar);
-       pos() += ar.size();
-}
-
-
-void MathCursor::paste(MathGridInset const & data)
-{
-       if (data.nargs() == 1) {
-               // single cell/part of cell
-               paste(data.cell(0));
-       } else {
-               // mulitple cells
-               idx_type idx; // index of upper left cell
-               MathGridInset * p = enclosingGrid(idx);
-               col_type const numcols = min(data.ncols(), p->ncols() - p->col(idx));
-               row_type const numrows = min(data.nrows(), p->nrows() - p->row(idx));
-               for (row_type row = 0; row < numrows; ++row) {
-                       for (col_type col = 0; col < numcols; ++col) {
-                               idx_type i = p->index(row + p->row(idx), col + p->col(idx));
-                               p->cell(i).append(data.cell(data.index(row, col)));
-                       }
-                       // append the left over horizontal cells to the last column
-                       idx_type i = p->index(row + p->row(idx), p->ncols() - 1);
-                       for (MathInset::col_type col = numcols; col < data.ncols(); ++col)
-                               p->cell(i).append(data.cell(data.index(row, col)));
-               }
-               // append the left over vertical cells to the last _cell_
-               idx_type i = p->nargs() - 1;
-               for (row_type row = numrows; row < data.nrows(); ++row)
-                       for (col_type col = 0; col < data.ncols(); ++col)
-                               p->cell(i).append(data.cell(data.index(row, col)));
-       }
+       dispatch(FuncRequest(LFUN_PASTE, data));
 }
 
 
 void MathCursor::backspace()
 {
        autocorrect_ = false;
-       if (pos() == 0) {
-               pullArg();
-               return;
-       }
 
        if (selection_) {
                selDel();
                return;
        }
 
-       if (prevAtom()->asScriptInset()) {
-               // simply enter nucleus
-               left();
+       if (pos() == 0) {
+               pullArg();
                return;
        }
 
-       if (inNucleus()) {
-               // we are in nucleus
-               if (pos() == 1) {
+       if (inMacroMode()) {
+               MathUnknownInset * p = activeMacro();
+               if (p->name().size() > 1) {
+                       p->setName(p->name().substr(0, p->name().size() - 1));
+                       return;
                }
        }
 
@@ -493,55 +462,10 @@ void MathCursor::erase()
                return;
        }
 
-       // if we are standing in front of a script inset, grab item before us and
-       // move it into nucleus
-       // and remove first thing.
-       if (hasNextAtom() && nextAtom()->asScriptInset()) {
-               if (hasPrevAtom()) {
-                       MathAtom at = prevAtom();
-                       --pos();
-                       array().erase(pos());
-                       pushLeft(nextAtom());
-                       if (array().empty())
-                               array().push_back(at);
-                       else
-                               array()[0] = at;
-                       pos() = 1;
-               } else {
-                       pushLeft(nextAtom());
-                       array().clear();
-               }
-               return;
-       }
-
        plainErase();
 }
 
 
-void MathCursor::delLine()
-{
-       autocorrect_ = false;
-       macroModeClose();
-
-       if (selection_) {
-               selDel();
-               return;
-       }
-
-       if (par()->nrows() > 1) {
-               // grid are the only things with more than one row...
-               lyx::Assert(par()->asGridInset());
-               par()->asGridInset()->delRow(hullRow());
-       }
-
-       if (idx() >= par()->nargs())
-               idx() = par()->nargs() - 1;
-
-       if (pos() > size())
-               pos() = size();
-}
-
-
 bool MathCursor::up(bool sel)
 {
        dump("up 1");
@@ -570,36 +494,34 @@ bool MathCursor::down(bool sel)
 }
 
 
-bool MathCursor::toggleLimits()
-{
-       if (!hasNextAtom())
-               return false;
-       MathScriptInset * t = nextAtom()->asScriptInset();
-       if (!t)
-               return false;
-       int old = t->limits();
-       t->limits(old < 0 ? 1 : -1);
-       return old != t->limits();
-}
-
-
 void MathCursor::macroModeClose()
 {
-       MathUnknownInset * p = inMacroMode();
-       if (!p)
+       if (!inMacroMode())
                return;
+       MathUnknownInset * p = activeMacro();
        p->finalize();
        string s = p->name();
        --pos();
        array().erase(pos());
-       if (s != "\\")
-               interpret(s);
+
+       // do nothing if the macro name is empty
+       if (s == "\\")
+               return;
+
+       string name = s.substr(1);
+
+       // prevent entering of recursive macros
+       if (formula()->lyxCode() == Inset::MATHMACRO_CODE
+                       && formula()->getInsetName() == name)
+               lyxerr << "can't enter recursive macro\n";
+
+       niceInsert(createMathInset(name));
 }
 
 
 string MathCursor::macroName() const
 {
-       return inMacroMode() ? inMacroMode()->name() : string();
+       return inMacroMode() ? activeMacro()->name() : string();
 }
 
 
@@ -617,7 +539,7 @@ void MathCursor::selCopy()
                theCutBuffer = grabSelection();
                selection_ = false;
        } else {
-               theCutBuffer = MathGridInset(1, 1);
+               theCutBuffer.erase();
        }
 }
 
@@ -678,15 +600,6 @@ void MathCursor::selClearOrDel()
 }
 
 
-void MathCursor::selGet(MathArray & ar)
-{
-       dump("selGet");
-       if (selection_)
-               ar = grabSelection().glue();
-}
-
-
-
 void MathCursor::drawSelection(MathPainterInfo & pi) const
 {
        if (!selection_)
@@ -698,20 +611,31 @@ void MathCursor::drawSelection(MathPainterInfo & pi) const
 }
 
 
-void MathCursor::handleNest(MathAtom const & at)
+void MathCursor::handleNest(MathAtom const & a)
 {
-       at->cell(0) = grabAndEraseSelection().glue();
+       MathAtom at = a;
+       at.nucleus()->cell(0) = asArray(grabAndEraseSelection());
        insert(at);
        pushRight(prevAtom());
 }
 
 
-void MathCursor::getPos(int & x, int & y)
+void MathCursor::getPos(int & x, int & y) const
 {
        par()->getPos(idx(), pos(), x, y);
 }
 
 
+int MathCursor::targetX() const
+{
+       if (targetx_ != -1)
+               return targetx_;
+       int x = 0, y = 0;
+       getPos(x, y);
+       return x;
+}
+
+
 MathInset * MathCursor::par() const
 {
        return cursor().par_;
@@ -742,18 +666,42 @@ MathCursor::pos_type MathCursor::pos() const
 }
 
 
+void MathCursor::adjust(pos_type from, difference_type diff)
+{
+       if (cursor().pos_ > from)
+               cursor().pos_ += diff;
+       if (Anchor_.back().pos_ > from)
+               Anchor_.back().pos_ += diff;
+       // just to be on the safe side
+       // theoretically unecessary
+       normalize();
+}
+
+
 MathCursor::pos_type & MathCursor::pos()
 {
        return cursor().pos_;
 }
 
 
-MathUnknownInset * MathCursor::inMacroMode() const
+bool MathCursor::inMacroMode() const
 {
        if (!hasPrevAtom())
-               return 0;
-       MathUnknownInset * p = prevAtom()->asUnknownInset();
-       return (p && !p->final()) ? p : 0;
+               return false;
+       MathUnknownInset const * p = prevAtom()->asUnknownInset();
+       return p && !p->final();
+}
+
+
+MathUnknownInset * MathCursor::activeMacro()
+{
+       return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : 0;
+}
+
+
+MathUnknownInset const * MathCursor::activeMacro() const
+{
+       return inMacroMode() ? prevAtom()->asUnknownInset() : 0;
 }
 
 
@@ -782,16 +730,10 @@ MathGridInset * MathCursor::enclosingGrid(MathCursor::idx_type & idx) const
 }
 
 
-MathHullInset * MathCursor::enclosingHull(MathCursor::idx_type & idx) const
+void MathCursor::popToHere(MathInset const * p)
 {
-       for (MathInset::difference_type i = depth() - 1; i >= 0; --i) {
-               MathHullInset * p = Cursor_[i].par_->asHullInset();
-               if (p) {
-                       idx = Cursor_[i].idx_;
-                       return p;
-               }
-       }
-       return 0;
+       while (depth() && Cursor_.back().par_ != p)
+               Cursor_.pop_back();
 }
 
 
@@ -828,7 +770,7 @@ void MathCursor::touch()
        MathIterator::const_iterator it = Cursor_.begin();
        MathIterator::const_iterator et = Cursor_.end();
        for ( ; it != et; ++it)
-               it->xcell().touch();
+               it->cell().touch();
 }
 
 
@@ -836,36 +778,22 @@ void MathCursor::normalize()
 {
        if (idx() >= par()->nargs()) {
                lyxerr << "this should not really happen - 1: "
-                      << idx() << " " << par()->nargs() << " in: " << par() << "\n";
+                      << idx() << ' ' << par()->nargs()
+                      << " in: " << par() << endl;
                dump("error 2");
        }
        idx() = min(idx(), par()->nargs() - 1);
 
        if (pos() > size()) {
                lyxerr << "this should not really happen - 2: "
-                       << pos() << " " << size() <<  " in idx: " << idx()
-                       << " in atom: '";
+                       << pos() << ' ' << size() <<  " in idx: " << idx()
+                      << " in atom: '";
                WriteStream wi(lyxerr, false, true);
                par()->write(wi);
-               lyxerr << "\n";
+               lyxerr << endl;
                dump("error 4");
        }
        pos() = min(pos(), size());
-
-       // remove empty scripts if possible
-       if (1) {
-               for (pos_type i = 0; i < size(); ++i) {
-                       MathScriptInset * p = array()[i]->asScriptInset();
-                       if (p) {
-                               p->removeEmptyScripts();
-                               //if (p->empty())
-                               //      array().erase(i);
-                       }
-               }
-       }
-
-       // fix again position
-       pos() = min(pos(), size());
 }
 
 
@@ -875,22 +803,6 @@ MathCursor::size_type MathCursor::size() const
 }
 
 
-MathCursor::col_type MathCursor::hullCol() const
-{
-       idx_type idx = 0;
-       MathHullInset * p = enclosingHull(idx);
-       return p->col(idx);
-}
-
-
-MathCursor::row_type MathCursor::hullRow() const
-{
-       idx_type idx = 0;
-       MathHullInset * p = enclosingHull(idx);
-       return p->row(idx);
-}
-
-
 bool MathCursor::hasPrevAtom() const
 {
        return pos() > 0;
@@ -949,19 +861,6 @@ MathArray & MathCursor::array() const
 }
 
 
-MathXArray & MathCursor::xarray() const
-{
-       static MathXArray dummy;
-
-       if (depth() == 0) {
-               lyxerr << "############  depth() == 0 not valid\n";
-               return dummy;
-       }
-
-       return cursor().xcell();
-}
-
-
 void MathCursor::idxNext()
 {
        par()->idxNext(idx(), pos());
@@ -974,57 +873,6 @@ void MathCursor::idxPrev()
 }
 
 
-void MathCursor::splitCell()
-{
-       if (idx() + 1 == par()->nargs())
-               return;
-       MathArray ar = array();
-       ar.erase(0, pos());
-       array().erase(pos(), size());
-       ++idx();
-       pos() = 0;
-       array().insert(0, ar);
-}
-
-
-void MathCursor::breakLine()
-{
-       // leave inner cells
-       while (popRight())
-               ;
-
-       idx_type dummy;
-       MathHullInset * p = enclosingHull(dummy);
-       if (!p)
-               return;
-
-       if (p->getType() == "simple" || p->getType() == "equation") {
-               p->mutate("eqnarray");
-               idx() = 1;
-               pos() = 0;
-       } else {
-               p->addRow(hullRow());
-
-               // split line
-               const row_type r = hullRow();
-               for (col_type c = hullCol() + 1; c < p->ncols(); ++c)
-                       std::swap(p->cell(p->index(r, c)), p->cell(p->index(r + 1, c)));
-
-               // split cell
-               splitCell();
-               std::swap(p->cell(idx()), p->cell(idx() + p->ncols() - 1));
-       }
-}
-
-
-//void MathCursor::readLine(MathArray & ar) const
-//{
-//     idx_type base = row() * par()->ncols();
-//     for (idx_type off = 0; off < par()->ncols(); ++off)
-//             ar.push_back(par()->cell(base + off));
-//}
-
-
 char MathCursor::valign() const
 {
        idx_type idx;
@@ -1073,7 +921,8 @@ bool MathCursor::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!
-  int xo, yo;
+  int xo = 0;
+       int yo = 0;
        getPos(xo, yo);
 
        // check if we had something else in mind, if not, this is the future goal
@@ -1085,7 +934,7 @@ bool MathCursor::goUpDown(bool up)
        // try neigbouring script insets
        // try left
        if (hasPrevAtom()) {
-               MathScriptInset * p = prevAtom()->asScriptInset();
+               MathScriptInset const * p = prevAtom()->asScriptInset();
                if (p && p->has(up)) {
                        --pos();
                        push(nextAtom());
@@ -1098,7 +947,7 @@ bool MathCursor::goUpDown(bool up)
 
        // try right
        if (hasNextAtom()) {
-               MathScriptInset * p = nextAtom()->asScriptInset();
+               MathScriptInset const * p = nextAtom()->asScriptInset();
                if (p && p->has(up)) {
                        push(nextAtom());
                        idx() = up;
@@ -1123,8 +972,12 @@ bool MathCursor::goUpDown(bool up)
        while (1) {
                ///lyxerr << "updown: We are in " << *par() << " idx: " << idx() << '\n';
                // ask inset first
-               if (par()->idxUpDown(idx(), pos(), up, targetx_))
+               if (par()->idxUpDown(idx(), pos(), up, targetx_)) {
+                       // try to find best position within this inset
+                       if (!selection())
+                               bruteFind2(xo, yo);
                        return true;
+               }
 
                // no such inset found, just take something "above"
                ///lyxerr << "updown: handled by strange case\n";
@@ -1181,11 +1034,28 @@ bool MathCursor::bruteFind
 }
 
 
-bool MathCursor::idxLineFirst()
+void MathCursor::bruteFind2(int x, int y)
 {
-       idx() -= idx() % par()->ncols();
-       pos() = 0;
-       return true;
+       double best_dist = 1e10;
+
+       MathIterator it = Cursor_;
+       it.back().setPos(0);
+       MathIterator et = Cursor_;
+       et.back().setPos(it.cell().size());
+       while (1) {
+               int xo, yo;
+               it.back().getPos(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'
+               if (d <= best_dist) {
+                       best_dist = d;
+                       Cursor_   = it;
+               }
+               if (it == et)
+                       break;
+               ++it;
+       }
 }
 
 
@@ -1209,97 +1079,26 @@ bool MathCursor::idxRight()
 }
 
 
-bool MathCursor::interpret(string const & s)
-{
-       //lyxerr << "interpret 1: '" << s << "'\n";
-       if (s.empty())
-               return true;
-
-       //lyxerr << "char: '" << s[0] << "'  int: " << int(s[0]) << endl;
-       //owner_->getIntl()->getTransManager().TranslateAndInsert(s[0], lt);
-       //lyxerr << "trans: '" << s[0] << "'  int: " << int(s[0]) << endl;
-
-       if (s.size() >= 5 && s.substr(0, 5) == "cases") {
-               unsigned int n = 1;
-               istringstream is(s.substr(5).c_str());
-               is >> n;
-               n = max(1u, n);
-               niceInsert(MathAtom(new MathCasesInset(n)));
-               return true;
-       }
-
-       if (s.size() >= 6 && s.substr(0, 6) == "matrix") {
-               unsigned int m = 1;
-               unsigned int n = 1;
-               string v_align;
-               string h_align;
-               istringstream is(s.substr(6).c_str());
-               is >> m >> n >> v_align >> h_align;
-               m = max(1u, m);
-               n = max(1u, n);
-               v_align += 'c';
-               niceInsert(MathAtom(new MathArrayInset("array", m, n, v_align[0], h_align)));
-               return true;
-       }
-
-       if (s.size() >= 7 && s.substr(0, 7) == "replace") {
-               ReplaceData rep;
-               istringstream is(s.substr(7).c_str());
-               string from, to;
-               is >> from >> to;
-               mathed_parse_cell(rep.from, from);
-               mathed_parse_cell(rep.to, to);
-               lyxerr << "replacing '" << from << "' with '" << to << "'\n";
-               par()->replace(rep);
-               return true;
-       }
-
-       string name = s.substr(1);
-
-       if (name == "over" || name == "choose" || name == "atop") {
-               MathAtom t(createMathInset(name));
-               t->asNestInset()->cell(0) = array();
-               array().clear();
-               pos() = 0;
-               niceInsert(t);
-               popRight();
-               left();
-               return true;
-       }
-
-       // prevent entering of recursive macros
-       if (formula()->lyxCode() == Inset::MATHMACRO_CODE
-               && formula()->getInsetName() == name)
-       {
-               lyxerr << "can't enter recursive macro\n";
-               return true;
-       }
-
-       niceInsert(createMathInset(name));
-       return true;
-}
-
-
 bool MathCursor::script(bool up)
 {
        // Hack to get \\^ and \\_ working
        if (inMacroMode() && macroName() == "\\") {
                if (up)
-                       interpret("\\mathcircumflex");
+                       niceInsert(createMathInset("mathcircumflex"));
                else
                        interpret('_');
                return true;
        }
 
        macroModeClose();
-       MathGridInset safe = grabAndEraseSelection();
+       string safe = grabAndEraseSelection();
        if (inNucleus()) {
                // we are in a nucleus of a script inset, move to _our_ script
                par()->asScriptInset()->ensure(up);
                idx() = up;
                pos() = 0;
        } else if (hasPrevAtom() && prevAtom()->asScriptInset()) {
-               prevAtom()->asScriptInset()->ensure(up);
+               prevAtom().nucleus()->asScriptInset()->ensure(up);
                pushRight(prevAtom());
                idx() = up;
                pos() = size();
@@ -1311,7 +1110,7 @@ bool MathCursor::script(bool up)
                pos() = 0;
        } else {
                plainInsert(MathAtom(new MathScriptInset(up)));
-               prevAtom()->asScriptInset()->ensure(up);
+               prevAtom().nucleus()->asScriptInset()->ensure(up);
                pushRight(prevAtom());
                idx() = up;
                pos() = 0;
@@ -1330,7 +1129,7 @@ bool MathCursor::interpret(char c)
                --pos();
                plainErase();
                int n = c - '0';
-               MathMacroTemplate * p = formula()->par()->asMacroTemplate();
+               MathMacroTemplate const * p = formula()->par()->asMacroTemplate();
                if (p && 1 <= n && n <= p->numargs())
                        insert(MathAtom(new MathMacroArgument(c - '0')));
                else {
@@ -1345,14 +1144,8 @@ bool MathCursor::interpret(char c)
                string name = macroName();
                //lyxerr << "interpret name: '" << name << "'\n";
 
-               if (name.empty() && c == '\\') {
-                       backspace();
-                       interpret("\\backslash");
-                       return true;
-               }
-
                if (isalpha(c)) {
-                       inMacroMode()->name() += c;
+                       activeMacro()->setName(activeMacro()->name() + c);
                        return true;
                }
 
@@ -1360,16 +1153,24 @@ bool MathCursor::interpret(char c)
                if (name == "\\") {
                        // remove the '\\'
                        backspace();
-                       if (c == '\\')
-                               interpret("\\backslash");
-                       else
-                               interpret(string("\\") + c);
+                       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 != ' ')
+               if (c == '{')
+                       niceInsert(MathAtom(new MathBraceInset));
+               else if (c != ' ')
                        interpret(c);
                return true;
        }
@@ -1400,7 +1201,7 @@ bool MathCursor::interpret(char c)
        }
 
        if (c == '\n') {
-               if (currentMode() == MathInset::TEXT_MODE) 
+               if (currentMode() == MathInset::TEXT_MODE)
                        insert(c);
                return true;
        }
@@ -1416,7 +1217,7 @@ bool MathCursor::interpret(char c)
                        return true;
                }
                if (hasPrevAtom() && prevAtom()->asSpaceInset()) {
-                       prevAtom()->asSpaceInset()->incSpace();
+                       prevAtom().nucleus()->asSpaceInset()->incSpace();
                        return true;
                }
                if (popRight())
@@ -1426,23 +1227,12 @@ bool MathCursor::interpret(char c)
        }
 
        if (c == '#') {
-               insert(c); // LM_TC_TEX;
-               return true;
-       }
-
-/*
-       if (c == '{' || c == '}', c)) {
-               insert(c); // LM_TC_TEX;
+               insert(c);
                return true;
        }
-*/
 
-       if (c == '{') {
-               niceInsert(MathAtom(new MathBraceInset));
-               return true;
-       }
-
-       if (c == '}') {
+       if (c == '{' || c == '}') {
+               niceInsert(createMathInset(string(1, c)));
                return true;
        }
 
@@ -1452,29 +1242,10 @@ bool MathCursor::interpret(char c)
        }
 
        if (c == '%') {
-               insert(createMathInset("%"));
-               return true;
-       }
-
-/*
-       if (isalpha(c) && lastcode_ == LM_TC_GREEK) {
-               insert(c, LM_TC_VAR);
-               return true;
-       }
-
-       if (isalpha(c) && lastcode_ == LM_TC_GREEK1) {
-               insert(c, LM_TC_VAR);
-               lastcode_ = LM_TC_VAR;
+               niceInsert(MathAtom(new MathCommentInset));
                return true;
        }
 
-       if (c == '\\') {
-               insert(c, LM_TC_TEX);
-               //bv->owner()->message(_("TeX mode"));
-               return true;
-       }
-*/
-
        // try auto-correction
        //if (autocorrect_ && hasPrevAtom() && math_autocorrect(prevAtom(), c))
        //      return true;
@@ -1498,11 +1269,11 @@ void MathCursor::setSelection(MathIterator const & where, size_type n)
 void MathCursor::insetToggle()
 {
        if (hasNextAtom()) {
-               // toggle next inset ...
-               nextAtom()->lock(!nextAtom()->lock());
+               // toggle previous inset ...
+               nextAtom().nucleus()->lock(!nextAtom()->lock());
        } else if (popLeft() && hasNextAtom()) {
                // ... or enclosing inset if we are in the last inset position
-               nextAtom()->lock(!nextAtom()->lock());
+               nextAtom().nucleus()->lock(!nextAtom()->lock());
                posRight();
        }
 }
@@ -1517,10 +1288,9 @@ string MathCursor::info() const
                os << "  ";
        }
        if (hasPrevAtom())
-               if (prevAtom()->asSymbolInset() || prevAtom()->asScriptInset())
-                       prevAtom()->infoize(os);
+               prevAtom()->infoize2(os);
        os << "                    ";
-       return os.str().c_str(); // .c_str() needed for lyxstring
+       return STRCONV(os.str());
 }
 
 
@@ -1552,29 +1322,34 @@ void region(MathCursorPos const & i1, MathCursorPos const & i2,
 }
 
 
-MathGridInset MathCursor::grabSelection() const
+string MathCursor::grabSelection() const
 {
        if (!selection_)
-               return MathGridInset();
+               return string();
+
        MathCursorPos i1;
        MathCursorPos i2;
        getSelection(i1, i2);
-       // shouldn't we assert on i1.par_ == i2.par_?
+
        if (i1.idx_ == i2.idx_) {
-               MathGridInset data(1, 1);
                MathArray::const_iterator it = i1.cell().begin();
-               data.cell(0) = MathArray(it + i1.pos_, it + i2.pos_);
-               return data;
+               return asString(MathArray(it + i1.pos_, it + i2.pos_));
        }
+
        row_type r1, r2;
        col_type c1, c2;
        region(i1, i2, r1, r2, c1, c2);
-       MathGridInset data(c2 - c1 + 1, r2 - r1 + 1);
-       for (row_type row = 0; row < data.nrows(); ++row)
-               for (col_type col = 0; col < data.ncols(); ++col) {
-                       idx_type i = i1.par_->index(row + r1, col + c1);
-                       data.cell(data.index(row, col)) = i1.par_->cell(i);
+
+       string data;
+       for (row_type row = r1; row <= r2; ++row) {
+               if (row > r1)
+                       data += "\\\\";
+               for (col_type col = c1; col <= c2; ++col) {
+                       if (col > c1)
+                               data += '&';
+                       data += asString(i1.par_->cell(i1.par_->index(row, col)));
                }
+       }
        return data;
 }
 
@@ -1599,11 +1374,11 @@ void MathCursor::eraseSelection()
 }
 
 
-MathGridInset MathCursor::grabAndEraseSelection()
+string MathCursor::grabAndEraseSelection()
 {
        if (!selection_)
-               return MathGridInset();
-       MathGridInset res = grabSelection();
+               return string();
+       string res = grabSelection();
        eraseSelection();
        selection_ = false;
        return res;
@@ -1627,97 +1402,21 @@ MathCursorPos MathCursor::normalAnchor() const
 }
 
 
-
-void MathCursor::handleExtern(const string & arg)
-{
-       string lang;
-       string extra;
-       istringstream iss(arg.c_str());
-       iss >> lang >> extra;
-       if (extra.empty())
-               extra = "noextra";
-
-
-       if (selection()) {
-               MathArray ar;
-               selGet(ar);
-               lyxerr << "use selection: " << ar << "\n";
-               insert(pipeThroughExtern(lang, extra, ar));
-               return;
-       }
-
-       MathArray eq;
-       eq.push_back(MathAtom(new MathCharInset('=')));
-
-       popToEnclosingHull();
-
-       idx_type idx = 0;
-       MathHullInset * hull = enclosingHull(idx);
-       lyx::Assert(hull);
-       idxLineFirst();
-
-       if (hull->getType() == "simple") {
-               MathArray::size_type pos = cursor().cell().find_last(eq);
-               MathArray ar;
-               if (pos == size()) {
-                       ar = array();
-                       lyxerr << "use whole cell: " << ar << "\n";
-               } else {
-                       ar = MathArray(array().begin() + pos + 1, array().end());
-                       lyxerr << "use partial cell form pos: " << pos << "\n";
-               }
-               end();
-               insert(eq);
-               insert(pipeThroughExtern(lang, extra, ar));
-               return;
-       }
-
-       if (hull->getType() == "equation") {
-               lyxerr << "use equation inset\n";
-               hull->mutate("eqnarray");
-               MathArray & ar = cursor().cell();
-               lyxerr << "use cell: " << ar << "\n";
-               idxRight();
-               cursor().cell() = eq;
-               idxRight();
-               cursor().cell() = pipeThroughExtern(lang, extra, ar);
-               idxLineLast();
-               return;
-       }
-
-       {
-               lyxerr << "use eqnarray\n";
-               idxLineLast();
-               MathArray ar = cursor().cell();
-               lyxerr << "use cell: " << ar << "\n";
-               breakLine();
-               idxRight();
-               cursor().cell() = eq;
-               idxRight();
-               cursor().cell() = pipeThroughExtern(lang, extra, ar);
-               idxLineLast();
-       }
-
-}
-
-
-int MathCursor::dispatch(string const & cmd)
+MathInset::result_type MathCursor::dispatch(FuncRequest const & cmd)
 {
-       // try to dispatch to adajcent items if they are not editable
-       // actually, this should only happen for mouse clicks...
-       if (hasNextAtom() && !openable(nextAtom(), false))
-               if (int res = nextAtom()->dispatch(cmd, 0, 0))
-                       return res;
-       if (hasPrevAtom() && !openable(prevAtom(), false))
-               if (int res = prevAtom()->dispatch(cmd, 0, 0))
-                       return res;
-
        for (int i = Cursor_.size() - 1; i >= 0; --i) {
                MathCursorPos & pos = Cursor_[i];
-               if (int res = pos.par_->dispatch(cmd, pos.idx_, pos.pos_))
+               MathInset::result_type
+                       res = pos.par_->dispatch(cmd, pos.idx_, pos.pos_);
+               if (res != MathInset::UNDISPATCHED) {
+                       if (res == MathInset::DISPATCHED_POP) {
+                               Cursor_.shrink(i + 1);
+                               selClear();
+                       }
                        return res;
+               }
        }
-       return 0;
+       return MathInset::UNDISPATCHED;
 }
 
 
@@ -1732,11 +1431,47 @@ MathInset::mode_type MathCursor::currentMode() const
 }
 
 
+void MathCursor::handleFont(string const & font)
+{
+       string safe;
+       if (selection()) {
+               macroModeClose();
+               safe = grabAndEraseSelection();
+       }
+
+       if (array().size()) {
+               // something left in the cell
+               if (pos() == 0) {
+                       // cursor in first position
+                       popLeft();
+               } else if (pos() == array().size()) {
+                       // cursor in last position
+                       popRight();
+               } else {
+                       // cursor in between. split cell
+                       MathArray::iterator bt = array().begin();
+                       MathAtom at = createMathInset(font);
+                       at.nucleus()->cell(0) = MathArray(bt, bt + pos());
+                       cursor().cell().erase(bt, bt + pos());
+                       popLeft();
+                       plainInsert(at);
+               }
+       } else {
+               // nothing left in the cell
+               pullArg();
+               plainErase();
+       }
+       insert(safe);
+}
+
+
 void releaseMathCursor(BufferView * bv)
 {
-       if (!mathcursor)
-               return;
-       mathcursor->formula()->hideInsetCursor(bv);
-       delete mathcursor;
-       mathcursor = 0;
+       if (mathcursor) {
+               InsetFormulaBase * f =  mathcursor->formula();
+               f->hideInsetCursor(bv);
+               delete mathcursor;
+               mathcursor = 0;
+               f->insetUnlock(bv);
+       }
 }