From 18f7dce3d9877c690f3d4dbb0239a816e1d42414 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Thu, 24 Dec 2020 10:48:52 +0100 Subject: [PATCH] Implement inset-split (only for text insets for now) (#10260) --- lib/RELEASE-NOTES | 3 ++ lib/ui/stdcontext.inc | 2 + src/FuncCode.h | 1 + src/LyXAction.cpp | 14 +++++++ src/Text.cpp | 75 +++++++++++++++++++++++++++++++++++++ src/Text.h | 2 + src/Text3.cpp | 8 ++++ src/insets/InsetFlex.cpp | 6 ++- src/insets/InsetTabular.cpp | 1 + src/insets/InsetText.cpp | 2 + 10 files changed, 112 insertions(+), 2 deletions(-) diff --git a/lib/RELEASE-NOTES b/lib/RELEASE-NOTES index 6fbaba3f6b..f73427cd3c 100644 --- a/lib/RELEASE-NOTES +++ b/lib/RELEASE-NOTES @@ -95,6 +95,9 @@ * paragraph-select is a new convenience function to select the paragraph surrounding the actual cursor position. +* split-inset is a new convenience function that splits an inset into two at the given + cursor position. This is only implemented for text insets currently. + * tabular-style-insert: Insert a table in a specified style. diff --git a/lib/ui/stdcontext.inc b/lib/ui/stdcontext.inc index d1895143b5..b4ee95455b 100644 --- a/lib/ui/stdcontext.inc +++ b/lib/ui/stdcontext.inc @@ -357,6 +357,8 @@ Menuset Item "Paste" "paste" Submenu "Paste Recent|e" "edit_pasterecent" Separator + OptItem "Split Inset|t" "inset-split" + Separator Item "Jump Back to Saved Bookmark|B" "bookmark-goto 0" OptItem "Forward Search|F" "forward-search" Separator diff --git a/src/FuncCode.h b/src/FuncCode.h index 6b970fb579..9857143c25 100644 --- a/src/FuncCode.h +++ b/src/FuncCode.h @@ -493,6 +493,7 @@ enum FuncCode LFUN_CITATION_OPEN, // sanda, 20200815 LFUN_TOOLBAR_SET, // spitz 20201217 // 385 + LFUN_INSET_SPLIT, // jspitzm 20201222 LFUN_LASTACTION // end of the table }; diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index 462e397d3a..1f0b9524a1 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -2225,6 +2225,20 @@ void LyXAction::init() */ { LFUN_INSET_SETTINGS, "inset-settings", ReadOnly | AtPoint, Edit }, +/*! + * \var lyx::FuncCode lyx::LFUN_INSET_SPLIT + * \li Action: Splits the current inset into two at current position. + * \li Syntax: inset-split [] + * \li Params: : this can be used to make sure the right kind of inset + is dissolved. For example "split" entry in the charstyles + sub-menu should only dissolve the charstyle inset, even if the + cursor is inside several nested insets of different type.\n + For values see #lyx::InsetLayout::lyxtype_ . + * \li Origin: spitz, 22 Dec 2020 + * \endvar + */ + { LFUN_INSET_SPLIT, "inset-split", AtPoint, Edit }, + /*! * \var lyx::FuncCode lyx::LFUN_INSET_TOGGLE * \li Action: Toggles the collapsible inset at cursor position, diff --git a/src/Text.cpp b/src/Text.cpp index d227bd5cd5..1f8288a71d 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -33,6 +33,7 @@ #include "ErrorList.h" #include "factory.h" #include "Font.h" +#include "FuncRequest.h" #include "Language.h" #include "Layout.h" #include "Lexer.h" @@ -1898,6 +1899,80 @@ bool Text::dissolveInset(Cursor & cur) } +bool Text::splitInset(Cursor & cur) +{ + LASSERT(this == cur.text(), return false); + + if (isMainText() || cur.inset().nargs() != 1) + return false; + + cur.recordUndo(); + if (cur.selection()) { + // start from selection begin + setCursor(cur, cur.selBegin().pit(), cur.selBegin().pos()); + cur.clearSelection(); + } + // save split position inside inset + // (we need to copy the whole inset first) + pos_type spos = cur.pos(); + pit_type spit = cur.pit(); + // some things only need to be done if the inset has content + bool const inset_non_empty = cur.lastpit() != 0 || cur.lastpos() != 0; + + // move right before the inset + cur.popBackward(); + cur.resetAnchor(); + // remember position outside inset + pos_type ipos = cur.pos(); + pit_type ipit = cur.pit(); + // select inset ... + ++cur.pos(); + cur.setSelection(); + // ... and copy + cap::copySelectionToTemp(cur); + cur.clearSelection(); + cur.resetAnchor(); + // paste copied inset + cap::pasteFromTemp(cur, cur.buffer()->errorList("Paste")); + cur.forceBufferUpdate(); + + // if the inset has text, cut after split position + // and paste to new inset + if (inset_non_empty) { + // go back to first inset + cur.text()->setCursor(cur, ipit, ipos); + cur.forwardPos(); + setCursor(cur, spit, spos); + cur.resetAnchor(); + setCursor(cur, cur.lastpit(), getPar(cur.lastpit()).size()); + cur.setSelection(); + cap::cutSelectionToTemp(cur); + cur.setMark(false); + cur.selHandle(false); + cur.resetAnchor(); + Cursor dummy = cur; + dummy.pos() = dummy.pit() = 0; + if (cur.bv().checkDepm(dummy, cur)) + cur.forceBufferUpdate(); + // Move out of and jump over inset + cur.popBackward(); + ++cur.pos(); + + // enter new inset + cur.forwardPos(); + cur.setCursor(cur); + cur.resetAnchor(); + cur.text()->selectAll(cur); + cutSelection(cur, false); + cap::pasteFromTemp(cur, cur.buffer()->errorList("Paste")); + cur.text()->setCursor(cur, 0, 0); + } + + cur.finishUndo(); + return true; +} + + void Text::getWord(CursorSlice & from, CursorSlice & to, word_location const loc) const { diff --git a/src/Text.h b/src/Text.h index 4defd94fa6..1410828604 100644 --- a/src/Text.h +++ b/src/Text.h @@ -245,6 +245,8 @@ public: // Dissolve the inset under cursor /// FIXME: replace Cursor with DocIterator. bool dissolveInset(Cursor & cur); + /// FIXME: replace Cursor with DocIterator. + bool splitInset(Cursor & cur); /// bool selectWordWhenUnderCursor(Cursor & cur, word_location); /// Change the case of the word at cursor position. diff --git a/src/Text3.cpp b/src/Text3.cpp index 07d7e80d0a..61b64efc87 100644 --- a/src/Text3.cpp +++ b/src/Text3.cpp @@ -1370,6 +1370,14 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) break; } + case LFUN_INSET_SPLIT: { + if (splitInset(cur)) { + needsUpdate = true; + cur.forceBufferUpdate(); + } + break; + } + case LFUN_GRAPHICS_SET_GROUP: { InsetGraphics * ins = graphics::getCurrentGraphicsInset(cur); if (!ins) diff --git a/src/insets/InsetFlex.cpp b/src/insets/InsetFlex.cpp index 4da349fd13..e6076102f6 100644 --- a/src/insets/InsetFlex.cpp +++ b/src/insets/InsetFlex.cpp @@ -94,6 +94,7 @@ bool InsetFlex::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & flag) const { switch (cmd.action()) { + case LFUN_INSET_SPLIT: case LFUN_INSET_DISSOLVE: if (!cmd.argument().empty()) { InsetLayout const & il = getLayout(); @@ -102,7 +103,7 @@ bool InsetFlex::getStatus(Cursor & cur, FuncRequest const & cmd, if (il.lyxtype() == type || (il.name() == DocumentClass::plainInsetLayout().name() && type == InsetLyXType::CHARSTYLE)) { - FuncRequest temp_cmd(LFUN_INSET_DISSOLVE); + FuncRequest temp_cmd(cmd.action()); return InsetCollapsible::getStatus(cur, temp_cmd, flag); } else return false; @@ -117,6 +118,7 @@ bool InsetFlex::getStatus(Cursor & cur, FuncRequest const & cmd, void InsetFlex::doDispatch(Cursor & cur, FuncRequest & cmd) { switch (cmd.action()) { + case LFUN_INSET_SPLIT: case LFUN_INSET_DISSOLVE: if (!cmd.argument().empty()) { InsetLayout const & il = getLayout(); @@ -126,7 +128,7 @@ void InsetFlex::doDispatch(Cursor & cur, FuncRequest & cmd) if (il.lyxtype() == type || (il.name() == DocumentClass::plainInsetLayout().name() && type == InsetLyXType::CHARSTYLE)) { - FuncRequest temp_cmd(LFUN_INSET_DISSOLVE); + FuncRequest temp_cmd(cmd.action()); InsetCollapsible::doDispatch(cur, temp_cmd); } else cur.undispatched(); diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index 181e68cb7c..b3e8bd8d49 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -4226,6 +4226,7 @@ bool InsetTableCell::getStatus(Cursor & cur, FuncRequest const & cmd, { bool enabled = true; switch (cmd.action()) { + case LFUN_INSET_SPLIT: case LFUN_INSET_DISSOLVE: enabled = false; break; diff --git a/src/insets/InsetText.cpp b/src/insets/InsetText.cpp index 5c4d32c20c..8e0500d9b2 100644 --- a/src/insets/InsetText.cpp +++ b/src/insets/InsetText.cpp @@ -320,6 +320,7 @@ void InsetText::doDispatch(Cursor & cur, FuncRequest & cmd) fixParagraphsFont(); break; + case LFUN_INSET_SPLIT: case LFUN_INSET_DISSOLVE: { bool const main_inset = text_.isMainText(); bool const target_inset = cmd.argument().empty() @@ -351,6 +352,7 @@ bool InsetText::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & status) const { switch (cmd.action()) { + case LFUN_INSET_SPLIT: case LFUN_INSET_DISSOLVE: { bool const main_inset = text_.isMainText(); bool const target_inset = cmd.argument().empty()