#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"
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);
}
// << " 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 += 2;
+ if (ar.empty()) {
+ Dimension const dim = coord_cache.getArrays().dim(&ar);
+ x += dim.wid / 3;
+ }
}
if (cur.idx() == 0)
return false;
--cur.idx();
- cur.pos() = cur.lastpos();
+ cur.pos() = lyxrc.mac_like_cursor_movement ? cur.lastpos() : 0;
return true;
}
LASSERT(&cur.inset() == this, return false);
if (nargs() == 0)
return false;
- cur.idx() = 0;
+ cur.idx() = firstIdx();
cur.pos() = 0;
return true;
}
LASSERT(&cur.inset() == this, return false);
if (nargs() == 0)
return false;
- cur.idx() = cur.lastidx();
+ cur.idx() = lastIdx();
cur.pos() = cur.lastpos();
return true;
}
}
-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)
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)
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:
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:
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;
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;
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;
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;
int y = 0;
istringstream is(to_utf8(cmd.argument()));
is >> x >> y;
- cur.setScreenPos(x, y);
+ cur.setTargetX(x);
break;
}
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);
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;
// 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)
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;
}
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);
idx_min = i;
}
}
+ if (idx_min == -1)
+ return this;
+
MathData & ar = cell(idx_min);
cur.push(*this);
cur.idx() = idx_min;
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);
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
cur.backspace();
int n = c - '0';
if (n >= 1 && n <= 9)
- cur.insert(new MathMacroArgument(n));
+ cur.insert(new InsetMathMacroArgument(n));
return true;
}
MathAtom const atom = cur.prevAtom();
if (atom->asNestInset() && atom->isActive()) {
cur.posBackward();
- cur.pushBackward(*cur.nextInset());
+ cur.nextInset()->edit(cur, true);
}
}
if (c == '{')
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;
#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, " "));