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:
parent
edebb90a9a
commit
bc3c0ce772
@ -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,11 +6347,13 @@ 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))
|
|
||||||
{
|
{
|
||||||
SetNavID(window->IDStack.back(), g.NavLayer, 0, ImRect());
|
ImGuiNavTreeNodeData* nav_tree_node_data = &g.NavTreeNodeStack.back();
|
||||||
NavMoveRequestCancel();
|
IM_ASSERT(nav_tree_node_data->ID == window->IDStack.back());
|
||||||
|
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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user