mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-11-04 07:01:04 +01:00 
			
		
		
		
	Internal: InputText: Refactor to clarify access pattern to the InputTextState (we are now accessing via a pointer which can be NULL, shortened its name while we are at it) + added an assert to track an issue that existed already before.
This commit is contained in:
		@@ -3205,7 +3205,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // NB: we are only allowed to access 'edit_state' if we are the active widget.
 | 
					    // NB: we are only allowed to access 'edit_state' if we are the active widget.
 | 
				
			||||||
    ImGuiInputTextState& edit_state = g.InputTextState;
 | 
					    ImGuiInputTextState* state = NULL;
 | 
				
			||||||
 | 
					    if (g.InputTextState.ID == id)
 | 
				
			||||||
 | 
					        state = &g.InputTextState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const bool focus_requested = FocusableItemRegister(window, id, (flags & (ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_AllowTabInput)) == 0);    // Using completion callback disable keyboard tabbing
 | 
					    const bool focus_requested = FocusableItemRegister(window, id, (flags & (ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_AllowTabInput)) == 0);    // Using completion callback disable keyboard tabbing
 | 
				
			||||||
    const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent);
 | 
					    const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent);
 | 
				
			||||||
@@ -3213,8 +3215,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const bool user_clicked = hovered && io.MouseClicked[0];
 | 
					    const bool user_clicked = hovered && io.MouseClicked[0];
 | 
				
			||||||
    const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_NavKeyboard));
 | 
					    const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_NavKeyboard));
 | 
				
			||||||
    const bool user_scroll_finish = is_multiline && edit_state.ID == id && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetScrollbarID(draw_window, ImGuiAxis_Y);
 | 
					    const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetScrollbarID(draw_window, ImGuiAxis_Y);
 | 
				
			||||||
    const bool user_scroll_active = is_multiline && edit_state.ID == id && g.ActiveId == GetScrollbarID(draw_window, ImGuiAxis_Y);
 | 
					    const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetScrollbarID(draw_window, ImGuiAxis_Y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool clear_active_id = false;
 | 
					    bool clear_active_id = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3223,41 +3225,46 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        if (g.ActiveId != id)
 | 
					        if (g.ActiveId != id)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            // Access state even if we don't own it yet.
 | 
				
			||||||
 | 
					            state = &g.InputTextState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Start edition
 | 
					            // Start edition
 | 
				
			||||||
            // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar)
 | 
					            // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar)
 | 
				
			||||||
            // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode)
 | 
					            // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode)
 | 
				
			||||||
            const int prev_len_w = edit_state.CurLenW;
 | 
					            const int prev_len_w = state->CurLenW;
 | 
				
			||||||
            const int init_buf_len = (int)strlen(buf);
 | 
					            const int init_buf_len = (int)strlen(buf);
 | 
				
			||||||
            edit_state.TextW.resize(buf_size+1);             // wchar count <= UTF-8 count. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
 | 
					            state->TextW.resize(buf_size+1);             // wchar count <= UTF-8 count. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
 | 
				
			||||||
            edit_state.InitialText.resize(init_buf_len + 1); // UTF-8. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
 | 
					            state->InitialText.resize(init_buf_len + 1); // UTF-8. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
 | 
				
			||||||
            memcpy(edit_state.InitialText.Data, buf, init_buf_len + 1);
 | 
					            memcpy(state->InitialText.Data, buf, init_buf_len + 1);
 | 
				
			||||||
            const char* buf_end = NULL;
 | 
					            const char* buf_end = NULL;
 | 
				
			||||||
            edit_state.CurLenW = ImTextStrFromUtf8(edit_state.TextW.Data, buf_size, buf, NULL, &buf_end);
 | 
					            state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end);
 | 
				
			||||||
            edit_state.CurLenA = (int)(buf_end - buf); // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8.
 | 
					            state->CurLenA = (int)(buf_end - buf); // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8.
 | 
				
			||||||
            edit_state.CursorAnimReset();
 | 
					            state->CursorAnimReset();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Preserve cursor position and undo/redo stack if we come back to same widget
 | 
					            // Preserve cursor position and undo/redo stack if we come back to same widget
 | 
				
			||||||
            // FIXME: We should probably compare the whole buffer to be on the safety side. Comparing buf (utf8) and edit_state.Text (wchar).
 | 
					            // FIXME: We should probably compare the whole buffer to be on the safety side. Comparing buf (utf8) and edit_state.Text (wchar).
 | 
				
			||||||
            const bool recycle_state = (edit_state.ID == id) && (prev_len_w == edit_state.CurLenW);
 | 
					            const bool recycle_state = (state->ID == id) && (prev_len_w == state->CurLenW);
 | 
				
			||||||
            if (recycle_state)
 | 
					            if (recycle_state)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                // Recycle existing cursor/selection/undo stack but clamp position
 | 
					                // Recycle existing cursor/selection/undo stack but clamp position
 | 
				
			||||||
                // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler.
 | 
					                // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler.
 | 
				
			||||||
                edit_state.CursorClamp();
 | 
					                state->CursorClamp();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                edit_state.ID = id;
 | 
					                state->ID = id;
 | 
				
			||||||
                edit_state.ScrollX = 0.0f;
 | 
					                state->ScrollX = 0.0f;
 | 
				
			||||||
                stb_textedit_initialize_state(&edit_state.Stb, !is_multiline);
 | 
					                stb_textedit_initialize_state(&state->Stb, !is_multiline);
 | 
				
			||||||
                if (!is_multiline && focus_requested_by_code)
 | 
					                if (!is_multiline && focus_requested_by_code)
 | 
				
			||||||
                    select_all = true;
 | 
					                    select_all = true;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (flags & ImGuiInputTextFlags_AlwaysInsertMode)
 | 
					            if (flags & ImGuiInputTextFlags_AlwaysInsertMode)
 | 
				
			||||||
                edit_state.Stb.insert_mode = 1;
 | 
					                state->Stb.insert_mode = 1;
 | 
				
			||||||
            if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl)))
 | 
					            if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl)))
 | 
				
			||||||
                select_all = true;
 | 
					                select_all = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        IM_ASSERT(state && state->ID == id);
 | 
				
			||||||
        SetActiveID(id, window);
 | 
					        SetActiveID(id, window);
 | 
				
			||||||
        SetFocusID(id, window);
 | 
					        SetFocusID(id, window);
 | 
				
			||||||
        FocusWindow(window);
 | 
					        FocusWindow(window);
 | 
				
			||||||
