overlays: add message box to home menu

This commit is contained in:
Megamouse 2023-01-21 00:53:49 +01:00
parent 9375e255e1
commit e064380a7d
17 changed files with 347 additions and 44 deletions

View File

@ -12,6 +12,14 @@ namespace rsx
static constexpr u16 available_side_width = (overlay::virtual_width - 6 * menu_entry_margin) / 2;
static constexpr u16 element_height = 25;
enum class page_navigation
{
stay,
back,
next,
exit
};
struct home_menu_entry : horizontal_layout
{
public:

View File

@ -15,6 +15,9 @@ namespace rsx
{
is_current_page = true;
m_message_box = std::make_shared<home_menu_message_box>(x, y, width, height);
m_config_changed = std::make_shared<bool>(g_backup_cfg.to_string() != g_cfg.to_string());
std::unique_ptr<overlay_element> resume = std::make_unique<home_menu_entry>(get_localized_string(localized_string_id::HOME_MENU_RESUME));
add_item(resume, [](pad_button btn) -> page_navigation
{

View File

@ -0,0 +1,108 @@
#include "stdafx.h"
#include "overlay_home_menu_message_box.h"
#include "Emu/System.h"
#include "Emu/system_config.h"
namespace rsx
{
namespace overlays
{
home_menu_message_box::home_menu_message_box(u16 x, u16 y, u16 width, u16 height)
: overlay_element()
{
back_color = {0.15f, 0.15f, 0.15f, 0.95f};
set_size(width, height);
set_pos(x, y);
m_label = std::make_unique<label>();
m_label->align_text(text_align::center);
m_label->set_font("Arial", 16);
m_label->back_color.a = 0.0f;
m_accept_btn = std::make_unique<image_button>(120, 20);
m_cancel_btn = std::make_unique<image_button>(120, 20);
m_accept_btn->set_size(120, 30);
m_cancel_btn->set_size(120, 30);
if (g_cfg.sys.enter_button_assignment == enter_button_assign::circle)
{
m_accept_btn->set_image_resource(resource_config::standard_image_resource::circle);
m_cancel_btn->set_image_resource(resource_config::standard_image_resource::cross);
}
else
{
m_accept_btn->set_image_resource(resource_config::standard_image_resource::cross);
m_cancel_btn->set_image_resource(resource_config::standard_image_resource::circle);
}
m_accept_btn->set_pos(x + 30, y + height + 20);
m_cancel_btn->set_pos(x + 180, y + height + 20);
m_accept_btn->set_text(localized_string_id::RSX_OVERLAYS_LIST_SELECT);
m_cancel_btn->set_text(localized_string_id::RSX_OVERLAYS_LIST_CANCEL);
m_accept_btn->set_font("Arial", 16);
m_cancel_btn->set_font("Arial", 16);
}
compiled_resource& home_menu_message_box::get_compiled()
{
if (!is_compiled)
{
compiled_resource& compiled = overlay_element::get_compiled();
compiled.add(m_label->get_compiled());
compiled.add(m_cancel_btn->get_compiled());
compiled.add(m_accept_btn->get_compiled());
}
return compiled_resources;
}
void home_menu_message_box::show(const std::string& text, std::function<void()> on_accept, std::function<void()> on_cancel)
{
m_on_accept = std::move(on_accept);
m_on_cancel = std::move(on_cancel);
m_label->set_text(text);
m_label->auto_resize();
m_label->set_pos(x + (w - m_label->w) / 2, y + (h - m_label->h) / 2);
m_visible = true;
refresh();
}
void home_menu_message_box::hide()
{
m_visible = false;
refresh();
}
page_navigation home_menu_message_box::handle_button_press(pad_button button_press)
{
switch (button_press)
{
case pad_button::cross:
{
Emu.GetCallbacks().play_sound(fs::get_config_dir() + "sounds/snd_decide.wav");
if (m_on_accept)
{
m_on_accept();
}
return page_navigation::next;
}
case pad_button::circle:
{
Emu.GetCallbacks().play_sound(fs::get_config_dir() + "sounds/snd_cancel.wav");
if (m_on_cancel)
{
m_on_cancel();
}
return page_navigation::back;
}
default:
{
return page_navigation::stay;
}
}
}
}
}

View File

@ -0,0 +1,28 @@
#pragma once
#include "overlay_home_menu_components.h"
namespace rsx
{
namespace overlays
{
struct home_menu_message_box : public overlay_element
{
public:
home_menu_message_box(u16 x, u16 y, u16 width, u16 height);
compiled_resource& get_compiled() override;
void show(const std::string& text, std::function<void()> on_accept = nullptr, std::function<void()> on_cancel = nullptr);
void hide();
page_navigation handle_button_press(pad_button button_press);
bool visible() const { return m_visible; }
private:
bool m_visible = false;
std::unique_ptr<label> m_label;
std::unique_ptr<image_button> m_cancel_btn;
std::unique_ptr<image_button> m_accept_btn;
std::function<void()> m_on_accept;
std::function<void()> m_on_cancel;
};
}
}

View File

@ -1,6 +1,7 @@
#include "stdafx.h"
#include "overlay_home_menu_page.h"
#include "Emu/System.h"
#include "Emu/system_config.h"
namespace rsx
{
@ -11,6 +12,30 @@ namespace rsx
, title(title)
, parent(parent)
{
if (parent)
{
m_message_box = parent->m_message_box;
m_config_changed = parent->m_config_changed;
}
m_save_btn = std::make_unique<image_button>(120, 20);
m_discard_btn = std::make_unique<image_button>(120, 20);
m_save_btn->set_size(120, 30);
m_discard_btn->set_size(120, 30);
m_save_btn->set_image_resource(resource_config::standard_image_resource::square);
m_discard_btn->set_image_resource(resource_config::standard_image_resource::triangle);
m_save_btn->set_pos(width - 2 * (30 + 120), height + 20);
m_discard_btn->set_pos(width - (30 + 120), height + 20);
m_save_btn->set_text(localized_string_id::HOME_MENU_SETTINGS_SAVE_BUTTON);
m_discard_btn->set_text(localized_string_id::HOME_MENU_SETTINGS_DISCARD_BUTTON);
m_save_btn->set_font("Arial", 16);
m_discard_btn->set_font("Arial", 16);
set_pos(x, y);
}
@ -96,8 +121,29 @@ namespace rsx
}
}
void home_menu_page::show_dialog(const std::string& text, std::function<void()> on_accept, std::function<void()> on_cancel)
{
if (m_message_box && !m_message_box->visible())
{
rsx_log.notice("home_menu_page::show_dialog: page='%s', text='%s'", title, text);
m_message_box->show(text, std::move(on_accept), std::move(on_cancel));
refresh();
}
}
page_navigation home_menu_page::handle_button_press(pad_button button_press)
{
if (m_message_box && m_message_box->visible())
{
const page_navigation navigation = m_message_box->handle_button_press(button_press);
if (navigation != page_navigation::stay)
{
m_message_box->hide();
refresh();
}
return navigation;
}
if (home_menu_page* page = get_current_page(false))
{
return page->handle_button_press(button_press);
@ -131,6 +177,41 @@ namespace rsx
}
return page_navigation::exit;
}
case pad_button::triangle:
{
if (m_config_changed && *m_config_changed)
{
show_dialog(get_localized_string(localized_string_id::HOME_MENU_SETTINGS_DISCARD), [this]()
{
rsx_log.notice("home_menu_page: discarding settings...");
if (m_config_changed && *m_config_changed)
{
g_cfg.from_string(g_backup_cfg.to_string());
Emu.GetCallbacks().update_emu_settings();
*m_config_changed = false;
}
});
}
break;
}
case pad_button::square:
{
if (m_config_changed && *m_config_changed)
{
show_dialog(get_localized_string(localized_string_id::HOME_MENU_SETTINGS_SAVE), [this]()
{
rsx_log.notice("home_menu_page: saving settings...");
Emu.GetCallbacks().save_emu_settings();
if (m_config_changed)
{
*m_config_changed = false;
}
});
}
break;
}
case pad_button::dpad_up:
case pad_button::ls_up:
{
@ -164,14 +245,42 @@ namespace rsx
return page_navigation::stay;
}
void home_menu_page::translate(s16 _x, s16 _y)
{
list_view::translate(_x, _y);
m_save_btn->translate(_x, _y);
m_discard_btn->translate(_x, _y);
}
compiled_resource& home_menu_page::get_compiled()
{
if (home_menu_page* page = get_current_page(false))
if (!is_compiled || (m_message_box && !m_message_box->is_compiled))
{
return page->get_compiled();
is_compiled = false;
if (home_menu_page* page = get_current_page(false))
{
compiled_resources = page->get_compiled();
}
else
{
compiled_resources = list_view::get_compiled();
if (m_message_box && m_message_box->visible())
{
compiled_resources.add(m_message_box->get_compiled());
}
else if (m_config_changed && *m_config_changed)
{
compiled_resources.add(m_save_btn->get_compiled());
compiled_resources.add(m_discard_btn->get_compiled());
}
}
is_compiled = true;
}
return list_view::get_compiled();
return compiled_resources;
}
}
}

View File

@ -3,19 +3,12 @@
#include "Emu/RSX/Overlays/overlays.h"
#include "Emu/RSX/Overlays/overlay_list_view.hpp"
#include "Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.h"
#include "Emu/RSX/Overlays/HomeMenu/overlay_home_menu_message_box.h"
namespace rsx
{
namespace overlays
{
enum class page_navigation
{
stay,
back,
next,
exit
};
struct home_menu_page : public list_view
{
public:
@ -25,20 +18,27 @@ namespace rsx
home_menu_page* get_current_page(bool include_this);
page_navigation handle_button_press(pad_button button_press);
void translate(s16 _x, s16 _y) override;
compiled_resource& get_compiled() override;
bool is_current_page = false;
home_menu_page* parent = nullptr;
std::string title;
std::shared_ptr<home_menu_message_box> m_message_box;
std::shared_ptr<bool> m_config_changed;
protected:
void add_page(std::shared_ptr<home_menu_page> page);
void add_item(std::unique_ptr<overlay_element>& element, std::function<page_navigation(pad_button)> callback);
void apply_layout(bool center_vertically = true);
void show_dialog(const std::string& text, std::function<void()> on_accept = nullptr, std::function<void()> on_cancel = nullptr);
std::vector<std::shared_ptr<home_menu_page>> m_pages;
private:
std::unique_ptr<image_button> m_save_btn;
std::unique_ptr<image_button> m_discard_btn;
std::vector<std::unique_ptr<overlay_element>> m_entries;
std::vector<std::function<page_navigation(pad_button)>> m_callbacks;
};

View File

@ -36,6 +36,7 @@ namespace rsx
rsx_log.notice("User toggled '%s' in '%s'. Setting '%s' to %d", text, title, setting->get_name(), value);
setting->set(value);
Emu.GetCallbacks().update_emu_settings();
if (m_config_changed) *m_config_changed = true;
refresh();
}
@ -78,6 +79,7 @@ namespace rsx
rsx_log.error("Can't toggle '%s' in '%s'. Setting '%s' to '%s' failed", text, title, setting->get_name(), next_value);
}
Emu.GetCallbacks().update_emu_settings();
if (m_config_changed) *m_config_changed = true;
refresh();
}
@ -115,6 +117,7 @@ namespace rsx
rsx_log.notice("User toggled '%s' in '%s'. Setting '%s' to %d", text, title, setting->get_name(), value);
setting->set(value);
Emu.GetCallbacks().update_emu_settings();
if (m_config_changed) *m_config_changed = true;
refresh();
}
}
@ -153,6 +156,7 @@ namespace rsx
rsx_log.notice("User toggled '%s' in '%s'. Setting '%s' to %d", text, title, setting->get_name(), value);
setting->set(value);
Emu.GetCallbacks().update_emu_settings();
if (m_config_changed) *m_config_changed = true;
refresh();
}
}
@ -191,6 +195,7 @@ namespace rsx
rsx_log.notice("User toggled '%s' in '%s'. Setting '%s' to %.2f", text, title, setting->get_name(), value);
setting->set(value);
Emu.GetCallbacks().update_emu_settings();
if (m_config_changed) *m_config_changed = true;
refresh();
}
}

