TreeNode: added ImGuiTreeNodeFlags_DrawTreeXXX flags. (#2920)

# Conflicts:
#	docs/CHANGELOG.txt
This commit is contained in:
ocornut 2024-07-03 19:03:25 +02:00
parent faa03031b4
commit e5b218e6d1
8 changed files with 154 additions and 17 deletions

View file

@ -55,6 +55,18 @@ Other changes:
- Windows: loosened code to allow hovering of resize grips, borders, and table
borders while hovering a sibling child window, so that the code in master matches
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_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 color for a given hierarchy level is latched in TreeNode(),
allowing advanced tree drawing code to potentially alter it.
- 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

View file

@ -1360,6 +1360,8 @@ ImGuiStyle::ImGuiStyle()
TabBarOverlineSize = 1.0f; // Thickness of tab-bar overline, which highlights the selected tab-bar.
TableAngledHeadersAngle = 35.0f * (IM_PI / 180.0f); // Angle of angled headers (supported values range from -50 degrees to +50 degrees).
TableAngledHeadersTextAlign = ImVec2(0.5f,0.0f);// Alignment of angled headers within the cell
TreeLinesFlags = ImGuiTreeNodeFlags_DrawLinesNone;
TreeLinesSize = 1.0f; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines.
ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
@ -3415,6 +3417,7 @@ static const ImGuiStyleVarInfo GStyleVarsInfo[] =
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabBarOverlineSize) }, // ImGuiStyleVar_TabBarOverlineSize
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersAngle)}, // ImGuiStyleVar_TableAngledHeadersAngle
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersTextAlign)},// ImGuiStyleVar_TableAngledHeadersTextAlign
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesSize)}, // ImGuiStyleVar_TreeLinesSize
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextBorderSize)}, // ImGuiStyleVar_SeparatorTextBorderSize
@ -3563,6 +3566,7 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx)
case ImGuiCol_TableRowBgAlt: return "TableRowBgAlt";
case ImGuiCol_TextLink: return "TextLink";
case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
case ImGuiCol_TreeLines: return "TreeLines";
case ImGuiCol_DragDropTarget: return "DragDropTarget";
case ImGuiCol_NavCursor: return "NavCursor";
case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight";
@ -10243,6 +10247,7 @@ static void ImGui::ErrorCheckNewFrameSanityChecks()
IM_ASSERT(g.Style.WindowBorderHoverPadding > 0.0f && "Invalid style setting!"); // Required otherwise cannot resize from borders.
IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);
IM_ASSERT(g.Style.ColorButtonPosition == ImGuiDir_Left || g.Style.ColorButtonPosition == ImGuiDir_Right);
IM_ASSERT(g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesNone || g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesFull || g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesToNodes);
// Error handling: we do not accept 100% silent recovery! Please contact me if you feel this is getting in your way.
if (g.IO.ConfigErrorRecovery)
@ -12794,7 +12799,7 @@ void ImGui::NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result)
}
// Called by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere
void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiTreeNodeStackData* tree_node_data)
void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, const ImGuiTreeNodeStackData* tree_node_data)
{
ImGuiContext& g = *GImGui;
g.NavMoveScoringItems = false;

12
imgui.h
View file

@ -1214,6 +1214,12 @@ enum ImGuiTreeNodeFlags_
ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 17, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop)
ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog,
// [EXPERIMENTAL] Draw lines connecting TreeNode hierarchy. Discuss in GitHub issue #2920.
// Default value is pulled from style.TreeLinesFlags. May be overridden in TreeNode calls.
ImGuiTreeNodeFlags_DrawLinesNone = 1 << 18, // No lines drawn
ImGuiTreeNodeFlags_DrawLinesFull = 1 << 19, // Horizontal lines to child nodes. Vertical line drawn down to TreePop() position: cover full contents.
ImGuiTreeNodeFlags_DrawLinesToNodes = 1 << 20, // Horizontal lines to child nodes. Vertical line drawn down to bottom-most child node. A little bit slower.
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7
ImGuiTreeNodeFlags_SpanTextWidth = ImGuiTreeNodeFlags_SpanLabelWidth,// Renamed in 1.90.7
@ -1666,7 +1672,8 @@ enum ImGuiCol_
ImGuiCol_TableRowBg, // Table row background (even rows)
ImGuiCol_TableRowBgAlt, // Table row background (odd rows)
ImGuiCol_TextLink, // Hyperlink color
ImGuiCol_TextSelectedBg,
ImGuiCol_TextSelectedBg, // Selected text inside an InputText
ImGuiCol_TreeLines, // Tree node hierarchy outlines when using ImGuiTreeNodeFlags_DrawLines
ImGuiCol_DragDropTarget, // Rectangle highlighting a drop target
ImGuiCol_NavCursor, // Color of keyboard/gamepad navigation cursor/rectangle, when visible
ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB
@ -1722,6 +1729,7 @@ enum ImGuiStyleVar_
ImGuiStyleVar_TabBarOverlineSize, // float TabBarOverlineSize
ImGuiStyleVar_TableAngledHeadersAngle, // float TableAngledHeadersAngle
ImGuiStyleVar_TableAngledHeadersTextAlign,// ImVec2 TableAngledHeadersTextAlign
ImGuiStyleVar_TreeLinesSize, // float TreeLinesSize
ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign
ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign
ImGuiStyleVar_SeparatorTextBorderSize, // float SeparatorTextBorderSize
@ -2181,6 +2189,8 @@ struct ImGuiStyle
float TabBarOverlineSize; // Thickness of tab-bar overline, which highlights the selected tab-bar.
float TableAngledHeadersAngle; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f degrees).
ImVec2 TableAngledHeadersTextAlign;// Alignment of angled headers within the cell
ImGuiTreeNodeFlags TreeLinesFlags; // Default way to draw lines connecting TreeNode hierarchy. ImGuiTreeNodeFlags_DrawLinesNone or ImGuiTreeNodeFlags_DrawLinesFull or ImGuiTreeNodeFlags_DrawLinesToNodes.
float TreeLinesSize; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines.
ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered).
ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.