@@ -3277,21 +3284,22 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (g.ActiveId == id)
 | 
					    if (g.ActiveId == id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        IM_ASSERT(state != NULL);
 | 
				
			||||||
        if (!is_editable && !g.ActiveIdIsJustActivated)
 | 
					        if (!is_editable && !g.ActiveIdIsJustActivated)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // When read-only we always use the live data passed to the function
 | 
					            // When read-only we always use the live data passed to the function
 | 
				
			||||||
            edit_state.TextW.resize(buf_size+1);
 | 
					 | 
				
			||||||
            const char* buf_end = NULL;
 | 
					            const char* buf_end = NULL;
 | 
				
			||||||
            edit_state.CurLenW = ImTextStrFromUtf8(edit_state.TextW.Data, edit_state.TextW.Size, buf, NULL, &buf_end);
 | 
					            state->TextW.resize(buf_size+1);
 | 
				
			||||||
            edit_state.CurLenA = (int)(buf_end - buf);
 | 
					            state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, buf, NULL, &buf_end);
 | 
				
			||||||
            edit_state.CursorClamp();
 | 
					            state->CurLenA = (int)(buf_end - buf);
 | 
				
			||||||
 | 
					            state->CursorClamp();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        backup_current_text_length = edit_state.CurLenA;
 | 
					        backup_current_text_length = state->CurLenA;
 | 
				
			||||||
        edit_state.BufCapacityA = buf_size;
 | 
					        state->BufCapacityA = buf_size;
 | 
				
			||||||
        edit_state.UserFlags = flags;
 | 
					        state->UserFlags = flags;
 | 
				
			||||||
        edit_state.UserCallback = callback;
 | 
					        state->UserCallback = callback;
 | 
				
			||||||
        edit_state.UserCallbackData = callback_user_data;
 | 
					        state->UserCallbackData = callback_user_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget.
 | 
					        // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget.
 | 
				
			||||||
        // Down the line we should have a cleaner library-wide concept of Selected vs Active.
 | 
					        // Down the line we should have a cleaner library-wide concept of Selected vs Active.
 | 
				
			||||||
