mirror of
https://github.com/Drezil/imgui.git
synced 2024-11-15 01:17:00 +00:00
Nav: Added proper version of ImGuiWindowFlags_NavFlattened that handles scrolling nicely. Marked as private as I'm not happy with the name. (#787)
This commit is contained in:
parent
b40dc5c4f2
commit
c851b33352
50
imgui.cpp
50
imgui.cpp
@ -2254,6 +2254,12 @@ static inline void NavUpdateAnyRequestFlag()
|
|||||||
g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || IMGUI_DEBUG_NAV_SCORING;
|
g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || IMGUI_DEBUG_NAV_SCORING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool NavMoveRequestButNoResultYet()
|
||||||
|
{
|
||||||
|
ImGuiContext& g = *GImGui;
|
||||||
|
return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void NavMoveRequestCancel()
|
static void NavMoveRequestCancel()
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
@ -2288,7 +2294,7 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con
|
|||||||
// Scoring for navigation
|
// Scoring for navigation
|
||||||
if (g.NavId != id && !(item_flags & ImGuiItemFlags_NoNav))
|
if (g.NavId != id && !(item_flags & ImGuiItemFlags_NoNav))
|
||||||
{
|
{
|
||||||
ImGuiNavMoveResult* result = &g.NavMoveResult;
|
ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
|
||||||
#if IMGUI_DEBUG_NAV_SCORING
|
#if IMGUI_DEBUG_NAV_SCORING
|
||||||
// [DEBUG] Score all items in NavWindow at all times
|
// [DEBUG] Score all items in NavWindow at all times
|
||||||
if (!g.NavMoveRequest)
|
if (!g.NavMoveRequest)
|
||||||
@ -2333,8 +2339,9 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
|
|||||||
// it may not scale very well for windows with ten of thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
|
// it may not scale very well for windows with ten of thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
|
||||||
// We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick)
|
// We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick)
|
||||||
window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask;
|
window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask;
|
||||||
if (g.NavWindow == window->NavRootWindow)
|
|
||||||
if (g.NavId == id || g.NavAnyRequest)
|
if (g.NavId == id || g.NavAnyRequest)
|
||||||
|
if (g.NavWindow->NavRootWindow == window->NavRootWindow)
|
||||||
|
if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
|
||||||
NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id);
|
NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2883,9 +2890,14 @@ static void ImGui::NavUpdate()
|
|||||||
g.NavJustMovedToId = 0;
|
g.NavJustMovedToId = 0;
|
||||||
|
|
||||||
// Process navigation move request
|
// Process navigation move request
|
||||||
if (g.NavMoveRequest && g.NavMoveResult.ID != 0)
|
if (g.NavMoveRequest && (g.NavMoveResultLocal.ID != 0 || g.NavMoveResultOther.ID != 0))
|
||||||
{
|
{
|
||||||
ImGuiNavMoveResult* result = &g.NavMoveResult;
|
// Select which result to use
|
||||||
|
ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
|
||||||
|
if (g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow) // Maybe entering a flattened child? In this case solve the tie using the regular scoring rules
|
||||||
|
if ((g.NavMoveResultOther.DistBox < g.NavMoveResultLocal.DistBox) || (g.NavMoveResultOther.DistBox == g.NavMoveResultLocal.DistBox && g.NavMoveResultOther.DistCenter < g.NavMoveResultLocal.DistCenter))
|
||||||
|
result = &g.NavMoveResultOther;
|
||||||
|
|
||||||
IM_ASSERT(g.NavWindow && result->Window);
|
IM_ASSERT(g.NavWindow && result->Window);
|
||||||
|
|
||||||
// Scroll to keep newly navigated item fully into view
|
// Scroll to keep newly navigated item fully into view
|
||||||
@ -2894,6 +2906,7 @@ static void ImGui::NavUpdate()
|
|||||||
|
|
||||||
// Apply result from previous frame navigation directional move request
|
// Apply result from previous frame navigation directional move request
|
||||||
ClearActiveID();
|
ClearActiveID();
|
||||||
|
g.NavWindow = result->Window;
|
||||||
SetNavIDAndMoveMouse(result->ID, g.NavLayer, result->RectRel);
|
SetNavIDAndMoveMouse(result->ID, g.NavLayer, result->RectRel);
|
||||||
g.NavJustMovedToId = result->ID;
|
g.NavJustMovedToId = result->ID;
|
||||||
g.NavMoveFromClampedRefRect = false;
|
g.NavMoveFromClampedRefRect = false;
|
||||||
@ -2903,7 +2916,7 @@ static void ImGui::NavUpdate()
|
|||||||
if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
|
if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
|
||||||
{
|
{
|
||||||
IM_ASSERT(g.NavMoveRequest);
|
IM_ASSERT(g.NavMoveRequest);
|
||||||
if (g.NavMoveResult.ID == 0)
|
if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
|
||||||
g.NavDisableHighlight = false;
|
g.NavDisableHighlight = false;
|
||||||
g.NavMoveRequestForward = ImGuiNavForward_None;
|
g.NavMoveRequestForward = ImGuiNavForward_None;
|
||||||
}
|
}
|
||||||
@ -3061,11 +3074,9 @@ static void ImGui::NavUpdate()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset search
|
// Reset search results
|
||||||
ImGuiNavMoveResult* result = &g.NavMoveResult;
|
g.NavMoveResultLocal.Clear();
|
||||||
result->ID = result->ParentID = 0;
|
g.NavMoveResultOther.Clear();
|
||||||
result->Window = NULL;
|
|
||||||
result->DistAxial = result->DistBox = result->DistCenter = FLT_MAX;
|
|
||||||
|
|
||||||
// When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items
|
// When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items
|
||||||
if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0)
|
if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0)
|
||||||
@ -4826,7 +4837,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla
|
|||||||
static void NavProcessMoveRequestWrapAround(ImGuiWindow* window)
|
static void NavProcessMoveRequestWrapAround(ImGuiWindow* window)
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
if (g.NavMoveRequest && g.NavWindow == window && g.NavMoveResult.ID == 0)
|
if (g.NavWindow == window && NavMoveRequestButNoResultYet())
|
||||||
if ((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == 0)
|
if ((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == 0)
|
||||||
{
|
{
|
||||||
g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
|
g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
|
||||||
@ -4928,7 +4939,7 @@ static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, b
|
|||||||
g.Style.ChildBorderSize = backup_border_size;
|
g.Style.ChildBorderSize = backup_border_size;
|
||||||
|
|
||||||
// Process navigation-in immediately so NavInit can run on first frame
|
// Process navigation-in immediately so NavInit can run on first frame
|
||||||
if (/*!(flags & ImGuiWindowFlags_NavFlattened) &&*/ (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll) && g.NavActivateId == id)
|
if (!(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll) && g.NavActivateId == id)
|
||||||
{
|
{
|
||||||
ImGui::FocusWindow(child_window);
|
ImGui::FocusWindow(child_window);
|
||||||
ImGui::NavInitWindow(child_window, false);
|
ImGui::NavInitWindow(child_window, false);
|
||||||
@ -4972,7 +4983,7 @@ void ImGui::EndChild()
|
|||||||
ImGuiWindow* parent_window = GetCurrentWindow();
|
ImGuiWindow* parent_window = GetCurrentWindow();
|
||||||
ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
|
ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
|
||||||
ItemSize(sz);
|
ItemSize(sz);
|
||||||
if (/*!(window->Flags & ImGuiWindowFlags_NavFlattened) &&*/ (window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll))
|
if (!(window->Flags & ImGuiWindowFlags_NavFlattened) && (window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll))
|
||||||
{
|
{
|
||||||
ItemAdd(bb, window->ChildId);
|
ItemAdd(bb, window->ChildId);
|
||||||
RenderNavHighlight(bb, window->ChildId);
|
RenderNavHighlight(bb, window->ChildId);
|
||||||
@ -5420,8 +5431,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|||||||
// Automatically disable manual moving/resizing when NoInputs is set
|
// Automatically disable manual moving/resizing when NoInputs is set
|
||||||
if (flags & ImGuiWindowFlags_NoInputs)
|
if (flags & ImGuiWindowFlags_NoInputs)
|
||||||
flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
|
flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
|
||||||
//if (flags & ImGuiWindowFlags_NavFlattened)
|
|
||||||
// IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow);
|
if (flags & ImGuiWindowFlags_NavFlattened)
|
||||||
|
IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow);
|
||||||
|
|
||||||
const int current_frame = g.FrameCount;
|
const int current_frame = g.FrameCount;
|
||||||
const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
|
const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
|
||||||
@ -5529,8 +5541,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|||||||
if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
|
if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
|
||||||
window->RootNonPopupWindow = parent_window->RootNonPopupWindow;
|
window->RootNonPopupWindow = parent_window->RootNonPopupWindow;
|
||||||
window->NavRootWindow = window;
|
window->NavRootWindow = window;
|
||||||
//while (window->NavRootWindow->Flags & ImGuiWindowFlags_NavFlattened)
|
while (window->NavRootWindow->Flags & ImGuiWindowFlags_NavFlattened)
|
||||||
// window->NavRootWindow = window->NavRootWindow->ParentWindow;
|
window->NavRootWindow = window->NavRootWindow->ParentWindow;
|
||||||
|
|
||||||
window->Active = true;
|
window->Active = true;
|
||||||
window->BeginOrderWithinParent = 0;
|
window->BeginOrderWithinParent = 0;
|
||||||
@ -10861,7 +10873,7 @@ void ImGui::EndMenuBar()
|
|||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
|
|
||||||
// Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings.
|
// Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings.
|
||||||
if (g.NavMoveRequest && g.NavMoveResult.ID == 0 && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
|
if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
|
||||||
{
|
{
|
||||||
ImGuiWindow* nav_earliest_child = g.NavWindow;
|
ImGuiWindow* nav_earliest_child = g.NavWindow;
|
||||||
while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu))
|
while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu))
|
||||||
@ -11029,7 +11041,7 @@ void ImGui::EndMenu()
|
|||||||
// Nav: When a left move request within our child menu failed, close the menu
|
// Nav: When a left move request within our child menu failed, close the menu
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
ImGuiWindow* window = g.CurrentWindow;
|
ImGuiWindow* window = g.CurrentWindow;
|
||||||
if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveRequest && g.NavMoveResult.ID == 0 && g.NavMoveDir == ImGuiDir_Left && window->DC.LayoutType == ImGuiLayoutType_Vertical)
|
if (g.NavWindow && g.NavWindow->ParentWindow == window && NavMoveRequestButNoResultYet() && g.NavMoveDir == ImGuiDir_Left && window->DC.LayoutType == ImGuiLayoutType_Vertical)
|
||||||
{
|
{
|
||||||
ClosePopupToLevel(g.OpenPopupStack.Size - 1);
|
ClosePopupToLevel(g.OpenPopupStack.Size - 1);
|
||||||
NavMoveRequestCancel();
|
NavMoveRequestCancel();
|
||||||
|
2
imgui.h
2
imgui.h
@ -552,9 +552,9 @@ enum ImGuiWindowFlags_
|
|||||||
ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // (WIP) Enable resize from any corners and borders. Your back-end needs to honor the different values of io.MouseCursor set by imgui.
|
ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // (WIP) Enable resize from any corners and borders. Your back-end needs to honor the different values of io.MouseCursor set by imgui.
|
||||||
ImGuiWindowFlags_NoNavFocus = 1 << 18, // No focusing of this window with gamepad/keyboard navigation
|
ImGuiWindowFlags_NoNavFocus = 1 << 18, // No focusing of this window with gamepad/keyboard navigation
|
||||||
ImGuiWindowFlags_NoNavInputs = 1 << 19, // No gamepad/keyboard navigation within the window
|
ImGuiWindowFlags_NoNavInputs = 1 << 19, // No gamepad/keyboard navigation within the window
|
||||||
//ImGuiWindowFlags_NavFlattened = 1 << 20, // Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!)
|
|
||||||
|
|
||||||
// [Internal]
|
// [Internal]
|
||||||
|
ImGuiWindowFlags_NavFlattened = 1 << 20, // (WIP) Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!)
|
||||||
ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild()
|
ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild()
|
||||||
ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip()
|
ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip()
|
||||||
ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup()
|
ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup()
|
||||||
|
@ -2148,7 +2148,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
|
|||||||
ImGui::RadioButton("Alpha", &alpha_flags, ImGuiColorEditFlags_AlphaPreview); ImGui::SameLine();
|
ImGui::RadioButton("Alpha", &alpha_flags, ImGuiColorEditFlags_AlphaPreview); ImGui::SameLine();
|
||||||
ImGui::RadioButton("Both", &alpha_flags, ImGuiColorEditFlags_AlphaPreviewHalf);
|
ImGui::RadioButton("Both", &alpha_flags, ImGuiColorEditFlags_AlphaPreviewHalf);
|
||||||
|
|
||||||
ImGui::BeginChild("#colors", ImVec2(0, 300), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
|
ImGui::BeginChild("#colors", ImVec2(0, 300), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
|
||||||
ImGui::PushItemWidth(-160);
|
ImGui::PushItemWidth(-160);
|
||||||
for (int i = 0; i < ImGuiCol_COUNT; i++)
|
for (int i = 0; i < ImGuiCol_COUNT; i++)
|
||||||
{
|
{
|
||||||
|
@ -514,7 +514,8 @@ struct ImGuiNavMoveResult
|
|||||||
float DistAxial;
|
float DistAxial;
|
||||||
ImRect RectRel; // Best candidate bounding box in window relative space
|
ImRect RectRel; // Best candidate bounding box in window relative space
|
||||||
|
|
||||||
ImGuiNavMoveResult() { ID = ParentID = 0; Window = NULL; DistBox = DistCenter = DistAxial = 0.0f; }
|
ImGuiNavMoveResult() { Clear(); }
|
||||||
|
void Clear() { ID = ParentID = 0; Window = NULL; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Storage for SetNexWindow** functions
|
// Storage for SetNexWindow** functions
|
||||||
@ -633,7 +634,8 @@ struct ImGuiContext
|
|||||||
ImGuiNavForward NavMoveRequestForward; // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu)
|
ImGuiNavForward NavMoveRequestForward; // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu)
|
||||||
ImGuiDir NavMoveDir; // Direction of the move request (left/right/up/down)
|
ImGuiDir NavMoveDir; // Direction of the move request (left/right/up/down)
|
||||||
ImGuiDir NavMoveDirLast; // Direction of the previous move request
|
ImGuiDir NavMoveDirLast; // Direction of the previous move request
|
||||||
ImGuiNavMoveResult NavMoveResult; // Best move request candidate
|
ImGuiNavMoveResult NavMoveResultLocal; // Best move request candidate within NavWindow
|
||||||
|
ImGuiNavMoveResult NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using the NavFlattened flag)
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
ImDrawData DrawData; // Main ImDrawData instance to pass render information to the user
|
ImDrawData DrawData; // Main ImDrawData instance to pass render information to the user
|
||||||
|
Loading…
Reference in New Issue
Block a user