mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-03-17 18:55:19 +01:00
overlays/home: Integrate the new dropdown widget
This commit is contained in:
parent
bb652ed840
commit
37f1533dad
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "Emu/RSX/Overlays/overlays.h"
|
||||
#include "Emu/RSX/Overlays/overlay_checkbox.h"
|
||||
#include "Emu/RSX/Overlays/overlay_select.h"
|
||||
#include "Emu/RSX/Overlays/overlay_slider.h"
|
||||
|
||||
#include "Emu/System.h"
|
||||
|
|
@ -121,19 +122,147 @@ namespace rsx
|
|||
public:
|
||||
home_menu_dropdown(cfg::_enum<T>* setting, const std::string& text)
|
||||
: home_menu_setting<T, cfg::_enum<T>>(setting, text)
|
||||
{}
|
||||
{
|
||||
for (size_t index = 0; index < setting->size(); index++)
|
||||
{
|
||||
auto translated = Emu.GetCallbacks().get_localized_setting(home_menu_setting<T, cfg::_enum<T>>::m_setting, static_cast<u32>(index));
|
||||
m_options.emplace_back(std::move(translated));
|
||||
}
|
||||
}
|
||||
|
||||
void sync_selection()
|
||||
{
|
||||
auto setting = home_menu_setting<T, cfg::_enum<T>>::m_setting;
|
||||
if (!setting || !m_dropdown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto current = fmt::format("%s", setting->get());
|
||||
const auto list = setting->to_list();
|
||||
for (s32 index = 0; index <= list.size(); ++index)
|
||||
{
|
||||
if (list[index] != current)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (index != m_dropdown->get_selected_index())
|
||||
{
|
||||
m_dropdown->select_item(index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void set_size(u16 w, u16 h = element_height) override
|
||||
{
|
||||
home_menu_setting<T, cfg::_enum<T>>::set_reserved_width(w / 2 + menu_entry_margin);
|
||||
auto dropdown = std::make_unique<overlays::select>(w / 2, element_height, m_options);
|
||||
dropdown->auto_resize();
|
||||
|
||||
home_menu_setting<T, cfg::_enum<T>>::set_reserved_width(dropdown->w + menu_entry_margin);
|
||||
home_menu_setting<T, cfg::_enum<T>>::set_size(w, h);
|
||||
|
||||
auto dropdown = std::make_unique<overlays::label>();
|
||||
// Center horizontally
|
||||
dropdown->set_pos(0, this->compute_vertically_centered(dropdown.get()));
|
||||
m_dropdown = horizontal_layout::add_element(dropdown);
|
||||
m_dropdown->set_size(w / 2, element_height);
|
||||
m_dropdown->set_font("Arial", 14);
|
||||
m_dropdown->align_text(home_menu_dropdown<T>::text_align::center);
|
||||
m_dropdown->back_color = { 0.3f, 0.3f, 0.3f, 1.0f };
|
||||
|
||||
// Select the correct item
|
||||
sync_selection();
|
||||
}
|
||||
|
||||
bool is_popup_visible() const
|
||||
{
|
||||
return m_popup_visible;
|
||||
}
|
||||
|
||||
s32 get_selected_index() const
|
||||
{
|
||||
return m_dropdown->get_selected_index();
|
||||
}
|
||||
|
||||
void open_popup(const overlay_element* parent = nullptr)
|
||||
{
|
||||
m_previous_selection = m_dropdown->get_selected_index();
|
||||
m_popup_visible = true;
|
||||
|
||||
if (!parent)
|
||||
{
|
||||
m_dropdown->get_popup()->set_pos(m_dropdown->x, m_dropdown->y + m_dropdown->h);
|
||||
return;
|
||||
}
|
||||
|
||||
u16 dropdown_y = m_dropdown->y;
|
||||
|
||||
// Check if the parent is a layout that can scroll
|
||||
if (auto container = dynamic_cast<const vertical_layout*>(parent))
|
||||
{
|
||||
// Apply the scroll (convert coordinate to view space from container space)
|
||||
dropdown_y = std::max<u16>(dropdown_y, container->scroll_offset_value) - container->scroll_offset_value;
|
||||
}
|
||||
|
||||
const int space_above = static_cast<int>(dropdown_y) - std::min<int>(parent->y, dropdown_y);
|
||||
const int space_below = std::max<int>(parent->y + parent->h, dropdown_y) - dropdown_y;
|
||||
|
||||
const int popup_height = m_dropdown->get_popup()->h;
|
||||
u16 popup_x = m_dropdown->x, popup_y = parent->y;
|
||||
if (space_below >= popup_height)
|
||||
{
|
||||
popup_y = dropdown_y + m_dropdown->h + 4;
|
||||
}
|
||||
else if (space_above >= popup_height)
|
||||
{
|
||||
popup_y = dropdown_y - popup_height - 4;
|
||||
}
|
||||
|
||||
m_dropdown->get_popup()->set_pos(popup_x, popup_y);
|
||||
}
|
||||
|
||||
void close_popup()
|
||||
{
|
||||
m_popup_visible = false;
|
||||
}
|
||||
|
||||
page_navigation handle_input(pad_button button)
|
||||
{
|
||||
switch (button)
|
||||
{
|
||||
case pad_button::circle:
|
||||
m_dropdown->select_item(m_previous_selection);
|
||||
close_popup();
|
||||
return page_navigation::exit;
|
||||
|
||||
case pad_button::cross:
|
||||
m_dropdown->select_item(m_dropdown->get_selected_index());
|
||||
close_popup();
|
||||
return page_navigation::exit;
|
||||
|
||||
case pad_button::dpad_up:
|
||||
case pad_button::ls_up:
|
||||
m_dropdown->select_previous();
|
||||
break;
|
||||
|
||||
case pad_button::dpad_down:
|
||||
case pad_button::ls_down:
|
||||
m_dropdown->select_next();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return page_navigation::stay;
|
||||
}
|
||||
|
||||
compiled_resource& render_popup()
|
||||
{
|
||||
if (this->m_popup_visible)
|
||||
{
|
||||
return m_dropdown->get_popup()->get_compiled();
|
||||
}
|
||||
|
||||
m_popup_compiled_resources.clear();
|
||||
return m_popup_compiled_resources;
|
||||
}
|
||||
|
||||
compiled_resource& get_compiled() override
|
||||
|
|
@ -142,11 +271,8 @@ namespace rsx
|
|||
|
||||
if (!this->is_compiled())
|
||||
{
|
||||
const std::string value_text = Emu.GetCallbacks().get_localized_setting(home_menu_setting<T, cfg::_enum<T>>::m_setting, static_cast<u32>(this->m_last_value));
|
||||
m_dropdown->set_text(value_text);
|
||||
m_dropdown->set_pos(m_dropdown->x, this->y + (this->h - m_dropdown->h) / 2);
|
||||
|
||||
this->compiled_resources = horizontal_layout::get_compiled();
|
||||
sync_selection();
|
||||
horizontal_layout::get_compiled();
|
||||
this->compiled_resources.add(m_dropdown->get_compiled());
|
||||
}
|
||||
|
||||
|
|
@ -154,7 +280,12 @@ namespace rsx
|
|||
}
|
||||
|
||||
private:
|
||||
label* m_dropdown;
|
||||
std::vector<std::string> m_options;
|
||||
select* m_dropdown = nullptr;
|
||||
|
||||
int m_previous_selection = -1;
|
||||
bool m_popup_visible = false;
|
||||
compiled_resource m_popup_compiled_resources;
|
||||
};
|
||||
|
||||
template <typename T, typename C>
|
||||
|
|
|
|||
|
|
@ -49,11 +49,13 @@ namespace rsx
|
|||
void home_menu_page::on_activate()
|
||||
{
|
||||
hide_scroll_indicators(false);
|
||||
hide_row_highliter(false);
|
||||
}
|
||||
|
||||
void home_menu_page::on_deactivate()
|
||||
{
|
||||
hide_scroll_indicators(true);
|
||||
hide_row_highliter(true);
|
||||
}
|
||||
|
||||
void home_menu_page::set_current_page(home_menu_page* page)
|
||||
|
|
@ -186,6 +188,16 @@ namespace rsx
|
|||
return page->handle_button_press(button_press, is_auto_repeat, auto_repeat_interval_ms);
|
||||
}
|
||||
|
||||
if (m_popup && m_popup.input_hook)
|
||||
{
|
||||
auto popup_action = m_popup.input_hook(button_press);
|
||||
if (popup_action == page_navigation::exit)
|
||||
{
|
||||
m_popup.dismiss();
|
||||
}
|
||||
return page_navigation::stay;
|
||||
}
|
||||
|
||||
switch (button_press)
|
||||
{
|
||||
case pad_button::dpad_left:
|
||||
|
|
@ -232,6 +244,7 @@ namespace rsx
|
|||
g_cfg.from_string(g_backup_cfg.to_string());
|
||||
Emu.GetCallbacks().update_emu_settings();
|
||||
*m_config_changed = false;
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -249,6 +262,7 @@ namespace rsx
|
|||
if (m_config_changed)
|
||||
{
|
||||
*m_config_changed = false;
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -330,6 +344,11 @@ namespace rsx
|
|||
|
||||
compiled_resource& home_menu_page::get_compiled()
|
||||
{
|
||||
if (m_popup)
|
||||
{
|
||||
m_is_compiled = false;
|
||||
}
|
||||
|
||||
if (m_message_box && !m_message_box->is_compiled())
|
||||
{
|
||||
m_is_compiled = false;
|
||||
|
|
@ -364,6 +383,11 @@ namespace rsx
|
|||
}
|
||||
}
|
||||
|
||||
if (m_popup)
|
||||
{
|
||||
compiled_resources.add(m_popup.get_compiled());
|
||||
}
|
||||
|
||||
m_is_compiled = true;
|
||||
return compiled_resources;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,20 @@ namespace rsx
|
|||
{
|
||||
namespace overlays
|
||||
{
|
||||
struct home_menu_popup
|
||||
{
|
||||
std::function<compiled_resource&()> get_compiled;
|
||||
std::function<page_navigation(pad_button)> input_hook;
|
||||
|
||||
void dismiss()
|
||||
{
|
||||
get_compiled = {};
|
||||
input_hook = {};
|
||||
}
|
||||
|
||||
operator bool() const { return !!get_compiled; }
|
||||
};
|
||||
|
||||
struct home_menu_page : public list_view
|
||||
{
|
||||
public:
|
||||
|
|
@ -35,6 +49,8 @@ namespace rsx
|
|||
std::shared_ptr<home_menu_message_box> m_message_box;
|
||||
std::shared_ptr<bool> m_config_changed;
|
||||
|
||||
home_menu_popup m_popup;
|
||||
|
||||
protected:
|
||||
virtual void add_page(home_menu::fa_icon icon, std::shared_ptr<home_menu_page> page);
|
||||
virtual void add_item(home_menu::fa_icon icon, std::string_view, std::function<page_navigation(pad_button)> callback);
|
||||
|
|
|
|||
|
|
@ -79,66 +79,64 @@ namespace rsx
|
|||
std::unique_ptr<overlay_element> elem = std::make_unique<home_menu_dropdown<T>>(setting, localized_text);
|
||||
elem->set_size(this->w, menu_entry_height);
|
||||
|
||||
add_item(elem, [this, setting](pad_button btn) -> page_navigation
|
||||
add_item(elem, [this, setting, elem = elem.get()](pad_button btn) -> page_navigation
|
||||
{
|
||||
if (setting)
|
||||
if (btn != pad_button::cross)
|
||||
{
|
||||
bool set_default = false;
|
||||
switch (btn)
|
||||
return page_navigation::stay;
|
||||
}
|
||||
|
||||
if (!setting)
|
||||
{
|
||||
return page_navigation::stay;
|
||||
}
|
||||
|
||||
// If we're receiving this, we need to open the popup and install the input hook
|
||||
auto dropdown = ensure(dynamic_cast<home_menu_dropdown<T>*>(elem));
|
||||
dropdown->open_popup(static_cast<const list_view*>(this));
|
||||
|
||||
auto render_fn = [dropdown]() -> compiled_resource&
|
||||
{
|
||||
return dropdown->render_popup();
|
||||
};
|
||||
|
||||
auto input_fn = [this, dropdown, setting](pad_button button) -> page_navigation
|
||||
{
|
||||
const auto result = dropdown->handle_input(button);
|
||||
|
||||
if (!setting || result != page_navigation::exit)
|
||||
{
|
||||
case pad_button::cross:
|
||||
break;
|
||||
case pad_button::select:
|
||||
set_default = true;
|
||||
break;
|
||||
default:
|
||||
return page_navigation::stay;
|
||||
return result;
|
||||
}
|
||||
|
||||
T value = setting->get();
|
||||
|
||||
if (set_default)
|
||||
{
|
||||
if (value == setting->def)
|
||||
{
|
||||
return page_navigation::stay;
|
||||
}
|
||||
|
||||
value = setting->def;
|
||||
}
|
||||
|
||||
usz new_index = 0;
|
||||
const std::string val = fmt::format("%s", value);
|
||||
const auto previous = fmt::format("%s", setting->get());
|
||||
const std::vector<std::string> list = setting->to_list();
|
||||
const int selected_idx = dropdown->get_selected_index();
|
||||
|
||||
for (usz i = 0; i < list.size(); i++)
|
||||
{
|
||||
const std::string& entry = list[i];
|
||||
if (entry == val)
|
||||
{
|
||||
if (set_default)
|
||||
{
|
||||
new_index = i;
|
||||
break;
|
||||
}
|
||||
|
||||
new_index = (i + 1) % list.size();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (const std::string& next_value = ::at32(list, new_index); setting->from_string(next_value))
|
||||
if (const std::string& next_value = ::at32(list, selected_idx); setting->from_string(next_value))
|
||||
{
|
||||
rsx_log.notice("User toggled dropdown in '%s'. Setting '%s' to %s", title, setting->get_name(), next_value);
|
||||
|
||||
if (next_value != previous)
|
||||
{
|
||||
Emu.GetCallbacks().update_emu_settings();
|
||||
if (m_config_changed)
|
||||
{
|
||||
*m_config_changed = true;
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rsx_log.error("Can't toggle dropdown in '%s'. Setting '%s' to '%s' failed", title, setting->get_name(), next_value);
|
||||
}
|
||||
Emu.GetCallbacks().update_emu_settings();
|
||||
if (m_config_changed) *m_config_changed = true;
|
||||
refresh();
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
m_popup.get_compiled = render_fn;
|
||||
m_popup.input_hook = input_fn;
|
||||
|
||||
return page_navigation::stay;
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue