From 789de09dda710a8826cf3bdfba29a4c1f72c6097 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Apr 2025 12:04:09 +0200 Subject: [PATCH] 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();