diff options
-rw-r--r-- | call/ScintillaCall.cxx | 4 | ||||
-rw-r--r-- | doc/ScintillaDoc.html | 15 | ||||
-rw-r--r-- | doc/ScintillaHistory.html | 3 | ||||
-rw-r--r-- | include/Scintilla.h | 1 | ||||
-rw-r--r-- | include/Scintilla.iface | 4 | ||||
-rw-r--r-- | include/ScintillaCall.h | 1 | ||||
-rw-r--r-- | include/ScintillaMessages.h | 1 | ||||
-rw-r--r-- | src/Editor.cxx | 70 | ||||
-rw-r--r-- | src/Editor.h | 1 | ||||
-rw-r--r-- | test/simpleTests.py | 47 |
10 files changed, 91 insertions, 56 deletions
diff --git a/call/ScintillaCall.cxx b/call/ScintillaCall.cxx index 4981d6299..6935eacbd 100644 --- a/call/ScintillaCall.cxx +++ b/call/ScintillaCall.cxx @@ -2363,6 +2363,10 @@ void ScintillaCall::SetSelectionMode(Scintilla::SelectionMode selectionMode) { Call(Message::SetSelectionMode, static_cast<uintptr_t>(selectionMode)); } +void ScintillaCall::ChangeSelectionMode(Scintilla::SelectionMode selectionMode) { + Call(Message::ChangeSelectionMode, static_cast<uintptr_t>(selectionMode)); +} + SelectionMode ScintillaCall::SelectionMode() { return static_cast<Scintilla::SelectionMode>(Call(Message::GetSelectionMode)); } diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html index 43407a40b..dcabdd9ee 100644 --- a/doc/ScintillaDoc.html +++ b/doc/ScintillaDoc.html @@ -979,6 +979,7 @@ struct Sci_TextRangeFull { <a class="message" href="#SCI_GETCURLINE">SCI_GETCURLINE(position length, char *text) → position</a><br /> <a class="message" href="#SCI_SELECTIONISRECTANGLE">SCI_SELECTIONISRECTANGLE → bool</a><br /> <a class="message" href="#SCI_SETSELECTIONMODE">SCI_SETSELECTIONMODE(int selectionMode)</a><br /> + <a class="message" href="#SCI_CHANGESELECTIONMODE">SCI_CHANGESELECTIONMODE(int selectionMode)</a><br /> <a class="message" href="#SCI_GETSELECTIONMODE">SCI_GETSELECTIONMODE → int</a><br /> <a class="message" href="#SCI_SETMOVEEXTENDSSELECTION">SCI_SETMOVEEXTENDSSELECTION(bool moveExtendsSelection)</a><br /> <a class="message" href="#SCI_GETMOVEEXTENDSSELECTION">SCI_GETMOVEEXTENDSSELECTION → bool</a><br /> @@ -1122,17 +1123,19 @@ struct Sci_TextRangeFull { <p><b id="SCI_SELECTIONISRECTANGLE">SCI_SELECTIONISRECTANGLE → bool</b><br /> This returns 1 if the current selection is in rectangle mode, 0 if not.</p> - <p><b id="SCI_SETSELECTIONMODE">SCI_SETSELECTIONMODE(int selectionMode)</b><br /> + <p> + <b id="SCI_SETSELECTIONMODE">SCI_SETSELECTIONMODE(int selectionMode)</b><br /> + <b id="SCI_CHANGESELECTIONMODE">SCI_CHANGESELECTIONMODE(int selectionMode)</b><br /> <b id="SCI_GETSELECTIONMODE">SCI_GETSELECTIONMODE → int</b><br /> - The two functions set and get the selection mode, which can be + The functions set, change, and get the selection mode, which can be stream (<code>SC_SEL_STREAM</code>=0) or rectangular (<code>SC_SEL_RECTANGLE</code>=1) or by lines (<code>SC_SEL_LINES</code>=2) or thin rectangular (<code>SC_SEL_THIN</code>=3). - When set in these modes, regular caret moves will extend or reduce the selection, - until the mode is cancelled by a call with same value or with <code>SCI_CANCEL</code>. - The get function returns the current mode even if the selection was made by mouse - or with regular extended moves. + When <code>SCI_SETSELECTIONMODE</code> sets these modes, regular caret moves will extend or reduce the selection, + until the mode is cancelled by a call with same value, or with <code>SCI_CANCEL</code>, or with <code>SCI_SETMOVEEXTENDSSELECTION</code>. + <code>SCI_CHANGESELECTIONMODE</code> sets the mode but does not make regular caret moves extend or reduce the selection.</p> + <p>The get function returns the current mode even if the selection was made by mouse or with regular extended moves. <code>SC_SEL_THIN</code> is the mode after a rectangular selection has been typed into and ensures that no characters are selected.</p> diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index f823ee0ef..b808bd4b8 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -591,7 +591,8 @@ Released 18 November 2023. </li> <li> - Add SCI_SETMOVEEXTENDSSELECTION to simplify selection mode manipulation. + Add SCI_SETMOVEEXTENDSSELECTION and SCI_CHANGESELECTIONMODE to + simplify selection mode manipulation. </li> <li> Improve performance of global replace by reducing cache invalidation overhead. diff --git a/include/Scintilla.h b/include/Scintilla.h index 5b85dac47..64238a5a3 100644 --- a/include/Scintilla.h +++ b/include/Scintilla.h @@ -874,6 +874,7 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SC_SEL_LINES 2 #define SC_SEL_THIN 3 #define SCI_SETSELECTIONMODE 2422 +#define SCI_CHANGESELECTIONMODE 2659 #define SCI_GETSELECTIONMODE 2423 #define SCI_SETMOVEEXTENDSSELECTION 2719 #define SCI_GETMOVEEXTENDSSELECTION 2706 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index b15606af0..c393d6179 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -2359,6 +2359,10 @@ val SC_SEL_THIN=3 # by lines (SC_SEL_LINES). set void SetSelectionMode=2422(SelectionMode selectionMode,) +# Set the selection mode to stream (SC_SEL_STREAM) or rectangular (SC_SEL_RECTANGLE/SC_SEL_THIN) or +# by lines (SC_SEL_LINES) without changing MoveExtendsSelection. +fun void ChangeSelectionMode=2659(SelectionMode selectionMode,) + # Get the mode of the current selection. get SelectionMode GetSelectionMode=2423(,) diff --git a/include/ScintillaCall.h b/include/ScintillaCall.h index 0c95ef9e7..7f8088748 100644 --- a/include/ScintillaCall.h +++ b/include/ScintillaCall.h @@ -634,6 +634,7 @@ public: void CopyRange(Position start, Position end); void CopyText(Position length, const char *text); void SetSelectionMode(Scintilla::SelectionMode selectionMode); + void ChangeSelectionMode(Scintilla::SelectionMode selectionMode); Scintilla::SelectionMode SelectionMode(); void SetMoveExtendsSelection(bool moveExtendsSelection); bool MoveExtendsSelection(); diff --git a/include/ScintillaMessages.h b/include/ScintillaMessages.h index e45398d72..eaf162ae5 100644 --- a/include/ScintillaMessages.h +++ b/include/ScintillaMessages.h @@ -556,6 +556,7 @@ enum class Message { CopyRange = 2419, CopyText = 2420, SetSelectionMode = 2422, + ChangeSelectionMode = 2659, GetSelectionMode = 2423, SetMoveExtendsSelection = 2719, GetMoveExtendsSelection = 2706, diff --git a/src/Editor.cxx b/src/Editor.cxx index ca7fe2e88..627179876 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -6009,6 +6009,43 @@ void Editor::SetSelectionNMessage(Message iMessage, uptr_t wParam, sptr_t lParam ContainerNeedsUpdate(Update::Selection); } +namespace { + +constexpr Selection::SelTypes SelTypeFromMode(SelectionMode mode) { + switch (mode) { + case SelectionMode::Rectangle: + return Selection::SelTypes::rectangle; + case SelectionMode::Lines: + return Selection::SelTypes::lines; + case SelectionMode::Thin: + return Selection::SelTypes::thin; + case SelectionMode::Stream: + default: + return Selection::SelTypes::stream; + } +} + +} + +void Editor::SetSelectionMode(uptr_t wParam, bool setMoveExtends) { + const Selection::SelTypes newSelType = SelTypeFromMode(static_cast<SelectionMode>(wParam)); + if (setMoveExtends) { + sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != newSelType)); + } + sel.selType = newSelType; + switch (sel.selType) { + case Selection::SelTypes::rectangle: + sel.Rectangular() = sel.RangeMain(); // adjust current selection + break; + case Selection::SelTypes::lines: + SetSelection(sel.RangeMain().caret, sel.RangeMain().anchor); // adjust current selection + break; + default: + ; + } + InvalidateWholeSelection(); +} + sptr_t Editor::StringResult(sptr_t lParam, const char *val) noexcept { const size_t len = val ? strlen(val) : 0; if (lParam) { @@ -8186,33 +8223,12 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { case Message::SelectionIsRectangle: return sel.selType == Selection::SelTypes::rectangle ? 1 : 0; - case Message::SetSelectionMode: { - switch (static_cast<SelectionMode>(wParam)) { - case SelectionMode::Stream: - sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::SelTypes::stream)); - sel.selType = Selection::SelTypes::stream; - break; - case SelectionMode::Rectangle: - sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::SelTypes::rectangle)); - sel.selType = Selection::SelTypes::rectangle; - sel.Rectangular() = sel.RangeMain(); // adjust current selection - break; - case SelectionMode::Lines: - sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::SelTypes::lines)); - sel.selType = Selection::SelTypes::lines; - SetSelection(sel.RangeMain().caret, sel.RangeMain().anchor); // adjust current selection - break; - case SelectionMode::Thin: - sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::SelTypes::thin)); - sel.selType = Selection::SelTypes::thin; - break; - default: - sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::SelTypes::stream)); - sel.selType = Selection::SelTypes::stream; - } - InvalidateWholeSelection(); - break; - } + case Message::SetSelectionMode: + SetSelectionMode(wParam, true); + break; + case Message::ChangeSelectionMode: + SetSelectionMode(wParam, false); + break; case Message::GetSelectionMode: switch (sel.selType) { case Selection::SelTypes::stream: diff --git a/src/Editor.h b/src/Editor.h index 8c6458879..e7e198aec 100644 --- a/src/Editor.h +++ b/src/Editor.h @@ -612,6 +612,7 @@ protected: // ScintillaBase subclass needs access to much of Editor void StyleSetMessage(Scintilla::Message iMessage, Scintilla::uptr_t wParam, Scintilla::sptr_t lParam); Scintilla::sptr_t StyleGetMessage(Scintilla::Message iMessage, Scintilla::uptr_t wParam, Scintilla::sptr_t lParam); void SetSelectionNMessage(Scintilla::Message iMessage, Scintilla::uptr_t wParam, Scintilla::sptr_t lParam); + void SetSelectionMode(uptr_t wParam, bool setMoveExtends); // Coercion functions for transforming WndProc parameters into pointers static void *PtrFromSPtr(Scintilla::sptr_t lParam) noexcept { diff --git a/test/simpleTests.py b/test/simpleTests.py index 6f82c4004..fd1f7423a 100644 --- a/test/simpleTests.py +++ b/test/simpleTests.py @@ -1747,6 +1747,10 @@ def selectionRepresentation(ed, n): caret = (ed.GetSelectionNCaret(n), ed.GetSelectionNCaretVirtualSpace(n)) return selectionRangeRepresentation((anchor, caret)) +def allSelectionsRepresentation(ed): + reps = [selectionRepresentation(ed, i) for i in range(ed.Selections)] + return ';'.join(reps) + class TestMultiSelection(unittest.TestCase): def setUp(self): @@ -2051,29 +2055,32 @@ class TestModalSelection(unittest.TestCase): def testCharacterSelection(self): self.ed.SetSelection(1, 1) - self.assertEqual(self.ed.Selections, 1) self.assertEqual(self.ed.MainSelection, 0) - self.assertEqual(self.ed.GetSelectionNCaret(0), 1) - self.assertEqual(self.ed.GetSelectionNAnchor(0), 1) + self.assertEqual(allSelectionsRepresentation(self.ed), "1-1") self.ed.SelectionMode = self.ed.SC_SEL_STREAM self.assertEqual(self.ed.GetSelectionMode(), self.ed.SC_SEL_STREAM) self.assertEqual(self.ed.MoveExtendsSelection, True) - self.assertEqual(self.ed.Selections, 1) - self.assertEqual(self.ed.MainSelection, 0) - self.assertEqual(self.ed.GetSelectionNCaret(0), 1) - self.assertEqual(self.ed.GetSelectionNAnchor(0), 1) + self.assertEqual(allSelectionsRepresentation(self.ed), "1-1") self.ed.CharRight() - self.assertEqual(self.ed.Selections, 1) - self.assertEqual(self.ed.MainSelection, 0) - self.assertEqual(self.ed.GetSelectionNCaret(0), 2) - self.assertEqual(self.ed.GetSelectionNAnchor(0), 1) + self.assertEqual(allSelectionsRepresentation(self.ed), "1-2") self.ed.LineDown() - self.assertEqual(self.ed.Selections, 1) - self.assertEqual(self.ed.MainSelection, 0) - self.assertEqual(self.ed.GetSelectionNCaret(0), 6) - self.assertEqual(self.ed.GetSelectionNAnchor(0), 1) + self.assertEqual(allSelectionsRepresentation(self.ed), "1-6") self.ed.ClearSelections() - + + def testChangeSelectionMode(self): + # Like testCharacterSelection but calling ChangeSelectionMode instead of SetSelectionMode + self.ed.SetSelection(1, 1) + self.assertEqual(allSelectionsRepresentation(self.ed), "1-1") + self.ed.ChangeSelectionMode(self.ed.SC_SEL_STREAM) + self.assertEqual(self.ed.GetSelectionMode(), self.ed.SC_SEL_STREAM) + self.assertEqual(self.ed.MoveExtendsSelection, False) + self.assertEqual(allSelectionsRepresentation(self.ed), "1-1") + self.ed.CharRight() + self.assertEqual(allSelectionsRepresentation(self.ed), "2-2") + self.ed.LineDown() + self.assertEqual(allSelectionsRepresentation(self.ed), "6-6") + self.ed.ClearSelections() + def testTurningOffMoveExtendsSelection(self): self.ed.SetSelection(1, 1) self.ed.SelectionMode = self.ed.SC_SEL_STREAM @@ -2083,13 +2090,9 @@ class TestModalSelection(unittest.TestCase): self.ed.MoveExtendsSelection = False self.assertEqual(self.ed.MoveExtendsSelection, False) self.ed.CharRight() - self.assertEqual(self.ed.Selections, 1) - self.assertEqual(self.ed.MainSelection, 0) - self.assertEqual(selectionRepresentation(self.ed, 0), "6-6") + self.assertEqual(allSelectionsRepresentation(self.ed), "6-6") self.ed.CharRight() - self.assertEqual(self.ed.Selections, 1) - self.assertEqual(self.ed.MainSelection, 0) - self.assertEqual(selectionRepresentation(self.ed, 0), "7-7") + self.assertEqual(allSelectionsRepresentation(self.ed), "7-7") self.ed.ClearSelections() def testRectangleSelection(self): |