diff --git a/dep/imgui/src/imgui.cpp b/dep/imgui/src/imgui.cpp index af082444b..b26edc46e 100644 --- a/dep/imgui/src/imgui.cpp +++ b/dep/imgui/src/imgui.cpp @@ -12776,6 +12776,8 @@ static void ImGui::NavUpdateCancelRequest() // Close open popup/menu ClosePopupToLevel(g.OpenPopupStack.Size - 1, true); } +#if 0 + // DUCKSTATION-CHANGE: We want to keep nav active, since we handle menu exits ourselves. else { // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were @@ -12783,6 +12785,7 @@ static void ImGui::NavUpdateCancelRequest() g.NavWindow->NavLastIds[0] = 0; g.NavId = 0; } +#endif } // Handle PageUp/PageDown/Home/End keys diff --git a/src/core/achievements.cpp b/src/core/achievements.cpp index 869c9f82b..8a9cabafd 100644 --- a/src/core/achievements.cpp +++ b/src/core/achievements.cpp @@ -2482,8 +2482,8 @@ void Achievements::DrawAchievementsWindow() TRANSLATE_NOOP("Achievements", "Active Challenges"), TRANSLATE_NOOP("Achievements", "Almost There"), }; - ImGuiFullscreen::BeginMenuButtons(); ImGuiFullscreen::ResetFocusHere(); + ImGuiFullscreen::BeginMenuButtons(); for (u32 bucket_type : {RC_CLIENT_ACHIEVEMENT_BUCKET_ACTIVE_CHALLENGE, RC_CLIENT_ACHIEVEMENT_BUCKET_RECENTLY_UNLOCKED, RC_CLIENT_ACHIEVEMENT_BUCKET_UNLOCKED, @@ -2948,8 +2948,8 @@ void Achievements::DrawLeaderboardsWindow() ImVec2(display_size.x, display_size.y - heading_height - LayoutScale(ImGuiFullscreen::LAYOUT_FOOTER_HEIGHT)), "leaderboards", background, 0.0f, ImVec2(ImGuiFullscreen::LAYOUT_MENU_WINDOW_X_PADDING, 0.0f), 0)) { - ImGuiFullscreen::BeginMenuButtons(); ImGuiFullscreen::ResetFocusHere(); + ImGuiFullscreen::BeginMenuButtons(); for (u32 bucket_index = 0; bucket_index < s_leaderboard_list->num_buckets; bucket_index++) { @@ -2969,14 +2969,19 @@ void Achievements::DrawLeaderboardsWindow() ImVec2(display_size.x, display_size.y - heading_height - LayoutScale(ImGuiFullscreen::LAYOUT_FOOTER_HEIGHT)), "leaderboard", background, 0.0f, ImVec2(ImGuiFullscreen::LAYOUT_MENU_WINDOW_X_PADDING, 0.0f), 0)) { + // Defer focus reset until loading finishes. + if (!s_is_showing_all_leaderboard_entries || + (ImGuiFullscreen::IsFocusResetFromWindowChange() && !s_leaderboard_entry_lists.empty())) + { + ImGuiFullscreen::ResetFocusHere(); + } + ImGuiFullscreen::BeginMenuButtons(); if (!s_is_showing_all_leaderboard_entries) { if (s_leaderboard_nearby_entries) { - ImGuiFullscreen::ResetFocusHere(); - for (u32 i = 0; i < s_leaderboard_nearby_entries->num_entries; i++) { DrawLeaderboardEntry(s_leaderboard_nearby_entries->entries[i], @@ -2999,9 +3004,6 @@ void Achievements::DrawLeaderboardsWindow() } else { - if (ImGuiFullscreen::IsFocusResetFromWindowChange() && !s_leaderboard_entry_lists.empty()) - ImGuiFullscreen::ResetFocusHere(); - for (const rc_client_leaderboard_entry_list_t* list : s_leaderboard_entry_lists) { for (u32 i = 0; i < list->num_entries; i++) diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp index 7da559095..3b0f0be2f 100644 --- a/src/core/fullscreen_ui.cpp +++ b/src/core/fullscreen_ui.cpp @@ -5345,10 +5345,10 @@ void FullscreenUI::DrawPauseMenu() 3, // Achievements }; + ResetFocusHere(); BeginMenuButtons(submenu_item_count[static_cast(s_current_pause_submenu)], 1.0f, ImGuiFullscreen::LAYOUT_MENU_BUTTON_X_PADDING, ImGuiFullscreen::LAYOUT_MENU_BUTTON_Y_PADDING, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); - ResetFocusHere(); switch (s_current_pause_submenu) { @@ -5617,6 +5617,7 @@ bool FullscreenUI::OpenSaveStateSelector(bool is_loading) if (PopulateSaveStateListEntries(System::GetGameTitle(), System::GetGameSerial()) > 0) { s_save_state_selector_open = true; + QueueResetFocus(FocusResetType::PopupOpened); return true; } @@ -5626,6 +5627,9 @@ bool FullscreenUI::OpenSaveStateSelector(bool is_loading) void FullscreenUI::CloseSaveStateSelector() { + if (s_save_state_selector_open) + QueueResetFocus(FocusResetType::PopupClosed); + ClearSaveStateEntryList(); s_save_state_selector_open = false; s_save_state_selector_loading = false; @@ -5674,14 +5678,13 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading) ImGui::PushStyleColor(ImGuiCol_ChildBg, ModAlpha(UIPrimaryColor, 0.9f)); + bool closed = false; + bool was_close_not_back = false; if (ImGui::BeginChild("state_titlebar", heading_size, false, ImGuiWindowFlags_NavFlattened)) { BeginNavBar(); if (NavButton(ICON_FA_BACKWARD, true, true)) - { - CloseSaveStateSelector(); - ReturnToPreviousWindow(); - } + closed = true; NavTitle(is_loading ? FSUI_CSTR("Load State") : FSUI_CSTR("Save State")); EndNavBar(); @@ -5692,13 +5695,15 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading) ImGui::PushStyleColor(ImGuiCol_ChildBg, ModAlpha(UIBackgroundColor, 0.9f)); ImGui::SetCursorPos(ImVec2(0.0f, heading_size.y)); - bool closed = false; - bool close_handled = false; - if (s_save_state_selector_open && - ImGui::BeginChild("state_list", + if (IsFocusResetFromWindowChange()) + ImGui::SetNextWindowScroll(ImVec2(0.0f, 0.0f)); + + + if (ImGui::BeginChild("state_list", ImVec2(io.DisplaySize.x, io.DisplaySize.y - LayoutScale(LAYOUT_FOOTER_HEIGHT) - heading_size.y), false, ImGuiWindowFlags_NavFlattened)) { + ResetFocusHere(); BeginMenuButtons(); const ImGuiStyle& style = ImGui::GetStyle(); @@ -5723,9 +5728,6 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading) ImGui::SetCursorPos(ImVec2(start_x, 0.0f)); for (u32 i = 0; i < s_save_state_selector_slots.size();) { - if (i == 0) - ResetFocusHere(); - SaveStateListEntry& entry = s_save_state_selector_slots[i]; if (static_cast(i) == s_save_state_selector_submenu_index) { @@ -5768,6 +5770,7 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading) DoSaveState(entry.slot, entry.global); closed = true; + was_close_not_back = true; } if (!entry.path.empty() && ActiveButton(FSUI_ICONSTR(ICON_FA_FOLDER_MINUS, "Delete Save"), false, true, @@ -5785,9 +5788,14 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading) removed = true; if (s_save_state_selector_slots.empty()) + { closed = true; + was_close_not_back = true; + } else + { is_open = false; + } } else { @@ -5808,19 +5816,8 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading) ImGui::EndPopup(); } - // don't let the back button flow through to the main window - if (WantsToCloseMenu()) - { - close_handled = true; - is_open = false; - } - - if (!is_open || closed) - { + if (!is_open) s_save_state_selector_submenu_index = -1; - if (!closed) - QueueResetFocus(FocusResetType::ViewChanged); - } ImGui::PopStyleColor(3); ImGui::PopStyleVar(3); @@ -5896,6 +5893,7 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading) DoSaveState(entry.slot, entry.global); closed = true; + was_close_not_back = true; } else if (hovered && (ImGui::IsItemClicked(ImGuiMouseButton_Right) || ImGui::IsKeyPressed(ImGuiKey_NavGamepadMenu, false) || @@ -5929,33 +5927,29 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading) ImGui::EndPopup(); ImGui::PopStyleVar(5); - if (closed) + if (IsGamepadInputSource()) { - CloseSaveStateSelector(); - ReturnToMainWindow(); - } - else if (!close_handled && WantsToCloseMenu()) - { - CloseSaveStateSelector(); - ReturnToPreviousWindow(); + SetFullscreenFooterText(std::array{std::make_pair(ICON_PF_XBOX_DPAD, FSUI_VSTR("Select State")), + std::make_pair(ICON_PF_BUTTON_Y, FSUI_VSTR("Delete State")), + std::make_pair(ICON_PF_BUTTON_A, FSUI_VSTR("Load State")), + std::make_pair(ICON_PF_BUTTON_B, FSUI_VSTR("Cancel"))}); } else { - if (IsGamepadInputSource()) - { - SetFullscreenFooterText(std::array{std::make_pair(ICON_PF_XBOX_DPAD, FSUI_VSTR("Select State")), - std::make_pair(ICON_PF_BUTTON_Y, FSUI_VSTR("Delete State")), - std::make_pair(ICON_PF_BUTTON_A, FSUI_VSTR("Load State")), - std::make_pair(ICON_PF_BUTTON_B, FSUI_VSTR("Cancel"))}); - } - else - { - SetFullscreenFooterText(std::array{ - std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT, - FSUI_VSTR("Select State")), - std::make_pair(ICON_PF_F1, FSUI_VSTR("Delete State")), std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Load State")), - std::make_pair(ICON_PF_ESC, FSUI_VSTR("Cancel"))}); - } + SetFullscreenFooterText(std::array{ + std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT, + FSUI_VSTR("Select State")), + std::make_pair(ICON_PF_F1, FSUI_VSTR("Delete State")), std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Load State")), + std::make_pair(ICON_PF_ESC, FSUI_VSTR("Cancel"))}); + } + + if (WantsToCloseMenu() || closed) + { + CloseSaveStateSelector(); + if (was_close_not_back) + ReturnToMainWindow(); + else if (s_current_main_window != MainWindowType::GameList) + ReturnToPreviousWindow(); } } @@ -5971,6 +5965,7 @@ bool FullscreenUI::OpenLoadStateSelectorForGameResume(const GameList::Entry* ent s_save_state_selector_loading = true; s_save_state_selector_open = true; s_save_state_selector_resuming = true; + QueueResetFocus(FocusResetType::PopupOpened); return true; } @@ -6313,6 +6308,9 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size) const GameList::Entry* selected_entry = nullptr; PopulateGameListEntryList(); + if (IsFocusResetFromWindowChange()) + ImGui::SetNextWindowScroll(ImVec2(0.0f, 0.0f)); + if (BeginFullscreenColumnWindow(0.0f, -530.0f, "game_list_entries")) { const ImVec2 image_size(LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT, LAYOUT_MENU_BUTTON_HEIGHT)); @@ -6509,6 +6507,9 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size) void FullscreenUI::DrawGameGrid(const ImVec2& heading_size) { + if (IsFocusResetFromWindowChange()) + ImGui::SetNextWindowScroll(ImVec2(0.0f, 0.0f)); + ImGuiIO& io = ImGui::GetIO(); if (!BeginFullscreenWindow( ImVec2(0.0f, heading_size.y), diff --git a/src/util/imgui_fullscreen.cpp b/src/util/imgui_fullscreen.cpp index 3255d25eb..454c7534c 100644 --- a/src/util/imgui_fullscreen.cpp +++ b/src/util/imgui_fullscreen.cpp @@ -593,12 +593,17 @@ bool ImGuiFullscreen::ResetFocusHere() if (ImGui::FindBlockingModal(window)) return false; - // Only fully reset the window on window change, that way setting page changes don't spend a frame without focus. - if (s_focus_reset_queued == FocusResetType::ViewChanged) - window->LastFrameActive = 0; - s_focus_reset_queued = FocusResetType::None; + // Set the flag that we drew an active/hovered item active for a frame, because otherwise there's one frame where + // there'll be no frame drawn, which will cancel the animation. Also set the appearing flag, so that the default + // focus set does actually go through. + if (!GImGui->NavDisableHighlight && GImGui->NavDisableMouseHover) + { + window->Appearing = true; + s_has_hovered_menu_item = s_had_hovered_menu_item; + } + ImGui::SetWindowFocus(); ImGui::NavInitWindow(window, true); @@ -613,8 +618,7 @@ bool ImGuiFullscreen::IsFocusResetQueued() bool ImGuiFullscreen::IsFocusResetFromWindowChange() { - return (s_focus_reset_queued != FocusResetType::None && s_focus_reset_queued != FocusResetType::PopupOpened && - s_focus_reset_queued != FocusResetType::PopupClosed); + return (s_focus_reset_queued != FocusResetType::None && s_focus_reset_queued != FocusResetType::PopupClosed); } ImGuiFullscreen::FocusResetType ImGuiFullscreen::GetQueuedFocusResetType() @@ -2181,6 +2185,9 @@ void ImGuiFullscreen::CloseFileSelector() if (!s_file_selector_open) return; + if (ImGui::IsPopupOpen(s_file_selector_title.c_str(), 0)) + ImGui::ClosePopupToLevel(GImGui->OpenPopupStack.Size - 1, true); + s_file_selector_open = false; s_file_selector_directory = false; std::string().swap(s_file_selector_title); @@ -2220,8 +2227,8 @@ void ImGuiFullscreen::DrawFileSelector() { ImGui::PushStyleColor(ImGuiCol_Text, UIBackgroundTextColor); - BeginMenuButtons(); ResetFocusHere(); + BeginMenuButtons(); if (!s_file_selector_current_directory.empty()) { @@ -2319,6 +2326,9 @@ void ImGuiFullscreen::CloseChoiceDialog() if (!s_choice_dialog_open) return; + if (ImGui::IsPopupOpen(s_choice_dialog_title.c_str(), 0)) + ImGui::ClosePopupToLevel(GImGui->OpenPopupStack.Size - 1, true); + s_choice_dialog_open = false; s_choice_dialog_checkable = false; std::string().swap(s_choice_dialog_title); @@ -2353,7 +2363,7 @@ void ImGuiFullscreen::DrawChoiceDialog() ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGui::OpenPopup(s_choice_dialog_title.c_str()); - bool is_open = !WantsToCloseMenu(); + bool is_open = true; s32 choice = -1; if (ImGui::BeginPopupModal(s_choice_dialog_title.c_str(), &is_open, @@ -2361,8 +2371,8 @@ void ImGuiFullscreen::DrawChoiceDialog() { ImGui::PushStyleColor(ImGuiCol_Text, UIBackgroundTextColor); - BeginMenuButtons(); ResetFocusHere(); + BeginMenuButtons(); if (s_choice_dialog_checkable) { @@ -2400,15 +2410,13 @@ void ImGuiFullscreen::DrawChoiceDialog() ImGui::EndPopup(); } - else - { - is_open = false; - } ImGui::PopStyleColor(3); ImGui::PopStyleVar(3); ImGui::PopFont(); + is_open &= !WantsToCloseMenu(); + if (choice >= 0) { const auto& option = s_choice_dialog_options[choice]; @@ -2526,6 +2534,9 @@ void ImGuiFullscreen::CloseInputDialog() if (!s_input_dialog_open) return; + if (ImGui::IsPopupOpen(s_input_dialog_title.c_str(), 0)) + ImGui::ClosePopupToLevel(GImGui->OpenPopupStack.Size - 1, true); + s_input_dialog_open = false; s_input_dialog_title = {}; s_input_dialog_message = {}; @@ -2589,6 +2600,9 @@ void ImGuiFullscreen::CloseMessageDialog() if (!s_message_dialog_open) return; + if (ImGui::IsPopupOpen(s_message_dialog_title.c_str(), 0)) + ImGui::ClosePopupToLevel(GImGui->OpenPopupStack.Size - 1, true); + s_message_dialog_open = false; s_message_dialog_title = {}; s_message_dialog_message = {}; @@ -2626,8 +2640,8 @@ void ImGuiFullscreen::DrawMessageDialog() if (ImGui::BeginPopupModal(win_id, &is_open, flags)) { - BeginMenuButtons(); ResetFocusHere(); + BeginMenuButtons(); ImGui::TextWrapped("%s", s_message_dialog_message.c_str()); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + LayoutScale(20.0f));