From d614634bf11460b5ce7445478e13a3a6ffe63f15 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Mon, 7 Apr 2025 21:46:53 -0400 Subject: [PATCH] Add mod UI API exports for slider, password input, and label radio and expose RmlUi debugger on F8 --- include/overloaded.h | 10 +++ src/main/rt64_render_context.cpp | 7 +- src/ui/elements/ui_container.cpp | 1 - src/ui/elements/ui_element.cpp | 37 ++++++++++ src/ui/elements/ui_element.h | 11 +++ src/ui/elements/ui_radio.cpp | 19 +++-- src/ui/elements/ui_radio.h | 2 + src/ui/elements/ui_slider.cpp | 22 ++++-- src/ui/elements/ui_slider.h | 3 +- src/ui/elements/ui_text_input.cpp | 6 +- src/ui/elements/ui_text_input.h | 2 +- src/ui/ui_api.cpp | 113 ++++++++++++++++++++++++++++-- src/ui/ui_api_events.cpp | 6 +- src/ui/ui_config_sub_menu.cpp | 4 +- src/ui/ui_helpers.h | 67 ++++++++++++++++++ src/ui/ui_state.cpp | 5 ++ 16 files changed, 283 insertions(+), 32 deletions(-) create mode 100644 include/overloaded.h diff --git a/include/overloaded.h b/include/overloaded.h new file mode 100644 index 0000000..2ead7ad --- /dev/null +++ b/include/overloaded.h @@ -0,0 +1,10 @@ +#ifndef __OVERLOADED_H__ +#define __OVERLOADED_H__ + +// Helper for std::visit +template +struct overloaded : Ts... { using Ts::operator()...; }; +template +overloaded(Ts...) -> overloaded; + +#endif diff --git a/src/main/rt64_render_context.cpp b/src/main/rt64_render_context.cpp index ae652c3..dd2f152 100644 --- a/src/main/rt64_render_context.cpp +++ b/src/main/rt64_render_context.cpp @@ -6,6 +6,7 @@ #define HLSL_CPU #include "hle/rt64_application.h" #include "rt64_render_hooks.h" +#include "overloaded.h" #include "ultramodern/ultramodern.hpp" #include "ultramodern/config.hpp" @@ -14,12 +15,6 @@ #include "recomp_ui.h" #include "concurrentqueue.h" -// Helper class for variant visiting. -template -struct overloaded : Ts... { using Ts::operator()...; }; -template -overloaded(Ts...) -> overloaded; - static RT64::UserConfiguration::Antialiasing device_max_msaa = RT64::UserConfiguration::Antialiasing::None; static bool sample_positions_supported = false; static bool high_precision_fb_enabled = false; diff --git a/src/ui/elements/ui_container.cpp b/src/ui/elements/ui_container.cpp index 3c76d2c..5b4e30d 100644 --- a/src/ui/elements/ui_container.cpp +++ b/src/ui/elements/ui_container.cpp @@ -6,7 +6,6 @@ namespace recompui { Container::Container(Element *parent, FlexDirection direction, JustifyContent justify_content) : Element(parent) { set_display(Display::Flex); - set_flex(1.0f, 1.0f); set_flex_direction(direction); set_justify_content(justify_content); } diff --git a/src/ui/elements/ui_element.cpp b/src/ui/elements/ui_element.cpp index a6160f7..80b7138 100644 --- a/src/ui/elements/ui_element.cpp +++ b/src/ui/elements/ui_element.cpp @@ -1,5 +1,6 @@ #include "RmlUi/Core/StringUtilities.h" +#include "overloaded.h" #include "recomp_ui.h" #include "ui_element.h" #include "../core/ui_context.h" @@ -28,6 +29,9 @@ Element::Element(Element* parent, uint32_t events_enabled, Rml::String base_clas base = base_owning.get(); } + set_display(Display::Block); + set_property(Rml::PropertyId::BoxSizing, Rml::Style::BoxSizing::BorderBox); + register_event_listeners(events_enabled); } @@ -372,6 +376,39 @@ float Element::get_client_height() { return base->GetClientHeight(); } +uint32_t Element::get_input_value_u32() { + ElementValue value = get_element_value(); + + return std::visit(overloaded { + [](double d) { return (uint32_t)d; }, + [](float f) { return (uint32_t)f; }, + [](uint32_t u) { return u; }, + [](std::monostate) { return 0U; } + }, value); +} + +float Element::get_input_value_float() { + ElementValue value = get_element_value(); + + return std::visit(overloaded { + [](double d) { return (float)d; }, + [](float f) { return f; }, + [](uint32_t u) { return (float)u; }, + [](std::monostate) { return 0.0f; } + }, value); +} + +double Element::get_input_value_double() { + ElementValue value = get_element_value(); + + return std::visit(overloaded { + [](double d) { return d; }, + [](float f) { return (double)f; }, + [](uint32_t u) { return (double)u; }, + [](std::monostate) { return 0.0; } + }, value); +} + void Element::queue_update() { ContextId cur_context = get_current_context(); diff --git a/src/ui/elements/ui_element.h b/src/ui/elements/ui_element.h index b4a8e97..9484b93 100644 --- a/src/ui/elements/ui_element.h +++ b/src/ui/elements/ui_element.h @@ -7,6 +7,7 @@ #include #include +#include namespace recompui { struct UICallback { @@ -15,6 +16,8 @@ struct UICallback { PTR(void) userdata; }; +using ElementValue = std::variant; + class ContextId; class Element : public Style, public Rml::EventListener { friend ContextId create_context(const std::filesystem::path& path); @@ -52,6 +55,8 @@ protected: // Use of this method in inherited classes is discouraged unless it's necessary. void set_attribute(const Rml::String &attribute_key, const Rml::String &attribute_value); virtual void process_event(const Event &e); + virtual ElementValue get_element_value() { return std::monostate{}; } + virtual void set_input_value(const ElementValue&) {} public: // Used for backwards compatibility with legacy UI elements. Element(Rml::Element *base); @@ -80,6 +85,12 @@ public: float get_client_height(); void queue_update(); void register_callback(ContextId context, PTR(void) callback, PTR(void) userdata); + uint32_t get_input_value_u32(); + float get_input_value_float(); + double get_input_value_double(); + void set_input_value_u32(uint32_t val) { set_input_value(val); } + void set_input_value_float(float val) { set_input_value(val); } + void set_input_value_double(double val) { set_input_value(val); } }; void queue_ui_callback(recompui::ResourceId resource, const Event& e, const UICallback& callback); diff --git a/src/ui/elements/ui_radio.cpp b/src/ui/elements/ui_radio.cpp index aa7438c..5f63730 100644 --- a/src/ui/elements/ui_radio.cpp +++ b/src/ui/elements/ui_radio.cpp @@ -1,3 +1,4 @@ +#include "overloaded.h" #include "ui_radio.h" namespace recompui { @@ -14,14 +15,15 @@ namespace recompui { set_line_height(20.0f); set_font_weight(400); set_font_style(FontStyle::Normal); - set_border_color(Color{ 242, 242, 242, 255 }); - set_border_bottom_width(0.0f); + set_border_color(Color{ 242, 242, 242, 0 }); + set_border_bottom_width(1.0f); set_color(Color{ 255, 255, 255, 153 }); set_padding_bottom(8.0f); set_text_transform(TextTransform::Uppercase); + set_height_auto(); hover_style.set_color(Color{ 255, 255, 255, 204 }); checked_style.set_color(Color{ 255, 255, 255, 255 }); - checked_style.set_border_bottom_width(1.0f); + checked_style.set_border_color(Color{ 242, 242, 242, 255 }); add_style(&hover_style, { hover_state }); add_style(&checked_style, { checked_state }); @@ -70,10 +72,19 @@ namespace recompui { void Radio::option_selected(uint32_t index) { set_index_internal(index, false, true); } + + void Radio::set_input_value(const ElementValue& val) { + std::visit(overloaded { + [this](uint32_t u) { set_index(u); }, + [this](float f) { set_index(f); }, + [this](double d) { set_index(d); }, + [](std::monostate) {} + }, val); + } Radio::Radio(Element *parent) : Container(parent, FlexDirection::Row, JustifyContent::FlexStart) { set_gap(24.0f); - set_flex_grow(0.0f); + set_align_items(AlignItems::FlexStart); } Radio::~Radio() { diff --git a/src/ui/elements/ui_radio.h b/src/ui/elements/ui_radio.h index b4303d9..8c31415 100644 --- a/src/ui/elements/ui_radio.h +++ b/src/ui/elements/ui_radio.h @@ -26,6 +26,8 @@ namespace recompui { void set_index_internal(uint32_t index, bool setup, bool trigger_callbacks); void option_selected(uint32_t index); + void set_input_value(const ElementValue& val) override; + ElementValue get_element_value() override { return get_index(); } public: Radio(Element *parent); virtual ~Radio(); diff --git a/src/ui/elements/ui_slider.cpp b/src/ui/elements/ui_slider.cpp index 6e2bf9e..a3994da 100644 --- a/src/ui/elements/ui_slider.cpp +++ b/src/ui/elements/ui_slider.cpp @@ -1,3 +1,4 @@ +#include "overloaded.h" #include "ui_slider.h" #include @@ -44,7 +45,8 @@ namespace recompui { void Slider::update_circle_position() { double ratio = std::clamp((value - min_value) / (max_value - min_value), 0.0, 1.0); - circle_element->set_left(slider_width_dp * ratio); + float slider_relative_left = slider_element->get_absolute_left() - get_absolute_left(); + circle_element->set_left(ratio * 100.0, Unit::Percent); } void Slider::update_label_text() { @@ -60,13 +62,23 @@ namespace recompui { value_label->set_text(text_buffer); } + + void Slider::set_input_value(const ElementValue& val) { + std::visit(overloaded { + [this](uint32_t u) { set_value(u); }, + [this](float f) { set_value(f); }, + [this](double d) { set_value(d); }, + [](std::monostate) {} + }, val); + } Slider::Slider(Element *parent, SliderType type) : Element(parent) { this->type = type; set_display(Display::Flex); - set_flex(1.0f, 1.0f, 100.0f, Unit::Percent); set_flex_direction(FlexDirection::Row); + set_text_align(TextAlign::Left); + set_min_width(120.0f); ContextId context = get_current_context(); @@ -76,7 +88,7 @@ namespace recompui { value_label->set_max_width(60.0f); slider_element = context.create_element(this); - slider_element->set_width(slider_width_dp); + slider_element->set_flex(1.0f, 0.0f); { bar_element = context.create_element(slider_element, true); @@ -87,11 +99,11 @@ namespace recompui { bar_element->add_pressed_callback([this](float x, float y){ bar_clicked(x, y); }); bar_element->add_dragged_callback([this](float x, float y, recompui::DragPhase phase){ bar_dragged(x, y, phase); }); - circle_element = context.create_element(slider_element, true); + circle_element = context.create_element(bar_element, true); circle_element->set_position(Position::Relative); circle_element->set_width(16.0f); circle_element->set_height(16.0f); - circle_element->set_margin_top(-8.0f); + circle_element->set_margin_top(-7.0f); circle_element->set_margin_right(-8.0f); circle_element->set_margin_left(-8.0f); circle_element->set_background_color(Color{ 204, 204, 204, 255 }); diff --git a/src/ui/elements/ui_slider.h b/src/ui/elements/ui_slider.h index a358db7..9ecb99a 100644 --- a/src/ui/elements/ui_slider.h +++ b/src/ui/elements/ui_slider.h @@ -22,7 +22,6 @@ namespace recompui { double min_value = 0.0; double max_value = 100.0; double step_value = 0.0; - float slider_width_dp = 300.0; std::vector> value_changed_callbacks; void set_value_internal(double v, bool setup, bool trigger_callbacks); @@ -32,6 +31,8 @@ namespace recompui { void update_value_from_mouse(float x); void update_circle_position(); void update_label_text(); + void set_input_value(const ElementValue& val) override; + ElementValue get_element_value() override { return get_value(); } public: Slider(Element *parent, SliderType type); diff --git a/src/ui/elements/ui_text_input.cpp b/src/ui/elements/ui_text_input.cpp index 547aa3c..0934f8d 100644 --- a/src/ui/elements/ui_text_input.cpp +++ b/src/ui/elements/ui_text_input.cpp @@ -21,9 +21,11 @@ namespace recompui { } } - TextInput::TextInput(Element *parent) : Element(parent, Events(EventType::Text), "input") { + TextInput::TextInput(Element *parent, bool text_visible) : Element(parent, Events(EventType::Text), "input") { + if (!text_visible) { + set_attribute("type", "password"); + } set_min_width(60.0f); - set_max_width(400.0f); set_border_color(Color{ 242, 242, 242, 255 }); set_border_bottom_width(1.0f); set_padding_bottom(6.0f); diff --git a/src/ui/elements/ui_text_input.h b/src/ui/elements/ui_text_input.h index a8feea9..4d9281b 100644 --- a/src/ui/elements/ui_text_input.h +++ b/src/ui/elements/ui_text_input.h @@ -11,7 +11,7 @@ namespace recompui { protected: virtual void process_event(const Event &e) override; public: - TextInput(Element *parent); + TextInput(Element *parent, bool text_visible = true); void set_text(std::string_view text); const std::string &get_text(); void add_text_changed_callback(std::function callback); diff --git a/src/ui/ui_api.cpp b/src/ui/ui_api.cpp index cd48a84..7a2676e 100644 --- a/src/ui/ui_api.cpp +++ b/src/ui/ui_api.cpp @@ -116,6 +116,16 @@ void recompui_destroy_element(uint8_t* rdram, recomp_context* ctx) { } } +void recompui_create_button(uint8_t* rdram, recomp_context* ctx) { + ContextId ui_context = get_context(rdram, ctx); + Element* parent = arg_element<1>(rdram, ctx, ui_context); + std::string text = _arg_string<2>(rdram, ctx); + uint32_t style = _arg<3, uint32_t>(rdram, ctx); + + Button* ret = ui_context.create_element