@@ -3299,37 +3307,37 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
        g.WantTextInputNextFrame = 1;
 | 
					        g.WantTextInputNextFrame = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Edit in progress
 | 
					        // Edit in progress
 | 
				
			||||||
        const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX;
 | 
					        const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX;
 | 
				
			||||||
        const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f));
 | 
					        const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const bool is_osx = io.ConfigMacOSXBehaviors;
 | 
					        const bool is_osx = io.ConfigMacOSXBehaviors;
 | 
				
			||||||
        if (select_all || (hovered && !is_osx && io.MouseDoubleClicked[0]))
 | 
					        if (select_all || (hovered && !is_osx && io.MouseDoubleClicked[0]))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            edit_state.SelectAll();
 | 
					            state->SelectAll();
 | 
				
			||||||
            edit_state.SelectedAllMouseLock = true;
 | 
					            state->SelectedAllMouseLock = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (hovered && is_osx && io.MouseDoubleClicked[0])
 | 
					        else if (hovered && is_osx && io.MouseDoubleClicked[0])
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Double-click select a word only, OS X style (by simulating keystrokes)
 | 
					            // Double-click select a word only, OS X style (by simulating keystrokes)
 | 
				
			||||||
            edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT);
 | 
					            state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT);
 | 
				
			||||||
            edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT);
 | 
					            state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (io.MouseClicked[0] && !edit_state.SelectedAllMouseLock)
 | 
					        else if (io.MouseClicked[0] && !state->SelectedAllMouseLock)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (hovered)
 | 
					            if (hovered)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                stb_textedit_click(&edit_state, &edit_state.Stb, mouse_x, mouse_y);
 | 
					                stb_textedit_click(state, &state->Stb, mouse_x, mouse_y);
 | 
				
			||||||
                edit_state.CursorAnimReset();
 | 
					                state->CursorAnimReset();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (io.MouseDown[0] && !edit_state.SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f))
 | 
					        else if (io.MouseDown[0] && !state->SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            stb_textedit_drag(&edit_state, &edit_state.Stb, mouse_x, mouse_y);
 | 
					            stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y);
 | 
				
			||||||
            edit_state.CursorAnimReset();
 | 
					            state->CursorAnimReset();
 | 
				
			||||||
            edit_state.CursorFollow = true;
 | 
					            state->CursorFollow = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (edit_state.SelectedAllMouseLock && !io.MouseDown[0])
 | 
					        if (state->SelectedAllMouseLock && !io.MouseDown[0])
 | 
				
			||||||
            edit_state.SelectedAllMouseLock = false;
 | 
					            state->SelectedAllMouseLock = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (io.InputQueueCharacters.Size > 0)
 | 
					        if (io.InputQueueCharacters.Size > 0)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -3342,7 +3350,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
                    // Insert character if they pass filtering
 | 
					                    // Insert character if they pass filtering
 | 
				
			||||||
                    unsigned int c = (unsigned int)io.InputQueueCharacters[n];
 | 
					                    unsigned int c = (unsigned int)io.InputQueueCharacters[n];
 | 
				
			||||||
                    if (InputTextFilterCharacter(&c, flags, callback, callback_user_data))
 | 
					                    if (InputTextFilterCharacter(&c, flags, callback, callback_user_data))
 | 
				
			||||||
                        edit_state.OnKeyPressed((int)c);
 | 
					                        state->OnKeyPressed((int)c);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Consume characters
 | 
					            // Consume characters
 | 
				
			||||||
@@ -3354,6 +3362,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
    if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id)
 | 
					    if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // Handle key-presses
 | 
					        // Handle key-presses
 | 
				
			||||||
 | 
					        IM_ASSERT(state != NULL);
 | 
				
			||||||
        const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0);
 | 
					        const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0);
 | 
				
			||||||
        const bool is_osx = io.ConfigMacOSXBehaviors;
 | 
					        const bool is_osx = io.ConfigMacOSXBehaviors;
 | 
				
			||||||
        const bool is_shortcut_key = (is_osx ? (io.KeySuper && !io.KeyCtrl) : (io.KeyCtrl && !io.KeySuper)) && !io.KeyAlt && !io.KeyShift; // OS X style: Shortcuts using Cmd/Super instead of Ctrl
 | 
					        const bool is_shortcut_key = (is_osx ? (io.KeySuper && !io.KeyCtrl) : (io.KeyCtrl && !io.KeySuper)) && !io.KeyAlt && !io.KeyShift; // OS X style: Shortcuts using Cmd/Super instead of Ctrl
 | 
				
			||||||
