#include "mathed/MacroTable.h"
#include "mathed/MathData.h"
#include "mathed/MathFactory.h"
-#include "mathed/MathMacro.h"
+#include "mathed/InsetMathMacro.h"
#include <sstream>
#include <limits>
}
-} // namespace anon
+} // namespace
CursorData::CursorData()
}
-bool Cursor::posBackward()
-{
- if (pos() == 0)
- return false;
- --pos();
- return true;
-}
-
-
-bool Cursor::posForward()
-{
- if (pos() == lastpos())
- return false;
- ++pos();
- return true;
-}
-
-
bool Cursor::posVisRight(bool skip_inset)
{
Cursor new_cur = *this; // where we will move to
return cit != row.end() && !cit->isVirtual();
}
-}
+} // namespace
void Cursor::getSurroundingPos(pos_type & left_pos, pos_type & right_pos) const
{
}
-void Cursor::info(odocstream & os) const
+void Cursor::info(odocstream & os, bool devel_mode) const
{
for (int i = 1, n = depth(); i < n; ++i) {
operator[](i).inset().infoize(os);
if (inset)
prevInset()->infoize2(os);
}
+ if (devel_mode) {
+ InsetMath * math = inset().asInsetMath();
+ if (math)
+ os << _(", Inset: ") << math->id();
+ os << _(", Cell: ") << idx();
+ os << _(", Position: ") << pos();
+ }
+
}
}
-bool Cursor::backspace()
+bool Cursor::backspace(bool const force)
{
if (selection()) {
cap::eraseSelection(*this);
}
}
- if (pos() != 0 && prevAtom()->nargs() > 0) {
+ if (pos() != 0 && !force && prevAtom()->confirmDeletion()) {
// let's require two backspaces for 'big stuff' and
// highlight on the first
resetAnchor();
}
-bool Cursor::erase()
+bool Cursor::erase(bool const force)
{
if (inMacroMode())
return true;
}
// 'clever' UI hack: only erase large items if previously slected
- if (pos() != lastpos() && nextAtom()->nargs() > 0) {
+ if (pos() != lastpos() && !force && nextAtom()->confirmDeletion()) {
resetAnchor();
selection(true);
++pos();
if (in && in->interpretString(*this, s))
return true;
bool const user_macro = buffer()->getMacro(name, *this, false);
- MathAtom atom = user_macro ? MathAtom(new MathMacro(buffer(), name))
+ MathAtom atom = user_macro ? MathAtom(new InsetMathMacro(buffer(), name))
: createInsetMath(name, buffer());
// try to put argument into macro, if we just inserted a macro
bool macroArg = false;
- MathMacro * atomAsMacro = atom.nucleus()->asMacro();
+ InsetMathMacro * atomAsMacro = atom.nucleus()->asMacro();
if (atomAsMacro) {
// macros here are still unfolded (in init mode in fact). So
// we have to resolve the macro here manually and check its arity
MacroData const * data = buffer()->getMacro(atomAsMacro->name());
if (!selection.empty() && data && data->numargs() - data->optionals() > 0) {
macroArg = true;
- atomAsMacro->setDisplayMode(MathMacro::DISPLAY_INTERACTIVE_INIT, 1);
+ atomAsMacro->setDisplayMode(InsetMathMacro::DISPLAY_INTERACTIVE_INIT, 1);
} else
// non-greedy case. Do not touch the arguments behind
- atomAsMacro->setDisplayMode(MathMacro::DISPLAY_INTERACTIVE_INIT, 0);
+ atomAsMacro->setDisplayMode(InsetMathMacro::DISPLAY_INTERACTIVE_INIT, 0);
}
// insert remembered selection into first argument of a non-macro
LASSERT(inMathed(), return false);
if (pos() < lastpos()) {
if (word) {
- // word: skip a group of insets with same math class
+ // word: skip a group of insets of the form X*(B*|R*|P*) (greedy
+ // match) where X is any math class, B is mathbin, R is mathrel, and
+ // P is mathpunct. Make sure that the following remains true:
+ // mathForward(true); mathBackward(true); mathForward(true)
+ // is the same as mathForward(true) and
+ // mathBackward(true); mathForward(true); mathBackward(true)
+ // is the same as mathBackward(true).
MathClass mc = nextMath().mathClass();
do
posForward();
while (pos() < lastpos() && mc == nextMath().mathClass());
+ if (pos() < lastpos() &&
+ ((mc = nextMath().mathClass()) == MC_BIN ||
+ mc == MC_REL || mc == MC_PUNCT))
+ do
+ posForward();
+ while (pos() < lastpos() && mc == nextMath().mathClass());
} else if (openable(nextAtom())) {
// single step: try to enter the next inset
pushBackward(nextMath());
LASSERT(inMathed(), return false);
if (pos() > 0) {
if (word) {
- // word: skip a group of insets with same math class
+ // word: skip a group of insets. See the comment in mathForward.
MathClass mc = prevMath().mathClass();
do
posBackward();
while (pos() > 0 && mc == prevMath().mathClass());
+ if (pos() > 0 && (mc == MC_BIN || mc == MC_REL || mc == MC_PUNCT)) {
+ mc = prevMath().mathClass();
+ do
+ posBackward();
+ while (pos() > 0 && mc == prevMath().mathClass());
+ }
} else if (openable(prevAtom())) {
// single step: try to enter the preceding inset
posBackward();
int yo = bv().getPos(*this).y_;
Cursor old = *this;
// To next/previous row
+ // FIXME: the y position is often guessed wrongly across styles and
+ // insets, which leads to weird behaviour.
if (up)
tm.editXY(*this, xo, yo - textRow().ascent() - 1);
else
tm.editXY(*this, xo, yo + textRow().descent() + 1);
+ x_target_ = old.x_target_;
clearSelection();
// This happens when you move out of an inset.
return os.str();
}
-}
+} // namespace
docstring Cursor::selectionAsString(bool with_label) const
}
-docstring Cursor::currentState() const
+docstring Cursor::currentState(bool devel_mode) const
{
if (inMathed()) {
odocstringstream os;
- info(os);
-#ifdef DEVEL_VERSION
- InsetMath * math = inset().asInsetMath();
- if (math)
- os << _(", Inset: ") << math->id();
- os << _(", Cell: ") << idx();
- os << _(", Position: ") << pos();
-#endif
+ info(os, devel_mode);
return os.str();
}
if (inTexted())
- return text()->currentState(*this);
+ return text()->currentState(*this, devel_mode);
return docstring();
}
}
+bool Cursor::confirmDeletion(bool const before) const
+{
+ if (!selection()) {
+ if (Inset const * inset = before ? prevInset() : nextInset())
+ return inset->confirmDeletion();
+ } else {
+ DocIterator dit = selectionBegin();
+ CursorSlice const end = selectionEnd().top();
+ for (; dit.top() < end; dit.top().forwardPos())
+ if (Inset const * inset = dit.nextInset())
+ if (inset->confirmDeletion())
+ return true;
+ }
+ return false;
+}
+
+
+void Cursor::moveToClosestEdge(int const x, bool const edit)
+{
+ if (Inset const * inset = nextInset()) {
+ // stay in front of insets for which we want to open the dialog
+ // (e.g. InsetMathSpace).
+ if (edit && (inset->hasSettings() || !inset->contextMenuName().empty()))
+ return;
+ CoordCache::Insets const & insetCache = bv().coordCache().getInsets();
+ if (!insetCache.has(inset))
+ return;
+ int const wid = insetCache.dim(inset).wid;
+ Point p = insetCache.xy(inset);
+ if (x > p.x_ + (wid + 1) / 2)
+ posForward();
+ }
+}
+
+
} // namespace lyx