View File

@ -368,6 +368,9 @@ void Emulator::Init(bool add_only)
// Disable incompatible settings
fixup_ppu_settings();
// Backup config
g_backup_cfg.from_string(g_cfg.to_string());
// Create directories (can be disabled if necessary)
auto make_path_verbose = [&](const std::string& path, bool must_exist_outside_emu_dir)
{
@ -1270,6 +1273,9 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
{
g_cfg.audio.provider.set(audio_provider::cell_audio);
}
// Backup config
g_backup_cfg.from_string(g_cfg.to_string());
}
// Set RTM usage
@ -3318,4 +3324,43 @@ bool Emulator::IsVsh()
return g_ps3_process_info.get_cellos_appname() == "vsh.self"sv;
}
void Emulator::SaveSettings(const std::string& settings, const std::string& title_id)
{
std::string config_name;
if (title_id.empty())
{
config_name = fs::get_config_dir() + "/config.yml";
}
else
{
config_name = rpcs3::utils::get_custom_config_path(title_id);
}
// Save config atomically
fs::pending_file temp(config_name);
temp.file.write(settings.c_str(), settings.size());
if (!temp.commit())
{
sys_log.error("Could not save config to %s (error=%s)", config_name, fs::g_tls_error);
}
// Check if the running config/title is the same as the edited config/title.
if (config_name == g_cfg.name || title_id == Emu.GetTitleID())
{
// Update current config
if (!g_cfg.from_string({settings.c_str(), settings.size()}, !Emu.IsStopped()))
{
sys_log.fatal("Failed to update configuration");
}
else if (!Emu.IsStopped()) // Don't spam the log while emulation is stopped. The config will be logged on boot anyway.
{
sys_log.notice("Updated configuration:\n%s\n", g_cfg.to_string());
}
}
// Backup config
g_backup_cfg.from_string(g_cfg.to_string());
}
Emulator Emu;

