Skip to content

Commit 2d0baaa

Browse files
committed
TreeNode: rename/rework ImGuiNavTreeNodeData system to be usable by more features. (#2920, #1131, #7553)
Reworked to it is easier during TreeNode code to request extra data to be stored.
1 parent 0a73c6e commit 2d0baaa

File tree

4 files changed

+57
-32
lines changed

4 files changed

+57
-32
lines changed

imgui.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -3795,7 +3795,7 @@ void ImGui::Shutdown()
37953795
g.FontStack.clear();
37963796
g.OpenPopupStack.clear();
37973797
g.BeginPopupStack.clear();
3798-
g.NavTreeNodeStack.clear();
3798+
g.TreeNodeStack.clear();
37993799

38003800
g.Viewports.clear_delete();
38013801

@@ -7131,7 +7131,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
71317131
window->DC.MenuBarAppending = false;
71327132
window->DC.MenuColumns.Update(style.ItemSpacing.x, window_just_activated_by_user);
71337133
window->DC.TreeDepth = 0;
7134-
window->DC.TreeJumpToParentOnPopMask = 0x00;
7134+
window->DC.TreeHasStackDataDepthMask = 0x00;
71357135
window->DC.ChildWindows.resize(0);
71367136
window->DC.StateStorage = &window->StateStorage;
71377137
window->DC.CurrentColumns = NULL;
@@ -12039,7 +12039,7 @@ void ImGui::NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result)
1203912039
}
1204012040

1204112041
// Called by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere
12042-
void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiNavTreeNodeData* tree_node_data)
12042+
void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiTreeNodeStackData* tree_node_data)
1204312043
{
1204412044
ImGuiContext& g = *GImGui;
1204512045
g.NavMoveScoringItems = false;

imgui_demo.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,7 @@ static void ShowDemoWindowWidgets()
953953
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only.");
954954
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap);
955955
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)");
956+
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsBackHere", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsBackHere);
956957
ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
957958
ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
958959
ImGui::Text("Hello!");
@@ -985,7 +986,7 @@ static void ShowDemoWindowWidgets()
985986
ImGui::Text("This is a drag and drop source");
986987
ImGui::EndDragDropSource();
987988
}
988-
if (i == 2)
989+
if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanTextWidth))
989990
{
990991
// Item 2 has an additional inline button to help demonstrate SpanTextWidth.
991992
ImGui::SameLine();
@@ -994,6 +995,8 @@ static void ShowDemoWindowWidgets()
994995
if (node_open)
995996
{
996997
ImGui::BulletText("Blah blah\nBlah Blah");
998+
ImGui::SameLine();
999+
ImGui::SmallButton("Button");
9971000
ImGui::TreePop();
9981001
}
9991002
}

imgui_internal.h

+12-10
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@ struct ImGuiLastItemData; // Status storage for last submitted items
135135
struct ImGuiLocEntry; // A localization entry.
136136
struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only
137137
struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result
138-
struct ImGuiNavTreeNodeData; // Temporary storage for last TreeNode() being a Left arrow landing candidate.
139138
struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions
140139
struct ImGuiNextWindowData; // Storage for SetNextWindow** functions
141140
struct ImGuiNextItemData; // Storage for SetNextItem** functions
@@ -154,6 +153,7 @@ struct ImGuiTableInstanceData; // Storage for one instance of a same table
154153
struct ImGuiTableTempData; // Temporary storage for one table (one per table in the stack), shared between tables.
155154
struct ImGuiTableSettings; // Storage for a table .ini settings
156155
struct ImGuiTableColumnsSettings; // Storage for a column .ini settings
156+
struct ImGuiTreeNodeStackData; // Temporary storage for TreeNode().
157157
struct ImGuiTypingSelectState; // Storage for GetTypingSelectRequest()
158158
struct ImGuiTypingSelectRequest; // Storage for GetTypingSelectRequest() (aimed to be public)
159159
struct ImGuiWindow; // Storage for one window
@@ -1251,14 +1251,16 @@ struct ImGuiLastItemData
12511251
ImGuiLastItemData() { memset(this, 0, sizeof(*this)); }
12521252
};
12531253

