From 586da87728128792ee637d084ce03a07adc55644 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 12 Sep 2025 16:03:18 +0200 Subject: [PATCH] InputText: Word-Wrap: hide vertical scrollbar but takes its width into account. (#3237, #952, #1062, #7363) Also increase IMGUI_VERSION_NUM for good measure, forgot to increase it when moving to public api. --- docs/CHANGELOG.txt | 6 +++--- imgui.h | 6 +++--- imgui_widgets.cpp | 14 ++++++++------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 457c25c41..4c8e2eee4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,12 +56,12 @@ Other Changes: window has the ImGuiWindowFlags_NoNavFocus flag. (#8914) - Bullet: fixed tesselation amount which looked out of place in very large sizes. - InputText: added ImGuiInputTextFlags_WordWrap flag to word-wrap multi-line buffers. - (#3237, #952, #1062, #7363) + (#3237, #952, #1062, #7363). Current caveats: - This is marked as beta because not being tested enough. Please report any incorrect cursor movement, selection behavior etc. bug to #3237. - - Vertical scrollbar is made always visible. - - Wrapping points are not ideal. Wrapping of long words/sections (e.g. words + - Wrapping style is not ideal. Wrapping of long words/sections (e.g. words larger than total available width) may be particularly unpleasing. + - Wrapping width needs to always account for the possibility of a vertical scrollbar. - It is currently much slower than regular text fields. - Ballpark estimate of cost on my 2019 desktop PC: For a 100 KB text buffer: +~0.3 ms/+~1.0 ms (Optimized vs Debug builds). diff --git a/imgui.h b/imgui.h index d26d95287..a68df790b 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.3 WIP" -#define IMGUI_VERSION_NUM 19227 +#define IMGUI_VERSION_NUM 19228 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 #define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch. @@ -1306,8 +1306,8 @@ enum ImGuiInputTextFlags_ // Multi-line Word-Wrapping [BETA] // - Not well tested yet. Please report any incorrect cursor movement, selection behavior etc. bug to https://github.com/ocornut/imgui/issues/3237. - // - Vertical scrollbar is made always visible. - // - Wrapping points are not ideal. Wrapping of long words/sections (e.g. words larger than total available width) may be particularly unpleasing. + // - Wrapping style is not ideal. Wrapping of long words/sections (e.g. words larger than total available width) may be particularly unpleasing. + // - Wrapping width needs to always account for the possibility of a vertical scrollbar. // - It is much slower than regular text fields. // Ballpark estimate of cost on my 2019 desktop PC: for a 100 KB text buffer: +~0.3 ms (Optimized) / +~1.0 ms (Debug build). // The CPU cost is very roughly proportional to text length, so a 10 KB buffer should cost about ten times less. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index bf90a9194..f4c12fcb8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4678,10 +4678,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Ensure no clip rect so mouse hover can reach FramePadding edges - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoMove; - if (flags & ImGuiInputTextFlags_WordWrap) - window_flags |= ImGuiWindowFlags_AlwaysVerticalScrollbar; // FIXME-WORDWRAP: Makes things much simpler. Otherwise requires more work to track cursor reliably and avoid one-frame glitch. - bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), ImGuiChildFlags_Borders, window_flags); + bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove); g.NavActivateId = backup_activate_id; PopStyleVar(3); PopStyleColor(); @@ -4721,11 +4718,16 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0; const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0; - const bool is_wordwrap = (flags & ImGuiInputTextFlags_WordWrap) != 0; - const float wrap_width = is_wordwrap ? GetContentRegionAvail().x : 0.0f; if (is_resizable) IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! + // Word-wrapping: enforcing a fixed width not altered by vertical scrollbar makes things easier, notably to track cursor reliably and avoid one-frame glitches. + // Instead of using ImGuiWindowFlags_AlwaysVerticalScrollbar we account for that space if the scrollbar is not visible. + const bool is_wordwrap = (flags & ImGuiInputTextFlags_WordWrap) != 0; + float wrap_width = 0.0f; + if (is_wordwrap) + wrap_width = ImMax(1.0f, GetContentRegionAvail().x + (draw_window->ScrollbarY ? 0.0f : -g.Style.ScrollbarSize)); + const bool input_requested_by_nav = (g.ActiveId != id) && ((g.NavActivateId == id) && ((g.NavActivateFlags & ImGuiActivateFlags_PreferInput) || (g.NavInputSource == ImGuiInputSource_Keyboard))); const bool user_clicked = hovered && io.MouseClicked[0];