FullscreenUI: Rewrite popup dialog handling

Add animations, fix background dimming.
This commit is contained in:
Stenzek 2025-03-29 17:30:05 +10:00
parent 576658b6eb
commit 0687e59bda
No known key found for this signature in database
3 changed files with 1460 additions and 1315 deletions

View File

@ -82,6 +82,8 @@ using ImGuiFullscreen::FocusResetType;
using ImGuiFullscreen::LAYOUT_FOOTER_HEIGHT;
using ImGuiFullscreen::LAYOUT_HORIZONTAL_MENU_ITEM_IMAGE_SIZE;
using ImGuiFullscreen::LAYOUT_LARGE_FONT_SIZE;
using ImGuiFullscreen::LAYOUT_LARGE_POPUP_PADDING;
using ImGuiFullscreen::LAYOUT_LARGE_POPUP_ROUNDING;
using ImGuiFullscreen::LAYOUT_MEDIUM_FONT_SIZE;
using ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT;
using ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY;
@ -89,10 +91,11 @@ using ImGuiFullscreen::LAYOUT_MENU_BUTTON_X_PADDING;
using ImGuiFullscreen::LAYOUT_MENU_BUTTON_Y_PADDING;
using ImGuiFullscreen::LAYOUT_SCREEN_HEIGHT;
using ImGuiFullscreen::LAYOUT_SCREEN_WIDTH;
using ImGuiFullscreen::LAYOUT_SMALL_POPUP_PADDING;
using ImGuiFullscreen::UIStyle;
using ImGuiFullscreen::AddNotification;
using ImGuiFullscreen::BeginFixedPopupModal;
using ImGuiFullscreen::BeginFixedPopupDialog;
using ImGuiFullscreen::BeginFullscreenColumns;
using ImGuiFullscreen::BeginFullscreenColumnWindow;
using ImGuiFullscreen::BeginFullscreenWindow;
@ -101,8 +104,10 @@ using ImGuiFullscreen::BeginMenuButtons;
using ImGuiFullscreen::BeginNavBar;
using ImGuiFullscreen::CancelPendingMenuClose;
using ImGuiFullscreen::CenterImage;
using ImGuiFullscreen::CloseFixedPopupDialog;
using ImGuiFullscreen::CloseFixedPopupDialogImmediately;
using ImGuiFullscreen::DarkerColor;
using ImGuiFullscreen::EndFixedPopupModal;
using ImGuiFullscreen::EndFixedPopupDialog;
using ImGuiFullscreen::EndFullscreenColumns;
using ImGuiFullscreen::EndFullscreenColumnWindow;
using ImGuiFullscreen::EndFullscreenWindow;
@ -116,6 +121,8 @@ using ImGuiFullscreen::GetCachedTexture;
using ImGuiFullscreen::GetCachedTextureAsync;
using ImGuiFullscreen::GetPlaceholderTexture;
using ImGuiFullscreen::HorizontalMenuItem;
using ImGuiFullscreen::IsAnyFixedPopupDialogOpen;
using ImGuiFullscreen::IsFixedPopupDialogOpen;
using ImGuiFullscreen::IsFocusResetFromWindowChange;
using ImGuiFullscreen::IsFocusResetQueued;
using ImGuiFullscreen::IsGamepadInputSource;
@ -137,6 +144,7 @@ using ImGuiFullscreen::NavTitle;
using ImGuiFullscreen::OpenChoiceDialog;
using ImGuiFullscreen::OpenConfirmMessageDialog;
using ImGuiFullscreen::OpenFileSelector;
using ImGuiFullscreen::OpenFixedPopupDialog;
using ImGuiFullscreen::OpenInfoMessageDialog;
using ImGuiFullscreen::OpenInputStringDialog;
using ImGuiFullscreen::PopPrimaryColor;
@ -226,7 +234,6 @@ static void DrawPauseMenu();
static void ExitFullscreenAndOpenURL(std::string_view url);
static void CopyTextToClipboard(std::string title, std::string_view text);
static void DrawAboutWindow();
static void OpenAboutWindow();
static void FixStateIfPaused();
static void GetStandardSelectionFooterText(SmallStringBase& dest, bool back_instead_of_cancel);
@ -430,7 +437,8 @@ struct SaveStateListEntry
static void InitializePlaceholderSaveStateListEntry(SaveStateListEntry* li, s32 slot, bool global);
static bool InitializeSaveStateListEntryFromSerial(SaveStateListEntry* li, const std::string& serial, s32 slot,
bool global);
static bool InitializeSaveStateListEntryFromPath(SaveStateListEntry* li, std::string path, s32 slot, bool global);
static bool InitializeSaveStateListEntryFromPath(SaveStateListEntry* li, std::string path, s32 slot, bool global,
std::string* media_path);
static void ClearSaveStateEntryList();
static u32 PopulateSaveStateListEntries(const std::string& serial,
std::optional<ExtendedSaveStateInfo> undo_save_state);
@ -492,6 +500,9 @@ static constexpr std::array s_theme_names = {
static constexpr std::array s_theme_values = {"", "Dark", "Light", "AMOLED", "CobaltSky",
"GreyMatter", "GreenGiant", "PinkyPals", "DarkRuby", "PurpleRain"};
static constexpr std::string_view RESUME_STATE_SELECTOR_DIALOG_NAME = "##resume_state_selector";
static constexpr std::string_view ABOUT_DIALOG_NAME = "##about_duckstation";
//////////////////////////////////////////////////////////////////////////
// State
//////////////////////////////////////////////////////////////////////////
@ -507,8 +518,6 @@ struct ALIGN_TO_CACHE_LINE UIState
bool tried_to_initialize = false;
bool pause_menu_was_open = false;
bool was_paused_on_quick_menu_open = false;
bool about_window_open = false;
bool achievements_login_window_open = false;
std::string current_game_title;
std::string current_game_serial;
std::string current_game_path;
@ -562,7 +571,6 @@ struct ALIGN_TO_CACHE_LINE UIState
s32 save_state_selector_submenu_index = -1;
bool save_state_selector_open = false;
bool save_state_selector_loading = true;
bool save_state_selector_resuming = false;
// Lazily populated cover images.
std::unordered_map<std::string, std::string> cover_image_map;
@ -755,8 +763,8 @@ bool FullscreenUI::HasActiveWindow()
bool FullscreenUI::AreAnyDialogsOpen()
{
return (s_state.save_state_selector_open || s_state.about_window_open ||
s_state.input_binding_type != InputBindingInfo::Type::Unknown || ImGuiFullscreen::IsChoiceDialogOpen() ||
return (s_state.save_state_selector_open || s_state.input_binding_type != InputBindingInfo::Type::Unknown ||
ImGuiFullscreen::IsAnyFixedPopupDialogOpen() || ImGuiFullscreen::IsChoiceDialogOpen() ||
ImGuiFullscreen::IsInputDialogOpen() || ImGuiFullscreen::IsFileSelectorOpen() ||
ImGuiFullscreen::IsMessageBoxDialogOpen());
}
@ -938,7 +946,6 @@ void FullscreenUI::Shutdown(bool clear_state)
s_state.current_pause_submenu = PauseSubMenu::None;
s_state.pause_menu_was_open = false;
s_state.was_paused_on_quick_menu_open = false;
s_state.about_window_open = false;
Achievements::ClearUIState();
ClearInputBindingVariables();
@ -1027,18 +1034,13 @@ void FullscreenUI::Render()
break;
}
if (s_state.save_state_selector_open)
{
if (s_state.save_state_selector_resuming)
DrawResumeStateSelector();
else
DrawSaveStateSelector(s_state.save_state_selector_loading);
}
if (s_state.about_window_open)
if (IsFixedPopupDialogOpen(ABOUT_DIALOG_NAME))
DrawAboutWindow();
if (s_state.input_binding_type != InputBindingInfo::Type::Unknown)
else if (IsFixedPopupDialogOpen(RESUME_STATE_SELECTOR_DIALOG_NAME))
DrawResumeStateSelector();
else if (s_state.save_state_selector_open)
DrawSaveStateSelector(s_state.save_state_selector_loading);
else if (s_state.input_binding_type != InputBindingInfo::Type::Unknown)
DrawInputBindingWindow();
ImGuiFullscreen::EndLayout();
@ -1253,17 +1255,17 @@ void FullscreenUI::DoResume()
return;
}
SaveStateListEntry slentry;
if (!InitializeSaveStateListEntryFromPath(&slentry, std::move(path), -1, false))
return;
CloseSaveStateSelector();
SaveStateListEntry slentry;
if (!InitializeSaveStateListEntryFromPath(&slentry, std::move(path), -1, false,
&s_state.save_state_selector_game_path))
{
return;
}
s_state.save_state_selector_slots.push_back(std::move(slentry));
s_state.save_state_selector_game_path = {};
s_state.save_state_selector_loading = true;
s_state.save_state_selector_open = true;
s_state.save_state_selector_resuming = true;
QueueResetFocus(FocusResetType::PopupOpened);
OpenFixedPopupDialog(RESUME_STATE_SELECTOR_DIALOG_NAME);
}
void FullscreenUI::DoStartFile()
@ -1969,7 +1971,7 @@ void FullscreenUI::DrawLandingWindow()
if (!AreAnyDialogsOpen())
{
if (ImGui::IsKeyPressed(ImGuiKey_GamepadBack, false) || ImGui::IsKeyPressed(ImGuiKey_F1, false))
OpenAboutWindow();
OpenFixedPopupDialog(ABOUT_DIALOG_NAME);
else if (ImGui::IsKeyPressed(ImGuiKey_GamepadStart, false) || ImGui::IsKeyPressed(ImGuiKey_F3, false))
DoResume();
else if (ImGui::IsKeyPressed(ImGuiKey_NavGamepadMenu, false) || ImGui::IsKeyPressed(ImGuiKey_F11, false))
@ -2323,6 +2325,9 @@ void FullscreenUI::ClearInputBindingVariables()
s_state.input_binding_display_name = {};
s_state.input_binding_new_bindings = {};
s_state.input_binding_value_ranges = {};
if (IsFixedPopupDialogOpen(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Set Input Binding")))
CloseFixedPopupDialogImmediately();
}
void FullscreenUI::BeginInputBinding(SettingsInterface* bsi, InputBindingInfo::Type type, std::string_view section,
@ -2341,6 +2346,7 @@ void FullscreenUI::BeginInputBinding(SettingsInterface* bsi, InputBindingInfo::T
s_state.input_binding_new_bindings = {};
s_state.input_binding_value_ranges = {};
s_state.input_binding_start_time = Timer::GetCurrentValue();
OpenFixedPopupDialog(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Set Input Binding"));
const bool game_settings = IsEditingGameSettings(bsi);
@ -2396,8 +2402,9 @@ void FullscreenUI::BeginInputBinding(SettingsInterface* bsi, InputBindingInfo::T
bsi->SetStringValue(s_state.input_binding_section.c_str(), s_state.input_binding_key.c_str(),
new_binding.c_str());
SetSettingsChanged(bsi);
ClearInputBindingVariables();
QueueResetFocus(FocusResetType::PopupClosed);
GPUThread::RunOnThread(&CloseFixedPopupDialog);
return InputInterceptHook::CallbackResult::RemoveHookAndStopProcessingEvent;
}
@ -2474,27 +2481,27 @@ void FullscreenUI::DrawInputBindingWindow()
INPUT_BINDING_TIMEOUT_SECONDS -
Timer::ConvertValueToSeconds(Timer::GetCurrentValue() - s_state.input_binding_start_time);
if (time_remaining <= 0.0)
{
InputManager::RemoveHook();
CloseFixedPopupDialog();
}
if (!BeginFixedPopupDialog(LayoutScale(LAYOUT_SMALL_POPUP_PADDING), LayoutScale(LAYOUT_SMALL_POPUP_PADDING),
LayoutScale(500.0f, 0.0f)))
{
InputManager::RemoveHook();
ClearInputBindingVariables();
QueueResetFocus(FocusResetType::PopupClosed);
return;
}
const char* title = FSUI_ICONSTR(ICON_FA_GAMEPAD, "Set Input Binding");
ImGui::SetNextWindowSize(LayoutScale(500.0f, 0.0f));
ImGui::OpenPopup(title);
if (BeginFixedPopupModal(title))
{
ImGui::TextWrapped("%s", SmallString::from_format(FSUI_FSTR("Setting {} binding {}."),
s_state.input_binding_section, s_state.input_binding_display_name)
ImGui::TextWrapped("%s", SmallString::from_format(FSUI_FSTR("Setting {} binding {}."), s_state.input_binding_section,
s_state.input_binding_display_name)
.c_str());
ImGui::TextUnformatted(FSUI_CSTR("Push a controller button or axis now."));
ImGui::NewLine();
ImGui::TextUnformatted(SmallString::from_format(FSUI_FSTR("Timing out in {:.0f} seconds..."), time_remaining));
EndFixedPopupModal();
}
EndFixedPopupDialog();
}
bool FullscreenUI::DrawToggleSetting(SettingsInterface* bsi, const char* title, const char* summary,
@ -2661,18 +2668,18 @@ void FullscreenUI::DrawIntRangeSetting(SettingsInterface* bsi, const char* title
value.has_value() ? SmallString::from_sprintf(format, value.value()) : SmallString(FSUI_VSTR("Use Global Setting"));
if (MenuButtonWithValue(title, summary, value_text.c_str(), enabled, height, font, summary_font))
ImGui::OpenPopup(title);
OpenFixedPopupDialog(title);
ImGui::SetNextWindowSize(LayoutScale(500.0f, 194.0f));
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
bool is_open = true;
if (BeginFixedPopupModal(title, &is_open))
if (!IsFixedPopupDialogOpen(title) ||
!BeginFixedPopupDialog(LayoutScale(LAYOUT_SMALL_POPUP_PADDING), LayoutScale(LAYOUT_SMALL_POPUP_PADDING),
LayoutScale(500.0f, 194.0f)))
{
return;
}
BeginMenuButtons();
const float end = ImGui::GetCurrentWindow()->WorkRect.GetWidth();
ImGui::SetNextItemWidth(end);
ImGui::SetNextItemWidth(ImGui::GetCurrentWindow()->WorkRect.GetWidth());
s32 dlg_value = static_cast<s32>(value.value_or(default_value));
if (ImGui::SliderInt("##value", &dlg_value, min_value, max_value, format, ImGuiSliderFlags_NoInput))
{
@ -2688,12 +2695,11 @@ void FullscreenUI::DrawIntRangeSetting(SettingsInterface* bsi, const char* title
if (MenuButtonWithoutSummary(FSUI_CSTR("OK"), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, UIStyle.LargeFont,
ImVec2(0.5f, 0.0f)))
{
ImGui::CloseCurrentPopup();
CloseFixedPopupDialog();
}
EndMenuButtons();
EndFixedPopupModal();
}
EndFixedPopupDialog();
}
void FullscreenUI::DrawFloatRangeSetting(SettingsInterface* bsi, const char* title, const char* summary,
@ -2708,13 +2714,15 @@ void FullscreenUI::DrawFloatRangeSetting(SettingsInterface* bsi, const char* tit
SmallString(FSUI_VSTR("Use Global Setting"));
if (MenuButtonWithValue(title, summary, value_text.c_str(), enabled, height, font, summary_font))
ImGui::OpenPopup(title);
OpenFixedPopupDialog(title);
ImGui::SetNextWindowSize(LayoutScale(500.0f, 194.0f));
bool is_open = true;
if (BeginFixedPopupModal(title, &is_open))
if (!IsFixedPopupDialogOpen(title) ||
!BeginFixedPopupDialog(LayoutScale(LAYOUT_SMALL_POPUP_PADDING), LayoutScale(LAYOUT_SMALL_POPUP_PADDING),
LayoutScale(500.0f, 194.0f)))
{
return;
}
BeginMenuButtons();
const float end = ImGui::GetCurrentWindow()->WorkRect.GetWidth();
@ -2737,12 +2745,11 @@ void FullscreenUI::DrawFloatRangeSetting(SettingsInterface* bsi, const char* tit
if (MenuButtonWithoutSummary(FSUI_CSTR("OK"), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, UIStyle.LargeFont,
ImVec2(0.5f, 0.0f)))
{
ImGui::CloseCurrentPopup();
CloseFixedPopupDialog();
}
EndMenuButtons();
EndFixedPopupModal();
}
EndFixedPopupDialog();
}
void FullscreenUI::DrawFloatSpinBoxSetting(SettingsInterface* bsi, const char* title, const char* summary,
@ -2760,15 +2767,17 @@ void FullscreenUI::DrawFloatSpinBoxSetting(SettingsInterface* bsi, const char* t
if (MenuButtonWithValue(title, summary, value_text.c_str(), enabled, height, font, summary_font))
{
ImGui::OpenPopup(title);
OpenFixedPopupDialog(title);
manual_input = false;
}
ImGui::SetNextWindowSize(LayoutScale(500.0f, 194.0f));
bool is_open = true;
if (BeginFixedPopupModal(title, &is_open))
if (!IsFixedPopupDialogOpen(title) ||
!BeginFixedPopupDialog(LayoutScale(LAYOUT_SMALL_POPUP_PADDING), LayoutScale(LAYOUT_SMALL_POPUP_PADDING),
LayoutScale(500.0f, 194.0f)))
{
return;
}
BeginMenuButtons();
float dlg_value = value.value_or(default_value) * multiplier;
@ -2837,8 +2846,7 @@ void FullscreenUI::DrawFloatSpinBoxSetting(SettingsInterface* bsi, const char* t
dlg_value_changed = true;
}
ImGui::SetCursorPosY(button_pos.y + (padding.y * 2.0f) +
LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + 10.0f));
ImGui::SetCursorPosY(button_pos.y + (padding.y * 2.0f) + LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + 10.0f));
}
if (dlg_value_changed)
@ -2855,12 +2863,11 @@ void FullscreenUI::DrawFloatSpinBoxSetting(SettingsInterface* bsi, const char* t
if (MenuButtonWithoutSummary(FSUI_CSTR("OK"), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, UIStyle.LargeFont,
ImVec2(0.5f, 0.0f)))
{
ImGui::CloseCurrentPopup();
CloseFixedPopupDialog();
}
EndMenuButtons();
EndFixedPopupModal();
}
EndFixedPopupDialog();
}
bool FullscreenUI::DrawIntRectSetting(SettingsInterface* bsi, const char* title, const char* summary,
@ -2887,18 +2894,20 @@ bool FullscreenUI::DrawIntRectSetting(SettingsInterface* bsi, const char* title,
TinyString(FSUI_VSTR("Default")));
if (MenuButtonWithValue(title, summary, value_text.c_str(), enabled, height, font, summary_font))
ImGui::OpenPopup(title);
OpenFixedPopupDialog(title);
ImGui::SetNextWindowSize(LayoutScale(500.0f, 370.0f));
bool is_open = true;
bool changed = false;
if (BeginFixedPopupModal(title, &is_open))
if (!IsFixedPopupDialogOpen(title) ||
!BeginFixedPopupDialog(LayoutScale(LAYOUT_SMALL_POPUP_PADDING), LayoutScale(LAYOUT_SMALL_POPUP_PADDING),
LayoutScale(500.0f, 370.0f)))
{
return false;
}
s32 dlg_left_value = static_cast<s32>(left_value.value_or(default_left));
s32 dlg_top_value = static_cast<s32>(top_value.value_or(default_top));
s32 dlg_right_value = static_cast<s32>(right_value.value_or(default_right));
s32 dlg_bottom_value = static_cast<s32>(bottom_value.value_or(default_bottom));
bool changed = false;
BeginMenuButtons();
@ -2964,12 +2973,11 @@ bool FullscreenUI::DrawIntRectSetting(SettingsInterface* bsi, const char* title,
if (MenuButtonWithoutSummary(FSUI_CSTR("OK"), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, UIStyle.LargeFont,
ImVec2(0.5f, 0.0f)))
{
ImGui::CloseCurrentPopup();
CloseFixedPopupDialog();
}
EndMenuButtons();
EndFixedPopupModal();
}
EndFixedPopupDialog();
return changed;
}
@ -2992,15 +3000,17 @@ void FullscreenUI::DrawIntSpinBoxSetting(SettingsInterface* bsi, const char* tit
if (MenuButtonWithValue(title, summary, value_text, enabled, height, font, summary_font))
{
ImGui::OpenPopup(title);
OpenFixedPopupDialog(title);
manual_input = false;
}
ImGui::SetNextWindowSize(LayoutScale(500.0f, 194.0f));
bool is_open = true;
if (BeginFixedPopupModal(title, &is_open))
if (!IsFixedPopupDialogOpen(title) ||
!BeginFixedPopupDialog(LayoutScale(LAYOUT_SMALL_POPUP_PADDING), LayoutScale(LAYOUT_SMALL_POPUP_PADDING),
LayoutScale(500.0f, 194.0f)))
{
return;
}
BeginMenuButtons();
s32 dlg_value = static_cast<s32>(value.value_or(default_value));
@ -3063,8 +3073,7 @@ void FullscreenUI::DrawIntSpinBoxSetting(SettingsInterface* bsi, const char* tit
dlg_value_changed = true;
}
ImGui::SetCursorPosY(button_pos.y + (padding.y * 2.0f) +
LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + 10.0f));
ImGui::SetCursorPosY(button_pos.y + (padding.y * 2.0f) + LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + 10.0f));
}
if (dlg_value_changed)
@ -3081,12 +3090,11 @@ void FullscreenUI::DrawIntSpinBoxSetting(SettingsInterface* bsi, const char* tit
if (MenuButtonWithoutSummary(FSUI_CSTR("OK"), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, UIStyle.LargeFont,
ImVec2(0.5f, 0.0f)))
{
ImGui::CloseCurrentPopup();
CloseFixedPopupDialog();
}
EndMenuButtons();
EndFixedPopupModal();
}
EndFixedPopupDialog();
}
[[maybe_unused]] void
@ -4737,7 +4745,7 @@ void FullscreenUI::DrawControllerSettingsPage()
"Determines the frequency at which the macro will toggle the buttons on and off (aka auto fire)."),
freq_summary, true))
{
ImGui::OpenPopup(freq_label.c_str());
OpenFixedPopupDialog(freq_label);
}
DrawFloatSpinBoxSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_DOWN, "Pressure"),
@ -4750,13 +4758,15 @@ void FullscreenUI::DrawControllerSettingsPage()
section, TinyString::from_format("Macro{}Deadzone", macro_index + 1).c_str(), 0.0f, 0.00f,
1.0f, 0.01f, 100.0f, "%.0f%%");
ImGui::SetNextWindowSize(LayoutScale(500.0f, 180.0f));
bool is_open = true;
if (BeginFixedPopupModal(freq_label, &is_open))
if (IsFixedPopupDialogOpen(freq_label) &&
BeginFixedPopupDialog(LayoutScale(LAYOUT_SMALL_POPUP_PADDING), LayoutScale(LAYOUT_SMALL_POPUP_PADDING),
LayoutScale(500.0f, 194.0f)))
{
ImGui::SetNextItemWidth(LayoutScale(450.0f));
if (ImGui::SliderInt("##value", &frequency, 0, 60, FSUI_CSTR("Toggle every %d frames"),
BeginMenuButtons();
ImGui::SetNextItemWidth(ImGui::GetCurrentWindow()->WorkRect.GetWidth());
if (ImGui::SliderInt("##value", &frequency, 0, 60,
(frequency == 0) ? FSUI_CSTR("Disabled") : FSUI_CSTR("Toggle every %d frames"),
ImGuiSliderFlags_NoInput))
{
if (frequency == 0)
@ -4765,12 +4775,16 @@ void FullscreenUI::DrawControllerSettingsPage()
bsi->SetIntValue(section.c_str(), freq_key.c_str(), frequency);
}
BeginMenuButtons();
if (MenuButton(FSUI_CSTR("OK"), nullptr, true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY))
ImGui::CloseCurrentPopup();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + LayoutScale(10.0f));
if (MenuButtonWithoutSummary(FSUI_CSTR("OK"), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, UIStyle.LargeFont,
ImVec2(0.5f, 0.0f)))
{
CloseFixedPopupDialog();
}
EndMenuButtons();
EndFixedPopupModal();
EndFixedPopupDialog();
}
}
@ -5553,7 +5567,7 @@ void FullscreenUI::DrawPostProcessingSettingsPage()
case PostProcessing::ShaderOption::Type::Bool:
{
bool value = (opt.value[0].int_value != 0);
tstr.format(ICON_FA_COGS "{}", opt.ui_name);
tstr.format(ICON_FA_COGS " {}", opt.ui_name);
if (ToggleButton(tstr,
(opt.default_value[0].int_value != 0) ? FSUI_CSTR("Default: Enabled") :
FSUI_CSTR("Default: Disabled"),
@ -5569,38 +5583,20 @@ void FullscreenUI::DrawPostProcessingSettingsPage()
case PostProcessing::ShaderOption::Type::Float:
{
tstr.format(ICON_FA_RULER_VERTICAL "{}##{}", opt.ui_name, opt.name);
tstr.format(ICON_FA_RULER_VERTICAL " {}##{}", opt.ui_name, opt.name);
str.format(FSUI_FSTR("Value: {} | Default: {} | Minimum: {} | Maximum: {}"), opt.value[0].float_value,
opt.default_value[0].float_value, opt.min_value[0].float_value, opt.max_value[0].float_value);
if (MenuButton(tstr, str))
ImGui::OpenPopup(tstr);
OpenFixedPopupDialog(tstr);
ImGui::SetNextWindowSize(LayoutScale(500.0f, 194.0f));
bool is_open = true;
if (BeginFixedPopupModal(tstr, &is_open))
if (IsFixedPopupDialogOpen(tstr) &&
BeginFixedPopupDialog(LayoutScale(LAYOUT_SMALL_POPUP_PADDING), LayoutScale(LAYOUT_SMALL_POPUP_PADDING),
LayoutScale(500.0f, 194.0f)))
{
BeginMenuButtons();
const float end = ImGui::GetCurrentWindow()->WorkRect.GetWidth();
#if 0
for (u32 i = 0; i < opt.vector_size; i++)
{
static constexpr const char* components[] = { "X", "Y", "Z", "W" };
if (opt.vector_size == 1)
tstr.Assign("##value");
else
tstr.Fmt("{}##value{}", components[i], i);
ImGui::SetNextItemWidth(end);
if (ImGui::SliderFloat(tstr, &opt.value[i].float_value, opt.min_value[i].float_value,
opt.max_value[i].float_value, "%f", ImGuiSliderFlags_NoInput))
{
SavePostProcessingChain();
}
}
#else
ImGui::SetNextItemWidth(end);
bool changed = false;
@ -5641,55 +5637,36 @@ void FullscreenUI::DrawPostProcessingSettingsPage()
SetSettingsChanged(bsi);
reload_pending = true;
}
#endif
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + LayoutScale(10.0f));
if (MenuButtonWithoutSummary(FSUI_CSTR("OK"), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, UIStyle.LargeFont,
ImVec2(0.5f, 0.0f)))
{
ImGui::CloseCurrentPopup();
CloseFixedPopupDialog();
}
EndMenuButtons();
EndFixedPopupModal();
EndFixedPopupDialog();
}
}
break;
case PostProcessing::ShaderOption::Type::Int:
{
tstr.format(ICON_FA_RULER_VERTICAL "{}##{}", opt.ui_name, opt.name);
tstr.format(ICON_FA_RULER_VERTICAL " {}##{}", opt.ui_name, opt.name);
str.format(FSUI_FSTR("Value: {} | Default: {} | Minimum: {} | Maximum: {}"), opt.value[0].int_value,
opt.default_value[0].int_value, opt.min_value[0].int_value, opt.max_value[0].int_value);
if (MenuButton(tstr, str))
ImGui::OpenPopup(tstr);
OpenFixedPopupDialog(tstr);
ImGui::SetNextWindowSize(LayoutScale(500.0f, 194.0f));
bool is_open = true;
if (BeginFixedPopupModal(tstr, &is_open))
if (IsFixedPopupDialogOpen(tstr) &&
BeginFixedPopupDialog(LayoutScale(LAYOUT_SMALL_POPUP_PADDING), LayoutScale(LAYOUT_SMALL_POPUP_PADDING),
LayoutScale(500.0f, 194.0f)))
{
BeginMenuButtons();
const float end = ImGui::GetCurrentWindow()->WorkRect.GetWidth();
#if 0
for (u32 i = 0; i < opt.vector_size; i++)
{
static constexpr const char* components[] = { "X", "Y", "Z", "W" };
if (opt.vector_size == 1)
tstr.Assign("##value");
else
tstr.Fmt("{}##value{}", components[i], i);
ImGui::SetNextItemWidth(end);
if (ImGui::SliderInt(tstr, &opt.value[i].int_value, opt.min_value[i].int_value,
opt.max_value[i].int_value, "%d", ImGuiSliderFlags_NoInput))
{
SavePostProcessingChain();
}
}
#else
bool changed = false;
ImGui::SetNextItemWidth(end);
switch (opt.vector_size)
@ -5729,17 +5706,16 @@ void FullscreenUI::DrawPostProcessingSettingsPage()
SetSettingsChanged(bsi);
reload_pending = true;
}
#endif
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + LayoutScale(10.0f));
if (MenuButtonWithoutSummary(FSUI_CSTR("OK"), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, UIStyle.LargeFont,
ImVec2(0.5f, 0.0f)))
{
ImGui::CloseCurrentPopup();
CloseFixedPopupDialog();
}
EndMenuButtons();
EndFixedPopupModal();
EndFixedPopupDialog();
}
}
break;
@ -6022,13 +5998,12 @@ void FullscreenUI::DrawAchievementsSettingsPage()
{
MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_USER, "Not Logged In"), false);
if (MenuButton(FSUI_ICONSTR(ICON_FA_KEY, "Login"), FSUI_CSTR("Logs in to RetroAchievements.")))
{
s_state.achievements_login_window_open = true;
QueueResetFocus(FocusResetType::PopupOpened);
}
static constexpr std::string_view popup_title = "##achievements_login";
if (s_state.achievements_login_window_open)
if (MenuButton(FSUI_ICONSTR(ICON_FA_KEY, "Login"), FSUI_CSTR("Logs in to RetroAchievements.")))
OpenFixedPopupDialog(popup_title);
if (IsFixedPopupDialogOpen(popup_title))
DrawAchievementsLoginWindow();
}
@ -6065,26 +6040,29 @@ void FullscreenUI::DrawAchievementsLoginWindow()
static char username[256] = {};
static char password[256] = {};
static std::unique_ptr<std::string> login_error;
static constexpr auto actually_close_popup = []() {
if (!BeginFixedPopupDialog(LayoutScale(LAYOUT_LARGE_POPUP_PADDING), LayoutScale(LAYOUT_LARGE_POPUP_ROUNDING),
LayoutScale(600.0f, 0.0f)))
{
std::memset(username, 0, sizeof(username));
std::memset(password, 0, sizeof(password));
s_state.achievements_login_window_open = false;
QueueResetFocus(FocusResetType::PopupClosed);
};
login_error.reset();
return;
}
ImGui::SetNextWindowSize(LayoutScale(600.0f, 0.0f));
const char* popup_title = FSUI_ICONSTR(ICON_FA_KEY, "RetroAchievements Login");
bool popup_closed = false;
ImGui::OpenPopup(popup_title);
if (BeginFixedPopupModal(popup_title, nullptr))
{
BeginMenuButtons();
if (!login_error)
{
ImGui::TextWrapped(
FSUI_CSTR("Please enter your user name and password for retroachievements.org below. Your password will "
"not be saved in DuckStation, an access token will be generated and used instead."));
}
else
{
ImGui::TextWrapped("%s", login_error->c_str());
}
ImGui::NewLine();
@ -6124,40 +6102,23 @@ void FullscreenUI::DrawAchievementsLoginWindow()
if (result)
{
actually_close_popup();
CloseFixedPopupDialog();
return;
}
// keep popup open on failure
// because of the whole popup stack thing, we need to hide the dialog while this popup is visible
s_state.achievements_login_window_open = false;
ImGuiFullscreen::OpenInfoMessageDialog(
FSUI_STR("Login Error"),
login_error = std::make_unique<std::string>(
fmt::format(FSUI_FSTR("Login Failed.\nError: {}\nPlease check your username and password, and try again."),
error.GetDescription()),
[]() {
s_state.achievements_login_window_open = true;
QueueResetFocus(FocusResetType::PopupOpened);
},
FSUI_ICONSTR(ICON_FA_TIMES, "Close"));
error.GetDescription()));
});
});
}
if (MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_TIMES, "Cancel"), !is_logging_in))
popup_closed = true;
popup_closed = popup_closed || (!is_logging_in && WantsToCloseMenu());
if (popup_closed)
ImGui::CloseCurrentPopup();
CloseFixedPopupDialog();
EndMenuButtons();
EndFixedPopupModal();
}
if (popup_closed)
actually_close_popup();
EndFixedPopupDialog();
}
void FullscreenUI::DrawAdvancedSettingsPage()
@ -6324,12 +6285,11 @@ void FullscreenUI::DrawPatchesOrCheatsSettingsPage(bool cheats)
constexpr s32 step_value = 1;
if (MenuButtonWithValue(title.c_str(), ci.description.c_str(), visible_value.c_str()))
ImGui::OpenPopup(title);
OpenFixedPopupDialog(title);
ImGui::SetNextWindowSize(LayoutScale(500.0f, 194.0f));
bool is_open = true;
if (BeginFixedPopupModal(title, &is_open))
if (IsFixedPopupDialogOpen(title) &&
BeginFixedPopupDialog(LayoutScale(LAYOUT_SMALL_POPUP_PADDING), LayoutScale(LAYOUT_SMALL_POPUP_PADDING),
LayoutScale(500.0f, 194.0f)))
{
BeginMenuButtons();
@ -6396,11 +6356,11 @@ void FullscreenUI::DrawPatchesOrCheatsSettingsPage(bool cheats)
if (MenuButtonWithoutSummary(FSUI_CSTR("OK"), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, UIStyle.LargeFont,
ImVec2(0.5f, 0.0f)))
{
ImGui::CloseCurrentPopup();
CloseFixedPopupDialog();
}
EndMenuButtons();
EndFixedPopupModal();
EndFixedPopupDialog();
}
}
else
@ -6776,7 +6736,7 @@ bool FullscreenUI::InitializeSaveStateListEntryFromSerial(SaveStateListEntry* li
{
const std::string path =
(global ? System::GetGlobalSaveStateFileName(slot) : System::GetGameSaveStateFileName(serial, slot));
if (!InitializeSaveStateListEntryFromPath(li, path.c_str(), slot, global))
if (!InitializeSaveStateListEntryFromPath(li, path.c_str(), slot, global, nullptr))
{
InitializePlaceholderSaveStateListEntry(li, slot, global);
return false;
@ -6785,7 +6745,8 @@ bool FullscreenUI::InitializeSaveStateListEntryFromSerial(SaveStateListEntry* li
return true;
}
bool FullscreenUI::InitializeSaveStateListEntryFromPath(SaveStateListEntry* li, std::string path, s32 slot, bool global)
bool FullscreenUI::InitializeSaveStateListEntryFromPath(SaveStateListEntry* li, std::string path, s32 slot, bool global,
std::string* media_path)
{
std::optional<ExtendedSaveStateInfo> ssi(System::GetExtendedSaveStateInfo(path.c_str()));
if (!ssi.has_value())
@ -6807,6 +6768,8 @@ bool FullscreenUI::InitializeSaveStateListEntryFromPath(SaveStateListEntry* li,
li->global = global;
if (ssi->screenshot.IsValid())
li->preview_texture = g_gpu_device->FetchAndUploadTextureImage(ssi->screenshot);
if (media_path)
*media_path = std::move(ssi->media_path);
return true;
}
@ -6865,7 +6828,6 @@ void FullscreenUI::OpenSaveStateSelector(const std::string& serial, const std::s
std::optional<ExtendedSaveStateInfo> undo_state = System::GetUndoSaveStateInfo();
GPUThread::RunOnThread([serial = std::move(serial), undo_state = std::move(undo_state), is_loading]() mutable {
s_state.save_state_selector_loading = is_loading;
s_state.save_state_selector_resuming = false;
s_state.save_state_selector_game_path = {};
if (PopulateSaveStateListEntries(serial, std::move(undo_state)) > 0)
{
@ -6883,7 +6845,6 @@ void FullscreenUI::OpenSaveStateSelector(const std::string& serial, const std::s
else
{
s_state.save_state_selector_loading = is_loading;
s_state.save_state_selector_resuming = false;
if (PopulateSaveStateListEntries(serial, std::nullopt) > 0)
{
s_state.save_state_selector_game_path = path;
@ -6905,8 +6866,10 @@ void FullscreenUI::CloseSaveStateSelector()
ClearSaveStateEntryList();
s_state.save_state_selector_open = false;
s_state.save_state_selector_loading = false;
s_state.save_state_selector_resuming = false;
s_state.save_state_selector_game_path = {};
if (IsFixedPopupDialogOpen(RESUME_STATE_SELECTOR_DIALOG_NAME))
CloseFixedPopupDialogImmediately();
}
void FullscreenUI::DrawSaveStateSelector(bool is_loading)
@ -7240,27 +7203,18 @@ bool FullscreenUI::OpenLoadStateSelectorForGameResume(const GameList::Entry* ent
CloseSaveStateSelector();
s_state.save_state_selector_slots.push_back(std::move(slentry));
s_state.save_state_selector_game_path = entry->path;
s_state.save_state_selector_loading = true;
s_state.save_state_selector_open = true;
s_state.save_state_selector_resuming = true;
QueueResetFocus(FocusResetType::PopupOpened);
OpenFixedPopupDialog(RESUME_STATE_SELECTOR_DIALOG_NAME);
return true;
}
void FullscreenUI::DrawResumeStateSelector()
{
ImGui::SetNextWindowSize(LayoutScale(820.0f, 625.0f));
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::OpenPopup(FSUI_CSTR("Load Resume State"));
ImGui::PushFont(UIStyle.LargeFont);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(40.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(30.0f, 30.0f));
bool is_open = true;
if (ImGui::BeginPopupModal(FSUI_CSTR("Load Resume State"), &is_open,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize))
if (!BeginFixedPopupDialog(LayoutScale(30.0f), LayoutScale(40.0f), LayoutScale(820.0f, 625.0f)))
{
CloseSaveStateSelector();
return;
}
SaveStateListEntry& entry = s_state.save_state_selector_slots.front();
SmallString time;
TimeToPrintableString(&time, entry.timestamp);
@ -7277,7 +7231,8 @@ void FullscreenUI::DrawResumeStateSelector()
const ImRect image_bb(pos, pos + ImVec2(image_width, image_height));
ImGui::GetWindowDrawList()->AddImage(
static_cast<ImTextureID>(entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get()),
image_bb.Min, image_bb.Max);
image_bb.Min, image_bb.Max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f),
ImGui::GetColorU32(IM_COL32(255, 255, 255, 255)));
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + image_height + LayoutScale(40.0f));
@ -7286,22 +7241,26 @@ void FullscreenUI::DrawResumeStateSelector()
if (MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_PLAY, "Load State")))
{
DoStartPath(s_state.save_state_selector_game_path, std::move(entry.path));
is_open = false;
std::string game_path = std::move(s_state.save_state_selector_game_path);
std::string state_path = std::move(entry.path);
CloseSaveStateSelector();
DoStartPath(std::move(game_path), std::move(state_path));
}
if (MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_LIGHTBULB, "Clean Boot")))
{
DoStartPath(s_state.save_state_selector_game_path);
is_open = false;
std::string game_path = std::move(s_state.save_state_selector_game_path);
CloseSaveStateSelector();
DoStartPath(std::move(game_path));
}
if (MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_FOLDER_MINUS, "Delete State")))
{
if (FileSystem::DeleteFile(entry.path.c_str()))
{
DoStartPath(s_state.save_state_selector_game_path);
is_open = false;
std::string game_path = std::move(s_state.save_state_selector_game_path);
CloseSaveStateSelector();
DoStartPath(std::move(game_path));
}
else
{
@ -7309,32 +7268,14 @@ void FullscreenUI::DrawResumeStateSelector()
}
}
if (MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_WINDOW_CLOSE, "Cancel")) || WantsToCloseMenu())
{
ImGui::CloseCurrentPopup();
is_open = false;
}
if (MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_WINDOW_CLOSE, "Cancel")))
CloseFixedPopupDialog();
EndMenuButtons();
ImGui::EndPopup();
}
ImGui::PopStyleVar(2);
ImGui::PopFont();
if (!is_open)
{
ClearSaveStateEntryList();
QueueResetFocus(FocusResetType::PopupClosed);
s_state.save_state_selector_open = false;
s_state.save_state_selector_loading = false;
s_state.save_state_selector_resuming = false;
s_state.save_state_selector_game_path = {};
}
else
{
SetStandardSelectionFooterText(false);
}
EndFixedPopupDialog();
}
void FullscreenUI::DoLoadState(std::string path)
@ -8409,11 +8350,6 @@ GPUTexture* FullscreenUI::GetCoverForCurrentGame()
// Overlays
//////////////////////////////////////////////////////////////////////////
void FullscreenUI::OpenAboutWindow()
{
s_state.about_window_open = true;
}
void FullscreenUI::ExitFullscreenAndOpenURL(std::string_view url)
{
Host::RunOnCPUThread([url = std::string(url)]() {
@ -8434,32 +8370,29 @@ void FullscreenUI::CopyTextToClipboard(std::string title, std::string_view text)
void FullscreenUI::DrawAboutWindow()
{
ImGui::SetNextWindowSize(LayoutScale(1020.0f, 590.0f));
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::OpenPopup(FSUI_CSTR("About DuckStation"));
ImGui::PushFont(UIStyle.LargeFont);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(40.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(30.0f, 30.0f));
if (ImGui::BeginPopupModal(FSUI_CSTR("About DuckStation"), &s_state.about_window_open,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize))
if (!BeginFixedPopupDialog(LayoutScale(LAYOUT_LARGE_POPUP_PADDING), LayoutScale(LAYOUT_LARGE_POPUP_ROUNDING),
LayoutScale(1020.0f, 590.0f)))
{
return;
}
const ImVec2 image_size = LayoutScale(64.0f, 64.0f);
const float indent = image_size.x + LayoutScale(8.0f);
ImGui::GetWindowDrawList()->AddImage(s_state.app_icon_texture.get(), ImGui::GetCursorScreenPos(),
ImGui::GetCursorScreenPos() + image_size);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + indent);
ImGui::TextUnformatted("DuckStation");
ImGui::PushStyleColor(ImGuiCol_Text, DarkerColor(UIStyle.BackgroundTextColor));
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + indent);
ImGui::TextUnformatted(g_scm_tag_str);
ImGui::PopStyleColor();
ImGui::NewLine();
ImGui::TextWrapped("%s", FSUI_CSTR("DuckStation is a free simulator/emulator of the Sony PlayStation(TM) "
"console, focusing on playability, speed, and long-term maintainability."));
ImGui::NewLine();
ImGui::TextWrapped(
"%s", FSUI_CSTR("Duck icon by icons8 (https://icons8.com/icon/74847/platforms.undefined.short-title)"));
ImGui::TextWrapped("%s",
FSUI_CSTR("Duck icon by icons8 (https://icons8.com/icon/74847/platforms.undefined.short-title)"));
ImGui::NewLine();
ImGui::TextWrapped(
"%s", FSUI_CSTR("\"PlayStation\" and \"PSX\" are registered trademarks of Sony Interactive Entertainment Europe "
@ -8476,22 +8409,13 @@ void FullscreenUI::DrawAboutWindow()
ExitFullscreenAndOpenURL("https://github.com/stenzek/duckstation/blob/master/CONTRIBUTORS.md");
if (MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_WINDOW_CLOSE, "Close")) || WantsToCloseMenu())
{
ImGui::CloseCurrentPopup();
s_state.about_window_open = false;
}
CloseFixedPopupDialog();
else
{
SetStandardSelectionFooterText(true);
}
EndMenuButtons();
ImGui::EndPopup();
}
ImGui::PopStyleVar(2);
ImGui::PopFont();
EndFixedPopupDialog();
}
void FullscreenUI::OpenAchievementsWindow()

