mirror of
https://github.com/stenzek/duckstation.git
synced 2026-04-17 03:26:58 +00:00
FullscreenUI: Use horizontal buttons for message dialogs
Unless it's a long string, then use vertical. Also add icons to the dialogs.
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#define ICON_EMOJI_OPTICAL_DISK "\xf0\x9f\x92\xbf"
|
||||
#define ICON_EMOJI_FLOPPY_DISK "\xf0\x9f\x92\xbe"
|
||||
#define ICON_EMOJI_INFORMATION "\xe2\x84\xb9"
|
||||
#define ICON_EMOJI_QUESTION_MARK "\xe2\x93\x98"
|
||||
#define ICON_EMOJI_FAST_FORWARD "\xe2\x8f\xa9"
|
||||
#define ICON_EMOJI_FAST_REVERSE "\xe2\x8f\xaa"
|
||||
#define ICON_EMOJI_RECORD "\xe2\x8f\xba"
|
||||
|
||||
@@ -639,7 +639,7 @@ void FullscreenUI::DoStartPath(std::string path, std::string state, std::optiona
|
||||
if (!IsInitialized())
|
||||
return;
|
||||
|
||||
OpenInfoMessageDialog(TRANSLATE_STR("System", "Error"),
|
||||
OpenInfoMessageDialog(ICON_EMOJI_NO_ENTRY_SIGN, TRANSLATE_STR("System", "Error"),
|
||||
fmt::format(TRANSLATE_FS("System", "Failed to boot system: {}"), error_desc));
|
||||
ClearSaveStateEntryList();
|
||||
UpdateRunIdleState();
|
||||
@@ -730,7 +730,7 @@ void FullscreenUI::ConfirmIfSavingMemoryCards(std::string action, std::function<
|
||||
}
|
||||
|
||||
OpenConfirmMessageDialog(
|
||||
FSUI_ICONVSTR(ICON_PF_MEMORY_CARD, "Memory Card Busy"),
|
||||
ICON_EMOJI_WARNING, FSUI_ICONVSTR(ICON_PF_MEMORY_CARD, "Memory Card Busy"),
|
||||
fmt::format(
|
||||
FSUI_FSTR("WARNING: Your game is still saving to the memory card. Continuing to {0} may IRREVERSIBLY "
|
||||
"DESTROY YOUR MEMORY CARD. We recommend resuming your game and waiting 5 seconds for it to "
|
||||
|
||||
@@ -101,7 +101,7 @@ void FullscreenUI::DoSetCoverImage(std::string entry_path)
|
||||
if (!existing_path.empty())
|
||||
{
|
||||
OpenConfirmMessageDialog(
|
||||
FSUI_ICONVSTR(ICON_FA_IMAGE, "Set Cover Image"),
|
||||
ICON_EMOJI_WARNING, FSUI_ICONVSTR(ICON_FA_IMAGE, "Set Cover Image"),
|
||||
FSUI_STR("A cover already exists for this game. Are you sure that you want to overwrite it?"),
|
||||
[path = std::move(path), existing_path = std::move(existing_path),
|
||||
new_path = std::move(new_path)](bool result) {
|
||||
|
||||
@@ -1552,7 +1552,7 @@ void FullscreenUI::StartAutomaticBindingForPort(u32 port)
|
||||
void FullscreenUI::StartClearBindingsForPort(u32 port)
|
||||
{
|
||||
OpenConfirmMessageDialog(
|
||||
FSUI_STR("Clear Mappings"),
|
||||
ICON_EMOJI_WARNING, FSUI_STR("Clear Mappings"),
|
||||
FSUI_STR("Are you sure you want to clear all mappings for this controller?\n\nYou cannot undo this action."),
|
||||
[port](bool result) {
|
||||
if (!result)
|
||||
@@ -1743,7 +1743,7 @@ void FullscreenUI::PopulatePatchesAndCheatsList()
|
||||
|
||||
void FullscreenUI::BeginResetSettings()
|
||||
{
|
||||
OpenConfirmMessageDialog(FSUI_STR("Restore Defaults"),
|
||||
OpenConfirmMessageDialog(ICON_EMOJI_WARNING, FSUI_STR("Restore Defaults"),
|
||||
FSUI_STR("Are you sure you want to restore the default settings? Any preferences will be "
|
||||
"lost.\n\nYou cannot undo this action."),
|
||||
[](bool result) {
|
||||
@@ -2053,7 +2053,7 @@ void FullscreenUI::DrawSettingsWindow()
|
||||
INFO_LOG("Removing empty game settings {}", s_settings_locals.game_settings_interface->GetPath());
|
||||
if (!FileSystem::DeleteFile(s_settings_locals.game_settings_interface->GetPath().c_str(), &error))
|
||||
{
|
||||
OpenInfoMessageDialog(FSUI_STR("Error"),
|
||||
OpenInfoMessageDialog(ICON_EMOJI_WARNING, FSUI_STR("Error"),
|
||||
fmt::format(FSUI_FSTR("An error occurred while deleting empty game settings:\n{}"),
|
||||
error.GetDescription()));
|
||||
}
|
||||
@@ -2064,7 +2064,7 @@ void FullscreenUI::DrawSettingsWindow()
|
||||
if (!s_settings_locals.game_settings_interface->Save(&error))
|
||||
{
|
||||
OpenInfoMessageDialog(
|
||||
FSUI_STR("Error"),
|
||||
ICON_EMOJI_WARNING, FSUI_STR("Error"),
|
||||
fmt::format(FSUI_FSTR("An error occurred while saving game settings:\n{}"), error.GetDescription()));
|
||||
}
|
||||
}
|
||||
@@ -2613,7 +2613,7 @@ void FullscreenUI::DrawCoverDownloaderWindow()
|
||||
});
|
||||
}))
|
||||
{
|
||||
OpenInfoMessageDialog(FSUI_STR("Cover Download Error"), error.TakeDescription());
|
||||
OpenInfoMessageDialog(ICON_EMOJI_NO_ENTRY_SIGN, FSUI_STR("Cover Download Error"), error.TakeDescription());
|
||||
}
|
||||
|
||||
// close the parent window if we weren't cancelled
|
||||
@@ -3117,7 +3117,7 @@ void FullscreenUI::DoSaveInputProfile()
|
||||
|
||||
void FullscreenUI::BeginResetControllerSettings()
|
||||
{
|
||||
OpenConfirmMessageDialog(FSUI_STR("Reset Controller Settings"),
|
||||
OpenConfirmMessageDialog(ICON_EMOJI_WARNING, FSUI_STR("Reset Controller Settings"),
|
||||
FSUI_STR("Are you sure you want to restore the default controller configuration?\n\nAll "
|
||||
"bindings and configuration will be lost. You cannot undo this action."),
|
||||
[](bool result) {
|
||||
@@ -4312,7 +4312,7 @@ void FullscreenUI::DrawPostProcessingSettingsPage()
|
||||
if (MenuButton(FSUI_ICONVSTR(ICON_PF_TRASH, "Clear Shaders"), FSUI_VSTR("Clears a shader from the chain.")))
|
||||
{
|
||||
OpenConfirmMessageDialog(
|
||||
FSUI_ICONVSTR(ICON_PF_TRASH, "Clear Shaders"),
|
||||
ICON_EMOJI_WARNING, FSUI_ICONVSTR(ICON_PF_TRASH, "Clear Shaders"),
|
||||
FSUI_STR("Are you sure you want to clear the current post-processing chain? All configuration will be lost."),
|
||||
[](bool confirmed) {
|
||||
if (!confirmed)
|
||||
@@ -4880,7 +4880,7 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock<std::mutex>& se
|
||||
if (Achievements::HasActiveGame())
|
||||
{
|
||||
OpenConfirmMessageDialog(
|
||||
FSUI_ICONVSTR(ICON_FA_HAT_COWBOY, "Hardcore Mode"),
|
||||
ICON_EMOJI_INFORMATION, FSUI_ICONVSTR(ICON_FA_HAT_COWBOY, "Hardcore Mode"),
|
||||
FSUI_STR("Hardcore mode will not be enabled until the system is reset. Do you want to reset the system now?"),
|
||||
[](bool result) {
|
||||
if (result)
|
||||
@@ -5100,9 +5100,14 @@ void FullscreenUI::StartAchievementsProgressRefresh()
|
||||
GPUThread::RunOnThread([error = std::move(error), progress, result]() mutable {
|
||||
delete progress;
|
||||
if (result)
|
||||
{
|
||||
ShowToast(OSDMessageType::Info, {}, FSUI_STR("Progress database updated."));
|
||||
}
|
||||
else
|
||||
FullscreenUI::OpenInfoMessageDialog(FSUI_STR("Update Progress"), error.TakeDescription());
|
||||
{
|
||||
FullscreenUI::OpenInfoMessageDialog(ICON_EMOJI_NO_ENTRY_SIGN, FSUI_STR("Update Progress"),
|
||||
error.TakeDescription());
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5119,9 +5124,14 @@ void FullscreenUI::StartAchievementsGameIconDownload()
|
||||
GPUThread::RunOnThread([error = std::move(error), progress, result]() mutable {
|
||||
delete progress;
|
||||
if (result)
|
||||
{
|
||||
ShowToast(OSDMessageType::Info, {}, FSUI_STR("Game icons downloaded."));
|
||||
}
|
||||
else
|
||||
FullscreenUI::OpenInfoMessageDialog(FSUI_STR("Download Game Icons"), error.TakeDescription());
|
||||
{
|
||||
FullscreenUI::OpenInfoMessageDialog(ICON_EMOJI_NO_ENTRY_SIGN, FSUI_STR("Download Game Icons"),
|
||||
error.TakeDescription());
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -168,8 +168,8 @@ public:
|
||||
MessageDialog();
|
||||
~MessageDialog();
|
||||
|
||||
void Open(std::string_view title, std::string message, CallbackVariant callback, std::string first_button_text,
|
||||
std::string second_button_text, std::string third_button_text);
|
||||
void Open(std::string_view icon, std::string_view title, std::string message, CallbackVariant callback,
|
||||
std::string first_button_text, std::string second_button_text, std::string third_button_text);
|
||||
void ClearState();
|
||||
|
||||
void Draw();
|
||||
@@ -177,6 +177,7 @@ public:
|
||||
private:
|
||||
static void InvokeCallback(const CallbackVariant& cb, std::optional<s32> choice);
|
||||
|
||||
std::string m_icon;
|
||||
std::string m_message;
|
||||
std::array<std::string, 3> m_buttons;
|
||||
CallbackVariant m_callback;
|
||||
@@ -4209,11 +4210,12 @@ FullscreenUI::MessageDialog::MessageDialog() = default;
|
||||
|
||||
FullscreenUI::MessageDialog::~MessageDialog() = default;
|
||||
|
||||
void FullscreenUI::MessageDialog::Open(std::string_view title, std::string message, CallbackVariant callback,
|
||||
std::string first_button_text, std::string second_button_text,
|
||||
std::string third_button_text)
|
||||
void FullscreenUI::MessageDialog::Open(std::string_view icon, std::string_view title, std::string message,
|
||||
CallbackVariant callback, std::string first_button_text,
|
||||
std::string second_button_text, std::string third_button_text)
|
||||
{
|
||||
SetTitleAndOpen(fmt::format("{}##message_dialog", title));
|
||||
m_icon = icon;
|
||||
m_message = std::move(message);
|
||||
m_callback = std::move(callback);
|
||||
m_buttons[0] = std::move(first_button_text);
|
||||
@@ -4244,22 +4246,51 @@ void FullscreenUI::MessageDialog::Draw()
|
||||
|
||||
std::optional<s32> result;
|
||||
|
||||
ResetFocusHere();
|
||||
BeginMenuButtons();
|
||||
if (!m_icon.empty())
|
||||
{
|
||||
ImGui::PushFont(nullptr, LayoutScale(50.0f), 0.0f);
|
||||
ImGui::TextUnformatted(IMSTR_START_END(m_icon));
|
||||
ImGui::PopFont();
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + LayoutScale(10.0f));
|
||||
}
|
||||
|
||||
ImGui::TextWrapped("%s", m_message.c_str());
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + LayoutScale(20.0f));
|
||||
|
||||
for (s32 button_index = 0; button_index < static_cast<s32>(m_buttons.size()); button_index++)
|
||||
{
|
||||
if (!m_buttons[button_index].empty() &&
|
||||
MenuButtonWithoutSummary(m_buttons[button_index], true, LAYOUT_CENTER_ALIGN_TEXT))
|
||||
{
|
||||
result = button_index;
|
||||
}
|
||||
}
|
||||
ResetFocusHere();
|
||||
|
||||
EndMenuButtons();
|
||||
// use vertical buttons for long text
|
||||
if (!m_buttons[0].empty() && StringUtil::GetUTF8CharacterCount(m_buttons[0]) >= 15)
|
||||
{
|
||||
BeginMenuButtons();
|
||||
|
||||
for (s32 button_index = 0; button_index < static_cast<s32>(m_buttons.size()); button_index++)
|
||||
{
|
||||
if (!m_buttons[button_index].empty() &&
|
||||
MenuButtonWithoutSummary(m_buttons[button_index], true, LAYOUT_CENTER_ALIGN_TEXT))
|
||||
{
|
||||
result = button_index;
|
||||
}
|
||||
}
|
||||
EndMenuButtons();
|
||||
}
|
||||
else
|
||||
{
|
||||
BeginHorizontalMenuButtons(
|
||||
static_cast<u32>(std::ranges::count_if(m_buttons, [](const std::string& str) { return !str.empty(); })));
|
||||
|
||||
for (s32 button_index = 0; button_index < static_cast<s32>(m_buttons.size()); button_index++)
|
||||
{
|
||||
if (!m_buttons[button_index].empty() &&
|
||||
HorizontalMenuButton(m_buttons[button_index], true, LAYOUT_CENTER_ALIGN_TEXT))
|
||||
{
|
||||
result = button_index;
|
||||
}
|
||||
}
|
||||
|
||||
EndHorizontalMenuButtons();
|
||||
}
|
||||
|
||||
SetStandardSelectionFooterText(false);
|
||||
|
||||
@@ -4294,27 +4325,28 @@ bool FullscreenUI::IsMessageBoxDialogOpen()
|
||||
return s_state.message_dialog.IsOpen();
|
||||
}
|
||||
|
||||
void FullscreenUI::OpenConfirmMessageDialog(std::string_view title, std::string message,
|
||||
void FullscreenUI::OpenConfirmMessageDialog(std::string_view icon, std::string_view title, std::string message,
|
||||
ConfirmMessageDialogCallback callback, std::string yes_button_text,
|
||||
std::string no_button_text)
|
||||
{
|
||||
s_state.message_dialog.Open(std::move(title), std::move(message), std::move(callback), std::move(yes_button_text),
|
||||
std::move(no_button_text), std::string());
|
||||
s_state.message_dialog.Open(icon, std::move(title), std::move(message), std::move(callback),
|
||||
std::move(yes_button_text), std::move(no_button_text), std::string());
|
||||
}
|
||||
|
||||
void FullscreenUI::OpenInfoMessageDialog(std::string_view title, std::string message,
|
||||
void FullscreenUI::OpenInfoMessageDialog(std::string_view icon, std::string_view title, std::string message,
|
||||
InfoMessageDialogCallback callback, std::string button_text)
|
||||
{
|
||||
s_state.message_dialog.Open(std::move(title), std::move(message), std::move(callback), std::move(button_text),
|
||||
s_state.message_dialog.Open(icon, std::move(title), std::move(message), std::move(callback), std::move(button_text),
|
||||
std::string(), std::string());
|
||||
}
|
||||
|
||||
void FullscreenUI::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 FullscreenUI::OpenMessageDialog(std::string_view icon, std::string_view title, std::string message,
|
||||
MessageDialogCallback callback, std::string first_button_text,
|
||||
std::string second_button_text, std::string third_button_text)
|
||||
{
|
||||
s_state.message_dialog.Open(std::move(title), std::move(message), std::move(callback), std::move(first_button_text),
|
||||
std::move(second_button_text), std::move(third_button_text));
|
||||
s_state.message_dialog.Open(icon, std::move(title), std::move(message), std::move(callback),
|
||||
std::move(first_button_text), std::move(second_button_text),
|
||||
std::move(third_button_text));
|
||||
}
|
||||
|
||||
void FullscreenUI::CloseMessageDialog()
|
||||
@@ -4501,8 +4533,8 @@ void FullscreenUI::ProgressDialog::ProgressCallbackImpl::AlertPrompt(PromptIcon
|
||||
{
|
||||
s_state.progress_dialog.m_prompt_waiting.test_and_set(std::memory_order_release);
|
||||
|
||||
Host::RunOnCoreThread([message = std::string(message)]() mutable {
|
||||
GPUThread::RunOnThread([message = std::move(message)]() mutable {
|
||||
Host::RunOnCoreThread([message = std::string(message), icon]() mutable {
|
||||
GPUThread::RunOnThread([message = std::move(message), icon]() mutable {
|
||||
if (!s_state.progress_dialog.IsOpen())
|
||||
{
|
||||
s_state.progress_dialog.m_prompt_waiting.clear(std::memory_order_release);
|
||||
@@ -4518,8 +4550,26 @@ void FullscreenUI::ProgressDialog::ProgressCallbackImpl::AlertPrompt(PromptIcon
|
||||
float width = s_state.progress_dialog.m_width;
|
||||
s_state.progress_dialog.CloseImmediately();
|
||||
|
||||
std::string_view icon_str;
|
||||
switch (icon)
|
||||
{
|
||||
case PromptIcon::Error:
|
||||
icon_str = ICON_EMOJI_NO_ENTRY_SIGN;
|
||||
break;
|
||||
case PromptIcon::Warning:
|
||||
icon_str = ICON_EMOJI_WARNING;
|
||||
break;
|
||||
case PromptIcon::Question:
|
||||
icon_str = ICON_EMOJI_QUESTION_MARK;
|
||||
break;
|
||||
case PromptIcon::Information:
|
||||
default:
|
||||
icon_str = ICON_EMOJI_INFORMATION;
|
||||
break;
|
||||
}
|
||||
|
||||
OpenInfoMessageDialog(
|
||||
s_state.progress_dialog.GetTitle(), std::move(message),
|
||||
icon_str, s_state.progress_dialog.GetTitle(), std::move(message),
|
||||
[existing_title = std::move(existing_title), progress_range, progress_value, last_frac, width]() mutable {
|
||||
s_state.progress_dialog.SetTitleAndOpen(std::move(existing_title));
|
||||
s_state.progress_dialog.m_progress_range = progress_range;
|
||||
@@ -4566,7 +4616,7 @@ bool FullscreenUI::ProgressDialog::ProgressCallbackImpl::ConfirmPrompt(PromptIco
|
||||
if (no_text.empty())
|
||||
no_text = FSUI_ICONSTR(ICON_FA_XMARK, "No");
|
||||
|
||||
OpenConfirmMessageDialog(s_state.progress_dialog.GetTitle(), std::move(message),
|
||||
OpenConfirmMessageDialog(ICON_EMOJI_QUESTION_MARK, s_state.progress_dialog.GetTitle(), std::move(message),
|
||||
[existing_title = std::move(existing_title), progress_range, progress_value,
|
||||
last_frac, width](bool result) mutable {
|
||||
s_state.progress_dialog.SetTitleAndOpen(std::move(existing_title));
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "common/small_string.h"
|
||||
#include "common/types.h"
|
||||
|
||||
#include "IconsEmoji.h"
|
||||
#include "IconsFontAwesome.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
@@ -510,13 +511,16 @@ using ConfirmMessageDialogCallback = std::function<void(bool)>;
|
||||
using InfoMessageDialogCallback = std::function<void()>;
|
||||
using MessageDialogCallback = std::function<void(s32)>;
|
||||
bool IsMessageBoxDialogOpen();
|
||||
void OpenConfirmMessageDialog(std::string_view title, std::string message, ConfirmMessageDialogCallback callback,
|
||||
void OpenConfirmMessageDialog(std::string_view icon, std::string_view title, std::string message,
|
||||
ConfirmMessageDialogCallback callback,
|
||||
std::string yes_button_text = FSUI_ICONSTR(ICON_FA_CHECK, "Yes"),
|
||||
std::string no_button_text = FSUI_ICONSTR(ICON_FA_XMARK, "No"));
|
||||
void OpenInfoMessageDialog(std::string_view title, std::string message, InfoMessageDialogCallback callback = {},
|
||||
void OpenInfoMessageDialog(std::string_view icon, std::string_view title, std::string message,
|
||||
InfoMessageDialogCallback callback = {},
|
||||
std::string button_text = FSUI_ICONSTR(ICON_FA_SQUARE_XMARK, "Close"));
|
||||
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 OpenMessageDialog(std::string_view icon, 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();
|
||||
|
||||
std::unique_ptr<ProgressCallbackWithPrompt> OpenModalProgressDialog(std::string title,
|
||||
|
||||
@@ -1071,9 +1071,10 @@ void Host::OnSystemAbnormalShutdown(const std::string_view reason)
|
||||
{
|
||||
GPUThread::RunOnThread([reason = std::string(reason)]() {
|
||||
FullscreenUI::OpenInfoMessageDialog(
|
||||
"Abnormal System Shutdown", fmt::format("Unfortunately, the virtual machine has abnormally shut down and cannot "
|
||||
"be recovered. More information about the error is below:\n\n{}",
|
||||
reason));
|
||||
ICON_EMOJI_NO_ENTRY_SIGN, "Abnormal System Shutdown",
|
||||
fmt::format("Unfortunately, the virtual machine has abnormally shut down and cannot "
|
||||
"be recovered. More information about the error is below:\n\n{}",
|
||||
reason));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1460,8 +1461,8 @@ void Host::ConfirmMessageAsync(std::string_view title, std::string_view message,
|
||||
callback(result);
|
||||
};
|
||||
|
||||
FullscreenUI::OpenConfirmMessageDialog(std::move(title), std::move(message), std::move(final_callback),
|
||||
fmt::format(ICON_FA_CHECK " {}", yes_text),
|
||||
FullscreenUI::OpenConfirmMessageDialog(ICON_EMOJI_QUESTION_MARK, std::move(title), std::move(message),
|
||||
std::move(final_callback), fmt::format(ICON_FA_CHECK " {}", yes_text),
|
||||
fmt::format(ICON_FA_XMARK " {}", no_text));
|
||||
FullscreenUI::UpdateRunIdleState();
|
||||
});
|
||||
|
||||
@@ -2136,8 +2136,8 @@ void Host::ConfirmMessageAsync(std::string_view title, std::string_view message,
|
||||
callback(result);
|
||||
};
|
||||
|
||||
FullscreenUI::OpenConfirmMessageDialog(std::move(title), std::move(message), std::move(final_callback),
|
||||
fmt::format(ICON_FA_CHECK " {}", yes_text),
|
||||
FullscreenUI::OpenConfirmMessageDialog(ICON_EMOJI_QUESTION_MARK, std::move(title), std::move(message),
|
||||
std::move(final_callback), fmt::format(ICON_FA_CHECK " {}", yes_text),
|
||||
fmt::format(ICON_FA_XMARK " {}", no_text));
|
||||
FullscreenUI::UpdateRunIdleState();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user