@@ -3363,27 +3372,29 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
        const bool is_ctrl_key_only = io.KeyCtrl && !io.KeyShift && !io.KeyAlt && !io.KeySuper;
 | 
					        const bool is_ctrl_key_only = io.KeyCtrl && !io.KeyShift && !io.KeyAlt && !io.KeySuper;
 | 
				
			||||||
        const bool is_shift_key_only = io.KeyShift && !io.KeyCtrl && !io.KeyAlt && !io.KeySuper;
 | 
					        const bool is_shift_key_only = io.KeyShift && !io.KeyCtrl && !io.KeyAlt && !io.KeySuper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const bool is_cut   = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && is_editable && !is_password && (!is_multiline || edit_state.HasSelection());
 | 
					        const bool is_cut   = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && is_editable && !is_password && (!is_multiline || state->HasSelection());
 | 
				
			||||||
        const bool is_copy  = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only  && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || edit_state.HasSelection());
 | 
					        const bool is_copy  = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only  && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || state->HasSelection());
 | 
				
			||||||
        const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && is_editable;
 | 
					        const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && is_editable;
 | 
				
			||||||
        const bool is_undo  = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && is_editable && is_undoable);
 | 
					        const bool is_undo  = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && is_editable && is_undoable);
 | 
				
			||||||
        const bool is_redo  = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && is_editable && is_undoable;
 | 
					        const bool is_redo  = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && is_editable && is_undoable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (IsKeyPressedMap(ImGuiKey_LeftArrow))                        { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }
 | 
					        if (IsKeyPressedMap(ImGuiKey_LeftArrow))                        { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }
 | 
				
			||||||
        else if (IsKeyPressedMap(ImGuiKey_RightArrow))                  { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }
 | 
					        else if (IsKeyPressedMap(ImGuiKey_RightArrow))                  { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }
 | 
				
			||||||
        else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline)     { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
 | 
					        else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline)     { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
 | 
				
			||||||
        else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline)   { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }
 | 
					        else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline)   { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }
 | 
				
			||||||
        else if (IsKeyPressedMap(ImGuiKey_Home))                        { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
 | 
					        else if (IsKeyPressedMap(ImGuiKey_Home))                        { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
 | 
				
			||||||
        else if (IsKeyPressedMap(ImGuiKey_End))                         { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
 | 
					        else if (IsKeyPressedMap(ImGuiKey_End))                         { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
 | 
				
			||||||
        else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable)       { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
 | 
					        else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable)       { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
 | 
				
			||||||
        else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable)
 | 
					        else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (!edit_state.HasSelection())
 | 
					            if (!state->HasSelection())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (is_wordmove_key_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT);
 | 
					                if (is_wordmove_key_down) 
 | 
				
			||||||
                else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) edit_state.OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT);
 | 
					                    state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT);
 | 
				
			||||||
 | 
					                else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) 
 | 
				
			||||||
 | 
					                    state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
 | 
					            state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (IsKeyPressedMap(ImGuiKey_Enter))
 | 
					        else if (IsKeyPressedMap(ImGuiKey_Enter))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -3396,14 +3407,14 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                unsigned int c = '\n'; // Insert new line
 | 
					                unsigned int c = '\n'; // Insert new line
 | 
				
			||||||
                if (InputTextFilterCharacter(&c, flags, callback, callback_user_data))
 | 
					                if (InputTextFilterCharacter(&c, flags, callback, callback_user_data))
 | 
				
			||||||
                    edit_state.OnKeyPressed((int)c);
 | 
					                    state->OnKeyPressed((int)c);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !io.KeyCtrl && !io.KeyShift && !io.KeyAlt && is_editable)
 | 
					        else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !io.KeyCtrl && !io.KeyShift && !io.KeyAlt && is_editable)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            unsigned int c = '\t'; // Insert TAB
 | 
					            unsigned int c = '\t'; // Insert TAB
 | 
				
			||||||
            if (InputTextFilterCharacter(&c, flags, callback, callback_user_data))
 | 
					            if (InputTextFilterCharacter(&c, flags, callback, callback_user_data))
 | 
				
			||||||
                edit_state.OnKeyPressed((int)c);
 | 
					                state->OnKeyPressed((int)c);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (IsKeyPressedMap(ImGuiKey_Escape))
 | 
					        else if (IsKeyPressedMap(ImGuiKey_Escape))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -3411,31 +3422,31 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (is_undo || is_redo)
 | 
					        else if (is_undo || is_redo)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            edit_state.OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO);
 | 
					            state->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO);
 | 
				
			||||||
            edit_state.ClearSelection();
 | 
					            state->ClearSelection();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A))
 | 
					        else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            edit_state.SelectAll();
 | 
					            state->SelectAll();
 | 
				
			||||||
            edit_state.CursorFollow = true;
 | 
					            state->CursorFollow = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (is_cut || is_copy)
 | 
					        else if (is_cut || is_copy)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Cut, Copy
 | 
					            // Cut, Copy
 | 
				
			||||||
            if (io.SetClipboardTextFn)
 | 
					            if (io.SetClipboardTextFn)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                const int ib = edit_state.HasSelection() ? ImMin(edit_state.Stb.select_start, edit_state.Stb.select_end) : 0;
 | 
					                const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0;
 | 
				
			||||||
                const int ie = edit_state.HasSelection() ? ImMax(edit_state.Stb.select_start, edit_state.Stb.select_end) : edit_state.CurLenW;
 | 
					                const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW;
 | 
				
			||||||
                edit_state.TempBuffer.resize((ie-ib) * 4 + 1);
 | 
					                state->TempBuffer.resize((ie-ib) * 4 + 1);
 | 
				
			||||||
                ImTextStrToUtf8(edit_state.TempBuffer.Data, edit_state.TempBuffer.Size, edit_state.TextW.Data+ib, edit_state.TextW.Data+ie);
 | 
					                ImTextStrToUtf8(state->TempBuffer.Data, state->TempBuffer.Size, state->TextW.Data+ib, state->TextW.Data+ie);
 | 
				
			||||||
                SetClipboardText(edit_state.TempBuffer.Data);
 | 
					                SetClipboardText(state->TempBuffer.Data);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (is_cut)
 | 
					            if (is_cut)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (!edit_state.HasSelection())
 | 
					                if (!state->HasSelection())
 | 
				
			||||||
                    edit_state.SelectAll();
 | 
					                    state->SelectAll();
 | 
				
			||||||
                edit_state.CursorFollow = true;
 | 
					                state->CursorFollow = true;
 | 
				
			||||||
                stb_textedit_cut(&edit_state, &edit_state.Stb);
 | 
					                stb_textedit_cut(state, &state->Stb);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (is_paste)
 | 
					        else if (is_paste)
 | 
				
			||||||
