1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 10:42:36 +01:00

overlays: add pages to home menu

This commit is contained in:
Megamouse 2023-01-21 00:53:49 +01:00
parent a56fc57a83
commit 9375e255e1
31 changed files with 1345 additions and 386 deletions

View File

@ -285,8 +285,8 @@ namespace cfg
int_type def; int_type def;
// Expose range // Expose range
static const s64 max = Max; static constexpr s64 max = Max;
static const s64 min = Min; static constexpr s64 min = Min;
_int(node* owner, const std::string& name, int_type def = std::min<int_type>(Max, std::max<int_type>(Min, 0)), bool dynamic = false) _int(node* owner, const std::string& name, int_type def = std::min<int_type>(Max, std::max<int_type>(Min, 0)), bool dynamic = false)
: _base(type::_int, owner, name, dynamic) : _base(type::_int, owner, name, dynamic)
@ -334,6 +334,7 @@ namespace cfg
void set(const s64& value) void set(const s64& value)
{ {
ensure(value >= Min && value <= Max);
m_value = static_cast<int_type>(value); m_value = static_cast<int_type>(value);
} }
@ -405,6 +406,7 @@ namespace cfg
void set(const f64& value) void set(const f64& value)
{ {
ensure(value >= Min && value <= Max);
m_value = static_cast<float_type>(value); m_value = static_cast<float_type>(value);
} }
@ -435,8 +437,8 @@ namespace cfg
int_type def; int_type def;
// Expose range // Expose range
static const u64 max = Max; static constexpr u64 max = Max;
static const u64 min = Min; static constexpr u64 min = Min;
uint(node* owner, const std::string& name, int_type def = std::max<int_type>(Min, 0), bool dynamic = false) uint(node* owner, const std::string& name, int_type def = std::max<int_type>(Min, 0), bool dynamic = false)
: _base(type::uint, owner, name, dynamic) : _base(type::uint, owner, name, dynamic)
@ -484,6 +486,7 @@ namespace cfg
void set(const u64& value) void set(const u64& value)
{ {
ensure(value >= Min && value <= Max);
m_value = static_cast<int_type>(value); m_value = static_cast<int_type>(value);
} }

View File

@ -427,5 +427,5 @@ using cell_audio = named_thread<cell_audio_thread>;
namespace audio namespace audio
{ {
cell_audio_config::raw_config get_raw_config(); cell_audio_config::raw_config get_raw_config();
void configure_audio(bool force_reset = false); extern void configure_audio(bool force_reset = false);
} }

View File

