From 789de09dda710a8826cf3bdfba29a4c1f72c6097 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Apr 2025 12:04:09 +0200 Subject: [PATCH 1/5] TreeNode: extracted TreeNodeDrawLineToChildNode() for usage by custom widgets (#2920) --- docs/CHANGELOG.txt | 8 ++++++-- imgui.cpp | 4 ++-- imgui.h | 2 +- imgui_internal.h | 1 + imgui_widgets.cpp | 30 +++++++++++++++++++----------- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5fe43da86..312b6de3e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -57,14 +57,18 @@ Other changes: one in docking (they accidentally diverged). (#8554) - TreeNode: added flags to draw tree hierarchy outlines linking parent and tree nodes: (#2920) - - ImGuiTreeNodeFlags_DrawLinesNone: No lines drawn. + - ImGuiTreeNodeFlags_DrawLinesNone: No lines drawn (default value in style.TreeLinesFlags). - ImGuiTreeNodeFlags_DrawLinesFull: Horizontal lines to child nodes. Vertical line drawn down to TreePop() position: cover full contents. - ImGuiTreeNodeFlags_DrawLinesToNodes: Horizontal lines to child nodes. Vertical line drawn down to bottom-most child node. - Added style.TreeLinesFlags which stores the default setting, which may be overriden in individual TreeNode() calls. - Added style.TreeLinesSize (default to 1.0f). - Added ImGuiCol_TreeLines (in default style this is the same as ImGuiCol_Border). - - The feature adds a little cost as extra data needs to be stored. + - Caveats: + - Tree nodes may be used in many creative ways (manually positioning openable + nodes in unusual ways, using indent to create tree-looking structures, etc.) + and the feature may not accurately represent them in every cases. + - The feature adds a little cost as extra data needs to be stored. - Nav: fixed assertion when holding gamepad FaceLeft/West button to open CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous diff --git a/imgui.cpp b/imgui.cpp index f0b633cf2..b32874ec5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16578,9 +16578,9 @@ void ImGui::DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int wi ImFormatString(buf, IM_ARRAYSIZE(buf), "[%04d] Window", window->BeginOrderWithinContext); //BulletText("[%04d] Window '%s'", window->BeginOrderWithinContext, window->Name); DebugNodeWindow(window, buf); - Indent(); + TreePush(buf); DebugNodeWindowsListByBeginStackParent(windows + i + 1, windows_size - i - 1, window); - Unindent(); + TreePop(); } } diff --git a/imgui.h b/imgui.h index a3efff402..d5e24f09e 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.0 WIP" -#define IMGUI_VERSION_NUM 19192 +#define IMGUI_VERSION_NUM 19193 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index 0b2b0e6a0..b4c2a429e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3467,6 +3467,7 @@ namespace ImGui // Widgets: Tree Nodes IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); + IMGUI_API void TreeNodeDrawLineToChildNode(const ImVec2& target_pos); IMGUI_API void TreePushOverrideID(ImGuiID id); IMGUI_API bool TreeNodeGetOpen(ImGuiID storage_id); IMGUI_API void TreeNodeSetOpen(ImGuiID storage_id, bool open); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6323e2271..56134d641 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6822,17 +6822,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l LogSetNextTextDecoration(">", NULL); } - if (draw_tree_lines && (window->DC.TreeHasStackDataDepthMask & (1 << (window->DC.TreeDepth - 1)))) - { - // Draw horizontal line from our parent node - ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; - float x1 = parent_data->DrawLinesX1 + ImTrunc(g.FontSize * 0.5f + g.Style.FramePadding.x); // GetTreeNodeToLabelSpacing() * 0.5f - float x2 = text_pos.x - text_offset_x; - float y = text_pos.y + ImTrunc(g.FontSize * 0.5f); - parent_data->DrawLinesY2 = ImMax(parent_data->DrawLinesY2, y); - if (x1 < x2) - window->DrawList->AddLine(ImVec2(x1, y), ImVec2(x2, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); - } + if (draw_tree_lines) + TreeNodeDrawLineToChildNode(ImVec2(text_pos.x - text_offset_x, text_pos.y + g.FontSize * 0.5f)); if (span_all_columns && !span_all_columns_label) TablePopBackgroundChannel(); @@ -6856,6 +6847,23 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l return is_open; } +// Draw horizontal line from our parent node +// This is only called for visible child nodes so we are not too fussy anymore about performances +void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if ((window->DC.TreeHasStackDataDepthMask & (1 << (window->DC.TreeDepth - 1))) == 0) + return; + + ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; + float x1 = parent_data->DrawLinesX1 + ImTrunc(g.FontSize * 0.5f + g.Style.FramePadding.x); // GetTreeNodeToLabelSpacing() * 0.5f + float y = ImTrunc(target_pos.y); + parent_data->DrawLinesY2 = ImMax(parent_data->DrawLinesY2, y); + if (x1 < target_pos.x) + window->DrawList->AddLine(ImVec2(x1, y), ImVec2(target_pos.x, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); +} + void ImGui::TreePush(const char* str_id) { ImGuiWindow* window = GetCurrentWindow(); From 74e453cf15c08cd1c34128a2cb020fe732efe61c Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Wed, 9 Apr 2025 14:56:54 +0200 Subject: [PATCH 2/5] Backends: SDL2, SDL3: don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561) --- backends/imgui_impl_sdl2.cpp | 41 ++++++++++++++++++++---------------- backends/imgui_impl_sdl3.cpp | 41 ++++++++++++++++++++---------------- docs/CHANGELOG.txt | 3 +++ 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 54f9599cc..b2dacc48e 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561) // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) // 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g.Linux debuggers not claiming capture back. (#6410, #3650) @@ -142,6 +143,7 @@ struct ImGui_ImplSDL2_Data SDL_Cursor* MouseLastCursor; int MouseLastLeaveFrame; bool MouseCanUseGlobalState; + bool MouseCanUseCapture; // Gamepad handling ImVector Gamepads; @@ -474,17 +476,6 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); - // Check and store if we are on a SDL backend that supports global mouse position - // ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list) - bool mouse_can_use_global_state = false; -#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE - const char* sdl_backend = SDL_GetCurrentVideoDriver(); - const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" }; - for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++) - if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0) - mouse_can_use_global_state = true; -#endif - // Setup backend capabilities flags ImGui_ImplSDL2_Data* bd = IM_NEW(ImGui_ImplSDL2_Data)(); io.BackendPlatformUserData = (void*)bd; @@ -495,7 +486,18 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void bd->Window = window; bd->WindowID = SDL_GetWindowID(window); bd->Renderer = renderer; - bd->MouseCanUseGlobalState = mouse_can_use_global_state; + + // Check and store if we are on a SDL backend that supports SDL_GetGlobalMouseState() and SDL_CaptureMouse() + // ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list) + bd->MouseCanUseGlobalState = false; + bd->MouseCanUseCapture = false; +#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE + const char* sdl_backend = SDL_GetCurrentVideoDriver(); + const char* capture_and_global_state_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" }; + for (const char* item : capture_and_global_state_whitelist) + if (strncmp(sdl_backend, item, strlen(item)) == 0) + bd->MouseCanUseGlobalState = bd->MouseCanUseCapture = true; +#endif ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; @@ -630,12 +632,15 @@ static void ImGui_ImplSDL2_UpdateMouseData() // We forward mouse input when hovered or captured (via SDL_MOUSEMOTION) or when focused (below) #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE // - SDL_CaptureMouse() let the OS know e.g. that our drags can extend outside of parent boundaries (we want updated position) and shouldn't trigger other operations outside. - // - Debuggers under Linux tends to leave captured mouse on break, which may be very inconvenient, so to migitate the issue we wait until mouse has moved to begin capture. - bool want_capture = false; - for (int button_n = 0; button_n < ImGuiMouseButton_COUNT && !want_capture; button_n++) - if (ImGui::IsMouseDragging(button_n, 1.0f)) - want_capture = true; - SDL_CaptureMouse(want_capture ? SDL_TRUE : SDL_FALSE); + // - Debuggers under Linux tends to leave captured mouse on break, which may be very inconvenient, so to mitigate the issue we wait until mouse has moved to begin capture. + if (bd->MouseCanUseCapture) + { + bool want_capture = false; + for (int button_n = 0; button_n < ImGuiMouseButton_COUNT && !want_capture; button_n++) + if (ImGui::IsMouseDragging(button_n, 1.0f)) + want_capture = true; + SDL_CaptureMouse(want_capture ? SDL_TRUE : SDL_FALSE); + } SDL_Window* focused_window = SDL_GetKeyboardFocus(); const bool is_app_focused = (bd->Window == focused_window); diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index ac2e841e6..c2dd81085 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561) // 2025-03-30: Update for SDL3 api changes: Revert SDL_GetClipboardText() memory ownership change. (#8530, #7801) // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) @@ -110,6 +111,7 @@ struct ImGui_ImplSDL3_Data SDL_Cursor* MouseLastCursor; int MousePendingLeaveFrame; bool MouseCanUseGlobalState; + bool MouseCanUseCapture; // Gamepad handling ImVector Gamepads; @@ -461,17 +463,6 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); IM_UNUSED(sdl_gl_context); // Unused in this branch - // Check and store if we are on a SDL backend that supports global mouse position - // ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list) - bool mouse_can_use_global_state = false; -#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE - const char* sdl_backend = SDL_GetCurrentVideoDriver(); - const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" }; - for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++) - if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0) - mouse_can_use_global_state = true; -#endif - // Setup backend capabilities flags ImGui_ImplSDL3_Data* bd = IM_NEW(ImGui_ImplSDL3_Data)(); io.BackendPlatformUserData = (void*)bd; @@ -482,7 +473,18 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void bd->Window = window; bd->WindowID = SDL_GetWindowID(window); bd->Renderer = renderer; - bd->MouseCanUseGlobalState = mouse_can_use_global_state; + + // Check and store if we are on a SDL backend that supports SDL_GetGlobalMouseState() and SDL_CaptureMouse() + // ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list) + bd->MouseCanUseGlobalState = false; + bd->MouseCanUseCapture = false; +#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE + const char* sdl_backend = SDL_GetCurrentVideoDriver(); + const char* capture_and_global_state_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" }; + for (const char* item : capture_and_global_state_whitelist) + if (strncmp(sdl_backend, item, strlen(item)) == 0) + bd->MouseCanUseGlobalState = bd->MouseCanUseCapture = true; +#endif ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText; @@ -596,12 +598,15 @@ static void ImGui_ImplSDL3_UpdateMouseData() // We forward mouse input when hovered or captured (via SDL_EVENT_MOUSE_MOTION) or when focused (below) #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE // - SDL_CaptureMouse() let the OS know e.g. that our drags can extend outside of parent boundaries (we want updated position) and shouldn't trigger other operations outside. - // - Debuggers under Linux tends to leave captured mouse on break, which may be very inconvenient, so to migitate the issue we wait until mouse has moved to begin capture. - bool want_capture = false; - for (int button_n = 0; button_n < ImGuiMouseButton_COUNT && !want_capture; button_n++) - if (ImGui::IsMouseDragging(button_n, 1.0f)) - want_capture = true; - SDL_CaptureMouse(want_capture); + // - Debuggers under Linux tends to leave captured mouse on break, which may be very inconvenient, so to mitigate the issue we wait until mouse has moved to begin capture. + if (bd->MouseCanUseCapture) + { + bool want_capture = false; + for (int button_n = 0; button_n < ImGuiMouseButton_COUNT && !want_capture; button_n++) + if (ImGui::IsMouseDragging(button_n, 1.0f)) + want_capture = true; + SDL_CaptureMouse(want_capture); + } SDL_Window* focused_window = SDL_GetKeyboardFocus(); const bool is_app_focused = (bd->Window == focused_window); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 312b6de3e..b45cc1e3a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -81,6 +81,9 @@ Other changes: - Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] - Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) +- Backends: SDL2, SDL3: don't attempt to call SDL_CaptureMouse() on drivers where we don't + call SDL_GetGlobalMouseState(). This is specifically for Wayland but we currently use + the same white-list as SDL_GetGlobalMouseState(). (#8561) [@vs49688] - Backends: SDL3: Update for SDL3 api changes: revert SDL_GetClipboardText() memory ownership change. (#8530, #7801) [@Green-Sky] - Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which From 5e7174dec6d7d708dbfd857c32c15671619babc2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Apr 2025 17:39:22 +0200 Subject: [PATCH 3/5] TreeNode: removed TreeLinesSize > 0.0f optimization check. (#2920) This is desirable but we'd need to avoid exposing 0.0f in style editor + assert on it. --- imgui_demo.cpp | 2 +- imgui_widgets.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 205551fbf..ac51635cf 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8286,7 +8286,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) style.TreeLinesFlags = option; ImGui::EndCombo(); } - ImGui::SliderFloat("TreeLinesSize", &style.TreeLinesSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("TreeLinesSize", &style.TreeLinesSize, 0.0f, 2.0f, "%.0f"); ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 56134d641..5122fef7d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6641,7 +6641,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l bool store_tree_node_stack_data = false; if ((flags & ImGuiTreeNodeFlags_DrawLinesMask_) == 0) flags |= g.Style.TreeLinesFlags; - const bool draw_tree_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) && (frame_bb.Min.y < window->ClipRect.Max.y);// && (g.Style.TreeLinesSize > 0.0f); + const bool draw_tree_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) && (frame_bb.Min.y < window->ClipRect.Max.y) && (g.Style.TreeLinesSize > 0.0f); if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) { if ((flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !g.NavIdIsAlive) From bcbbfdaad4b98249cedcfd4914c70b01c4cb3243 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Apr 2025 17:43:48 +0200 Subject: [PATCH 4/5] TreeNode: DrawLines: latch X1 offset during TreePush(). (#2920) --- imgui_widgets.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 5122fef7d..b61817b9c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6562,7 +6562,7 @@ static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags, float x1) tree_node_data->NavRect = g.LastItemData.NavRect; // Initially I tried to latch value for GetColorU32(ImGuiCol_TreeLines) but it's not a good trade-off for very large trees. - tree_node_data->DrawLinesX1 = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) ? x1 : +FLT_MAX; + tree_node_data->DrawLinesX1 = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) ? (x1 + g.FontSize * 0.5f + g.Style.FramePadding.x) : +FLT_MAX; tree_node_data->DrawLinesY2 = -FLT_MAX; window->DC.TreeHasStackDataDepthMask |= (1 << window->DC.TreeDepth); } @@ -6857,11 +6857,12 @@ void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) return; ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; - float x1 = parent_data->DrawLinesX1 + ImTrunc(g.FontSize * 0.5f + g.Style.FramePadding.x); // GetTreeNodeToLabelSpacing() * 0.5f + float x1 = ImTrunc(parent_data->DrawLinesX1); + float x2 = ImTrunc(target_pos.x); float y = ImTrunc(target_pos.y); parent_data->DrawLinesY2 = ImMax(parent_data->DrawLinesY2, y); - if (x1 < target_pos.x) - window->DrawList->AddLine(ImVec2(x1, y), ImVec2(target_pos.x, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); + if (x1 < x2) + window->DrawList->AddLine(ImVec2(x1, y), ImVec2(x2, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); } void ImGui::TreePush(const char* str_id) @@ -6916,7 +6917,7 @@ void ImGui::TreePop() y2 = ImMin(y2, window->ClipRect.Max.y); if (y1 < y2) { - float x = data->DrawLinesX1 + ImTrunc(g.FontSize * 0.5f + g.Style.FramePadding.x); // GetTreeNodeToLabelSpacing() * 0.5f + float x = ImTrunc(data->DrawLinesX1); window->DrawList->AddLine(ImVec2(x, y1), ImVec2(x, y2), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); } } From 43caca05c27aebaa8f8fc3064d47042dce6c7f8b Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Apr 2025 17:58:23 +0200 Subject: [PATCH 5/5] TreeNode: DrawLines: tweak X2 offset to avoid losing line when ItemSpacing is large. (#2920) --- imgui_widgets.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index b61817b9c..c1d1f54ba 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6823,7 +6823,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l } if (draw_tree_lines) - TreeNodeDrawLineToChildNode(ImVec2(text_pos.x - text_offset_x, text_pos.y + g.FontSize * 0.5f)); + TreeNodeDrawLineToChildNode(ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.5f)); if (span_all_columns && !span_all_columns_label) TablePopBackgroundChannel(); @@ -6858,7 +6858,7 @@ void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; float x1 = ImTrunc(parent_data->DrawLinesX1); - float x2 = ImTrunc(target_pos.x); + float x2 = ImTrunc(target_pos.x - g.Style.ItemInnerSpacing.x); float y = ImTrunc(target_pos.y); parent_data->DrawLinesY2 = ImMax(parent_data->DrawLinesY2, y); if (x1 < x2)