@@ -3459,8 +3470,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
                clipboard_filtered[clipboard_filtered_len] = 0;
 | 
					                clipboard_filtered[clipboard_filtered_len] = 0;
 | 
				
			||||||
                if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
 | 
					                if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    stb_textedit_paste(&edit_state, &edit_state.Stb, clipboard_filtered, clipboard_filtered_len);
 | 
					                    stb_textedit_paste(state, &state->Stb, clipboard_filtered, clipboard_filtered_len);
 | 
				
			||||||
                    edit_state.CursorFollow = true;
 | 
					                    state->CursorFollow = true;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                MemFree(clipboard_filtered);
 | 
					                MemFree(clipboard_filtered);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -3469,15 +3480,16 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (g.ActiveId == id)
 | 
					    if (g.ActiveId == id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        IM_ASSERT(state != NULL);
 | 
				
			||||||
        const char* apply_new_text = NULL;
 | 
					        const char* apply_new_text = NULL;
 | 
				
			||||||
        int apply_new_text_length = 0;
 | 
					        int apply_new_text_length = 0;
 | 
				
			||||||
        if (cancel_edit)
 | 
					        if (cancel_edit)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents.
 | 
					            // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents.
 | 
				
			||||||
            if (is_editable && strcmp(buf, edit_state.InitialText.Data) != 0)
 | 
					            if (is_editable && strcmp(buf, state->InitialText.Data) != 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                apply_new_text = edit_state.InitialText.Data;
 | 
					                apply_new_text = state->InitialText.Data;
 | 
				
			||||||
                apply_new_text_length = edit_state.InitialText.Size - 1;
 | 
					                apply_new_text_length = state->InitialText.Size - 1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3492,8 +3504,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
            // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks.
 | 
					            // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks.
 | 
				
			||||||
            if (is_editable)
 | 
					            if (is_editable)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                edit_state.TempBuffer.resize(edit_state.TextW.Size * 4 + 1);
 | 
					                state->TempBuffer.resize(state->TextW.Size * 4 + 1);
 | 
				
			||||||
                ImTextStrToUtf8(edit_state.TempBuffer.Data, edit_state.TempBuffer.Size, edit_state.TextW.Data, NULL);
 | 
					                ImTextStrToUtf8(state->TempBuffer.Data, state->TempBuffer.Size, state->TextW.Data, NULL);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // User callback
 | 
					            // User callback
 | 
				
			||||||
@@ -3531,44 +3543,44 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
                    callback_data.UserData = callback_user_data;
 | 
					                    callback_data.UserData = callback_user_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    callback_data.EventKey = event_key;
 | 
					                    callback_data.EventKey = event_key;
 | 
				
			||||||
                    callback_data.Buf = edit_state.TempBuffer.Data;
 | 
					                    callback_data.Buf = state->TempBuffer.Data;
 | 
				
			||||||
                    callback_data.BufTextLen = edit_state.CurLenA;
 | 
					                    callback_data.BufTextLen = state->CurLenA;
 | 
				
			||||||
                    callback_data.BufSize = edit_state.BufCapacityA;
 | 
					                    callback_data.BufSize = state->BufCapacityA;
 | 
				
			||||||
                    callback_data.BufDirty = false;
 | 
					                    callback_data.BufDirty = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188)
 | 
					                    // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188)
 | 
				
			||||||
                    ImWchar* text = edit_state.TextW.Data;
 | 
					                    ImWchar* text = state->TextW.Data;
 | 
				
			||||||
                    const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + edit_state.Stb.cursor);
 | 
					                    const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + state->Stb.cursor);
 | 
				
			||||||
                    const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + edit_state.Stb.select_start);
 | 
					                    const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_start);
 | 
				
			||||||
                    const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + edit_state.Stb.select_end);
 | 
					                    const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // Call user code
 | 
					                    // Call user code
 | 
				
			||||||
                    callback(&callback_data);
 | 
					                    callback(&callback_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // Read back what user may have modified
 | 
					                    // Read back what user may have modified
 | 
				
			||||||
                    IM_ASSERT(callback_data.Buf == edit_state.TempBuffer.Data);  // Invalid to modify those fields
 | 
					                    IM_ASSERT(callback_data.Buf == state->TempBuffer.Data);  // Invalid to modify those fields
 | 
				
			||||||
                    IM_ASSERT(callback_data.BufSize == edit_state.BufCapacityA);
 | 
					                    IM_ASSERT(callback_data.BufSize == state->BufCapacityA);
 | 
				
			||||||
                    IM_ASSERT(callback_data.Flags == flags);
 | 
					                    IM_ASSERT(callback_data.Flags == flags);
 | 
				
			||||||
                    if (callback_data.CursorPos != utf8_cursor_pos)            { edit_state.Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); edit_state.CursorFollow = true; }
 | 
					                    if (callback_data.CursorPos != utf8_cursor_pos)            { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; }
 | 
				
			||||||
                    if (callback_data.SelectionStart != utf8_selection_start)  { edit_state.Stb.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); }
 | 
					                    if (callback_data.SelectionStart != utf8_selection_start)  { state->Stb.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); }
 | 
				
			||||||
                    if (callback_data.SelectionEnd != utf8_selection_end)      { edit_state.Stb.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); }
 | 
					                    if (callback_data.SelectionEnd != utf8_selection_end)      { state->Stb.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); }
 | 
				
			||||||
                    if (callback_data.BufDirty)
 | 
					                    if (callback_data.BufDirty)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
 | 
					                        IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
 | 
				
			||||||
                        if (callback_data.BufTextLen > backup_current_text_length && is_resizable)
 | 
					                        if (callback_data.BufTextLen > backup_current_text_length && is_resizable)
 | 
				
			||||||
                            edit_state.TextW.resize(edit_state.TextW.Size + (callback_data.BufTextLen - backup_current_text_length));
 | 
					                            state->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length));
 | 
				
			||||||
                        edit_state.CurLenW = ImTextStrFromUtf8(edit_state.TextW.Data, edit_state.TextW.Size, callback_data.Buf, NULL);
 | 
					                        state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, callback_data.Buf, NULL);
 | 
				
			||||||
                        edit_state.CurLenA = callback_data.BufTextLen;  // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
 | 
					                        state->CurLenA = callback_data.BufTextLen;  // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
 | 
				
			||||||
                        edit_state.CursorAnimReset();
 | 
					                        state->CursorAnimReset();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Will copy result string if modified
 | 
					            // Will copy result string if modified
 | 
				
			||||||
            if (is_editable && strcmp(edit_state.TempBuffer.Data, buf) != 0)
 | 
					            if (is_editable && strcmp(state->TempBuffer.Data, buf) != 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                apply_new_text = edit_state.TempBuffer.Data;
 | 
					                apply_new_text = state->TempBuffer.Data;
 | 
				
			||||||
                apply_new_text_length = edit_state.CurLenA;
 | 
					                apply_new_text_length = state->CurLenA;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3598,9 +3610,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Clear temporary user storage
 | 
					        // Clear temporary user storage
 | 
				
			||||||
        edit_state.UserFlags = 0;
 | 
					        state->UserFlags = 0;
 | 
				
			||||||
        edit_state.UserCallback = NULL;
 | 
					        state->UserCallback = NULL;
 | 
				
			||||||
        edit_state.UserCallbackData = NULL;
 | 
					        state->UserCallbackData = NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value)
 | 
					    // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value)
 | 
				
			||||||