@ -1268,7 +1268,7 @@ bool rsxaudio_data_thread::enqueue_data(RsxaudioPort dst, bool silence, const vo
namespace audio namespace audio
{ {
void configure_rsxaudio() extern void configure_rsxaudio()
{ {
if (g_cfg.audio.provider == audio_provider::rsxaudio && g_fxo->is_init<rsx_audio_backend>()) if (g_cfg.audio.provider == audio_provider::rsxaudio && g_fxo->is_init<rsx_audio_backend>())
{ {

View File

@ -0,0 +1,217 @@
#include "stdafx.h"
#include "overlay_home_menu.h"
#include "Emu/RSX/RSXThread.h"
namespace rsx
{
namespace overlays
{
std::string get_time_string()
{
std::ostringstream ost;
const std::time_t dateTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
const std::tm tm = *std::localtime(&dateTime);
ost << std::put_time(&tm, "%Y/%m/%e %H:%M:%S");
return ost.str();
}
home_menu_dialog::home_menu_dialog()
{
m_allow_input_on_pause = true;
m_dim_background = std::make_unique<overlay_element>();
m_dim_background->set_size(overlay::virtual_width, overlay::virtual_height);
m_dim_background->back_color.a = 0.5f;
m_main_menu = std::make_unique<home_menu_main_menu>(20, 85, 1240, 540, false, nullptr);
m_description = std::make_unique<label>();
m_description->set_font("Arial", 20);
m_description->set_pos(20, 37);
m_description->set_text(m_main_menu->title);
m_description->auto_resize();
m_description->back_color.a = 0.f;
m_time_display = std::make_unique<label>();
m_time_display->set_font("Arial", 14);
m_time_display->set_text(get_time_string());
m_time_display->auto_resize();
m_time_display->set_pos(overlay::virtual_width - (20 + m_time_display->w), (m_description->y + m_description->h) - m_time_display->h);
m_time_display->back_color.a = 0.f;
fade_animation.duration = 0.15f;
return_code = selection_code::canceled;
}
void home_menu_dialog::update()
{
static u64 frame = 0;
if (Emu.IsPaused())
{
// Let's keep updating the animation anyway
frame++;
}
else
{
frame = rsx::get_current_renderer()->vblank_count;
}
if (fade_animation.active)
{
fade_animation.update(frame);
}
static std::string last_time;
std::string new_time = get_time_string();
if (last_time != new_time)
{
m_time_display->set_text(new_time);
m_time_display->auto_resize();
last_time = std::move(new_time);
}
}
void home_menu_dialog::on_button_pressed(pad_button button_press)
{
if (fade_animation.active) return;
// Increase auto repeat interval for some buttons
switch (button_press)
{
case pad_button::dpad_left:
case pad_button::dpad_right:
case pad_button::ls_left:
case pad_button::ls_right:
m_auto_repeat_ms_interval = 10;
break;
default:
m_auto_repeat_ms_interval = m_auto_repeat_ms_interval_default;
break;
}
const page_navigation navigation = m_main_menu->handle_button_press(button_press);
switch (navigation)
{
case page_navigation::back:
case page_navigation::next:
{
if (home_menu_page* page = m_main_menu->get_current_page(true))
{
std::string path = page->title;
for (home_menu_page* parent = page->parent; parent; parent = parent->parent)
{
path = parent->title + " > " + path;
}
m_description->set_text(path);
m_description->auto_resize();
}
break;
}
case page_navigation::exit:
{
fade_animation.current = color4f(1.f);
fade_animation.end = color4f(0.f);
fade_animation.active = true;
fade_animation.on_finish = [this]
{
close(true, true);
if (g_cfg.misc.pause_during_home_menu)
{
Emu.BlockingCallFromMainThread([]()
{
Emu.Resume();
});
}
};
break;
}
case page_navigation::stay:
{
break;
}
}
}
compiled_resource home_menu_dialog::get_compiled()
{
if (!visible)
{
return {};
}
compiled_resource result;
result.add(m_dim_background->get_compiled());
result.add(m_main_menu->get_compiled());
result.add(m_description->get_compiled());
result.add(m_time_display->get_compiled());
fade_animation.apply(result);
return result;
}
struct home_menu_dialog_thread
{
static constexpr auto thread_name = "Home Menu Thread"sv;
};
error_code home_menu_dialog::show(std::function<void(s32 status)> on_close)
{
visible = false;
fade_animation.current = color4f(0.f);
fade_animation.end = color4f(1.f);
fade_animation.active = true;
this->on_close = std::move(on_close);
visible = true;
auto& list_thread = g_fxo->get<named_thread<home_menu_dialog_thread>>();
const auto notify = std::make_shared<atomic_t<bool>>(false);
list_thread([&, notify]()
{
const u64 tbit = alloc_thread_bit();
g_thread_bit = tbit;
*notify = true;
notify->notify_one();
auto ref = g_fxo->get<display_manager>().get(uid);
if (const auto error = run_input_loop())
{
if (error != selection_code::canceled)
{
rsx_log.error("Home menu dialog input loop exited with error code=%d", error);
}
}
thread_bits &= ~tbit;
thread_bits.notify_all();
});
if (g_cfg.misc.pause_during_home_menu)
{
Emu.BlockingCallFromMainThread([]()
{
Emu.Pause(false, false);
});
}
while (list_thread < thread_state::errored && !*notify)
{
notify->wait(false, atomic_wait_timeout{1'000'000});
}
return CELL_OK;
}
} // namespace overlays
} // namespace RSX

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "overlays.h" #include "Emu/RSX/Overlays/overlays.h"
#include "overlay_list_view.hpp"
#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/ErrorCodes.h"
#include "overlay_home_menu_main_menu.h"
namespace rsx namespace rsx
{ {
@ -10,33 +10,23 @@ namespace rsx
{ {
struct home_menu_dialog : public user_interface struct home_menu_dialog : public user_interface
{ {
private:
struct home_menu_entry : horizontal_layout
{
public:
home_menu_entry(const std::string& text);
static constexpr u16 height = 40;
};
std::vector<std::unique_ptr<overlay_element>> m_entries;
std::vector<std::function<bool()>> m_callbacks;
std::unique_ptr<overlay_element> m_dim_background;
std::unique_ptr<list_view> m_list;
std::unique_ptr<label> m_description;
animation_color_interpolate fade_animation;
public: public:
home_menu_dialog(); explicit home_menu_dialog();
void update() override; void update() override;
void on_button_pressed(pad_button button_press) override; void on_button_pressed(pad_button button_press) override;
compiled_resource get_compiled() override; compiled_resource get_compiled() override;
void add_item(const std::string& text, std::function<bool()> callback);
error_code show(std::function<void(s32 status)> on_close); error_code show(std::function<void(s32 status)> on_close);
private:
std::unique_ptr<overlay_element> m_dim_background;
std::unique_ptr<home_menu_main_menu> m_main_menu;
std::unique_ptr<label> m_description;
std::unique_ptr<label> m_time_display;
animation_color_interpolate fade_animation;
}; };
} }
} }

View File

@ -0,0 +1,67 @@
#include "stdafx.h"
#include "overlay_home_menu_components.h"
namespace rsx
{
namespace overlays
{
home_menu_entry::home_menu_entry(const std::string& text)
{
std::unique_ptr<overlay_element> text_stack = std::make_unique<vertical_layout>();
std::unique_ptr<overlay_element> padding = std::make_unique<spacer>();
std::unique_ptr<overlay_element> title = std::make_unique<label>(text);
padding->set_size(1, 1);
title->set_size(overlay::virtual_width - 2 * menu_entry_margin, menu_entry_height);
title->set_font("Arial", 16);
title->set_wrap_text(true);
title->align_text(text_align::center);
// Make back color transparent for text
title->back_color.a = 0.f;
static_cast<vertical_layout*>(text_stack.get())->pack_padding = 5;
static_cast<vertical_layout*>(text_stack.get())->add_element(padding);
static_cast<vertical_layout*>(text_stack.get())->add_element(title);
// Pack
this->pack_padding = 15;
add_element(text_stack);
}
home_menu_checkbox::home_menu_checkbox(cfg::_bool* setting, const std::string& text) : home_menu_setting(setting, text)
{
m_background.set_size(menu_entry_margin, menu_entry_margin);
m_background.set_pos(overlay::virtual_width / 2 + menu_entry_margin, 0);
m_checkbox.set_size(m_background.w - 2, m_background.h - 2);
m_checkbox.set_pos(m_background.x, m_background.y);
}
compiled_resource& home_menu_checkbox::get_compiled()
{
update_value();
if (!is_compiled)
{
const f32 col = m_last_value ? 1.0f : 0.3f;
const f32 bkg = m_last_value ? 0.3f : 1.0f;
m_background.back_color.r = bkg;
m_background.back_color.g = bkg;
m_background.back_color.b = bkg;
m_checkbox.back_color.r = col;
m_checkbox.back_color.g = col;
m_checkbox.back_color.b = col;
m_background.set_pos(m_background.x, y + (h - m_background.h) / 2);
m_checkbox.set_pos(m_background.x + 1, m_background.y + 1);
compiled_resources = horizontal_layout::get_compiled();
compiled_resources.add(m_background.get_compiled());
compiled_resources.add(m_checkbox.get_compiled());
}
return compiled_resources;
}
}
}

View File

@ -0,0 +1,201 @@
#pragma once
#include "Emu/RSX/Overlays/overlays.h"
#include "Utilities/Config.h"
namespace rsx
{
namespace overlays
{
static constexpr u16 menu_entry_height = 40;
static constexpr u16 menu_entry_margin = 20;
static constexpr u16 available_side_width = (overlay::virtual_width - 6 * menu_entry_margin) / 2;
static constexpr u16 element_height = 25;
struct home_menu_entry : horizontal_layout
{
public:
home_menu_entry(const std::string& text);
};
template <typename T, typename C>
struct home_menu_setting : horizontal_layout
{
public:
home_menu_setting(C* setting, const std::string& text) : m_setting(setting)
{
std::unique_ptr<overlay_element> layout = std::make_unique<vertical_layout>();
std::unique_ptr<overlay_element> padding = std::make_unique<spacer>();
std::unique_ptr<overlay_element> title = std::make_unique<label>(text);
padding->set_size(1, 1);
title->set_size(available_side_width, menu_entry_height);
title->set_font("Arial", 16);
title->set_wrap_text(true);
title->align_text(text_align::right);
// Make back color transparent for text
title->back_color.a = 0.f;
static_cast<vertical_layout*>(layout.get())->pack_padding = 5;
static_cast<vertical_layout*>(layout.get())->add_element(padding);
static_cast<vertical_layout*>(layout.get())->add_element(title);
// Pack
this->pack_padding = 15;
add_element(layout);
update_value(true);
}
void update_value(bool initializing = false)
{
if (m_setting)
{
if (const T new_value = m_setting->get(); new_value != m_last_value || initializing)
{
m_last_value = new_value;
is_compiled = false;
}
}
}
protected:
T m_last_value = {};
C* m_setting = nullptr;
};
struct home_menu_checkbox : public home_menu_setting<bool, cfg::_bool>
{
public:
home_menu_checkbox(cfg::_bool* setting, const std::string& text);
compiled_resource& get_compiled() override;
private:
overlay_element m_background;
overlay_element m_checkbox;
};
template <typename T>
struct home_menu_dropdown : public home_menu_setting<T, cfg::_enum<T>>
{
public:
home_menu_dropdown(cfg::_enum<T>* setting, const std::string& text) : home_menu_setting<T, cfg::_enum<T>>(setting, text)
{
m_dropdown.set_size(available_side_width / 2, element_height);
m_dropdown.set_pos(overlay::virtual_width / 2 + menu_entry_margin, 0);
m_dropdown.set_font("Arial", 14);
m_dropdown.align_text(this->text_align::center);
m_dropdown.back_color = { 0.3f, 0.3f, 0.3f, 1.0f };
}
compiled_resource& get_compiled()
{
this->update_value();
if (!this->is_compiled)
{
m_dropdown.set_text(fmt::format("%s", this->m_last_value));
m_dropdown.set_pos(m_dropdown.x, this->y + (this->h - m_dropdown.h) / 2);
this->compiled_resources = horizontal_layout::get_compiled();
this->compiled_resources.add(m_dropdown.get_compiled());
}
return this->compiled_resources;
}
private:
label m_dropdown;
};
template <typename T, typename C>
struct home_menu_slider : public home_menu_setting<T, C>
{
public:
home_menu_slider(C* setting, const std::string& text, const std::string& suffix, T minimum = C::min, T maximum = C::max)
: home_menu_setting<T, C>(setting, text)
, m_suffix(suffix)
, m_minimum(minimum)
, m_maximum(maximum)
{
m_slider.set_size(available_side_width / 2, element_height);
m_slider.set_pos(overlay::virtual_width / 2 + menu_entry_margin, 0);
m_slider.back_color = { 0.3f, 0.3f, 0.3f, 1.0f };
m_handle.set_size(element_height / 2, element_height);
m_handle.set_pos(m_slider.x, 0);
m_handle.back_color = { 1.0f, 1.0f, 1.0f, 1.0f };
m_value_label.back_color = m_slider.back_color;
m_value_label.set_font("Arial", 14);
}
compiled_resource& get_compiled() override
{
this->update_value();
if (!this->is_compiled)
{
const f64 percentage = std::clamp((this->m_last_value - static_cast<T>(m_minimum)) / std::fabs(m_maximum - m_minimum), 0.0, 1.0);
m_slider.set_pos(m_slider.x, this->y + (this->h - m_slider.h) / 2);
m_handle.set_pos(m_slider.x + static_cast<u16>(percentage * (m_slider.w - m_handle.w)), this->y + (this->h - m_handle.h) / 2);
if constexpr (std::is_floating_point<T>::value)
{
m_value_label.set_text(fmt::format("%.2f%s", this->m_last_value, m_suffix));
}
else
{
m_value_label.set_text(fmt::format("%d%s", this->m_last_value, m_suffix));
}
m_value_label.auto_resize();
constexpr u16 handle_margin = 10;
if ((m_handle.x - m_slider.x) > (m_slider.w - (m_handle.w + 2 * handle_margin + m_value_label.w)))
{
m_value_label.set_pos(m_handle.x - (handle_margin + m_value_label.w), m_handle.y);
}
else
{
m_value_label.set_pos(m_handle.x + m_handle.w + handle_margin, m_handle.y);
}
this->compiled_resources = horizontal_layout::get_compiled();
this->compiled_resources.add(m_slider.get_compiled());
this->compiled_resources.add(m_handle.get_compiled());
this->compiled_resources.add(m_value_label.get_compiled());
}
return this->compiled_resources;
}
private:
overlay_element m_slider;
overlay_element m_handle;
label m_value_label;
std::string m_suffix;
T m_minimum{};
T m_maximum{};
};
template <s64 Min, s64 Max>
struct home_menu_signed_slider : public home_menu_slider<s64, cfg::_int<Min, Max>>
{
using home_menu_slider<s64, cfg::_int<Min, Max>>::home_menu_slider;
};
template <u64 Min, u64 Max>
struct home_menu_unsigned_slider : public home_menu_slider<u64, cfg::uint<Min, Max>>
{
using home_menu_slider<u64, cfg::uint<Min, Max>>::home_menu_slider;
};
template <s32 Min, s32 Max>
struct home_menu_float_slider : public home_menu_slider<f64, cfg::_float<Min, Max>>
{
using home_menu_slider<f64, cfg::_float<Min, Max>>::home_menu_slider;
};
}
}

View File

@ -0,0 +1,65 @@
#include "stdafx.h"
#include "overlay_home_menu_main_menu.h"
#include "overlay_home_menu_components.h"
#include "Emu/System.h"
extern atomic_t<bool> g_user_asked_for_recording;
extern atomic_t<bool> g_user_asked_for_screenshot;
namespace rsx
{
namespace overlays
{
home_menu_main_menu::home_menu_main_menu(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent)
: home_menu_page(x, y, width, height, use_separators, parent, get_localized_string(localized_string_id::HOME_MENU_TITLE))
{
is_current_page = true;
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
{
if (btn != pad_button::cross) return page_navigation::stay;
rsx_log.notice("User selected resume in home menu");
return page_navigation::exit;
});
add_page(std::make_shared<home_menu_settings>(x, y, width, height, use_separators, this));
std::unique_ptr<overlay_element> screenshot = std::make_unique<home_menu_entry>(get_localized_string(localized_string_id::HOME_MENU_SCREENSHOT));
add_item(screenshot, [](pad_button btn) -> page_navigation
{
if (btn != pad_button::cross) return page_navigation::stay;
rsx_log.notice("User selected screenshot in home menu");
g_user_asked_for_screenshot = true;
return page_navigation::exit;
});
std::unique_ptr<overlay_element> recording = std::make_unique<home_menu_entry>(get_localized_string(localized_string_id::HOME_MENU_RECORDING));
add_item(recording, [](pad_button btn) -> page_navigation
{
if (btn != pad_button::cross) return page_navigation::stay;
rsx_log.notice("User selected recording in home menu");
g_user_asked_for_recording = true;
return page_navigation::exit;
});
std::unique_ptr<overlay_element> exit_game = std::make_unique<home_menu_entry>(get_localized_string(localized_string_id::HOME_MENU_EXIT_GAME));
add_item(exit_game, [](pad_button btn) -> page_navigation
{
if (btn != pad_button::cross) return page_navigation::stay;
rsx_log.notice("User selected exit game in home menu");
Emu.CallFromMainThread([]
{
Emu.GracefulShutdown(false, true);
});
return page_navigation::stay;
});
apply_layout();
}
}
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "overlay_home_menu_page.h"
#include "overlay_home_menu_settings.h"
namespace rsx
{
namespace overlays
{
struct home_menu_main_menu : public home_menu_page
{
home_menu_main_menu(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent);
};
}
}

View File

@ -0,0 +1,177 @@
#include "stdafx.h"
#include "overlay_home_menu_page.h"
#include "Emu/System.h"
namespace rsx
{
namespace overlays
{
home_menu_page::home_menu_page(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent, const std::string& title)
: list_view(width, height, use_separators)
, title(title)
, parent(parent)
{
set_pos(x, y);
}
void home_menu_page::set_current_page(home_menu_page* page)
{
if (page)
{
is_current_page = false;
page->is_current_page = true;
rsx_log.notice("Home menu: changing current page from '%s' to '%s'", title, page->title);
}
}
home_menu_page* home_menu_page::get_current_page(bool include_this)
{
if (is_current_page)
{
if (include_this)
{
return this;
}
}
else
{
for (auto& page : m_pages)
{
if (page)
{
if (home_menu_page* p = page->get_current_page(true))
{
return p;
}
}
}
}
return nullptr;
}
void home_menu_page::add_page(std::shared_ptr<home_menu_page> page)
{
ensure(page);
std::unique_ptr<overlay_element> elem = std::make_unique<home_menu_entry>(page->title);
m_pages.push_back(page);
add_item(elem, [this, page](pad_button btn) -> page_navigation
{
if (btn != pad_button::cross) return page_navigation::stay;
rsx_log.notice("User selected '%s' in '%s'", page->title, title);
set_current_page(page.get());
return page_navigation::next;
});
}
void home_menu_page::add_item(std::unique_ptr<overlay_element>& element, std::function<page_navigation(pad_button)> callback)
{
m_callbacks.push_back(std::move(callback));
m_entries.push_back(std::move(element));
}
void home_menu_page::apply_layout(bool center_vertically)
{
// Center vertically if necessary
if (center_vertically)
{
usz total_height = 0;
for (auto& entry : m_entries)
{
total_height += entry->h;
}
if (total_height < h)
{
advance_pos = (h - ::narrow<u16>(total_height)) / 2;
}
}
for (auto& entry : m_entries)
{
add_entry(entry);
}
}
page_navigation home_menu_page::handle_button_press(pad_button button_press)
{
if (home_menu_page* page = get_current_page(false))
{
return page->handle_button_press(button_press);
}
switch (button_press)
{
case pad_button::dpad_left:
case pad_button::dpad_right:
case pad_button::ls_left:
case pad_button::ls_right:
case pad_button::cross:
{
if (const usz index = static_cast<usz>(get_selected_index()); index < m_callbacks.size())
{
if (const std::function<page_navigation(pad_button)>& func = ::at32(m_callbacks, index))
{
Emu.GetCallbacks().play_sound(fs::get_config_dir() + "sounds/snd_decide.wav");
return func(button_press);
}
}
break;
}
case pad_button::circle:
{
Emu.GetCallbacks().play_sound(fs::get_config_dir() + "sounds/snd_cancel.wav");
if (parent)
{
set_current_page(parent);
return page_navigation::back;
}
return page_navigation::exit;
}
case pad_button::dpad_up:
case pad_button::ls_up:
{
select_previous();
break;
}
case pad_button::dpad_down:
case pad_button::ls_down:
{
select_next();
break;
}
case pad_button::L1:
{
select_previous(10);
break;
}
case pad_button::R1:
{
select_next(10);
break;
}
default:
{
rsx_log.trace("[ui] Button %d pressed", static_cast<u8>(button_press));
break;
}
}
Emu.GetCallbacks().play_sound(fs::get_config_dir() + "sounds/snd_cursor.wav");
return page_navigation::stay;
}
compiled_resource& home_menu_page::get_compiled()
{
if (home_menu_page* page = get_current_page(false))
{
return page->get_compiled();
}
return list_view::get_compiled();
}
}
}

View File

@ -0,0 +1,46 @@
#pragma once
#include "Emu/RSX/Overlays/overlays.h"
#include "Emu/RSX/Overlays/overlay_list_view.hpp"
#include "Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.h"
namespace rsx
{
namespace overlays
{
enum class page_navigation
{
stay,
back,
next,
exit
};
struct home_menu_page : public list_view
{
public:
home_menu_page(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent, const std::string& text);
void set_current_page(home_menu_page* page);
home_menu_page* get_current_page(bool include_this);
page_navigation handle_button_press(pad_button button_press);
compiled_resource& get_compiled() override;
bool is_current_page = false;
home_menu_page* parent = nullptr;
std::string title;
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);
std::vector<std::shared_ptr<home_menu_page>> m_pages;
private:
std::vector<std::unique_ptr<overlay_element>> m_entries;
std::vector<std::function<page_navigation(pad_button)>> m_callbacks;
};
}
}

View File

@ -0,0 +1,135 @@
#include "stdafx.h"
#include "overlay_home_menu_settings.h"
#include "overlay_home_menu_components.h"
// TODO: Localization of the setting names
// TODO: Localization of the dropdown values
namespace rsx
{
namespace overlays
{
home_menu_settings::home_menu_settings(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent)
: home_menu_page(x, y, width, height, use_separators, parent, get_localized_string(localized_string_id::HOME_MENU_SETTINGS))
{
add_page(std::make_shared<home_menu_settings_audio>(x, y, width, height, use_separators, this));
add_page(std::make_shared<home_menu_settings_video>(x, y, width, height, use_separators, this));
add_page(std::make_shared<home_menu_settings_input>(x, y, width, height, use_separators, this));
add_page(std::make_shared<home_menu_settings_advanced>(x, y, width, height, use_separators, this));
add_page(std::make_shared<home_menu_settings_overlays>(x, y, width, height, use_separators, this));
add_page(std::make_shared<home_menu_settings_performance_overlay>(x, y, width, height, use_separators, this));
add_page(std::make_shared<home_menu_settings_debug>(x, y, width, height, use_separators, this));
apply_layout();
}
home_menu_settings_audio::home_menu_settings_audio(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent)
: home_menu_settings_page(x, y, width, height, use_separators, parent, get_localized_string(localized_string_id::HOME_MENU_SETTINGS_AUDIO))
{
add_signed_slider(&g_cfg.audio.volume, "Master Volume", " %", 1);
add_dropdown(&g_cfg.audio.renderer, "Audio Backend");
add_checkbox(&g_cfg.audio.enable_buffering, "Enable Buffering");
add_signed_slider(&g_cfg.audio.desired_buffer_duration, "Desired Audio Buffer Duration", " ms", 1);
add_checkbox(&g_cfg.audio.enable_time_stretching, "Enable Time Stretching");
add_signed_slider(&g_cfg.audio.time_stretching_threshold, "Time Stretching Threshold", " %", 1);
apply_layout();
}
home_menu_settings_video::home_menu_settings_video(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent)
: home_menu_settings_page(x, y, width, height, use_separators, parent, get_localized_string(localized_string_id::HOME_MENU_SETTINGS_VIDEO))
{
add_dropdown(&g_cfg.video.frame_limit, "Frame limit");
add_unsigned_slider(&g_cfg.video.anisotropic_level_override, "Anisotropic Filter Override", "", 2);
if (g_cfg.video.renderer == video_renderer::vulkan && g_cfg.video.output_scaling == output_scaling_mode::fsr)
{
add_unsigned_slider(&g_cfg.video.vk.rcas_sharpening_intensity, "FidelityFX CAS Sharpening Intensity", " %", 1);
}
add_checkbox(&g_cfg.video.stretch_to_display_area, "Stretch To Display Area");
add_unsigned_slider(&g_cfg.video.driver_wakeup_delay, "Driver Wake-Up Delay", " µs", 20, g_cfg.video.driver_wakeup_delay.min, 800);
add_signed_slider(&g_cfg.video.vblank_rate, "VBlank Frequency", " Hz", 1);
add_checkbox(&g_cfg.video.vblank_ntsc, "VBlank NTSC Fixup");
apply_layout();
}
home_menu_settings_advanced::home_menu_settings_advanced(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent)
: home_menu_settings_page(x, y, width, height, use_separators, parent, get_localized_string(localized_string_id::HOME_MENU_SETTINGS_ADVANCED))
{
add_checkbox(&g_cfg.core.spu_loop_detection, "SPU Loop Detection");
add_signed_slider(&g_cfg.core.preferred_spu_threads, "Preferred SPU Threads", "", 1);
add_unsigned_slider(&g_cfg.core.max_cpu_preempt_count_per_frame, "Max Power Saving CPU-Preemptions", "", 1);
add_checkbox(&g_cfg.core.rsx_accurate_res_access, "Accurate RSX reservation access");
add_dropdown(&g_cfg.core.sleep_timers_accuracy, "Sleep Timers Accuracy");
apply_layout();
}
home_menu_settings_input::home_menu_settings_input(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent)
: home_menu_settings_page(x, y, width, height, use_separators, parent, get_localized_string(localized_string_id::HOME_MENU_SETTINGS_INPUT))
{
add_checkbox(&g_cfg.io.background_input_enabled, "Background Input Enabled");
add_checkbox(&g_cfg.io.show_move_cursor, "Show PS Move Cursor");
if (g_cfg.io.camera == camera_handler::qt)
{
add_dropdown(&g_cfg.io.camera_flip_option, "Camera Flip");
}
add_dropdown(&g_cfg.io.pad_mode, "Pad Handler Mode");
add_unsigned_slider(&g_cfg.io.pad_sleep, "Pad Handler Sleep", " µs", 100);
apply_layout();
}
home_menu_settings_overlays::home_menu_settings_overlays(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent)
: home_menu_settings_page(x, y, width, height, use_separators, parent, get_localized_string(localized_string_id::HOME_MENU_SETTINGS_OVERLAYS))
{
add_checkbox(&g_cfg.misc.show_trophy_popups, "Show Trophy Popups");
add_checkbox(&g_cfg.misc.show_shader_compilation_hint, "Show Shader Compilation Hint");
apply_layout();
}
home_menu_settings_performance_overlay::home_menu_settings_performance_overlay(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent)
: home_menu_settings_page(x, y, width, height, use_separators, parent, get_localized_string(localized_string_id::HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY))
{
add_checkbox(&g_cfg.video.perf_overlay.perf_overlay_enabled, "Enable Performance Overlay");
add_checkbox(&g_cfg.video.perf_overlay.framerate_graph_enabled, "Enable Framerate Graph");
add_checkbox(&g_cfg.video.perf_overlay.frametime_graph_enabled, "Enable Frametime Graph");
add_dropdown(&g_cfg.video.perf_overlay.level, "Detail level");
add_dropdown(&g_cfg.video.perf_overlay.framerate_graph_detail_level, "Framerate Graph Detail Level");
add_dropdown(&g_cfg.video.perf_overlay.frametime_graph_detail_level, "Frametime Graph Detail Level");
add_unsigned_slider(&g_cfg.video.perf_overlay.framerate_datapoint_count, "Framerate Datapoints", "", 1);
add_unsigned_slider(&g_cfg.video.perf_overlay.frametime_datapoint_count, "Frametime Datapoints", "", 1);
add_unsigned_slider(&g_cfg.video.perf_overlay.update_interval, "Metrics Update Interval", " ms", 1);
add_dropdown(&g_cfg.video.perf_overlay.position, "Position");
add_checkbox(&g_cfg.video.perf_overlay.center_x, "Center Horizontally");
add_checkbox(&g_cfg.video.perf_overlay.center_y, "Center Vertically");
add_unsigned_slider(&g_cfg.video.perf_overlay.margin_x, "Horizontal Margin", " px", 1);
add_unsigned_slider(&g_cfg.video.perf_overlay.margin_y, "Vertical Margin", " px", 1);
add_unsigned_slider(&g_cfg.video.perf_overlay.font_size, "Font Size", " px", 1);
add_unsigned_slider(&g_cfg.video.perf_overlay.opacity, "Opacity", " %", 1);
apply_layout();
}
home_menu_settings_debug::home_menu_settings_debug(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent)
: home_menu_settings_page(x, y, width, height, use_separators, parent, get_localized_string(localized_string_id::HOME_MENU_SETTINGS_DEBUG))
{
add_checkbox(&g_cfg.video.overlay, "Debug Overlay");
add_checkbox(&g_cfg.video.disable_video_output, "Disable Video Output");
add_float_slider(&g_cfg.video.texture_lod_bias, "Texture LOD Bias Addend", "", 0.25f);
apply_layout();
}
}
}

View File

@ -0,0 +1,238 @@
#pragma once
#include "overlay_home_menu_page.h"
#include "Emu/System.h"
#include "Emu/system_config.h"
namespace rsx
{
namespace overlays
{
struct home_menu_settings : public home_menu_page
{
public:
home_menu_settings(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent);
private:
std::vector<std::shared_ptr<home_menu_page>> m_settings_pages;
};
struct home_menu_settings_page : public home_menu_page
{
using home_menu_page::home_menu_page;
void add_checkbox(cfg::_bool* setting, const std::string& text)
{
ensure(setting && setting->get_is_dynamic());
std::unique_ptr<overlay_element> elem = std::make_unique<home_menu_checkbox>(setting, text);
add_item(elem, [this, setting, text](pad_button btn) -> page_navigation
{
if (btn != pad_button::cross) return page_navigation::stay;
if (setting)
{
const bool value = !setting->get();
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();
refresh();
}
return page_navigation::stay;
});
}
template <typename T>
void add_dropdown(cfg::_enum<T>* setting, const std::string& text)
{
ensure(setting && setting->get_is_dynamic());
std::unique_ptr<overlay_element> elem = std::make_unique<home_menu_dropdown<T>>(setting, text);
add_item(elem, [this, setting, text](pad_button btn) -> page_navigation
{
if (btn != pad_button::cross) return page_navigation::stay;
if (setting)
{
usz new_index = 0;
T value = setting->get();
const std::string val = fmt::format("%s", value);
const std::vector<std::string> list = setting->to_list();
for (usz i = 0; i < list.size(); i++)
{
const std::string& entry = list[i];
if (entry == val)
{
new_index = (i + 1) % list.size();
break;
}
}
if (const std::string& next_value = ::at32(list, new_index); setting->from_string(next_value))
{
rsx_log.notice("User toggled '%s' in '%s'. Setting '%s' to %s", text, title, setting->get_name(), next_value);
}
else
{
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();
refresh();
}
return page_navigation::stay;
});
}
template <s64 Min, s64 Max>
void add_signed_slider(cfg::_int<Min, Max>* setting, const std::string& text, const std::string& suffix, s64 step_size, s64 minimum = Min, s64 maximum = Max)
{
ensure(setting && setting->get_is_dynamic());
std::unique_ptr<overlay_element> elem = std::make_unique<home_menu_signed_slider<Min, Max>>(setting, text, suffix, minimum, maximum);
add_item(elem, [this, setting, text, step_size, minimum, maximum](pad_button btn) -> page_navigation
{
if (setting)
{
s64 value = setting->get();
switch (btn)
{
case pad_button::dpad_left:
case pad_button::ls_left:
value = std::max(value - step_size, minimum);
break;
case pad_button::dpad_right:
case pad_button::ls_right:
value = std::min(value + step_size, maximum);
break;
default:
return page_navigation::stay;
}
if (value != setting->get())
{
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();
refresh();
}
}
return page_navigation::stay;
});
}
template <u64 Min, u64 Max>
void add_unsigned_slider(cfg::uint<Min, Max>* setting, const std::string& text, const std::string& suffix, u64 step_size, u64 minimum = Min, u64 maximum = Max)
{
ensure(setting && setting->get_is_dynamic());
std::unique_ptr<overlay_element> elem = std::make_unique<home_menu_unsigned_slider<Min, Max>>(setting, text, suffix, minimum, maximum);
add_item(elem, [this, setting, text, step_size, minimum, maximum](pad_button btn) -> page_navigation
{
if (setting)
{
u64 value = setting->get();
switch (btn)
{
case pad_button::dpad_left:
case pad_button::ls_left:
value = step_size > value ? minimum : std::max(value - step_size, minimum);
break;
case pad_button::dpad_right:
case pad_button::ls_right:
value = std::min(value + step_size, maximum);
break;
default:
return page_navigation::stay;
}
if (value != setting->get())
{
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();
refresh();
}
}
return page_navigation::stay;
});
}
template <s32 Min, s32 Max>
void add_float_slider(cfg::_float<Min, Max>* setting, const std::string& text, const std::string& suffix, f32 step_size, s32 minimum = Min, s32 maximum = Max)
{
ensure(setting && setting->get_is_dynamic());
std::unique_ptr<overlay_element> elem = std::make_unique<home_menu_float_slider<Min, Max>>(setting, text, suffix, minimum, maximum);
add_item(elem, [this, setting, text, step_size, minimum, maximum](pad_button btn) -> page_navigation
{
if (setting)
{
f64 value = setting->get();
switch (btn)
{
case pad_button::dpad_left:
case pad_button::ls_left:
value = std::max(value - step_size, static_cast<f64>(minimum));
break;
case pad_button::dpad_right:
case pad_button::ls_right:
value = std::min(value + step_size, static_cast<f64>(maximum));
break;
default:
return page_navigation::stay;
}
if (value != setting->get())
{
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();
refresh();
}
}
return page_navigation::stay;
});
}
};
struct home_menu_settings_audio : public home_menu_settings_page
{
home_menu_settings_audio(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent);
};
struct home_menu_settings_video : public home_menu_settings_page
{
home_menu_settings_video(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent);
};
struct home_menu_settings_advanced : public home_menu_settings_page
{
home_menu_settings_advanced(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent);
};
struct home_menu_settings_input : public home_menu_settings_page
{
home_menu_settings_input(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent);
};
struct home_menu_settings_overlays : public home_menu_settings_page
{
home_menu_settings_overlays(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent);
};
struct home_menu_settings_performance_overlay : public home_menu_settings_page
{
home_menu_settings_performance_overlay(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent);
};
struct home_menu_settings_debug : public home_menu_settings_page
{
home_menu_settings_debug(u16 x, u16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent);
};
}
}

View File

@ -1,268 +0,0 @@
#include "stdafx.h"
#include "overlay_home_menu.h"
#include "Emu/RSX/RSXThread.h"
extern atomic_t<bool> g_user_asked_for_recording;
extern atomic_t<bool> g_user_asked_for_screenshot;
namespace rsx
{
namespace overlays
{
home_menu_dialog::home_menu_entry::home_menu_entry(const std::string& text)
{
std::unique_ptr<overlay_element> text_stack = std::make_unique<vertical_layout>();
std::unique_ptr<overlay_element> padding = std::make_unique<spacer>();
std::unique_ptr<overlay_element> header_text = std::make_unique<label>(text);
padding->set_size(1, 1);
header_text->set_size(1240, height);
header_text->set_font("Arial", 16);
header_text->set_wrap_text(true);
header_text->align_text(text_align::center);
// Make back color transparent for text
header_text->back_color.a = 0.f;
static_cast<vertical_layout*>(text_stack.get())->pack_padding = 5;
static_cast<vertical_layout*>(text_stack.get())->add_element(padding);
static_cast<vertical_layout*>(text_stack.get())->add_element(header_text);
// Pack
this->pack_padding = 15;
add_element(text_stack);
}
home_menu_dialog::home_menu_dialog()
{
m_allow_input_on_pause = true;
m_dim_background = std::make_unique<overlay_element>();
m_dim_background->set_size(1280, 720);
m_dim_background->back_color.a = 0.5f;
m_list = std::make_unique<list_view>(1240, 540, false);
m_list->set_pos(20, 85);
m_description = std::make_unique<label>();
m_description->set_font("Arial", 20);
m_description->set_pos(20, 37);
m_description->set_text(get_localized_string(localized_string_id::HOME_MENU_TITLE));
m_description->auto_resize();
m_description->back_color.a = 0.f;
fade_animation.duration = 0.15f;
return_code = selection_code::canceled;
}
void home_menu_dialog::update()
{
static u64 frame = 0;
if (Emu.IsPaused())
{
// Let's keep updating the animation anyway
frame++;
}
else
{
frame = rsx::get_current_renderer()->vblank_count;
}
if (fade_animation.active)
{
fade_animation.update(frame);
}
}
void home_menu_dialog::on_button_pressed(pad_button button_press)
{
if (fade_animation.active) return;
bool close_dialog = false;
switch (button_press)
{
case pad_button::cross:
Emu.GetCallbacks().play_sound(fs::get_config_dir() + "sounds/snd_decide.wav");
if (const usz index = static_cast<usz>(m_list->get_selected_index()); index < m_callbacks.size())
{
if (const std::function<bool()>& func = ::at32(m_callbacks, index))
{
close_dialog = func();
}
}
break;
case pad_button::circle:
Emu.GetCallbacks().play_sound(fs::get_config_dir() + "sounds/snd_cancel.wav");
close_dialog = true;
break;
case pad_button::dpad_up:
case pad_button::ls_up:
m_list->select_previous();
break;
case pad_button::dpad_down:
case pad_button::ls_down:
m_list->select_next();
break;
case pad_button::L1:
m_list->select_previous(10);
break;
case pad_button::R1:
m_list->select_next(10);
break;
default:
rsx_log.trace("[ui] Button %d pressed", static_cast<u8>(button_press));
break;
}
if (close_dialog)
{
fade_animation.current = color4f(1.f);
fade_animation.end = color4f(0.f);
fade_animation.active = true;
fade_animation.on_finish = [this]
{
close(true, true);
if (g_cfg.misc.pause_during_home_menu)
{
Emu.BlockingCallFromMainThread([]()
{
Emu.Resume();
});
}
};
}
else
{
Emu.GetCallbacks().play_sound(fs::get_config_dir() + "sounds/snd_cursor.wav");
}
}
compiled_resource home_menu_dialog::get_compiled()
{
if (!visible)
{
return {};
}
compiled_resource result;
result.add(m_dim_background->get_compiled());
result.add(m_list->get_compiled());
result.add(m_description->get_compiled());
fade_animation.apply(result);
return result;
}
struct home_menu_dialog_thread
{
static constexpr auto thread_name = "Home Menu Thread"sv;
};
void home_menu_dialog::add_item(const std::string& text, std::function<bool()> callback)
{
m_callbacks.push_back(std::move(callback));
m_entries.push_back(std::make_unique<home_menu_entry>(text));
}
error_code home_menu_dialog::show(std::function<void(s32 status)> on_close)
{
visible = false;
add_item(get_localized_string(localized_string_id::HOME_MENU_RESUME), []() -> bool
{
rsx_log.notice("User selected resume in home menu");
return true;
});
add_item(get_localized_string(localized_string_id::HOME_MENU_SCREENSHOT), []() -> bool
{
rsx_log.notice("User selected screenshot in home menu");
g_user_asked_for_screenshot = true;
return true;
});
add_item(get_localized_string(localized_string_id::HOME_MENU_RECORDING), []() -> bool
{
rsx_log.notice("User selected recording in home menu");
g_user_asked_for_recording = true;
return true;
});
add_item(get_localized_string(localized_string_id::HOME_MENU_EXIT_GAME), []() -> bool
{
rsx_log.notice("User selected exit game in home menu");
Emu.CallFromMainThread([]
{
Emu.GracefulShutdown(false, true);
});
return false;
});
// Center vertically if necessary
if (const usz total_height = home_menu_entry::height * m_entries.size(); total_height < m_list->h)
{
m_list->advance_pos = (m_list->h - total_height) / 2;
}
for (auto& entry : m_entries)
{
m_list->add_entry(entry);
}
fade_animation.current = color4f(0.f);
fade_animation.end = color4f(1.f);
fade_animation.active = true;
this->on_close = std::move(on_close);
visible = true;
auto& list_thread = g_fxo->get<named_thread<home_menu_dialog_thread>>();
const auto notify = std::make_shared<atomic_t<bool>>(false);
list_thread([&, notify]()
{
const u64 tbit = alloc_thread_bit();
g_thread_bit = tbit;
*notify = true;
notify->notify_one();
auto ref = g_fxo->get<display_manager>().get(uid);
if (const auto error = run_input_loop())
{
if (error != selection_code::canceled)
{
rsx_log.error("Home menu dialog input loop exited with error code=%d", error);
}
}
thread_bits &= ~tbit;
thread_bits.notify_all();
});
if (g_cfg.misc.pause_during_home_menu)
{
Emu.BlockingCallFromMainThread([]()
{
Emu.Pause(false, false);
});
}
while (list_thread < thread_state::errored && !*notify)
{
notify->wait(false, atomic_wait_timeout{1'000'000});
}
return CELL_OK;
}
} // namespace overlays
} // namespace RSX

View File

@ -128,7 +128,7 @@ namespace rsx
media_list_dialog::media_list_dialog() media_list_dialog::media_list_dialog()
{ {
m_dim_background = std::make_unique<overlay_element>(); m_dim_background = std::make_unique<overlay_element>();
m_dim_background->set_size(1280, 720); m_dim_background->set_size(overlay::virtual_width, overlay::virtual_height);
m_dim_background->back_color.a = 0.5f; m_dim_background->back_color.a = 0.5f;
m_description = std::make_unique<label>(); m_description = std::make_unique<label>();
@ -136,7 +136,7 @@ namespace rsx
m_description->set_pos(20, 37); m_description->set_pos(20, 37);
m_description->set_text("Select media"); // Fallback. I don't think this will ever be used, so I won't localize it. m_description->set_text("Select media"); // Fallback. I don't think this will ever be used, so I won't localize it.
m_description->auto_resize(); m_description->auto_resize();
m_description->back_color.a = 0.f; m_description->back_color.a = 0.f;
} }
void media_list_dialog::on_button_pressed(pad_button button_press) void media_list_dialog::on_button_pressed(pad_button button_press)

View File

@ -16,7 +16,7 @@ namespace rsx
message_dialog::message_dialog(bool allow_custom_background) message_dialog::message_dialog(bool allow_custom_background)
: custom_background_allowed(allow_custom_background) : custom_background_allowed(allow_custom_background)
{ {
background.set_size(1280, 720); background.set_size(overlay::virtual_width, overlay::virtual_height);
background.back_color.a = 0.85f; background.back_color.a = 0.85f;
text_display.set_size(1100, 40); text_display.set_size(1100, 40);
@ -367,7 +367,7 @@ namespace rsx
background_poster.fore_color = color4f(color, color, color, 1.); background_poster.fore_color = color4f(color, color, color, 1.);
background.back_color.a = 0.f; background.back_color.a = 0.f;
background_poster.set_size(1280, 720); background_poster.set_size(overlay::virtual_width, overlay::virtual_height);
background_poster.set_raw_image(background_image.get()); background_poster.set_raw_image(background_image.get());
background_poster.set_blur_strength(static_cast<u8>(background_blur_strength)); background_poster.set_blur_strength(static_cast<u8>(background_blur_strength));

View File

@ -874,7 +874,7 @@ namespace rsx
return compiled_resources; return compiled_resources;
} }
void reset_performance_overlay() extern void reset_performance_overlay()
{ {
if (!g_cfg.misc.use_native_interface) if (!g_cfg.misc.use_native_interface)
return; return;

View File

@ -82,7 +82,7 @@ namespace rsx
save_dialog::save_dialog() save_dialog::save_dialog()
{ {
m_dim_background = std::make_unique<overlay_element>(); m_dim_background = std::make_unique<overlay_element>();
m_dim_background->set_size(1280, 720); m_dim_background->set_size(overlay::virtual_width, overlay::virtual_height);
m_list = std::make_unique<list_view>(1240, 540); m_list = std::make_unique<list_view>(1240, 540);
m_description = std::make_unique<label>(); m_description = std::make_unique<label>();

View File

@ -69,7 +69,7 @@ namespace rsx
user_list_dialog::user_list_dialog() user_list_dialog::user_list_dialog()
{ {
m_dim_background = std::make_unique<overlay_element>(); m_dim_background = std::make_unique<overlay_element>();
m_dim_background->set_size(1280, 720); m_dim_background->set_size(overlay::virtual_width, overlay::virtual_height);
m_dim_background->back_color.a = 0.5f; m_dim_background->back_color.a = 0.5f;
m_list = std::make_unique<list_view>(1240, 540); m_list = std::make_unique<list_view>(1240, 540);
@ -80,7 +80,7 @@ namespace rsx
m_description->set_pos(20, 37); m_description->set_pos(20, 37);
m_description->set_text("Select user"); // Fallback. I don't think this will ever be used, so I won't localize it. m_description->set_text("Select user"); // Fallback. I don't think this will ever be used, so I won't localize it.
m_description->auto_resize(); m_description->auto_resize();
m_description->back_color.a = 0.f; m_description->back_color.a = 0.f;
fade_animation.duration = 0.15f; fade_animation.duration = 0.15f;

View File

@ -18,6 +18,38 @@ namespace rsx
{ {
namespace overlays namespace overlays
{ {
enum pad_button : u8
{
dpad_up = 0,
dpad_down,
dpad_left,
dpad_right,
select,
start,
ps,
triangle,
circle,
square,
cross,
L1,
R1,
L2,
R2,
L3,
R3,
ls_up,
ls_down,
ls_left,
ls_right,
rs_up,
rs_down,
rs_left,
rs_right,
pad_button_max_enum
};
// Bitfield of UI signals to overlay manager // Bitfield of UI signals to overlay manager
enum status_bits : u32 enum status_bits : u32
{ {
@ -57,38 +89,6 @@ namespace rsx
error = -3 error = -3
}; };
enum pad_button : u8
{
dpad_up = 0,
dpad_down,
dpad_left,
dpad_right,
select,
start,
ps,
triangle,
circle,
square,
cross,
L1,
R1,
L2,
R2,
L3,
R3,
ls_up,
ls_down,
ls_left,
ls_right,
rs_up,
rs_down,
rs_left,
rs_right,
pad_button_max_enum
};
protected: protected:
Timer m_input_timer; Timer m_input_timer;
static constexpr u64 m_auto_repeat_ms_interval_default = 200; static constexpr u64 m_auto_repeat_ms_interval_default = 200;

View File

@ -81,6 +81,7 @@ struct EmuCallbacks
std::function<void()> init_kb_handler; std::function<void()> init_kb_handler;
std::function<void()> init_mouse_handler; std::function<void()> init_mouse_handler;
std::function<void(std::string_view title_id)> init_pad_handler; std::function<void(std::string_view title_id)> init_pad_handler;
std::function<void()> update_emu_settings;
std::function<std::unique_ptr<class GSFrameBase>()> get_gs_frame; 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 camera_handler_base>()> get_camera_handler;
std::function<std::shared_ptr<class music_handler_base>()> get_music_handler; std::function<std::shared_ptr<class music_handler_base>()> get_music_handler;

View File

@ -153,6 +153,14 @@ enum class localized_string_id
HOME_MENU_TITLE, HOME_MENU_TITLE,
HOME_MENU_EXIT_GAME, HOME_MENU_EXIT_GAME,
HOME_MENU_RESUME, HOME_MENU_RESUME,
HOME_MENU_SETTINGS,
HOME_MENU_SETTINGS_AUDIO,
HOME_MENU_SETTINGS_VIDEO,
HOME_MENU_SETTINGS_INPUT,
HOME_MENU_SETTINGS_ADVANCED,
HOME_MENU_SETTINGS_OVERLAYS,
HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY,
HOME_MENU_SETTINGS_DEBUG,
HOME_MENU_SCREENSHOT, HOME_MENU_SCREENSHOT,
HOME_MENU_RECORDING, HOME_MENU_RECORDING,

View File

@ -19,7 +19,7 @@
#include "Emu/Io/pad_config.h" #include "Emu/Io/pad_config.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/system_config.h" #include "Emu/system_config.h"
#include "Emu/RSX/Overlays/overlay_home_menu.h" #include "Emu/RSX/Overlays/HomeMenu/overlay_home_menu.h"
#include "Emu/RSX/Overlays/overlay_message.h" #include "Emu/RSX/Overlays/overlay_message.h"
#include "Utilities/Thread.h" #include "Utilities/Thread.h"
#include "util/atomic.hpp" #include "util/atomic.hpp"

View File

@ -84,10 +84,14 @@
<ClCompile Include="Emu\NP\rpcn_config.cpp" /> <ClCompile Include="Emu\NP\rpcn_config.cpp" />
<ClCompile Include="Emu\perf_monitor.cpp" /> <ClCompile Include="Emu\perf_monitor.cpp" />
<ClCompile Include="Emu\RSX\Common\texture_cache.cpp" /> <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_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" />
<ClCompile Include="Emu\RSX\Overlays\overlay_animated_icon.cpp" /> <ClCompile Include="Emu\RSX\Overlays\overlay_animated_icon.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_controls.cpp" /> <ClCompile Include="Emu\RSX\Overlays\overlay_controls.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_cursor.cpp" /> <ClCompile Include="Emu\RSX\Overlays\overlay_cursor.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_home_menu.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_media_list_dialog.cpp" /> <ClCompile Include="Emu\RSX\Overlays\overlay_media_list_dialog.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_osk_panel.cpp" /> <ClCompile Include="Emu\RSX\Overlays\overlay_osk_panel.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_shader_compile_notification.cpp" /> <ClCompile Include="Emu\RSX\Overlays\overlay_shader_compile_notification.cpp" />
@ -535,10 +539,14 @@
<ClInclude Include="Emu\RSX\Core\RSXDisplay.h" /> <ClInclude Include="Emu\RSX\Core\RSXDisplay.h" />
<ClInclude Include="Emu\RSX\Core\RSXReservationLock.hpp" /> <ClInclude Include="Emu\RSX\Core\RSXReservationLock.hpp" />
<ClInclude Include="Emu\RSX\Core\RSXVertexTypes.h" /> <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_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" />
<ClInclude Include="Emu\RSX\Overlays\overlay_animated_icon.h" /> <ClInclude Include="Emu\RSX\Overlays\overlay_animated_icon.h" />
<ClInclude Include="Emu\RSX\Overlays\overlay_cursor.h" /> <ClInclude Include="Emu\RSX\Overlays\overlay_cursor.h" />
<ClInclude Include="Emu\RSX\Overlays\overlay_edit_text.hpp" /> <ClInclude Include="Emu\RSX\Overlays\overlay_edit_text.hpp" />
<ClInclude Include="Emu\RSX\Overlays\overlay_home_menu.h" />
<ClInclude Include="Emu\RSX\Overlays\overlay_list_view.hpp" /> <ClInclude Include="Emu\RSX\Overlays\overlay_list_view.hpp" />
<ClInclude Include="Emu\RSX\Overlays\overlay_loading_icon.hpp" /> <ClInclude Include="Emu\RSX\Overlays\overlay_loading_icon.hpp" />
<ClInclude Include="Emu\RSX\Overlays\overlay_media_list_dialog.h" /> <ClInclude Include="Emu\RSX\Overlays\overlay_media_list_dialog.h" />

View File

@ -79,6 +79,12 @@
<Filter Include="Emu\GPU\RSX\Core"> <Filter Include="Emu\GPU\RSX\Core">
<UniqueIdentifier>{99b3a1c9-93ea-4498-86b0-1000793013fa}</UniqueIdentifier> <UniqueIdentifier>{99b3a1c9-93ea-4498-86b0-1000793013fa}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Emu\GPU\RSX\Overlays\HomeMenu">
<UniqueIdentifier>{787ed009-9e17-4ef0-abae-885a708d33e7}</UniqueIdentifier>
</Filter>
<Filter Include="Emu\GPU\RSX\Overlays\HomeMenu\Pages">
<UniqueIdentifier>{017e5a5d-b190-4032-baed-57f8020861a5}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Crypto\aes.cpp"> <ClCompile Include="Crypto\aes.cpp">
@ -1108,8 +1114,20 @@
<ClCompile Include="Emu\Cell\Modules\HLE_PATCHES.cpp"> <ClCompile Include="Emu\Cell\Modules\HLE_PATCHES.cpp">
<Filter>Emu\Cell\Modules</Filter> <Filter>Emu\Cell\Modules</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\RSX\Overlays\overlay_home_menu.cpp"> <ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_components.cpp">
<Filter>Emu\GPU\RSX\Overlays</Filter> <Filter>Emu\GPU\RSX\Overlays\HomeMenu</Filter>
</ClCompile>
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_page.cpp">
<Filter>Emu\GPU\RSX\Overlays\HomeMenu</Filter>
</ClCompile>
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu.cpp">
<Filter>Emu\GPU\RSX\Overlays\HomeMenu</Filter>
</ClCompile>
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_main_menu.cpp">
<Filter>Emu\GPU\RSX\Overlays\HomeMenu\Pages</Filter>
</ClCompile>
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_settings.cpp">
<Filter>Emu\GPU\RSX\Overlays\HomeMenu\Pages</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\RSX\Overlays\overlay_animated_icon.cpp"> <ClCompile Include="Emu\RSX\Overlays\overlay_animated_icon.cpp">
<Filter>Emu\GPU\RSX\Overlays</Filter> <Filter>Emu\GPU\RSX\Overlays</Filter>
@ -2242,8 +2260,20 @@
<ClInclude Include="Emu\RSX\Common\expected.hpp"> <ClInclude Include="Emu\RSX\Common\expected.hpp">
<Filter>Emu\GPU\RSX\Common</Filter> <Filter>Emu\GPU\RSX\Common</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\RSX\Overlays\overlay_home_menu.h"> <ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_components.h">
<Filter>Emu\GPU\RSX\Overlays</Filter> <Filter>Emu\GPU\RSX\Overlays\HomeMenu</Filter>
</ClInclude>
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_page.h">
<Filter>Emu\GPU\RSX\Overlays\HomeMenu</Filter>
</ClInclude>
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu.h">
<Filter>Emu\GPU\RSX\Overlays\HomeMenu</Filter>
</ClInclude>
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_main_menu.h">
<Filter>Emu\GPU\RSX\Overlays\HomeMenu\Pages</Filter>
</ClInclude>
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_settings.h">
<Filter>Emu\GPU\RSX\Overlays\HomeMenu\Pages</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\RSX\Overlays\overlay_loading_icon.hpp"> <ClInclude Include="Emu\RSX\Overlays\overlay_loading_icon.hpp">
<Filter>Emu\GPU\RSX\Overlays</Filter> <Filter>Emu\GPU\RSX\Overlays</Filter>

View File

@ -1,4 +1,6 @@
#include "stdafx.h"
#include "main_application.h" #include "main_application.h"
#include "display_sleep_control.h"
#include "util/types.hpp" #include "util/types.hpp"
#include "util/logs.hpp" #include "util/logs.hpp"
@ -9,6 +11,7 @@
#include "Input/pad_thread.h" #include "Input/pad_thread.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/system_config.h" #include "Emu/system_config.h"
#include "Emu/system_utils.hpp"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/Io/Null/NullKeyboardHandler.h" #include "Emu/Io/Null/NullKeyboardHandler.h"
#include "Emu/Io/Null/NullMouseHandler.h" #include "Emu/Io/Null/NullMouseHandler.h"
@ -37,6 +40,17 @@
LOG_CHANNEL(sys_log, "SYS"); LOG_CHANNEL(sys_log, "SYS");
namespace audio
{
extern void configure_audio(bool force_reset = false);
extern void configure_rsxaudio();
}
namespace rsx::overlays
{
extern void reset_performance_overlay();
}
/** Emu.Init() wrapper for user management */ /** Emu.Init() wrapper for user management */
void main_application::InitializeEmulator(const std::string& user, bool show_gui) void main_application::InitializeEmulator(const std::string& user, bool show_gui)
{ {
@ -50,10 +64,52 @@ void main_application::InitializeEmulator(const std::string& user, bool show_gui
sys_log.always()("%s", firmware_string); sys_log.always()("%s", firmware_string);
} }
void main_application::OnEmuSettingsChange()
{
if (Emu.IsRunning())
{
if (g_cfg.misc.prevent_display_sleep)
{
enable_display_sleep();
}
else
{
disable_display_sleep();
}
}
rpcs3::utils::configure_logs();
if (!Emu.IsStopped())
{
// Force audio provider
if (Emu.IsVsh())
{
g_cfg.audio.provider.set(audio_provider::rsxaudio);
}
else
{
g_cfg.audio.provider.set(audio_provider::cell_audio);
}
}
audio::configure_audio();
audio::configure_rsxaudio();
rsx::overlays::reset_performance_overlay();
}
/** RPCS3 emulator has functions it desires to call from the GUI at times. Initialize them in here. */ /** RPCS3 emulator has functions it desires to call from the GUI at times. Initialize them in here. */
EmuCallbacks main_application::CreateCallbacks() EmuCallbacks main_application::CreateCallbacks()
{ {
EmuCallbacks callbacks; EmuCallbacks callbacks{};
callbacks.update_emu_settings = [this]()
{
Emu.CallFromMainThread([&]()
{
OnEmuSettingsChange();
});
};
callbacks.init_kb_handler = [this]() callbacks.init_kb_handler = [this]()
{ {

View File

@ -20,6 +20,8 @@ public:
protected: protected:
virtual QThread* get_thread() = 0; virtual QThread* get_thread() = 0;
void OnEmuSettingsChange();
EmuCallbacks CreateCallbacks(); EmuCallbacks CreateCallbacks();
std::string m_active_user; std::string m_active_user;

View File

@ -8,7 +8,6 @@
#include "persistent_settings.h" #include "persistent_settings.h"
#include "gs_frame.h" #include "gs_frame.h"
#include "gl_gs_frame.h" #include "gl_gs_frame.h"
#include "display_sleep_control.h"
#include "localized_emu.h" #include "localized_emu.h"
#include "qt_camera_handler.h" #include "qt_camera_handler.h"
#include "qt_music_handler.h" #include "qt_music_handler.h"
@ -19,10 +18,6 @@
#include "Emu/Io/Null/null_camera_handler.h" #include "Emu/Io/Null/null_camera_handler.h"
#include "Emu/Io/Null/null_music_handler.h" #include "Emu/Io/Null/null_music_handler.h"
#include "Emu/Cell/Modules/cellAudio.h"
#include "Emu/Cell/lv2/sys_rsxaudio.h"
#include "Emu/RSX/Overlays/overlay_perf_metrics.h"
#include "Emu/system_utils.hpp"
#include "Emu/vfs_config.h" #include "Emu/vfs_config.h"
#include "trophy_notification_helper.h" #include "trophy_notification_helper.h"
#include "save_data_dialog.h" #include "save_data_dialog.h"
@ -238,7 +233,7 @@ void gui_application::InitializeConnects()
{ {
connect(m_main_window, &main_window::RequestLanguageChange, this, &gui_application::LoadLanguage); connect(m_main_window, &main_window::RequestLanguageChange, this, &gui_application::LoadLanguage);
connect(m_main_window, &main_window::RequestGlobalStylesheetChange, this, &gui_application::OnChangeStyleSheetRequest); connect(m_main_window, &main_window::RequestGlobalStylesheetChange, this, &gui_application::OnChangeStyleSheetRequest);
connect(m_main_window, &main_window::NotifyEmuSettingsChange, this, &gui_application::OnEmuSettingsChange); connect(m_main_window, &main_window::NotifyEmuSettingsChange, this, [this](){ OnEmuSettingsChange(); });
connect(this, &gui_application::OnEmulatorRun, m_main_window, &main_window::OnEmuRun); connect(this, &gui_application::OnEmulatorRun, m_main_window, &main_window::OnEmuRun);
connect(this, &gui_application::OnEmulatorStop, m_main_window, &main_window::OnEmuStop); connect(this, &gui_application::OnEmulatorStop, m_main_window, &main_window::OnEmuStop);
@ -640,40 +635,6 @@ void gui_application::OnChangeStyleSheetRequest()
} }
} }
void gui_application::OnEmuSettingsChange()
{
if (Emu.IsRunning())
{
if (g_cfg.misc.prevent_display_sleep)
{
enable_display_sleep();
}
else
{
disable_display_sleep();
}
}
rpcs3::utils::configure_logs();
if (!Emu.IsStopped())
{
// Force audio provider
if (Emu.IsVsh())
{
g_cfg.audio.provider.set(audio_provider::rsxaudio);
}
else
{
g_cfg.audio.provider.set(audio_provider::cell_audio);
}
}
audio::configure_audio();
audio::configure_rsxaudio();
rsx::overlays::reset_performance_overlay();
}
/** /**
* Using connects avoids timers being unable to be used in a non-qt thread. So, even if this looks stupid to just call func, it's succinct. * Using connects avoids timers being unable to be used in a non-qt thread. So, even if this looks stupid to just call func, it's succinct.
*/ */

View File

@ -85,7 +85,6 @@ private:
private Q_SLOTS: private Q_SLOTS:
void OnChangeStyleSheetRequest(); void OnChangeStyleSheetRequest();
static void OnEmuSettingsChange();
Q_SIGNALS: Q_SIGNALS:
void OnEmulatorRun(bool start_playtime); void OnEmulatorRun(bool start_playtime);

View File

@ -172,6 +172,14 @@ private:
case localized_string_id::HOME_MENU_TITLE: return tr("Home Menu"); case localized_string_id::HOME_MENU_TITLE: return tr("Home Menu");
case localized_string_id::HOME_MENU_EXIT_GAME: return tr("Exit Game"); 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_RESUME: return tr("Resume Game");
case localized_string_id::HOME_MENU_SETTINGS: return tr("Settings");
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");
case localized_string_id::HOME_MENU_SETTINGS_ADVANCED: return tr("Advanced");
case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS: return tr("Overlays");
case localized_string_id::HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY: return tr("Performance Overlay");
case localized_string_id::HOME_MENU_SETTINGS_DEBUG: return tr("Debug");
case localized_string_id::HOME_MENU_SCREENSHOT: return tr("Take Screenshot"); case localized_string_id::HOME_MENU_SCREENSHOT: return tr("Take Screenshot");
case localized_string_id::HOME_MENU_RECORDING: return tr("Start/Stop Recording"); case localized_string_id::HOME_MENU_RECORDING: return tr("Start/Stop Recording");
case localized_string_id::EMULATION_PAUSED_RESUME_WITH_START: return tr("Press and hold the START button to resume"); case localized_string_id::EMULATION_PAUSED_RESUME_WITH_START: return tr("Press and hold the START button to resume");