1254-
// Store data emitted by TreeNode() for usage by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere.
1255-
// This is the minimum amount of data that we need to perform the equivalent of NavApplyItemToResult() and which we can't infer in TreePop()
1256-
// Only stored when the node is a potential candidate for landing on a Left arrow jump.
1257-
struct ImGuiNavTreeNodeData
1254+
// Store data emitted by TreeNode() for usage by TreePop()
1255+
// - To implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere: store the minimum amount of data
1256+
// which we can't infer in TreePop(), to perform the equivalent of NavApplyItemToResult().
1257+
// Only stored when the node is a potential candidate for landing on a Left arrow jump.
1258+
struct ImGuiTreeNodeStackData
12581259
{
12591260
ImGuiID ID;
1260-
ImGuiItemFlags InFlags;
1261-
ImRect NavRect;
1261+
ImGuiTreeNodeFlags TreeFlags;
1262+
ImGuiItemFlags InFlags; // Used for nav landing
1263+
ImRect NavRect; // Used for nav landing
12621264
};
12631265

12641266
struct IMGUI_API ImGuiStackSizes
@@ -2038,7 +2040,7 @@ struct ImGuiContext
20382040
ImVector<ImGuiGroupData> GroupStack; // Stack for BeginGroup()/EndGroup() - not inherited by Begin()
20392041
ImVector<ImGuiPopupData> OpenPopupStack; // Which popups are open (persistent)
20402042
ImVector<ImGuiPopupData> BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame)
2041-
ImVector<ImGuiNavTreeNodeData> NavTreeNodeStack; // Stack for TreeNode() when a NavLeft requested is emitted.
2043+
ImVector<ImGuiTreeNodeStackData>TreeNodeStack; // Stack for TreeNode()
20422044

20432045
// Viewports
20442046
ImVector<ImGuiViewportP*> Viewports; // Active viewports (Size==1 in 'master' branch). Each viewports hold their copy of ImDrawData.
@@ -2503,7 +2505,7 @@ struct IMGUI_API ImGuiWindowTempData
25032505
ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs.
25042506
ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items measurement
25052507
int TreeDepth; // Current tree depth.
2506-
ImU32 TreeJumpToParentOnPopMask; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary.
2508+
ImU32 TreeHasStackDataDepthMask; // Store whether given depth has ImGuiTreeNodeStackData data. Could be turned into a ImU64 if necessary.
25072509
ImVector<ImGuiWindow*> ChildWindows;
25082510
ImGuiStorage* StateStorage; // Current persistent per-window storage (store e.g. tree node open/close state)
25092511
ImGuiOldColumns* CurrentColumns; // Current columns set
@@ -3201,7 +3203,7 @@ namespace ImGui
32013203
IMGUI_API void NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags);
32023204
IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags);
32033205
IMGUI_API void NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result);
3204-
IMGUI_API void NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiNavTreeNodeData* tree_node_data);
3206+
IMGUI_API void NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiTreeNodeStackData* tree_node_data);
32053207
IMGUI_API void NavMoveRequestCancel();
32063208
IMGUI_API void NavMoveRequestApplyResult();
32073209
IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags);

imgui_widgets.cpp

+38-18
Original file line numberDiff line numberDiff line change
@@ -6310,6 +6310,21 @@ bool ImGui::TreeNodeUpdateNextOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
63106310
return is_open;
63116311
}
63126312

