]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/InsetMathNest.cpp
de.po
[lyx.git] / src / mathed / InsetMathNest.cpp
index d4438a6e73001e082663fee32ed6991db6fa0680..8cd1254098d2c0f125a8de5f31a5f096a5498296 100644 (file)
@@ -32,8 +32,8 @@
 #include "MathCompletionList.h"
 #include "MathData.h"
 #include "MathFactory.h"
-#include "MathMacro.h"
-#include "MathMacroArgument.h"
+#include "InsetMathMacro.h"
+#include "InsetMathMacroArgument.h"
 #include "MathParser.h"
 #include "MathStream.h"
 #include "MathSupport.h"
@@ -118,11 +118,8 @@ InsetMathNest & InsetMathNest::operator=(InsetMathNest const & inset)
 void InsetMathNest::setBuffer(Buffer & buffer)
 {
        InsetMath::setBuffer(buffer);
-       for (idx_type i = 0, n = nargs(); i != n; ++i) {
-               MathData & data = cell(i);
-               for (size_t j = 0; j != data.size(); ++j)
-                       data[j].nucleus()->setBuffer(buffer);
-       }
+       for (MathData & data : cells_)
+               data.setBuffer(buffer);
 }
 
 
@@ -171,8 +168,10 @@ void InsetMathNest::cursorPos(BufferView const & bv,
 //             << " asc: " << ascent() << "  des: " << descent()
 //             << " ar.asc: " << ar.ascent() << " ar.des: " << ar.descent() << endl;
        // move cursor visually into empty cells ("blue rectangles");
-       if (ar.empty())
-               x += 3;
+       if (ar.empty()) {
+               Dimension const dim = coord_cache.getArrays().dim(&ar);
+               x += dim.wid / 3;
+       }
 }
 
 
@@ -217,7 +216,7 @@ bool InsetMathNest::idxPrev(Cursor & cur) const
        if (cur.idx() == 0)
                return false;
        --cur.idx();
-       cur.pos() = cur.lastpos();
+       cur.pos() = lyxrc.mac_like_cursor_movement ? cur.lastpos() : 0;
        return true;
 }
 
@@ -233,7 +232,7 @@ bool InsetMathNest::idxFirst(Cursor & cur) const
        LASSERT(&cur.inset() == this, return false);
        if (nargs() == 0)
                return false;
-       cur.idx() = 0;
+       cur.idx() = firstIdx();
        cur.pos() = 0;
        return true;
 }
@@ -244,7 +243,7 @@ bool InsetMathNest::idxLast(Cursor & cur) const
        LASSERT(&cur.inset() == this, return false);
        if (nargs() == 0)
                return false;
-       cur.idx() = cur.lastidx();
+       cur.idx() = lastIdx();
        cur.pos() = cur.lastpos();
        return true;
 }
@@ -275,54 +274,6 @@ void InsetMathNest::draw(PainterInfo &, int, int) const
 }
 
 