View File

@ -82,6 +82,7 @@ struct EmuCallbacks
std::function<void()> init_mouse_handler;
std::function<void(std::string_view title_id)> init_pad_handler;
std::function<void()> update_emu_settings;
std::function<void()> save_emu_settings;
std::function<std::unique_ptr<class GSFrameBase>()> get_gs_frame;
std::function<std::shared_ptr<class camera_handler_base>()> get_camera_handler;
std::function<std::shared_ptr<class music_handler_base>()> get_music_handler;
@ -343,6 +344,8 @@ public:
friend void init_fxo_for_exec(utils::serial*, bool);
static bool IsVsh();
static void SaveSettings(const std::string& settings, const std::string& title_id);
};
extern Emulator Emu;

View File

@ -154,6 +154,10 @@ enum class localized_string_id
HOME_MENU_EXIT_GAME,
HOME_MENU_RESUME,
HOME_MENU_SETTINGS,
HOME_MENU_SETTINGS_SAVE,
HOME_MENU_SETTINGS_SAVE_BUTTON,
HOME_MENU_SETTINGS_DISCARD,
HOME_MENU_SETTINGS_DISCARD_BUTTON,
HOME_MENU_SETTINGS_AUDIO,
HOME_MENU_SETTINGS_VIDEO,
HOME_MENU_SETTINGS_INPUT,