@@ -3613,7 +3625,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
    const int buf_display_max_length = 2 * 1024 * 1024;
 | 
					    const int buf_display_max_length = 2 * 1024 * 1024;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Select which buffer we are going to display. We set buf to NULL to prevent accidental usage from now on.
 | 
					    // Select which buffer we are going to display. We set buf to NULL to prevent accidental usage from now on.
 | 
				
			||||||
    const char* buf_display = (g.ActiveId == id && is_editable) ? edit_state.TempBuffer.Data : buf; 
 | 
					    const char* buf_display = (state != NULL && is_editable) ? state->TempBuffer.Data : buf;
 | 
				
			||||||
    buf = NULL;
 | 
					    buf = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Render
 | 
					    // Render
 | 
				
			||||||
@@ -3629,7 +3641,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
    if (g.ActiveId == id || user_scroll_active)
 | 
					    if (g.ActiveId == id || user_scroll_active)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // Animate cursor
 | 
					        // Animate cursor
 | 
				
			||||||
        edit_state.CursorAnim += io.DeltaTime;
 | 
					        IM_ASSERT(state != NULL);
 | 
				
			||||||
 | 
					        state->CursorAnim += io.DeltaTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // This is going to be messy. We need to:
 | 
					        // This is going to be messy. We need to:
 | 
				
			||||||
        // - Display the text (this alone can be more easily clipped)
 | 
					        // - Display the text (this alone can be more easily clipped)
 | 
				
			||||||