-void InsetMathNest::drawSelection(PainterInfo & pi, int x, int y) const
-{
-       BufferView & bv = *pi.base.bv;
-       // this should use the x/y values given, not the cached values
-       Cursor & cur = bv.cursor();
-       if (!cur.selection())
-               return;
-       if (&cur.inset() != this)
-               return;
-
-       // FIXME: hack to get position cache warm
-       bool const original_drawing_state = pi.pain.isDrawingEnabled();
-       pi.pain.setDrawingEnabled(false);
-       draw(pi, x, y);
-       pi.pain.setDrawingEnabled(original_drawing_state);
-
-       CursorSlice s1 = cur.selBegin();
-       CursorSlice s2 = cur.selEnd();
-
-       //lyxerr << "InsetMathNest::drawing selection: "
-       //      << " s1: " << s1 << " s2: " << s2 << endl;
-       if (s1.idx() == s2.idx()) {
-               MathData const & c = cell(s1.idx());
-               Geometry const & g = bv.coordCache().getArrays().geometry(&c);
-               int x1 = g.pos.x_ + c.pos2x(pi.base.bv, s1.pos());
-               int y1 = g.pos.y_ - g.dim.ascent();
-               int x2 = g.pos.x_ + c.pos2x(pi.base.bv, s2.pos());
-               int y2 = g.pos.y_ + g.dim.descent();
-               pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, Color_selection);
-       //lyxerr << "InsetMathNest::drawing selection 3: "
-       //      << " x1: " << x1 << " x2: " << x2
-       //      << " y1: " << y1 << " y2: " << y2 << endl;
-       } else {
-               for (idx_type i = 0; i < nargs(); ++i) {
-                       if (idxBetween(i, s1.idx(), s2.idx())) {
-                               MathData const & c = cell(i);
-                               Geometry const & g = bv.coordCache().getArrays().geometry(&c);
-                               int x1 = g.pos.x_;
-                               int y1 = g.pos.y_ - g.dim.ascent();
-                               int x2 = g.pos.x_ + g.dim.width();
-                               int y2 = g.pos.y_ + g.dim.descent();
-                               pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, Color_selection);
-                       }
-               }
-       }
-}
-
-
 void InsetMathNest::validate(LaTeXFeatures & features) const
 {
        for (idx_type i = 0; i < nargs(); ++i)
@@ -606,7 +557,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_CUT:
                cur.recordUndo();
-               cutSelection(cur, true, true);
+               cutSelection(cur, true);
                cur.message(_("Cut"));
                // Prevent stale position >= size crash
                // Probably not necessary anymore, see eraseSelection (gb 2005-10-09)
@@ -781,20 +732,18 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_MOUSE_DOUBLE:
        case LFUN_WORD_SELECT:
                cur.pos() = 0;
-               cur.resetAnchor();
-               cur.selection(true);
+               cur.bv().mouseSetCursor(cur);
                cur.pos() = cur.lastpos();
-               cur.bv().cursor() = cur;
+               cur.bv().mouseSetCursor(cur, true);
                break;
 
        case LFUN_MOUSE_TRIPLE:
                cur.idx() = 0;
                cur.pos() = 0;
-               cur.resetAnchor();
-               cur.selection(true);
+               cur.bv().mouseSetCursor(cur);
                cur.idx() = cur.lastidx();
                cur.pos() = cur.lastpos();
-               cur.bv().cursor() = cur;
+               cur.bv().mouseSetCursor(cur, true);
                break;
 
        case LFUN_LINE_BEGIN:
@@ -844,12 +793,24 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_CELL_FORWARD:
                cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
-               cur.inset().idxNext(cur);
+               cur.selHandle(false);
+               cur.clearTargetX();
+               cur.macroModeClose();
+               if (!cur.inset().idxNext(cur)) {
+                       cur.idx() = firstIdx();
+                       cur.pos() = 0;
+               }
                break;
 
        case LFUN_CELL_BACKWARD:
                cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
-               cur.inset().idxPrev(cur);
+               cur.selHandle(false);
+               cur.clearTargetX();
+               cur.macroModeClose();
+               if (!cur.inset().idxPrev(cur)) {
+                       cur.idx() = lastIdx();
+                       cur.pos() = lyxrc.mac_like_cursor_movement ? cur.lastpos() : 0;
+               }
                break;
 
        case LFUN_WORD_DELETE_BACKWARD:
@@ -860,9 +821,9 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                else if (!cur.inMacroMode())
                        cur.recordUndoSelection();
                // if the inset can not be removed from within, delete it
-               if (!cur.backspace()) {
-                       FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD);
-                       cur.innerText()->dispatch(cur, cmd);
+               if (!cur.backspace(cmd.getArg(0) == "force")) {
+                       FuncRequest newcmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD, "force");
+                       cur.innerText()->dispatch(cur, newcmd);
                }
                break;
 
@@ -874,9 +835,9 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                else
                        cur.recordUndoSelection();
                // if the inset can not be removed from within, delete it
-               if (!cur.erase()) {
-                       FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD);
-                       cur.innerText()->dispatch(cur, cmd);
+               if (!cur.erase(cmd.getArg(0) == "force")) {
+                       FuncRequest newcmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD, "force");
+                       cur.innerText()->dispatch(cur, newcmd);
                }
                break;
 
@@ -884,8 +845,12 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                if (cur.selection())
                        cur.clearSelection();
                else  {
-                       cmd = FuncRequest(LFUN_FINISHED_FORWARD);
-                       cur.undispatched();
+                       if (cur.inMacroMode())
+                               cur.macroModeClose(true);
+                       else {
+                               cmd = FuncRequest(LFUN_FINISHED_FORWARD);
+                               cur.undispatched();
+                       }
                }
                break;
 
@@ -898,40 +863,37 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                break;
 
        case LFUN_SELF_INSERT:
-               if (cmd.argument().size() != 1) {
-                       cur.recordUndoSelection();
-                       docstring const arg = cmd.argument();
-                       if (!interpretString(cur, arg))
-                               cur.insert(arg);
+               // special case first for big delimiters
+               if (cmd.argument().size() != 1 && interpretString(cur, cmd.argument()))
                        break;
-               }
-               // Don't record undo steps if we are in macro mode and thus
-               // cmd.argument is the next character of the macro name.
-               // Otherwise we'll get an invalid cursor if we undo after
-               // the macro was finished and the macro is a known command,
-               // e.g. sqrt. Cursor::macroModeClose replaces in this case
-               // the InsetMathUnknown with name "frac" by an empty
-               // InsetMathFrac -> a pos value > 0 is invalid.
-               // A side effect is that an undo before the macro is finished
-               // undoes the complete macro, not only the last character.
-               // At the time we hit '\' we are not in macro mode, still.
-               if (!cur.inMacroMode())
-                       cur.recordUndoSelection();
 
-               // spacial handling of space. If we insert an inset
-               // via macro mode, we want to put the cursor inside it
-               // if relevant. Think typing "\frac<space>".
-               if (cmd.argument()[0] == ' '
-                   && cur.inMacroMode() && cur.macroName() != "\\"
-                   && cur.macroModeClose() && cur.pos() > 0) {
-                       MathAtom const atom = cur.prevAtom();
-                       if (atom->asNestInset() && atom->isActive()) {
-                               cur.posBackward();
-                               cur.pushBackward(*cur.nextInset());
+               for (char_type c : cmd.argument()) {
+                       // Don't record undo steps if we are in macro mode and thus
+                       // cmd.argument is the next character of the macro name.
+                       // Otherwise we'll get an invalid cursor if we undo after
+                       // the macro was finished and the macro is a known command,
+                       // e.g. sqrt. Cursor::macroModeClose replaces in this case
+                       // the InsetMathUnknown with name "frac" by an empty
+                       // InsetMathFrac -> a pos value > 0 is invalid.
+                       // A side effect is that an undo before the macro is finished
+                       // undoes the complete macro, not only the last character.
+                       // At the time we hit '\' we are not in macro mode, still.
+                       if (!cur.inMacroMode())
+                               cur.recordUndoSelection();
+
+                       // special handling of space. If we insert an inset
+                       // via macro mode, we want to put the cursor inside it
+                       // if relevant. Think typing "\frac<space>".
+                       if (c == ' '
+                           && cur.inMacroMode() && cur.macroName() != "\\"
+                           && cur.macroModeClose() && cur.pos() > 0)
+                               cur.editInsertedInset();
+                       else if (!interpretChar(cur, c)) {
+                               cmd = FuncRequest(LFUN_FINISHED_FORWARD);
+                               cur.undispatched();
+                               // FIXME: can we avoid skipping the end of the string?
+                               break;
                        }
-               } else if (!interpretChar(cur, cmd.argument()[0])) {
-                       cmd = FuncRequest(LFUN_FINISHED_FORWARD);
-                       cur.undispatched();
                }
                break;
 
@@ -944,7 +906,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                int y = 0;
                istringstream is(to_utf8(cmd.argument()));
                is >> x >> y;
-               cur.setScreenPos(x, y);
+               cur.setTargetX(x);
                break;
        }
 
@@ -1254,7 +1216,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                bool fold = act == LFUN_MATH_MACRO_FOLD;
                bool found = findMacroToFoldUnfold(it, fold);
                if (found) {
-                       MathMacro * macro = it.nextInset()->asInsetMath()->asMacro();
+                       InsetMathMacro * macro = it.nextInset()->asInsetMath()->asMacro();
                        cur.recordUndoInset();
                        if (fold)
                                macro->fold(cur);
@@ -1290,22 +1252,6 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                break;
        }
 
-       case LFUN_UNICODE_INSERT: {
-               if (cmd.argument().empty())
-                       break;
-               docstring hexstring = cmd.argument();
-               if (isHex(hexstring)) {
-                       char_type c = hexToInt(hexstring);
-                       if (c >= 32 && c < 0x10ffff) {
-                               docstring s = docstring(1, c);
-                               FuncCode code = currentMode() == MATH_MODE ?
-                                       LFUN_MATH_INSERT : LFUN_SELF_INSERT;
-                               lyx::dispatch(FuncRequest(code, s));
-                       }
-               }
-               break;
-       }
-
        case LFUN_DIALOG_SHOW_NEW_INSET: {
                docstring const & name = cmd.argument();
                string data;
@@ -1350,7 +1296,7 @@ bool InsetMathNest::findMacroToFoldUnfold(Cursor & it, bool fold) const {
                // go backward through the current cell
                Inset * inset = it.nextInset();
                while (inset && inset->asInsetMath()) {
-                       MathMacro * macro = inset->asInsetMath()->asMacro();
+                       InsetMathMacro * macro = inset->asInsetMath()->asMacro();
                        if (macro) {
                                // found the an macro to open/close?
                                if (macro->folded() != fold)
@@ -1530,10 +1476,9 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd,
 void InsetMathNest::edit(Cursor & cur, bool front, EntryDirection entry_from)
 {
        cur.push(*this);
-       bool enter_front = (entry_from == Inset::ENTRY_DIRECTION_RIGHT ||
+       bool enter_front = (entry_from == Inset::ENTRY_DIRECTION_LEFT ||
                (entry_from == Inset::ENTRY_DIRECTION_IGNORE && front));
-       cur.idx() = enter_front ? 0 : cur.lastidx();
-       cur.pos() = enter_front ? 0 : cur.lastpos();
+       enter_front ? idxFirst(cur) : idxLast(cur);
        cur.resetAnchor();
        //lyxerr << "InsetMathNest::edit, cur:\n" << cur << endl;
 }
@@ -1541,7 +1486,7 @@ void InsetMathNest::edit(Cursor & cur, bool front, EntryDirection entry_from)
 
 Inset * InsetMathNest::editXY(Cursor & cur, int x, int y)
 {
-       int idx_min = 0;
+       int idx_min = -1;
        int dist_min = 1000000;
        for (idx_type i = 0, n = nargs(); i != n; ++i) {
                int const d = cell(i).dist(cur.bv(), x, y);
@@ -1550,6 +1495,9 @@ Inset * InsetMathNest::editXY(Cursor & cur, int x, int y)
                        idx_min = i;
                }
        }
+       if (idx_min == -1)
+               return this;
+
        MathData & ar = cell(idx_min);
        cur.push(*this);
        cur.idx() = idx_min;
@@ -1579,6 +1527,10 @@ void InsetMathNest::lfunMousePress(Cursor & cur, FuncRequest & cmd)
                        return;
                }
        }
+
+       // set cursor after the inset if x is nearer to that position (bug 9748)
+       cur.moveToClosestEdge(cmd.x(), true);
+
        bool do_selection = cmd.button() == mouse_button::button1
                && cmd.modifier() == ShiftModifier;
        bv.mouseSetCursor(cur, do_selection);
@@ -1623,6 +1575,9 @@ void InsetMathNest::lfunMouseMotion(Cursor & cur, FuncRequest & cmd)
                return;
        }
 
+       // set cursor after the inset if x is nearer to that position (bug 9748)
+       cur.moveToClosestEdge(cmd.x());
+
        CursorSlice old = bvcur.top();
 
        // We continue with our existing selection or start a new one, so don't
@@ -1675,7 +1630,7 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
                        cur.backspace();
                        int n = c - '0';
                        if (n >= 1 && n <= 9)
-                               cur.insert(new MathMacroArgument(n));
+                               cur.insert(new InsetMathMacroArgument(n));
                        return true;
                }
 
@@ -1763,7 +1718,7 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
                        MathAtom const atom = cur.prevAtom();
                        if (atom->asNestInset() && atom->isActive()) {
                                cur.posBackward();
-                               cur.pushBackward(*cur.nextInset());
+                               cur.nextInset()->edit(cur, true);
                        }
                }
                if (c == '{')
@@ -1940,6 +1895,7 @@ bool InsetMathNest::interpretString(Cursor & cur, docstring const & str)
                                prev = prev.substr(1);
                                latexkeys const * l = in_word_set(prev);
                                if (l && l->inset == "big") {
+                                       cur.recordUndoSelection();
                                        cur.cell()[cur.pos() - 1] =
                                                MathAtom(new InsetMathBig(prev, str));
                                        return true;
@@ -2069,8 +2025,7 @@ bool InsetMathNest::insertCompletion(Cursor & cur, docstring const & s,
 #if 0
                // FIXME: this creates duplicates in the completion popup
                // which looks ugly. Moreover the changes the list lengths
-               // which seems to
-               confuse the popup as well.
+               // which seems to confuse the popup as well.
                MathCompletionList::addToFavorites(inset->name());
 #endif
                lyx::dispatch(FuncRequest(LFUN_SELF_INSERT, " "));