6313+
// Store ImGuiTreeNodeStackData for just submitted node.
6314+
static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags)
6315+
{
6316+
ImGuiContext& g = *GImGui;
6317+
ImGuiWindow* window = g.CurrentWindow;
6318+
6319+
g.TreeNodeStack.resize(g.TreeNodeStack.Size + 1);
6320+
ImGuiTreeNodeStackData* tree_node_data = &g.TreeNodeStack.back();
6321+
tree_node_data->ID = g.LastItemData.ID;
6322+
tree_node_data->TreeFlags = flags;
6323+
tree_node_data->InFlags = g.LastItemData.InFlags;
6324+
tree_node_data->NavRect = g.LastItemData.NavRect;
6325+
window->DC.TreeHasStackDataDepthMask |= (1 << window->DC.TreeDepth);
6326+
}
6327+
63136328
bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end)
63146329
{
63156330
ImGuiWindow* window = GetCurrentWindow();
@@ -6379,20 +6394,19 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
63796394
// For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop().
63806395
// It will become tempting to enable ImGuiTreeNodeFlags_NavLeftJumpsBackHere by default or move it to ImGuiStyle.
63816396
// Currently only supports 32 level deep and we are fine with (1 << Depth) overflowing into a zero, easy to increase.
6382-
if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
6383-
if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())
6384-
{
6385-
g.NavTreeNodeStack.resize(g.NavTreeNodeStack.Size + 1);
6386-
ImGuiNavTreeNodeData* nav_tree_node_data = &g.NavTreeNodeStack.back();
6387-
nav_tree_node_data->ID = id;
6388-
nav_tree_node_data->InFlags = g.LastItemData.InFlags;
6389-
nav_tree_node_data->NavRect = g.LastItemData.NavRect;
6390-
window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth);
6391-
}
6397+
bool store_tree_node_stack_data = false;
6398+
if (!(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
6399+
{
6400+
if ((flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && is_open && !g.NavIdIsAlive)
6401+
if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())
6402+
store_tree_node_stack_data = true;
6403+
}
63926404

63936405
const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0;
63946406
if (!item_add)
63956407
{
6408+
if (store_tree_node_stack_data && is_open)
6409+
TreeNodeStoreStackData(flags); // Call before TreePushOverrideID()
63966410
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
63976411
TreePushOverrideID(id);
63986412
IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
@@ -6533,8 +6547,11 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
65336547
else
65346548
RenderText(text_pos, label, label_end, false);
65356549

6550+
if (store_tree_node_stack_data && is_open)
6551+
TreeNodeStoreStackData(flags); // Call before TreePushOverrideID()
65366552
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
65376553
TreePushOverrideID(id);
6554+
65386555
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
65396556
return is_open;
65406557
}
@@ -6573,16 +6590,19 @@ void ImGui::TreePop()
65736590
window->DC.TreeDepth--;
65746591
ImU32 tree_depth_mask = (1 << window->DC.TreeDepth);
65756592

6576-
// Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled)
6577-
if (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask) // Only set during request
6593+
if (window->DC.TreeHasStackDataDepthMask & tree_depth_mask) // Only set during request
65786594
{
6579-
ImGuiNavTreeNodeData* nav_tree_node_data = &g.NavTreeNodeStack.back();
6580-
IM_ASSERT(nav_tree_node_data->ID == window->IDStack.back());
6581-
if (g.NavIdIsAlive && g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())
6582-
NavMoveRequestResolveWithPastTreeNode(&g.NavMoveResultLocal, nav_tree_node_data);
6583-
g.NavTreeNodeStack.pop_back();
6595+
ImGuiTreeNodeStackData* data = &g.TreeNodeStack.back();
6596+
IM_ASSERT(data->ID == window->IDStack.back());
6597+
if (data->TreeFlags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere)
6598+
{
6599+
// Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled)
6600+
if (g.NavIdIsAlive && g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())
6601+
NavMoveRequestResolveWithPastTreeNode(&g.NavMoveResultLocal, data);
6602+
}
6603+
g.TreeNodeStack.pop_back();
6604+
window->DC.TreeHasStackDataDepthMask &= ~tree_depth_mask;
65846605
}
6585-
window->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1;
65866606

65876607
IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much.
65886608
PopID();

0 commit comments

Comments
 (0)