mirror of
https://github.com/ocornut/imgui.git
synced 2024-11-27 16:29:02 +08:00
Shortcut()/SetShortcutRouting(): use mixed current window focus scope + ParentWindowForFocusRoute. (#6798, #2637, #456)
Amend d474836 Begin: tweak clearing of CurrentWindow as FocusWindow() relies on it now. Addded SetWindowParentWindowForFocusRoute() helper.
This commit is contained in:
parent
e0c8c80ada
commit
46e5f44ec8
74
imgui.cpp
74
imgui.cpp
@ -6439,13 +6439,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
}
|
||||
|
||||
// Add to focus scope stack
|
||||
if ((flags & ImGuiWindowFlags_NavFlattened) == 0)
|
||||
PushFocusScope(window->ID);
|
||||
PushFocusScope((flags & ImGuiWindowFlags_NavFlattened) ? g.CurrentFocusScopeId : window->ID);
|
||||
window->NavRootFocusScopeId = g.CurrentFocusScopeId;
|
||||
|
||||
// We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
|
||||
g.CurrentWindow = NULL;
|
||||
|
||||
// Add to popup stack
|
||||
if (flags & ImGuiWindowFlags_Popup)
|
||||
{
|
||||
@ -6510,6 +6506,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
if (window->Appearing)
|
||||
SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
|
||||
|
||||
// We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
|
||||
g.CurrentWindow = NULL;
|
||||
|
||||
// When reusing window again multiple times a frame, just append content (don't need to setup again)
|
||||
if (first_begin_of_the_frame)
|
||||
{
|
||||
@ -7083,7 +7082,6 @@ void ImGui::End()
|
||||
if (window->DC.CurrentColumns)
|
||||
EndColumns();
|
||||
PopClipRect(); // Inner window clip rectangle
|
||||
if ((window->Flags & ImGuiWindowFlags_NavFlattened) == 0)
|
||||
PopFocusScope();
|
||||
|
||||
// Stop logging
|
||||
@ -7209,7 +7207,7 @@ void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags)
|
||||
g.NavMousePosDirty = true;
|
||||
g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
|
||||
g.NavLayer = ImGuiNavLayer_Main;
|
||||
g.NavFocusScopeId = window ? window->NavRootFocusScopeId : 0;
|
||||
SetNavFocusScope(window ? window->NavRootFocusScopeId : 0);
|
||||
g.NavIdIsAlive = false;
|
||||
g.NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid;
|
||||
|
||||
@ -7822,6 +7820,33 @@ void ImGui::PopFocusScope()
|
||||
g.CurrentFocusScopeId = g.FocusScopeStack.Size ? g.FocusScopeStack.back().ID : 0;
|
||||
}
|
||||
|
||||
void ImGui::SetNavFocusScope(ImGuiID focus_scope_id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.NavFocusScopeId = focus_scope_id;
|
||||
g.NavFocusScopePath.resize(0); // Invalidate
|
||||
if (focus_scope_id == 0)
|
||||
return;
|
||||
IM_ASSERT(g.NavWindow != NULL);
|
||||
|
||||
// Store current path (in reverse order)
|
||||
if (focus_scope_id == g.CurrentFocusScopeId)
|
||||
{
|
||||
// Top of focus stack contains local focus scopes inside current window
|
||||
for (int n = g.FocusScopeStack.Size - 1; n >= 0 && g.FocusScopeStack.Data[n].WindowID == g.CurrentWindow->ID; n--)
|
||||
g.NavFocusScopePath.push_back(g.FocusScopeStack.Data[n]);
|
||||
}
|
||||
else if (focus_scope_id == g.NavWindow->NavRootFocusScopeId)
|
||||
g.NavFocusScopePath.push_back({ focus_scope_id, g.NavWindow->ID });
|
||||
else
|
||||
return;
|
||||
|
||||
// Then follow on manually set ParentWindowForFocusRoute field (#6798)
|
||||
for (ImGuiWindow* window = g.NavWindow->ParentWindowForFocusRoute; window != NULL; window = window->ParentWindowForFocusRoute)
|
||||
g.NavFocusScopePath.push_back({ window->NavRootFocusScopeId, window->ID });
|
||||
IM_ASSERT(g.NavFocusScopePath.Size < 100); // Maximum depth is technically 251 as per CalcRoutingScore(): 254 - 3
|
||||
}
|
||||
|
||||
// Focus = move navigation cursor, set scrolling, set focus window.
|
||||
void ImGui::FocusItem()
|
||||
{
|
||||
@ -8318,12 +8343,11 @@ ImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord)
|
||||
// - 254: ImGuiInputFlags_RouteGlobalLow
|
||||
// - 255: never route
|
||||
// 'flags' should include an explicit routing policy
|
||||
static int CalcRoutingScore(ImGuiWindow* location, ImGuiID owner_id, ImGuiInputFlags flags)
|
||||
static int CalcRoutingScore(ImGuiID focus_scope_id, ImGuiID owner_id, ImGuiInputFlags flags)
|
||||
{
|
||||
if (flags & ImGuiInputFlags_RouteFocused)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* focused = g.NavWindow;
|
||||
|
||||
// ActiveID gets top priority
|
||||
// (we don't check g.ActiveIdUsingAllKeys here. Routing is applied but if input ownership is tested later it may discard it)
|
||||
@ -8336,13 +8360,12 @@ static int CalcRoutingScore(ImGuiWindow* location, ImGuiID owner_id, ImGuiInputF
|
||||
// - When Window/ChildB is focused -> Window scores 4, Window/ChildB scores 3 (best)
|
||||
// Assuming only WindowA is submitting a routing request,
|
||||
// - When Window/ChildB is focused -> Window scores 4 (best), Window/ChildB doesn't have a score.
|
||||
// FIXME: This could be later abstracted as a focus path
|
||||
for (int next_score = 3; focused != NULL; next_score++, focused = focused->ParentWindowForFocusRoute)
|
||||
if (focused == location)
|
||||
{
|
||||
IM_ASSERT(next_score < 255);
|
||||
return next_score;
|
||||
}
|
||||
if (focus_scope_id == 0)
|
||||
return 255;
|
||||
for (int index_in_focus_path = 0; index_in_focus_path < g.NavFocusScopePath.Size; index_in_focus_path++)
|
||||
if (g.NavFocusScopePath.Data[index_in_focus_path].ID == focus_scope_id)
|
||||
return 3 + index_in_focus_path;
|
||||
|
||||
return 255;
|
||||
}
|
||||
|
||||
@ -8383,7 +8406,7 @@ bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiI
|
||||
return true;
|
||||
}
|
||||
|
||||
const int score = CalcRoutingScore(g.CurrentWindow, owner_id, flags);
|
||||
const int score = CalcRoutingScore(g.CurrentFocusScopeId, owner_id, flags);
|
||||
IMGUI_DEBUG_LOG_INPUTROUTING("SetShortcutRouting(%s, owner_id=0x%08X, flags=%04X) -> score %d\n", GetKeyChordName(key_chord), owner_id, flags, score);
|
||||
if (score == 255)
|
||||
return false;
|
||||
@ -11095,7 +11118,7 @@ void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id
|
||||
IM_ASSERT(nav_layer == ImGuiNavLayer_Main || nav_layer == ImGuiNavLayer_Menu);
|
||||
g.NavId = id;
|
||||
g.NavLayer = nav_layer;
|
||||
g.NavFocusScopeId = focus_scope_id;
|
||||
SetNavFocusScope(focus_scope_id);
|
||||
g.NavWindow->NavLastIds[nav_layer] = id;
|
||||
g.NavWindow->NavRectRel[nav_layer] = rect_rel;
|
||||
|
||||
@ -11117,7 +11140,7 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
|
||||
const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent;
|
||||
g.NavId = id;
|
||||
g.NavLayer = nav_layer;
|
||||
g.NavFocusScopeId = g.CurrentFocusScopeId;
|
||||
SetNavFocusScope(g.CurrentFocusScopeId);
|
||||
window->NavLastIds[nav_layer] = id;
|
||||
if (g.LastItemData.ID == id)
|
||||
window->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect);
|
||||
@ -11375,6 +11398,7 @@ static void ImGui::NavProcessItem()
|
||||
if (g.NavWindow != window)
|
||||
SetNavWindow(window); // Always refresh g.NavWindow, because some operations such as FocusItem() may not have a window.
|
||||
g.NavLayer = window->DC.NavLayerCurrent;
|
||||
SetNavFocusScope(g.CurrentFocusScopeId); // Will set g.NavFocusScopeId AND store g.NavFocusScopePath
|
||||
g.NavFocusScopeId = g.CurrentFocusScopeId;
|
||||
g.NavIdIsAlive = true;
|
||||
if (g.LastItemData.InFlags & ImGuiItemFlags_HasSelectionUserData)
|
||||
@ -11604,7 +11628,7 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
|
||||
if (window->Flags & ImGuiWindowFlags_NoNavInputs)
|
||||
{
|
||||
g.NavId = 0;
|
||||
g.NavFocusScopeId = window->NavRootFocusScopeId;
|
||||
SetNavFocusScope(window->NavRootFocusScopeId);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -11623,7 +11647,7 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
|
||||
else
|
||||
{
|
||||
g.NavId = window->NavLastIds[0];
|
||||
g.NavFocusScopeId = window->NavRootFocusScopeId;
|
||||
SetNavFocusScope(window->NavRootFocusScopeId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -14507,6 +14531,14 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
Text("NavActivateFlags: %04X", g.NavActivateFlags);
|
||||
Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover);
|
||||
Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId);
|
||||
Text("NavFocusScopePath[] = ");
|
||||
for (int path_n = g.NavFocusScopePath.Size - 1; path_n >= 0; path_n--)
|
||||
{
|
||||
const ImGuiFocusScopeData& focus_scope = g.NavFocusScopePath[path_n];
|
||||
SameLine(0.0f, 0.0f);
|
||||
Text("0x%08X/", focus_scope.ID);
|
||||
SetItemTooltip("In window \"%s\"", FindWindowByID(focus_scope.WindowID)->Name);
|
||||
}
|
||||
Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL");
|
||||
Unindent();
|
||||
|
||||
|
@ -2003,6 +2003,7 @@ struct ImGuiContext
|
||||
ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow'
|
||||
ImGuiID NavId; // Focused item for navigation
|
||||
ImGuiID NavFocusScopeId; // Focused focus scope (e.g. selection code often wants to "clear other items" when landing on an item of the same scope)
|
||||
ImVector<ImGuiFocusScopeData> NavFocusScopePath; // Reversed copy focus scope stack for NavId (should contains NavFocusScopeId)
|
||||
ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItem()
|
||||
ImGuiID NavActivateDownId; // ~~ IsKeyDown(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyDown(ImGuiKey_NavGamepadActivate) ? NavId : 0
|
||||
ImGuiID NavActivatePressedId; // ~~ IsKeyPressed(ImGuiKey_Space) || IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate) ? NavId : 0 (no repeat)
|
||||
@ -2952,6 +2953,7 @@ namespace ImGui
|
||||
IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond = 0);
|
||||
IMGUI_API void SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size);
|
||||
IMGUI_API void SetWindowHiddenAndSkipItemsForCurrentFrame(ImGuiWindow* window);
|
||||
inline void SetWindowParentWindowForFocusRoute(ImGuiWindow* window, ImGuiWindow* parent_window) { window->ParentWindowForFocusRoute = parent_window; }
|
||||
inline ImRect WindowRectAbsToRel(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x - off.x, r.Min.y - off.y, r.Max.x - off.x, r.Max.y - off.y); }
|
||||
inline ImRect WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); }
|
||||
inline ImVec2 WindowPosRelToAbs(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x + off.x, p.y + off.y); }
|
||||
@ -3110,6 +3112,7 @@ namespace ImGui
|
||||
IMGUI_API void NavUpdateCurrentWindowIsScrollPushableX();
|
||||
IMGUI_API void SetNavWindow(ImGuiWindow* window);
|
||||
IMGUI_API void SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel);
|
||||
IMGUI_API void SetNavFocusScope(ImGuiID focus_scope_id);
|
||||
|
||||
// Focus/Activation
|
||||
// This should be part of a larger set of API: FocusItem(offset = -1), FocusItemByID(id), ActivateItem(offset = -1), ActivateItemByID(id) etc. which are
|
||||
|
Loading…
Reference in New Issue
Block a user