mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-31 13:11:05 +01:00 
			
		
		
		
	Nav, TreeNode: Pressing Left with ImGuiTreeNodeFlags_NavLeftJumpsBackHere now goes through proper navigation logic: honor scrolling and selection. (#1079, #1131)
Added a stack for this purpose which other features might build on (e.g. #2920). However this is currently gated by many tests and not a performance concern, but making stack happen all the time may be undesirable.
This commit is contained in:
		| @@ -44,6 +44,8 @@ Breaking changes: | |||||||
|  |  | ||||||
| Other changes: | Other changes: | ||||||
|  |  | ||||||
|  | - Nav, TreeNode: Pressing Left with ImGuiTreeNodeFlags_NavLeftJumpsBackHere now goes | ||||||
|  |   through proper navigation logic: honor scrolling and selection. (#1079, #1131) | ||||||
| - Sliders: Fixed an integer overflow and div-by-zero in SliderInt() when | - Sliders: Fixed an integer overflow and div-by-zero in SliderInt() when | ||||||
|   v_max=INT_MAX (#6675, #6679) [@jbarthelmes] |   v_max=INT_MAX (#6675, #6679) [@jbarthelmes] | ||||||
| - ImDrawList: Fixed OOB access in _CalcCircleAutoSegmentCount when passing excessively | - ImDrawList: Fixed OOB access in _CalcCircleAutoSegmentCount when passing excessively | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								imgui.cpp
									
									
									
									
									
								
							| @@ -3653,6 +3653,7 @@ void ImGui::Shutdown() | |||||||
|     g.FontStack.clear(); |     g.FontStack.clear(); | ||||||
|     g.OpenPopupStack.clear(); |     g.OpenPopupStack.clear(); | ||||||
|     g.BeginPopupStack.clear(); |     g.BeginPopupStack.clear(); | ||||||
|  |     g.NavTreeNodeStack.clear(); | ||||||
|  |  | ||||||
|     g.Viewports.clear_delete(); |     g.Viewports.clear_delete(); | ||||||
|  |  | ||||||
| @@ -11191,6 +11192,19 @@ void ImGui::NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result) | |||||||
|     NavUpdateAnyRequestFlag(); |     NavUpdateAnyRequestFlag(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Called by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere | ||||||
|  | void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiNavTreeNodeData* tree_node_data) | ||||||
|  | { | ||||||
|  |     ImGuiContext& g = *GImGui; | ||||||
|  |     g.NavMoveScoringItems = false; | ||||||
|  |     g.LastItemData.ID = tree_node_data->ID; | ||||||
|  |     g.LastItemData.InFlags = tree_node_data->InFlags; | ||||||
|  |     g.LastItemData.NavRect = tree_node_data->NavRect; | ||||||
|  |     NavApplyItemToResult(result); // Result this instead of implementing a NavApplyPastTreeNodeToResult() | ||||||
|  |     NavClearPreferredPosForAxis(ImGuiAxis_Y); | ||||||
|  |     NavUpdateAnyRequestFlag(); | ||||||
|  | } | ||||||
|  |  | ||||||
| void ImGui::NavMoveRequestCancel() | void ImGui::NavMoveRequestCancel() | ||||||
| { | { | ||||||
|     ImGuiContext& g = *GImGui; |     ImGuiContext& g = *GImGui; | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								imgui.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								imgui.h
									
									
									
									
									
								
							| @@ -26,7 +26,7 @@ | |||||||
| // Library Version | // Library Version | ||||||
| // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') | // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') | ||||||
| #define IMGUI_VERSION       "1.89.9 WIP" | #define IMGUI_VERSION       "1.89.9 WIP" | ||||||
| #define IMGUI_VERSION_NUM   18981 | #define IMGUI_VERSION_NUM   18982 | ||||||
| #define IMGUI_HAS_TABLE | #define IMGUI_HAS_TABLE | ||||||
|  |  | ||||||
| /* | /* | ||||||
|   | |||||||
| @@ -135,6 +135,7 @@ struct ImGuiLastItemData;           // Status storage for last submitted items | |||||||
| struct ImGuiLocEntry;               // A localization entry. | struct ImGuiLocEntry;               // A localization entry. | ||||||
| struct ImGuiMenuColumns;            // Simple column measurement, currently used for MenuItem() only | struct ImGuiMenuColumns;            // Simple column measurement, currently used for MenuItem() only | ||||||
| struct ImGuiNavItemData;            // Result of a gamepad/keyboard directional navigation move query result | struct ImGuiNavItemData;            // Result of a gamepad/keyboard directional navigation move query result | ||||||
|  | struct ImGuiNavTreeNodeData;        // Temporary storage for last TreeNode() being a Left arrow landing candidate. | ||||||
| struct ImGuiMetricsConfig;          // Storage for ShowMetricsWindow() and DebugNodeXXX() functions | struct ImGuiMetricsConfig;          // Storage for ShowMetricsWindow() and DebugNodeXXX() functions | ||||||
| struct ImGuiNextWindowData;         // Storage for SetNextWindow** functions | struct ImGuiNextWindowData;         // Storage for SetNextWindow** functions | ||||||
| struct ImGuiNextItemData;           // Storage for SetNextItem** functions | struct ImGuiNextItemData;           // Storage for SetNextItem** functions | ||||||
| @@ -1201,6 +1202,16 @@ struct ImGuiLastItemData | |||||||
|     ImGuiLastItemData()     { memset(this, 0, sizeof(*this)); } |     ImGuiLastItemData()     { memset(this, 0, sizeof(*this)); } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | // Store data emitted by TreeNode() for usage by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere. | ||||||
|  | // This is the minimum amount of data that we need to perform the equivalent of NavApplyItemToResult() and which we can't infer in TreePop() | ||||||
|  | // Only stored when the node is a potential candidate for landing on a Left arrow jump. | ||||||
|  | struct ImGuiNavTreeNodeData | ||||||
|  | { | ||||||
|  |     ImGuiID                 ID; | ||||||
|  |     ImGuiItemFlags          InFlags; | ||||||
|  |     ImRect                  NavRect; | ||||||
|  | }; | ||||||
|  |  | ||||||
| struct IMGUI_API ImGuiStackSizes | struct IMGUI_API ImGuiStackSizes | ||||||
| { | { | ||||||
|     short   SizeOfIDStack; |     short   SizeOfIDStack; | ||||||
| @@ -1865,6 +1876,8 @@ struct ImGuiContext | |||||||
|     ImVector<ImGuiGroupData>GroupStack;                         // Stack for BeginGroup()/EndGroup() - not inherited by Begin() |     ImVector<ImGuiGroupData>GroupStack;                         // Stack for BeginGroup()/EndGroup() - not inherited by Begin() | ||||||
|     ImVector<ImGuiPopupData>OpenPopupStack;                     // Which popups are open (persistent) |     ImVector<ImGuiPopupData>OpenPopupStack;                     // Which popups are open (persistent) | ||||||
|     ImVector<ImGuiPopupData>BeginPopupStack;                    // Which level of BeginPopup() we are in (reset every frame) |     ImVector<ImGuiPopupData>BeginPopupStack;                    // Which level of BeginPopup() we are in (reset every frame) | ||||||
|  |     ImVector<ImGuiNavTreeNodeData> NavTreeNodeStack;            // Stack for TreeNode() when a NavLeft requested is emitted. | ||||||
|  |  | ||||||
|     int                     BeginMenuCount; |     int                     BeginMenuCount; | ||||||
|  |  | ||||||
|     // Viewports |     // Viewports | ||||||
| @@ -2930,6 +2943,7 @@ namespace ImGui | |||||||
|     IMGUI_API void          NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags); |     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          NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags); | ||||||
|     IMGUI_API void          NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result); |     IMGUI_API void          NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result); | ||||||
|  |     IMGUI_API void          NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiNavTreeNodeData* tree_node_data); | ||||||
|     IMGUI_API void          NavMoveRequestCancel(); |     IMGUI_API void          NavMoveRequestCancel(); | ||||||
|     IMGUI_API void          NavMoveRequestApplyResult(); |     IMGUI_API void          NavMoveRequestApplyResult(); | ||||||
|     IMGUI_API void          NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); |     IMGUI_API void          NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); | ||||||
|   | |||||||
| @@ -6155,18 +6155,29 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l | |||||||
|     if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth)) == 0) |     if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth)) == 0) | ||||||
|         interact_bb.Max.x = frame_bb.Min.x + text_width + style.ItemSpacing.x * 2.0f; |         interact_bb.Max.x = frame_bb.Min.x + text_width + style.ItemSpacing.x * 2.0f; | ||||||
|  |  | ||||||
|     // Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child. |     // Compute open and multi-select states before ItemAdd() as it clear NextItem data. | ||||||
|     // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop(). |  | ||||||
|     // This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero. |  | ||||||
|     const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; |  | ||||||
|     bool is_open = TreeNodeUpdateNextOpen(id, flags); |     bool is_open = TreeNodeUpdateNextOpen(id, flags); | ||||||
|     if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) |  | ||||||
|         window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth); |  | ||||||
|  |  | ||||||
|     bool item_add = ItemAdd(interact_bb, id); |     bool item_add = ItemAdd(interact_bb, id); | ||||||
|     g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; |     g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; | ||||||
|     g.LastItemData.DisplayRect = frame_bb; |     g.LastItemData.DisplayRect = frame_bb; | ||||||
|  |  | ||||||
|  |     // If a NavLeft request is happening and ImGuiTreeNodeFlags_NavLeftJumpsBackHere enabled: | ||||||
|  |     // Store data for the current depth to allow returning to this node from any child item. | ||||||
|  |     // 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. | ||||||
|  |     // Currently only supports 32 level deep and we are fine with (1 << Depth) overflowing into a zero, easy to increase. | ||||||
|  |     if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) | ||||||
|  |         if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) | ||||||
|  |         { | ||||||
|  |             g.NavTreeNodeStack.resize(g.NavTreeNodeStack.Size + 1); | ||||||
|  |             ImGuiNavTreeNodeData* nav_tree_node_data = &g.NavTreeNodeStack.back(); | ||||||
|  |             nav_tree_node_data->ID = id; | ||||||
|  |             nav_tree_node_data->InFlags = g.LastItemData.InFlags; | ||||||
|  |             nav_tree_node_data->NavRect = g.LastItemData.NavRect; | ||||||
|  |             window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; | ||||||
|     if (!item_add) |     if (!item_add) | ||||||
|     { |     { | ||||||
|         if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) |         if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) | ||||||
| @@ -6336,12 +6347,14 @@ void ImGui::TreePop() | |||||||
|     ImU32 tree_depth_mask = (1 << window->DC.TreeDepth); |     ImU32 tree_depth_mask = (1 << window->DC.TreeDepth); | ||||||
|  |  | ||||||
|     // Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled) |     // Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled) | ||||||
|     if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) |     if (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask) // Only set during request | ||||||
|         if (g.NavIdIsAlive && (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask)) |     { | ||||||
|         { |         ImGuiNavTreeNodeData* nav_tree_node_data = &g.NavTreeNodeStack.back(); | ||||||
|             SetNavID(window->IDStack.back(), g.NavLayer, 0, ImRect()); |         IM_ASSERT(nav_tree_node_data->ID == window->IDStack.back()); | ||||||
|             NavMoveRequestCancel(); |         if (g.NavIdIsAlive && g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) | ||||||
|         } |             NavMoveRequestResolveWithPastTreeNode(&g.NavMoveResultLocal, nav_tree_node_data); | ||||||
|  |         g.NavTreeNodeStack.pop_back(); | ||||||
|  |     } | ||||||
|     window->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1; |     window->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1; | ||||||
|  |  | ||||||
|     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. |     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. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user