Skip to content

Commit 2c07d58

Browse files
committed
TreeNode: Added ImGuiTreeNodeFlags_SpanAllColumns for use in tables. (#3151, #3565, #2451, #2438)
1 parent 085ed7b commit 2c07d58

File tree

5 files changed

+50
-18
lines changed

5 files changed

+50
-18
lines changed

docs/CHANGELOG.txt

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ Other changes:
9191
then expand slightly. A full rectangle is always visible and it may protrude slightly. (#4281, #3272)
9292
- Drag and Drop: Fixed submitting a tooltip from drop target location when using AcceptDragDropPayload()
9393
with ImGuiDragDropFlags_AcceptNoPreviewTooltip and submitting a tooltip manually.
94+
- TreeNode: Added ImGuiTreeNodeFlags_SpanAllColumns for use in tables. (#3151, #3565, #2451, #2438)
9495
- Tables: Fixed an edge-case when no columns are visible + table scrollbar is visible + user
9596
code is always testing return value of TableSetColumnIndex() to coarse clip. With an active
9697
clipper it would have asserted. Without a clipper, the scrollbar range would be wrong.

docs/TODO.txt

-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
187187
- tree node / selectable render mismatch which is visible if you use them both next to each other (e.g. cf. property viewer)
188188
- tree node: tweak color scheme to distinguish headers from selected tree node (#581)
189189
- tree node: leaf/non-leaf highlight mismatch.
190-
- tree node: flag to disable formatting and/or detect "%s"
191190
- tree node/opt: could avoid formatting when clipped (flag assuming we don't care about width/height, assume single line height? format only %s/%c to be able to count height?)
192191

193192
- settings: write more decent code to allow saving/loading new fields: columns, selected tree nodes?

imgui.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
// Library Version
2525
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
2626
#define IMGUI_VERSION "1.90 WIP"
27-
#define IMGUI_VERSION_NUM 18993
27+
#define IMGUI_VERSION_NUM 18994
2828
#define IMGUI_HAS_TABLE
2929

3030
/*
@@ -1055,7 +1055,8 @@ enum ImGuiTreeNodeFlags_
10551055
ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding().
10561056
ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line. In the future we may refactor the hit system to be front-to-back, allowing natural overlaps and then this can become the default.
10571057
ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (bypass the indented area).
1058-
ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop)
1058+
ImGuiTreeNodeFlags_SpanAllColumns = 1 << 13, // Frame will span all columns of its container table (text will still fit in current column)
1059+
ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 14, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop)
10591060
//ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 14, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible
10601061
ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog,
10611062

@@ -1092,7 +1093,7 @@ enum ImGuiSelectableFlags_
10921093
{
10931094
ImGuiSelectableFlags_None = 0,
10941095
ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this doesn't close parent popup window
1095-
ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column)
1096+
ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Frame will span all columns of its container table (text will still fit in current column)
10961097
ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too
10971098
ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text
10981099
ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one

imgui_demo.cpp

+11-6
Original file line numberDiff line numberDiff line change
@@ -875,10 +875,10 @@ static void ShowDemoWindowWidgets()
875875
// if (once)
876876
// ImGui::Text("This will be displayed only once.");
877877

878-
IMGUI_DEMO_MARKER("Widgets/Trees");
879-
if (ImGui::TreeNode("Trees"))
878+
IMGUI_DEMO_MARKER("Widgets/Tree Nodes");
879+
if (ImGui::TreeNode("Tree Nodes"))
880880
{
881-
IMGUI_DEMO_MARKER("Widgets/Trees/Basic trees");
881+
IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees");
882882
if (ImGui::TreeNode("Basic trees"))
883883
{
884884
for (int i = 0; i < 5; i++)
@@ -899,7 +899,7 @@ static void ShowDemoWindowWidgets()
899899
ImGui::TreePop();
900900
}
901901

902-
IMGUI_DEMO_MARKER("Widgets/Trees/Advanced, with Selectable nodes");
902+
IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes");
903903
if (ImGui::TreeNode("Advanced, with Selectable nodes"))
904904
{
905905
HelpMarker(
@@ -912,6 +912,7 @@ static void ShowDemoWindowWidgets()
912912
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
913913
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node.");
914914
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth);
915+
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only.");
915916
ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
916917
ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
917918
ImGui::Text("Hello!");
@@ -5016,6 +5017,10 @@ static void ShowDemoWindowTables()
50165017
{
50175018
static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
50185019

5020+
static ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAllColumns;
5021+
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanFullWidth);
5022+
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags, ImGuiTreeNodeFlags_SpanAllColumns);
5023+
50195024
if (ImGui::BeginTable("3ways", 3, flags))
50205025
{
50215026
// The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
@@ -5039,7 +5044,7 @@ static void ShowDemoWindowTables()
50395044
const bool is_folder = (node->ChildCount > 0);
50405045
if (is_folder)
50415046
{
5042-
bool open = ImGui::TreeNodeEx(node->Name, ImGuiTreeNodeFlags_SpanFullWidth);
5047+
bool open = ImGui::TreeNodeEx(node->Name, tree_node_flags);
50435048
ImGui::TableNextColumn();
50445049
ImGui::TextDisabled("--");
50455050
ImGui::TableNextColumn();
@@ -5053,7 +5058,7 @@ static void ShowDemoWindowTables()
50535058
}
50545059
else
50555060
{
5056-
ImGui::TreeNodeEx(node->Name, ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth);
5061+
ImGui::TreeNodeEx(node->Name, tree_node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen);
50575062
ImGui::TableNextColumn();
50585063
ImGui::Text("%d", node->Size);
50595064
ImGui::TableNextColumn();

imgui_widgets.cpp

+34-8
Original file line numberDiff line numberDiff line change
@@ -6161,10 +6161,11 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
61616161

61626162
// We vertically grow up to current line height up the typical widget height.
61636163
const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2);
6164+
const bool span_all_columns = (flags & ImGuiTreeNodeFlags_SpanAllColumns) != 0 && (g.CurrentTable != NULL);
61646165
ImRect frame_bb;
6165-
frame_bb.Min.x = (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x;
6166+
frame_bb.Min.x = span_all_columns ? window->ParentWorkRect.Min.x : (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x;
61666167
frame_bb.Min.y = window->DC.CursorPos.y;
6167-
frame_bb.Max.x = window->WorkRect.Max.x;
6168+
frame_bb.Max.x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x;
61686169
frame_bb.Max.y = window->DC.CursorPos.y + frame_height;
61696170
if (display_frame)
61706171
{
@@ -6174,23 +6175,38 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
61746175
frame_bb.Max.x += IM_TRUNC(window->WindowPadding.x * 0.5f);
61756176
}
61766177

6177-
const float text_offset_x = g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2); // Collapser arrow width + Spacing
6178+
const float text_offset_x = g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2); // Collapsing arrow width + Spacing
61786179
const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it
6179-
const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x * 2 : 0.0f); // Include collapser
6180+
const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x * 2 : 0.0f); // Include collapsing
61806181
ImVec2 text_pos(window->DC.CursorPos.x + text_offset_x, window->DC.CursorPos.y + text_offset_y);
61816182
ItemSize(ImVec2(text_width, frame_height), padding.y);
61826183

61836184
// For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing
61846185
ImRect interact_bb = frame_bb;
6185-
if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth)) == 0)
6186+
if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_SpanAllColumns)) == 0)
61866187
interact_bb.Max.x = frame_bb.Min.x + text_width + style.ItemSpacing.x * 2.0f;
61876188

6189+
// Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable..
6190+
const float backup_clip_rect_min_x = window->ClipRect.Min.x;
6191+
const float backup_clip_rect_max_x = window->ClipRect.Max.x;
6192+
if (span_all_columns)
6193+
{
6194+
window->ClipRect.Min.x = window->ParentWorkRect.Min.x;
6195+
window->ClipRect.Max.x = window->ParentWorkRect.Max.x;
6196+
}
6197+
61886198
// Compute open and multi-select states before ItemAdd() as it clear NextItem data.
61896199
bool is_open = TreeNodeUpdateNextOpen(id, flags);
61906200
bool item_add = ItemAdd(interact_bb, id);
61916201
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;
61926202
g.LastItemData.DisplayRect = frame_bb;
61936203

6204+
if (span_all_columns)
6205+
{
6206+
window->ClipRect.Min.x = backup_clip_rect_min_x;
6207+
window->ClipRect.Max.x = backup_clip_rect_max_x;
6208+
}
6209+
61946210
// If a NavLeft request is happening and ImGuiTreeNodeFlags_NavLeftJumpsBackHere enabled:
61956211
// Store data for the current depth to allow returning to this node from any child item.
61966212
// For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop().
@@ -6216,6 +6232,9 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
62166232
return is_open;
62176233
}
62186234

6235+
if (span_all_columns)
6236+
TablePushBackgroundChannel();
6237+
62196238
ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None;
62206239
if ((flags & ImGuiTreeNodeFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap))
62216240
button_flags |= ImGuiButtonFlags_AllowOverlap;
@@ -6316,7 +6335,6 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
63166335

63176336
if (g.LogEnabled)
63186337
LogSetNextTextDecoration("###", "###");
6319-
RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size);
63206338
}
63216339
else
63226340
{
@@ -6333,9 +6351,17 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
63336351
RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 0.70f);
63346352
if (g.LogEnabled)
63356353
LogSetNextTextDecoration(">", NULL);
6336-
RenderText(text_pos, label, label_end, false);
63376354
}
63386355

6356+
if (span_all_columns)
6357+
TablePopBackgroundChannel();
6358+
6359+
// Label
6360+
if (display_frame)
6361+
RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size);
6362+
else
6363+
RenderText(text_pos, label, label_end, false);
6364+
63396365
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
63406366
TreePushOverrideID(id);
63416367
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
@@ -6511,7 +6537,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
65116537
}
65126538
//if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(0, 255, 0, 255)); }
65136539

6514-
// Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackground for every Selectable..
6540+
// Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable..
65156541
const float backup_clip_rect_min_x = window->ClipRect.Min.x;
65166542
const float backup_clip_rect_max_x = window->ClipRect.Max.x;
65176543
if (span_all_columns)

0 commit comments

Comments
 (0)