}
-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
}
-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();
}
+bool Cursor::confirmDeletion(bool const before) const
+{
+ if (!selection()) {
+ if (Inset const * inset = before ? prevInset() : nextInset())
+ return inset->confirmDeletion();
+ } else {
+ DocIterator dit = selectionBegin();
+ DocIterator const sel_end = selectionEnd();
+ for (; dit < sel_end; dit.posForward())
+ if (Inset const * inset = dit.nextInset())
+ if (inset->confirmDeletion())
+ return true;
+ }
+ return false;
+}
+
+
} // namespace lyx
//
// common part
//
- /// move one step backwards
- bool posBackward();
- /// move one step forward
- bool posForward();
/// move visually one step to the right
/**
* @note: This method may move into an inset unless skip_inset == true.
/// and after leaving the word the result is empty.
DocIterator newWord() const { return new_word_; }
+ /// Return true if the next or previous inset has confirmDeletion depending
+ /// on the boolean before. If there is a selection, return true if at least
+ /// one inset in the selection has confirmDeletion.
+ bool confirmDeletion(bool before = false) const;
+
public:
//private:
///
void insert(MathData const &);
/// return false for empty math insets
- bool erase();
- /// return false for empty math insets
- bool backspace();
+ /// Use force to skip the confirmDeletion check.
+ bool erase(bool force = false);
+ bool backspace(bool force = false);
+
/// move the cursor up by sending an internal LFUN_UP
/// return true if fullscreen update is needed
bool up();
}
+bool DocIterator::posBackward()
+{
+ if (pos() == 0)
+ return false;
+ --pos();
+ return true;
+}
+
+
+bool DocIterator::posForward()
+{
+ if (pos() == lastpos())
+ return false;
+ ++pos();
+ return true;
+}
+
+
// This duplicates code above, but is in the critical path.
// So please think twice before adding stuff
void DocIterator::forwardPos()
//
// elementary moving
//
+ /// move one step backwards
+ bool posBackward();
+ /// move one step forward
+ bool posForward();
/**
* move on one logical position, descend into nested insets
* including collapsed insets
/*!
* \var lyx::FuncCode lyx::LFUN_CHAR_DELETE_BACKWARD
* \li Action: Deletes one character in the backward direction (usually the "BackSpace" key).
- * \li Syntax: char-delete-backward
+ * \li Syntax: char-delete-backward [force]
+ * \li Params: force: Delete big insets, do no only select them.
* \endvar
*/
{ LFUN_CHAR_DELETE_BACKWARD, "char-delete-backward", SingleParUpdate, Edit },
/*!
* \var lyx::FuncCode lyx::LFUN_CHAR_DELETE_FORWARD
* \li Action: Deletes one character in the backward direction (usually the "Delete" key).
- * \li Syntax: char-delete-forward
+ * \li Syntax: char-delete-forward [force]
+ * \li Params: force: Delete big insets, do no only select them.
* \endvar
*/
{ LFUN_CHAR_DELETE_FORWARD, "char-delete-forward", SingleParUpdate, Edit },
/*!
* \var lyx::FuncCode lyx::LFUN_WORD_DELETE_BACKWARD
* \li Action: Deletes characters to the beginning of the word (usually the "C+BackSpace" key).
- * \li Syntax: word-delete-backward
+ * \li Syntax: word-delete-backward [force]
+ * \li Params: force: Delete big insets, do no only select them.
* \endvar
*/
{ LFUN_WORD_DELETE_BACKWARD, "word-delete-backward", Noop, Edit },
/*!
* \var lyx::FuncCode lyx::LFUN_WORD_DELETE_FORWARD
* \li Action: Deletes characters to the end of the word (usually the "C+Delete" key).
- * \li Syntax: word-delete-forward
+ * \li Syntax: word-delete-forward [force]
+ * \li Params: force: Delete big insets, do no only select them.
* \endvar
*/
{ LFUN_WORD_DELETE_FORWARD, "word-delete-forward", Noop, Edit },
}
-void Text::deleteWordForward(Cursor & cur)
+void Text::deleteWordForward(Cursor & cur, bool const force)
{
LBUFERR(this == cur.text());
if (cur.lastpos() == 0)
cur.selection(true);
cursorForwardOneWord(cur);
cur.setSelection();
- cutSelection(cur, true, false);
- cur.checkBufferStructure();
+ if (force || !cur.confirmDeletion()) {
+ cutSelection(cur, true, false);
+ cur.checkBufferStructure();
+ }
}
}
-void Text::deleteWordBackward(Cursor & cur)
+void Text::deleteWordBackward(Cursor & cur, bool const force)
{
LBUFERR(this == cur.text());
if (cur.lastpos() == 0)
cur.selection(true);
cursorBackwardOneWord(cur);
cur.setSelection();
- cutSelection(cur, true, false);
- cur.checkBufferStructure();
+ if (force || !cur.confirmDeletion()) {
+ cutSelection(cur, true, false);
+ cur.checkBufferStructure();
+ }
}
}
///
bool cursorVisRightOneWord(Cursor & cur);
/// Delete from cursor up to the end of the current or next word.
- void deleteWordForward(Cursor & cur);
+ /// Use force to skip the confirmDeletion check.
+ void deleteWordForward(Cursor & cur, bool force = false);
/// Delete from cursor to start of current or prior word.
- void deleteWordBackward(Cursor & cur);
+ void deleteWordBackward(Cursor & cur, bool force = false);
///
bool cursorUpParagraph(Cursor & cur);
///
if (cur.selection())
cutSelection(cur, true, false);
else
- deleteWordForward(cur);
+ deleteWordForward(cur, cmd.getArg(0) == "force");
finishChange(cur, false);
break;
if (cur.selection())
cutSelection(cur, true, false);
else
- deleteWordBackward(cur);
+ deleteWordBackward(cur, cmd.getArg(0) == "force");
finishChange(cur, false);
break;
if (cur.pos() == cur.paragraph().size())
// Par boundary, force full-screen update
singleParUpdate = false;
+ else if (cmd.getArg(0) != "force" && cur.confirmDeletion()) {
+ cur.resetAnchor();
+ cur.selection(true);
+ cur.posForward();
+ cur.setSelection();
+ break;
+ }
needsUpdate |= erase(cur);
cur.resetAnchor();
} else {
// Par boundary, full-screen update
if (par_boundary)
singleParUpdate = false;
+ else if (cmd.getArg(0) != "force" && cur.confirmDeletion(true)) {
+ cur.resetAnchor();
+ cur.selection(true);
+ cur.posBackward();
+ cur.setSelection();
+ break;
+ }
needsUpdate |= backspace(cur);
cur.resetAnchor();
if (par_boundary && !first_par && cur.pos() > 0
//
enum { TEXT_TO_INSET_OFFSET = 4 };
+ /// Determine the action of backspace and delete: do we select instead of
+ /// deleting if not already selected?
+ virtual bool confirmDeletion() const { return false; }
+
protected:
/// Constructors
Inset(Buffer * buf) : buffer_(buf) {}
std::string contextMenuName() const;
///
void doDispatch(Cursor & cur, FuncRequest & cmd);
+
+ ///
+ bool confirmDeletion() const { return !text().empty(); }
+
protected:
///
void iterateForToc(DocIterator const & cdit, bool output_active,
InsetCode lyxCode() const { return MATH_HULL_CODE; }
///
bool canPaintChange(BufferView const &) const;
+ ///
+ bool confirmDeletion() const { return nargs() != 1 || !cell(0).empty(); }
protected:
InsetMathHull(InsetMathHull const &);
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);
+ if (!cur.backspace(cmd.getArg(0) == "force")) {
+ FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD, "force");
cur.innerText()->dispatch(cur, cmd);
}
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);
+ if (!cur.erase(cmd.getArg(0) == "force")) {
+ FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD, "force");
cur.innerText()->dispatch(cur, cmd);
}
break;
///
InsetCode lyxCode() const { return MATH_NEST_CODE; }
+ ///
+ bool confirmDeletion() const { return nargs() > 0; }
+
protected:
///
InsetMathNest(InsetMathNest const & inset);