mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-11-04 07:01:04 +01:00 
			
		
		
		
	InputText: made double-click select word, triple-line select line. Word delimitation logic differs slightly from the one used by CTRL+arrows. (#2244)
This commit is contained in:
		@@ -39,6 +39,8 @@ Breaking Changes:
 | 
			
		||||
Other Changes:
 | 
			
		||||
 | 
			
		||||
- Added IsMouseTripleClicked() function. Tracking multi-click count in IO structure. (#3229) [@kudaba]
 | 
			
		||||
- InputText: made double-click select word, triple-line select line. Word delimitation logic differs
 | 
			
		||||
  slightly from the one used by CTRL+arrows. (#2244)
 | 
			
		||||
- Backends: Vulkan: Call vkCmdSetScissor() at the end of render with a full-viewport to reduce
 | 
			
		||||
  likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling
 | 
			
		||||
  vkCmdSetScissor() explicitly every frame. (#4644)
 | 
			
		||||
 
 | 
			
		||||
@@ -3679,17 +3679,18 @@ static void    STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* ob
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// When ImGuiInputTextFlags_Password is set, we don't want actions such as CTRL+Arrow to leak the fact that underlying data are blanks or separators.
 | 
			
		||||
static bool is_separator(unsigned int c)                                        { return ImCharIsBlankW(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; }
 | 
			
		||||
static bool is_separator(unsigned int c)                                        { return ImCharIsBlankW(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|' || c=='\n' || c=='\r'; }
 | 
			
		||||
static int  is_word_boundary_from_right(ImGuiInputTextState* obj, int idx)      { if (obj->Flags & ImGuiInputTextFlags_Password) return 0; return idx > 0 ? (is_separator(obj->TextW[idx - 1]) && !is_separator(obj->TextW[idx]) ) : 1; }
 | 
			
		||||
static int  is_word_boundary_from_left(ImGuiInputTextState* obj, int idx)       { if (obj->Flags & ImGuiInputTextFlags_Password) return 0; return idx > 0 ? (!is_separator(obj->TextW[idx - 1]) && is_separator(obj->TextW[idx])) : 1; }
 | 
			
		||||
static int  STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx)   { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; }
 | 
			
		||||
#ifdef __APPLE__    // FIXME: Move setting to IO structure
 | 
			
		||||
static int  is_word_boundary_from_left(ImGuiInputTextState* obj, int idx)       { if (obj->Flags & ImGuiInputTextFlags_Password) return 0; return idx > 0 ? (!is_separator(obj->TextW[idx - 1]) && is_separator(obj->TextW[idx]) ) : 1; }
 | 
			
		||||
static int  STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx)  { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; }
 | 
			
		||||
#else
 | 
			
		||||
static int  STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx)  { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; }
 | 
			
		||||
#endif
 | 
			
		||||
static int  STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx)   { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; }
 | 
			
		||||
static int  STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx)   { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; }
 | 
			
		||||
#define STB_TEXTEDIT_MOVEWORDLEFT   STB_TEXTEDIT_MOVEWORDLEFT_IMPL    // They need to be #define for stb_textedit.h
 | 
			
		||||
#define STB_TEXTEDIT_MOVEWORDRIGHT  STB_TEXTEDIT_MOVEWORDRIGHT_IMPL
 | 
			
		||||
#ifdef __APPLE__    // FIXME: Move setting to IO structure
 | 
			
		||||
#define STB_TEXTEDIT_MOVEWORDRIGHT  STB_TEXTEDIT_MOVEWORDRIGHT_MAC
 | 
			
		||||
#else
 | 
			
		||||
#define STB_TEXTEDIT_MOVEWORDRIGHT  STB_TEXTEDIT_MOVEWORDRIGHT_WIN
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n)
 | 
			
		||||
{
 | 
			
		||||
@@ -3881,11 +3882,12 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f
 | 
			
		||||
    // Generic named filters
 | 
			
		||||
    if (apply_named_filters && (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific)))
 | 
			
		||||
    {
 | 
			
		||||
        // The libc allows overriding locale, with e.g. 'setlocale(LC_NUMERIC, "de_DE.UTF-8");' which affect the output/input of printf/scanf.
 | 
			
		||||
        // The libc allows overriding locale, with e.g. 'setlocale(LC_NUMERIC, "de_DE.UTF-8");' which affect the output/input of printf/scanf to use e.g. ',' instead of '.'.
 | 
			
		||||
        // The standard mandate that programs starts in the "C" locale where the decimal point is '.'.
 | 
			
		||||
        // We don't really intend to provide widespread support for it, but out of empathy for people stuck with using odd API, we support the bare minimum aka overriding the decimal point.
 | 
			
		||||
        // Change the default decimal_point with:
 | 
			
		||||
        //   ImGui::GetCurrentContext()->PlatformLocaleDecimalPoint = *localeconv()->decimal_point;
 | 
			
		||||
        // Users of non-default decimal point (in particular ',') may be affected by word-selection logic (is_word_boundary_from_right/is_word_boundary_from_left) functions.
 | 
			
		||||
        ImGuiContext& g = *GImGui;
 | 
			
		||||
        const unsigned c_decimal_point = (unsigned int)g.PlatformLocaleDecimalPoint;
 | 
			
		||||
 | 
			
		||||
@@ -4176,19 +4178,41 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
 | 
			
		||||
        const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f));
 | 
			
		||||
 | 
			
		||||
        const bool is_osx = io.ConfigMacOSXBehaviors;
 | 
			
		||||
        if (select_all || (hovered && !is_osx && io.MouseClickedCount[0] == 2))
 | 
			
		||||
        if (select_all)
 | 
			
		||||
        {
 | 
			
		||||
            state->SelectAll();
 | 
			
		||||
            state->SelectedAllMouseLock = true;
 | 
			
		||||
        }
 | 
			
		||||
        else if (hovered && is_osx && io.MouseClickedCount[0] == 2)
 | 
			
		||||
        else if (hovered && io.MouseClickedCount[0] >= 2 && !io.KeyShift)
 | 
			
		||||
        {
 | 
			
		||||
            // Double-click select a word only, OS X style (by simulating keystrokes)
 | 
			
		||||
            state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT);
 | 
			
		||||
            state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT);
 | 
			
		||||
            stb_textedit_click(state, &state->Stb, mouse_x, mouse_y);
 | 
			
		||||
            const int multiclick_count = (io.MouseClickedCount[0] - 2);
 | 
			
		||||
            if ((multiclick_count % 2) == 0)
 | 
			
		||||
            {
 | 
			
		||||
                // Double-click: Select word
 | 
			
		||||
                // 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)
 | 
			
		||||
                    state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT);
 | 
			
		||||
                //state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT);
 | 
			
		||||
                if (!STB_TEXT_HAS_SELECTION(&state->Stb))
 | 
			
		||||
                    ImStb::stb_textedit_prep_selection_at_cursor(&state->Stb);
 | 
			
		||||
                state->Stb.cursor = ImStb::STB_TEXTEDIT_MOVEWORDRIGHT_MAC(state, state->Stb.cursor);
 | 
			
		||||
                state->Stb.select_end = state->Stb.cursor;
 | 
			
		||||
                ImStb::stb_textedit_clamp(state, &state->Stb);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // Triple-click: Select line
 | 
			
		||||
                state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART);
 | 
			
		||||
                state->OnKeyPressed(STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT);
 | 
			
		||||
            }
 | 
			
		||||
            state->CursorAnimReset();
 | 
			
		||||
        }
 | 
			
		||||
        else if (io.MouseClicked[0] && !state->SelectedAllMouseLock)
 | 
			
		||||
        {
 | 
			
		||||
            // FIXME: unselect on late click could be done release?
 | 
			
		||||
            if (hovered)
 | 
			
		||||
            {
 | 
			
		||||
                stb_textedit_click(state, &state->Stb, mouse_x, mouse_y);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user