@@ -3637,19 +3650,19 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
        // - Measure text height (for scrollbar)
 | 
					        // - Measure text height (for scrollbar)
 | 
				
			||||||
        // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
 | 
					        // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
 | 
				
			||||||
        // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.
 | 
					        // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.
 | 
				
			||||||
        const ImWchar* text_begin = edit_state.TextW.Data;
 | 
					        const ImWchar* text_begin = state->TextW.Data;
 | 
				
			||||||
        ImVec2 cursor_offset, select_start_offset;
 | 
					        ImVec2 cursor_offset, select_start_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Count lines + find lines numbers straddling 'cursor' and 'select_start' position.
 | 
					            // Count lines + find lines numbers straddling 'cursor' and 'select_start' position.
 | 
				
			||||||
            const ImWchar* searches_input_ptr[2];
 | 
					            const ImWchar* searches_input_ptr[2];
 | 
				
			||||||
            searches_input_ptr[0] = text_begin + edit_state.Stb.cursor;
 | 
					            searches_input_ptr[0] = text_begin + state->Stb.cursor;
 | 
				
			||||||
            searches_input_ptr[1] = NULL;
 | 
					            searches_input_ptr[1] = NULL;
 | 
				
			||||||
            int searches_remaining = 1;
 | 
					            int searches_remaining = 1;
 | 
				
			||||||
            int searches_result_line_number[2] = { -1, -999 };
 | 
					            int searches_result_line_number[2] = { -1, -999 };
 | 
				
			||||||
            if (edit_state.Stb.select_start != edit_state.Stb.select_end)
 | 
					            if (state->Stb.select_start != state->Stb.select_end)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                searches_input_ptr[1] = text_begin + ImMin(edit_state.Stb.select_start, edit_state.Stb.select_end);
 | 
					                searches_input_ptr[1] = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end);
 | 
				
			||||||
                searches_result_line_number[1] = -1;
 | 
					                searches_result_line_number[1] = -1;
 | 
				
			||||||
                searches_remaining++;
 | 
					                searches_remaining++;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -3685,20 +3698,20 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Scroll
 | 
					        // Scroll
 | 
				
			||||||
        if (edit_state.CursorFollow)
 | 
					        if (state->CursorFollow)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Horizontal scroll in chunks of quarter width
 | 
					            // Horizontal scroll in chunks of quarter width
 | 
				
			||||||
            if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll))
 | 
					            if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                const float scroll_increment_x = size.x * 0.25f;
 | 
					                const float scroll_increment_x = size.x * 0.25f;
 | 
				
			||||||
                if (cursor_offset.x < edit_state.ScrollX)
 | 
					                if (cursor_offset.x < state->ScrollX)
 | 
				
			||||||
                    edit_state.ScrollX = (float)(int)ImMax(0.0f, cursor_offset.x - scroll_increment_x);
 | 
					                    state->ScrollX = (float)(int)ImMax(0.0f, cursor_offset.x - scroll_increment_x);
 | 
				
			||||||
                else if (cursor_offset.x - size.x >= edit_state.ScrollX)
 | 
					                else if (cursor_offset.x - size.x >= state->ScrollX)
 | 
				
			||||||
                    edit_state.ScrollX = (float)(int)(cursor_offset.x - size.x + scroll_increment_x);
 | 
					                    state->ScrollX = (float)(int)(cursor_offset.x - size.x + scroll_increment_x);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                edit_state.ScrollX = 0.0f;
 | 
					                state->ScrollX = 0.0f;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Vertical scroll
 | 
					            // Vertical scroll
 | 
				
			||||||