File diff suppressed because it is too large Load Diff

View File

@ -44,6 +44,9 @@ static constexpr float LAYOUT_HORIZONTAL_MENU_PADDING = 30.0f;
static constexpr float LAYOUT_HORIZONTAL_MENU_ITEM_WIDTH = 250.0f;
static constexpr float LAYOUT_HORIZONTAL_MENU_ITEM_IMAGE_SIZE = 150.0f;
static constexpr float LAYOUT_SHADOW_OFFSET = 1.0f;
static constexpr float LAYOUT_SMALL_POPUP_PADDING = 20.0f;
static constexpr float LAYOUT_LARGE_POPUP_PADDING = 30.0f;
static constexpr float LAYOUT_LARGE_POPUP_ROUNDING = 40.0f;
struct ALIGN_TO_CACHE_LINE UIStyles
{
@ -185,8 +188,16 @@ void UploadAsyncTextures();
void BeginLayout();
void EndLayout();
bool BeginFixedPopupModal(const char* name, bool* p_open = nullptr);
void EndFixedPopupModal();
bool IsAnyFixedPopupDialogOpen();
bool IsFixedPopupDialogOpen(std::string_view name);
void OpenFixedPopupDialog(std::string_view name);
void CloseFixedPopupDialog();
void CloseFixedPopupDialogImmediately();
bool BeginFixedPopupDialog(float scaled_window_padding = LayoutScale(20.0f),
float scaled_window_rounding = LayoutScale(20.0f),
const ImVec2& scaled_window_size = ImVec2(0.0f, 0.0f));
void EndFixedPopupDialog();
void RenderOverlays();
@ -357,7 +368,7 @@ void CloseChoiceDialog();
using InputStringDialogCallback = std::function<void(std::string text)>;
bool IsInputDialogOpen();
void OpenInputStringDialog(std::string title, std::string message, std::string caption, std::string ok_button_text,
void OpenInputStringDialog(std::string_view title, std::string message, std::string caption, std::string ok_button_text,
InputStringDialogCallback callback);
void CloseInputDialog();
@ -365,12 +376,12 @@ using ConfirmMessageDialogCallback = std::function<void(bool)>;
using InfoMessageDialogCallback = std::function<void()>;
using MessageDialogCallback = std::function<void(s32)>;
bool IsMessageBoxDialogOpen();
void OpenConfirmMessageDialog(std::string title, std::string message, ConfirmMessageDialogCallback callback,
void OpenConfirmMessageDialog(std::string_view title, std::string message, ConfirmMessageDialogCallback callback,
std::string yes_button_text = ICON_FA_CHECK " Yes",
std::string no_button_text = ICON_FA_TIMES " No");
void OpenInfoMessageDialog(std::string title, std::string message, InfoMessageDialogCallback callback = {},
void OpenInfoMessageDialog(std::string_view title, std::string message, InfoMessageDialogCallback callback = {},
std::string button_text = ICON_FA_WINDOW_CLOSE " Close");
void OpenMessageDialog(std::string title, std::string message, MessageDialogCallback callback,
void OpenMessageDialog(std::string_view title, std::string message, MessageDialogCallback callback,
std::string first_button_text, std::string second_button_text, std::string third_button_text);
void CloseMessageDialog();
@ -405,6 +416,46 @@ void ClearToast();
void GetChoiceDialogHelpText(SmallStringBase& dest);
void GetFileSelectorHelpText(SmallStringBase& dest);
void GetInputDialogHelpText(SmallStringBase& dest);
// Wrapper for an animated popup dialog.
class PopupDialog
{
public:
PopupDialog();
~PopupDialog();
ALWAYS_INLINE const std::string& GetTitle() const { return m_title; }
ALWAYS_INLINE bool IsOpen() const { return (m_state != State::Inactive); }
void StartClose();
void CloseImmediately();
void ClearState();
protected:
enum class State
{
Inactive,
ClosingTrigger,
Open,
OpeningTrigger,
Opening,
Closing,
};
static constexpr float OPEN_TIME = 0.2f;
static constexpr float CLOSE_TIME = 0.1f;
void SetTitleAndOpen(std::string title);
bool BeginRender(float scaled_window_padding = LayoutScale(20.0f), float scaled_window_rounding = LayoutScale(20.0f),
const ImVec2& scaled_window_size = ImVec2(0.0f, 0.0f));
void EndRender();
std::string m_title;
float m_animation_time_remaining = 0.0f;
State m_state = State::Inactive;
};
} // namespace ImGuiFullscreen
// Host UI triggers from Big Picture mode.