View file

@ -3920,6 +3920,7 @@ static void DemoWindowWidgetsTreeNodes()
IMGUI_DEMO_MARKER("Widgets/Tree Nodes");
if (ImGui::TreeNode("Tree Nodes"))
{
// See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven tree.
IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees");
if (ImGui::TreeNode("Basic trees"))
{
@ -3946,6 +3947,35 @@ static void DemoWindowWidgetsTreeNodes()
ImGui::TreePop();
}
IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Hierarchy lines");
if (ImGui::TreeNode("Hierarchy lines"))
{
static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DefaultOpen;
HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags");
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", &base_flags, ImGuiTreeNodeFlags_DrawLinesNone);
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", &base_flags, ImGuiTreeNodeFlags_DrawLinesFull);
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, ImGuiTreeNodeFlags_DrawLinesToNodes);
if (ImGui::TreeNodeEx("Parent", base_flags))
{
if (ImGui::TreeNodeEx("Child 1", base_flags))
{
ImGui::Button("Button for Child 1");
ImGui::TreePop();
}
if (ImGui::TreeNodeEx("Child 2", base_flags))
{
ImGui::Button("Button for Child 2");
ImGui::TreePop();
}
ImGui::Text("Remaining contents");
ImGui::Text("Remaining contents");
ImGui::TreePop();
}
ImGui::TreePop();
}
IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes");
if (ImGui::TreeNode("Advanced, with Selectable nodes"))
{
@ -3964,6 +3994,12 @@ static void DemoWindowWidgetsTreeNodes()
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap);
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)");
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsBackHere", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsBackHere);
HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags");
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", &base_flags, ImGuiTreeNodeFlags_DrawLinesNone);
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", &base_flags, ImGuiTreeNodeFlags_DrawLinesFull);
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, ImGuiTreeNodeFlags_DrawLinesToNodes);
ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
ImGui::Text("Hello!");
@ -4607,10 +4643,11 @@ static void DemoWindowLayout()
ImGui::SmallButton("SmallButton()");
// Tree
// (here the node appears after a button and has odd intent, so we use ImGuiTreeNodeFlags_DrawLinesNone to disable hierarchy outline)
const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
ImGui::Button("Button##1");
ImGui::SameLine(0.0f, spacing);
if (ImGui::TreeNode("Node##1"))
if (ImGui::TreeNodeEx("Node##1", ImGuiTreeNodeFlags_DrawLinesNone))
{
// Placeholder tree data
for (int i = 0; i < 6; i++)
@ -6592,7 +6629,7 @@ static void DemoWindowTables()
{
static ImGuiTableFlags table_flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
static ImGuiTreeNodeFlags tree_node_flags_base = ImGuiTreeNodeFlags_SpanAllColumns;
static ImGuiTreeNodeFlags tree_node_flags_base = ImGuiTreeNodeFlags_SpanAllColumns | ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_DrawLinesFull;
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanLabelWidth);
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanAllColumns);
@ -8139,6 +8176,14 @@ bool ImGui::ShowStyleSelector(const char* label)
return false;
}
static const char* GetTreeLinesFlagsName(ImGuiTreeNodeFlags flags)
{
if (flags == ImGuiTreeNodeFlags_DrawLinesNone) return "DrawLinesNone";
if (flags == ImGuiTreeNodeFlags_DrawLinesFull) return "DrawLinesFull";
if (flags == ImGuiTreeNodeFlags_DrawLinesToNodes) return "DrawLinesToNodes";
return "";
}
void ImGui::ShowStyleEditor(ImGuiStyle* ref)
{
IMGUI_DEMO_MARKER("Tools/Style Editor");
@ -8233,6 +8278,15 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1);
ImGui::SeparatorText("Widgets");
if (ImGui::BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags)))
{
const ImGuiTreeNodeFlags options[] = { ImGuiTreeNodeFlags_DrawLinesNone, ImGuiTreeNodeFlags_DrawLinesFull, ImGuiTreeNodeFlags_DrawLinesToNodes };
for (ImGuiTreeNodeFlags option : options)
if (ImGui::Selectable(GetTreeLinesFlagsName(option), style.TreeLinesFlags == option))
style.TreeLinesFlags = option;
ImGui::EndCombo();
}
ImGui::SliderFloat("TreeLinesSize", &style.TreeLinesSize, 0.0f, 1.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.");
@ -9285,8 +9339,10 @@ struct ExampleAppPropertyEditor
ImGui::TableNextColumn();
ImGui::PushID(node->UID);
ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None;
tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; // Standard opening mode as we are likely to want to add selection afterwards
tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Left arrow support
tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;// Standard opening mode as we are likely to want to add selection afterwards
tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Left arrow support
tree_flags |= ImGuiTreeNodeFlags_SpanFullWidth; // Span full width for easier mouse reach
tree_flags |= ImGuiTreeNodeFlags_DrawLinesToNodes; // Always draw hierarchy outlines
if (node == VisibleNode)
tree_flags |= ImGuiTreeNodeFlags_Selected;
if (node->Childs.Size == 0)

View file

@ -236,6 +236,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f);
colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive];
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border];
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_NavCursor] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
@ -300,6 +301,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f);
colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive];
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border];
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
@ -365,6 +367,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
colors[ImGuiCol_TableRowBgAlt] = ImVec4(0.30f, 0.30f, 0.30f, 0.09f);
colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive];
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border];
colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f);

