diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.h b/rpcs3/Emu/RSX/Overlays/overlay_controls.h index e98965197c..2842a14109 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.h @@ -191,6 +191,7 @@ namespace rsx u16 margin_left = 0; u16 margin_top = 0; + // NOTE: These two only apply for text. Containers maintain their own scroll values. f32 horizontal_scroll_offset = 0.0f; f32 vertical_scroll_offset = 0.0f; diff --git a/rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp b/rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp index eb312e14b5..1ac3f5c487 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp @@ -216,11 +216,16 @@ namespace rsx { m_scroll_indicator_top->set_visible(!hidden); m_scroll_indicator_bottom->set_visible(!hidden); - m_highlight_box->set_visible(!hidden); refresh(); } + void list_view::hide_row_highliter(bool hidden) + { + m_highlight_box->set_visible(!hidden); + refresh(); + } + void list_view::disable_selection_pulse(bool disabled) { m_highlight_box->pulse_effect_enabled = !disabled; @@ -275,6 +280,13 @@ namespace rsx m_highlight_box->refresh(); } + void list_view::set_pos(s16 x, s16 y) + { + vertical_layout::set_pos(x, y); + + update_selection(); + } + compiled_resource& list_view::get_compiled() { if (is_compiled()) diff --git a/rpcs3/Emu/RSX/Overlays/overlay_list_view.hpp b/rpcs3/Emu/RSX/Overlays/overlay_list_view.hpp index 5680d63682..360ab6c718 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_list_view.hpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_list_view.hpp @@ -50,11 +50,13 @@ namespace rsx void hide_prompt_buttons(bool hidden = true); void hide_scroll_indicators(bool hidden = true); + void hide_row_highliter(bool hidden = false); void disable_selection_pulse(bool disabled = true); void set_cancel_only(bool cancel_only); void translate(s16 _x, s16 _y) override; void set_size(u16 w, u16 h) override; + void set_pos(s16 x, s16 y) override; compiled_resource& get_compiled() override; }; diff --git a/rpcs3/Emu/RSX/Overlays/overlay_select.cpp b/rpcs3/Emu/RSX/Overlays/overlay_select.cpp index a27b824da7..d17a437002 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_select.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_select.cpp @@ -1 +1,225 @@ #include "stdafx.h" +#include "overlay_select.h" + +namespace rsx::overlays +{ + constexpr u16 max_dropdown_arrow_dimension = 12; + constexpr u16 dropdown_arrow_spacing = 4; + constexpr u16 dropdown_pack_padding = 6; + + select_popup::select_popup(u16 w, u16 h) + : list_view(w, h, false) + { + hide_prompt_buttons(); + hide_scroll_indicators(); + pack_padding = dropdown_pack_padding; + } + + select::select(u16 w, u16 h, const std::vector& options) + { + std::vector> labels; + for (const auto& option : options) + { + std::unique_ptr element = std::make_unique(); + labels.push_back(std::move(element)); + + auto label = dynamic_cast(labels.back().get()); + label->set_padding(8, 0, 0, 0); + label->set_text(option); + label->set_font("Arial", 14); + label->set_padding(4); + label->back_color.a = 0.f; + label->auto_resize(); + } + + create_popup(labels); + set_padding(8, 10, 6, 12); + set_size(w, h); + select_item(0); + } + + select::select(u16 w, u16 h, const std::vector& options) + { + std::vector> labels; + for (const auto& option : options) + { + std::unique_ptr element = std::make_unique(); + labels.push_back(std::move(element)); + + auto label = dynamic_cast(labels.back().get()); + label->set_padding(8, 0, 0, 0); + label->set_unicode_text(option); + label->set_padding(4); + label->set_font("Arial", 14); + label->back_color.a = 0.f; + label->auto_resize(); + } + + create_popup(labels); + set_padding(8, 10, 6, 12); + set_size(w, h); + select_item(0); + } + + select::select(u16 w, u16 h, std::vector>& options) + { + create_popup(options); + set_padding(8, 10, 6, 12); + set_size(w, h); + select_item(0); + } + + void select::create_popup(std::vector>& options) + { + u16 max_w = 0; + u16 max_h = 0; + + for (const auto& option : options) + { + max_w = std::max(max_w, option->w); + max_h += option->h + dropdown_pack_padding; + } + + m_popup = std::make_unique(max_w, max_h + dropdown_pack_padding + 4); + m_popup->back_color = color4f(0.3f, 0.3f, 0.3f, 1.0f); + + for (auto& option : options) + { + m_popup->add_entry(option); + } + } + + void select::auto_resize() + { + u16 _h = max_dropdown_arrow_dimension; // Minimum arrow dimension + if (m_label) + { + _h = std::max(_h, m_label->h); + } + + // Compute length of longest entry + u16 text_w = 0, text_h = 0; + for (auto& option : m_popup->m_items) + { + if (option->text.empty()) + { + continue; + } + + u16 tw = 0, th = 0; + option->measure_text(tw, th, true); + text_w = std::max(text_w, tw); + text_h = std::max(text_h, th); + } + + _h = std::max(_h, text_h); + _h += padding_top + padding_bottom; + + if (text_w == 0) + { + // Avoid using auto_resize with manually generated options list + text_w = m_popup->w; + } + + u16 _w = text_w + dropdown_arrow_spacing + std::max(_h / 2, max_dropdown_arrow_dimension); // Enough to fit longest string + space for the arrow and padding + _w += padding_left + padding_right; + set_size(_w, _h); + } + + void select::set_size(u16 w, u16 h) + { + clear_items(); + + if (const u16 min_x = (padding_left + padding_right + max_dropdown_arrow_dimension + (2 * dropdown_arrow_spacing)); w < min_x) + { + w = min_x; + } + + if (const u16 min_y = (padding_top + padding_bottom + 16); h < min_y) + { + h = min_y; + } + + box_layout::set_size(w, h); + + auto background = std::make_unique(); + background->set_size(w, h); + background->radius = std::min(h / 4, 5); + background->back_color = color4f(0.3f, 0.3f, 0.3f, 1.0f); + + const u16 arrow_size = std::min(h / 2, max_dropdown_arrow_dimension); + auto arrow = std::make_unique(); + arrow->set_size(arrow_size, arrow_size); + arrow->back_color = color4f(0.8f, 0.8f, 0.8f, 1.f); + + auto textfield = std::make_unique