imgui icon indicating copy to clipboard operation
imgui copied to clipboard

InputText: Implement double/triple-click + drag word/line selection

Open ronak69 opened this issue 4 months ago • 5 comments

Select word/line on double/triple click was already implemented but
holding down the last click and dragging the mouse to incrementally
select was not.

To do this, `ImGuiInputTextState` keeps track of the current selection
mode (based on the number of mouse clicks) and the originating cursor
position over which the clicks happened. Later, on mouse moves, the
appropriate selection for mouse position and origin gets constructed.

Logic based on https://github.com/rxi/lite/commit/53d555b362f10044b473d452220d85c943f3dfd2.

Before:

https://github.com/user-attachments/assets/fe373069-676c-4feb-996c-b56a796d0cef

After:

https://github.com/user-attachments/assets/219b3e72-4969-4ee3-b363-d100750fd3c6


Some issues in double click selection:
Even if the cursor is already at a word boundary double-click will jump left. This patch fixes it. But I don't know why selection gets checked here. In my testing, the selection is never there and this assertion never fails.
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index ad1c1ea9a..282a35ae3 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -4638,7 +4638,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
                 // We always use the "Mac" word advance for double-click select vs CTRL+Right which use the platform dependent variant:
                 // FIXME: There are likely many ways to improve this behavior, but there's no "right" behavior (depends on use-case, software, OS)
                 const bool is_bol = (state->Stb->cursor == 0) || ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb->cursor - 1) == '\n';
-                if (STB_TEXT_HAS_SELECTION(state->Stb) || !is_bol)
+                const bool move_left = !ImStb::is_word_boundary_from_right(state, state->Stb->cursor);
+                IM_ASSERT(!STB_TEXT_HAS_SELECTION(state->Stb));
+                if (move_left && (STB_TEXT_HAS_SELECTION(state->Stb) || !is_bol))
                     state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT);
                 //state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT);
                 if (!STB_TEXT_HAS_SELECTION(state->Stb))

See the difference it makes:

Before:

https://github.com/user-attachments/assets/bbf2a9ea-6b42-47b8-8990-0eae49765893

After:

https://github.com/user-attachments/assets/e36f63ed-59ab-4889-8bfd-97c783fd35ec

Also, the is_bol check prevents selection if the clicks happen at the very last character. It should fallback to select the last word of the text instead.

ronak69 avatar Oct 01 '24 17:10 ronak69