View file

@ -998,6 +998,7 @@ enum ImGuiTreeNodeFlagsPrivate_
ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 28,// FIXME-WIP: Hard-coded for CollapsingHeader()
ImGuiTreeNodeFlags_UpsideDownArrow = 1 << 29,// FIXME-WIP: Turn Down arrow into an Up arrow, for reversed trees (#6517)
ImGuiTreeNodeFlags_OpenOnMask_ = ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_OpenOnArrow,
ImGuiTreeNodeFlags_DrawLinesMask_ = ImGuiTreeNodeFlags_DrawLinesNone | ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes,
};
enum ImGuiSeparatorFlags_
@ -1291,8 +1292,11 @@ struct ImGuiTreeNodeStackData
{
ImGuiID ID;
ImGuiTreeNodeFlags TreeFlags;
ImGuiItemFlags ItemFlags; // Used for nav landing
ImRect NavRect; // Used for nav landing
ImGuiItemFlags ItemFlags; // Used for nav landing
ImRect NavRect; // Used for nav landing
ImU32 DrawLinesCol;
float DrawLinesX1;
float DrawLinesY2;
};
// sizeof() = 20
@ -3178,7 +3182,7 @@ namespace ImGui
IMGUI_API void NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags);
IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags);
IMGUI_API void NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result);
IMGUI_API void NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiTreeNodeStackData* tree_node_data);
IMGUI_API void NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, const ImGuiTreeNodeStackData* tree_node_data);
IMGUI_API void NavMoveRequestCancel();
IMGUI_API void NavMoveRequestApplyResult();
IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags);

View file

@ -451,6 +451,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// But at this point we do NOT have a correct value for .Max.y (unless a height has been explicitly passed in). It will only be updated in EndTable().
table->WorkRect = table->OuterRect = table->InnerRect = outer_rect;
table->HasScrollbarYPrev = table->HasScrollbarYCurr = false;
table->InnerWindow->DC.TreeDepth++; // This is designed to always linking ImGuiTreeNodeFlags_DrawLines linking accross a table
}
// Push a standardized ID for both child-using and not-child-using tables
@ -1510,6 +1511,7 @@ void ImGui::EndTable()
}
else
{
table->InnerWindow->DC.TreeDepth--;
ItemSize(table->OuterRect.GetSize());
ItemAdd(table->OuterRect, 0);
}

View file