View File

@ -4,6 +4,7 @@
#include "util/sysinfo.hpp"
cfg_root g_cfg{};
cfg_root g_backup_cfg{};
bool cfg_root::node_core::enable_tsx_by_default()
{

View File

@ -336,3 +336,4 @@ struct cfg_root : cfg::node
};
extern cfg_root g_cfg;
extern cfg_root g_backup_cfg;

View File

@ -86,6 +86,7 @@
<ClCompile Include="Emu\RSX\Common\texture_cache.cpp" />
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu.cpp" />
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_components.cpp" />
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_message_box.cpp" />
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_main_menu.cpp" />
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_page.cpp" />
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_settings.cpp" />
@ -541,6 +542,7 @@
<ClInclude Include="Emu\RSX\Core\RSXVertexTypes.h" />
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu.h" />
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_components.h" />
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_message_box.h" />
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_main_menu.h" />
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_page.h" />
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_settings.h" />

View File

@ -1135,6 +1135,9 @@
<ClCompile Include="Emu\RSX\Overlays\overlay_shader_compile_notification.cpp">
<Filter>Emu\GPU\RSX\Overlays</Filter>
</ClCompile>
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_message_box.cpp">
<Filter>Emu\GPU\RSX\Overlays\HomeMenu</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Crypto\aes.h">
@ -2284,6 +2287,9 @@
<ClInclude Include="Emu\RSX\Program\RSXOverlay.h">
<Filter>Emu\GPU\RSX\Program</Filter>
</ClInclude>
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_message_box.h">
<Filter>Emu\GPU\RSX\Overlays\HomeMenu</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl">