@@ -3714,14 +3727,14 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
                render_pos.y = draw_window->DC.CursorPos.y;
 | 
					                render_pos.y = draw_window->DC.CursorPos.y;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        edit_state.CursorFollow = false;
 | 
					        state->CursorFollow = false;
 | 
				
			||||||
        const ImVec2 render_scroll = ImVec2(edit_state.ScrollX, 0.0f);
 | 
					        const ImVec2 render_scroll = ImVec2(state->ScrollX, 0.0f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Draw selection
 | 
					        // Draw selection
 | 
				
			||||||
        if (edit_state.Stb.select_start != edit_state.Stb.select_end)
 | 
					        if (state->Stb.select_start != state->Stb.select_end)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            const ImWchar* text_selected_begin = text_begin + ImMin(edit_state.Stb.select_start, edit_state.Stb.select_end);
 | 
					            const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end);
 | 
				
			||||||
            const ImWchar* text_selected_end = text_begin + ImMax(edit_state.Stb.select_start, edit_state.Stb.select_end);
 | 
					            const ImWchar* text_selected_end = text_begin + ImMax(state->Stb.select_start, state->Stb.select_end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            float bg_offy_up = is_multiline ? 0.0f : -1.0f;    // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection.
 | 
					            float bg_offy_up = is_multiline ? 0.0f : -1.0f;    // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection.
 | 
				
			||||||
            float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
 | 
					            float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
 | 
				
			||||||
@@ -3754,7 +3767,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash.
 | 
					        // We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash.
 | 
				
			||||||
        const int buf_display_len = edit_state.CurLenA;
 | 
					        const int buf_display_len = state->CurLenA;
 | 
				
			||||||
        if (is_multiline || buf_display_len < buf_display_max_length)
 | 
					        if (is_multiline || buf_display_len < buf_display_max_length)
 | 
				
			||||||
            draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos - render_scroll, GetColorU32(ImGuiCol_Text), buf_display, buf_display + buf_display_len, 0.0f, is_multiline ? NULL : &clip_rect);
 | 
					            draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos - render_scroll, GetColorU32(ImGuiCol_Text), buf_display, buf_display + buf_display_len, 0.0f, is_multiline ? NULL : &clip_rect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user