@ -6390,6 +6390,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl
// - TreeNodeV()
// - TreeNodeEx()
// - TreeNodeExV()
// - TreeNodeStoreStackData() [Internal]
// - TreeNodeBehavior() [Internal]
// - TreePush()
// - TreePop()
@ -6548,17 +6549,27 @@ bool ImGui::TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags)
// Store ImGuiTreeNodeStackData for just submitted node.
// Currently only supports 32 level deep and we are fine with (1 << Depth) overflowing into a zero, easy to increase.
static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags)
static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags, float x1)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
g.TreeNodeStack.resize(g.TreeNodeStack.Size + 1);
ImGuiTreeNodeStackData* tree_node_data = &g.TreeNodeStack.back();
ImGuiTreeNodeStackData* tree_node_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1];
tree_node_data->ID = g.LastItemData.ID;
tree_node_data->TreeFlags = flags;
tree_node_data->ItemFlags = g.LastItemData.ItemFlags;
tree_node_data->NavRect = g.LastItemData.NavRect;
if (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes))
{
tree_node_data->DrawLinesCol = ImGui::GetColorU32(ImGuiCol_TreeLines);
tree_node_data->DrawLinesX1 = x1;
tree_node_data->DrawLinesY2 = -FLT_MAX;
}
else
{
tree_node_data->DrawLinesCol = 0;
}
window->DC.TreeHasStackDataDepthMask |= (1 << window->DC.TreeDepth);
}
@ -6634,18 +6645,28 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
// For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop().
// It will become tempting to enable ImGuiTreeNodeFlags_NavLeftJumpsBackHere by default or move it to ImGuiStyle.
bool store_tree_node_stack_data = false;
if (!(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
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);
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
{
if ((flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && is_open && !g.NavIdIsAlive)
if ((flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !g.NavIdIsAlive)
if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())
store_tree_node_stack_data = true;
if (draw_tree_lines)
store_tree_node_stack_data = true;
}
const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0;
if (!is_visible)
{
if (store_tree_node_stack_data && is_open)
TreeNodeStoreStackData(flags); // Call before TreePushOverrideID()
if (draw_tree_lines && (flags & ImGuiTreeNodeFlags_DrawLinesToNodes) && (window->DC.TreeHasStackDataDepthMask & (1 << window->DC.TreeDepth)))
{
ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1];
parent_data->DrawLinesY2 = ImMax(parent_data->DrawLinesY2, window->DC.CursorPos.y); // Don't need to aim to mid Y position as we are clipped anyway.
}
if (is_open && store_tree_node_stack_data)
TreeNodeStoreStackData(flags, text_pos.x - text_offset_x); // Call before TreePushOverrideID()
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
TreePushOverrideID(id);
IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
@ -6807,6 +6828,18 @@ 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), parent_data->DrawLinesCol, g.Style.TreeLinesSize);
}
if (span_all_columns && !span_all_columns_label)
TablePopBackgroundChannel();
@ -6821,7 +6854,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
}
if (store_tree_node_stack_data && is_open)
TreeNodeStoreStackData(flags); // Call before TreePushOverrideID()
TreeNodeStoreStackData(flags, text_pos.x - text_offset_x); // Call before TreePushOverrideID()
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
TreePushOverrideID(id); // Could use TreePush(label) but this avoid computing twice
@ -6865,7 +6898,7 @@ void ImGui::TreePop()
if (window->DC.TreeHasStackDataDepthMask & tree_depth_mask) // Only set during request
{
ImGuiTreeNodeStackData* data = &g.TreeNodeStack.back();
const ImGuiTreeNodeStackData* data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1];
IM_ASSERT(data->ID == window->IDStack.back());
if (data->TreeFlags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere)
{
@ -6873,6 +6906,18 @@ void ImGui::TreePop()
if (g.NavIdIsAlive && g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())
NavMoveRequestResolveWithPastTreeNode(&g.NavMoveResultLocal, data);
}
if (data->DrawLinesCol != 0 && window->DC.CursorPos.y >= window->ClipRect.Min.y)
{
// Draw vertical line of the hierarchy
float y1 = ImMax(data->NavRect.Max.y, window->ClipRect.Min.y);
float y2 = (data->TreeFlags & ImGuiTreeNodeFlags_DrawLinesToNodes) ? data->DrawLinesY2 : ImTrunc(window->DC.CursorPos.y - g.Style.ItemSpacing.y - g.FontSize * 0.5f);
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
window->DrawList->AddLine(ImVec2(x, y1), ImVec2(x, y2), data->DrawLinesCol, g.Style.TreeLinesSize);
}
}
g.TreeNodeStack.pop_back();
window->DC.TreeHasStackDataDepthMask &= ~tree_depth_mask;
}