View File

@ -111,6 +111,14 @@ EmuCallbacks main_application::CreateCallbacks()
});
};
callbacks.save_emu_settings = [this]()
{
Emu.BlockingCallFromMainThread([&]()
{
Emulator::SaveSettings(g_cfg.to_string(), Emu.GetTitleID());
});
};
callbacks.init_kb_handler = [this]()
{
switch (g_cfg.io.keyboard.get())

View File

@ -268,40 +268,8 @@ void emu_settings::RestoreDefaults()
void emu_settings::SaveSettings()
{
YAML::Emitter out;
std::string config_name;
if (m_title_id.empty())
{
config_name = fs::get_config_dir() + "/config.yml";
}
else
{
config_name = rpcs3::utils::get_custom_config_path(m_title_id);
}
emit_data(out, m_current_settings);
// Save config atomically
fs::pending_file temp(config_name);
temp.file.write(out.c_str(), out.size());
if (!temp.commit())
{
cfg_log.error("Could not save config to %s (error=%s)", config_name, fs::g_tls_error);
}
// Check if the running config/title is the same as the edited config/title.
if (config_name == g_cfg.name || m_title_id == Emu.GetTitleID())
{
// Update current config
if (!g_cfg.from_string({out.c_str(), out.size()}, !Emu.IsStopped()))
{
cfg_log.fatal("Failed to update configuration");
}
else if (!Emu.IsStopped()) // Don't spam the log while emulation is stopped. The config will be logged on boot anyway.
{
cfg_log.notice("Updated configuration:\n%s\n", g_cfg.to_string());
}
}
Emulator::SaveSettings(out.c_str(), m_title_id);
}
void emu_settings::EnhanceComboBox(QComboBox* combobox, emu_settings_type type, bool is_ranged, bool use_max, int max, bool sorted, bool strict)

View File

@ -173,6 +173,10 @@ private:
case localized_string_id::HOME_MENU_EXIT_GAME: return tr("Exit Game");
case localized_string_id::HOME_MENU_RESUME: return tr("Resume Game");
case localized_string_id::HOME_MENU_SETTINGS: return tr("Settings");
case localized_string_id::HOME_MENU_SETTINGS_SAVE: return tr("Save custom configuration?");
case localized_string_id::HOME_MENU_SETTINGS_SAVE_BUTTON: return tr("Save");
case localized_string_id::HOME_MENU_SETTINGS_DISCARD: return tr("Discard the current settings' changes?");
case localized_string_id::HOME_MENU_SETTINGS_DISCARD_BUTTON: return tr("Discard");
case localized_string_id::HOME_MENU_SETTINGS_AUDIO: return tr("Audio");
case localized_string_id::HOME_MENU_SETTINGS_VIDEO: return tr("Video");
case localized_string_id::HOME_MENU_SETTINGS_INPUT: return tr("Input");