mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-11-04 07:01:04 +01: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:
		
							
								
								
									
										76
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										76
									
								
								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,8 +7082,7 @@ void ImGui::End()
 | 
			
		||||
    if (window->DC.CurrentColumns)
 | 
			
		||||
        EndColumns();
 | 
			
		||||
    PopClipRect();   // Inner window clip rectangle
 | 
			
		||||
    if ((window->Flags & ImGuiWindowFlags_NavFlattened) == 0)
 | 
			
		||||
        PopFocusScope();
 | 
			
		||||
    PopFocusScope();
 | 
			
		||||
 | 
			
		||||
    // Stop logging
 | 
			
		||||
    if (!(window->Flags & ImGuiWindowFlags_ChildWindow))    // FIXME: add more options for scope of 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();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user