Text input.

This commit is contained in:
Dario 2025-01-19 00:29:40 -03:00 committed by Mr-Wiseguy
parent de88b5de46
commit 0a33cf03ef
12 changed files with 189 additions and 69 deletions

View file

@ -196,6 +196,7 @@ set (SOURCES
${CMAKE_SOURCE_DIR}/src/ui/elements/ui_scroll_container.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_scroll_container.cpp
${CMAKE_SOURCE_DIR}/src/ui/elements/ui_slider.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_slider.cpp
${CMAKE_SOURCE_DIR}/src/ui/elements/ui_style.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_style.cpp
${CMAKE_SOURCE_DIR}/src/ui/elements/ui_text_input.cpp
${CMAKE_SOURCE_DIR}/src/ui/elements/ui_toggle.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_toggle.cpp
${CMAKE_SOURCE_DIR}/rsp/aspMain.cpp ${CMAKE_SOURCE_DIR}/rsp/aspMain.cpp

View file

@ -67,11 +67,11 @@ namespace recompui {
function(); function();
} }
break; break;
case EventType::Hover: case EventType::Hover:
set_style_enabled(hover_state, e.hover.active); set_style_enabled(hover_state, std::get<EventHover>(e.variant).active);
break; break;
case EventType::Enable: case EventType::Enable:
set_style_enabled(disabled_state, !e.enable.enable); set_style_enabled(disabled_state, !std::get<EventEnable>(e.variant).active);
break; break;
default: default:
assert(false && "Unknown event type."); assert(false && "Unknown event type.");

View file

@ -13,22 +13,26 @@ namespace recompui {
void Clickable::process_event(const Event &e) { void Clickable::process_event(const Event &e) {
switch (e.type) { switch (e.type) {
case EventType::Click: case EventType::Click: {
const EventClick &click = std::get<EventClick>(e.variant);
for (const auto &function : pressed_callbacks) { for (const auto &function : pressed_callbacks) {
function(e.click.mouse.x, e.click.mouse.y); function(click.x, click.y);
} }
break; break;
}
case EventType::Hover: case EventType::Hover:
set_style_enabled(hover_state, e.hover.active); set_style_enabled(hover_state, std::get<EventHover>(e.variant).active);
break; break;
case EventType::Enable: case EventType::Enable:
set_style_enabled(disabled_state, !e.enable.enable); set_style_enabled(disabled_state, !std::get<EventEnable>(e.variant).active);
break; break;
case EventType::Drag: case EventType::Drag: {
const EventDrag &drag = std::get<EventDrag>(e.variant);
for (const auto &function : dragged_callbacks) { for (const auto &function : dragged_callbacks) {
function(e.drag.mouse.x, e.drag.mouse.y, e.drag.phase); function(drag.x, drag.y, drag.phase);
} }
break; break;
}
default: default:
break; break;
} }

View file

@ -89,6 +89,10 @@ void Element::register_event_listeners(uint32_t events_enabled) {
base->AddEventListener(Rml::EventId::Dragstart, this); base->AddEventListener(Rml::EventId::Dragstart, this);
base->AddEventListener(Rml::EventId::Dragend, this); base->AddEventListener(Rml::EventId::Dragend, this);
} }
if (events_enabled & Events(EventType::Text)) {
base->AddEventListener(Rml::EventId::Change, this);
}
} }
void Element::apply_style(Style *style) { void Element::apply_style(Style *style) {
@ -170,6 +174,16 @@ void Element::ProcessEvent(Rml::Event &event) {
case Rml::EventId::Dragend: case Rml::EventId::Dragend:
process_event(Event::drag_event(event.GetParameter("mouse_x", 0.0f), event.GetParameter("mouse_y", 0.0f), DragPhase::End)); process_event(Event::drag_event(event.GetParameter("mouse_x", 0.0f), event.GetParameter("mouse_y", 0.0f), DragPhase::End));
break; break;
case Rml::EventId::Change: {
if (events_enabled & Events(EventType::Text)) {
Rml::Variant *value_variant = base->GetAttribute("value");
if (value_variant != nullptr) {
process_event(Event::text_event(value_variant->Get<std::string>()));
}
}
break;
}
default: default:
break; break;
} }
@ -180,6 +194,10 @@ void Element::ProcessEvent(Rml::Event &event) {
} }
} }
void Element::set_attribute(const Rml::String &attribute_key, const Rml::String &attribute_value) {
base->SetAttribute(attribute_key, attribute_value);
}
void Element::process_event(const Event &) { void Element::process_event(const Event &) {
// Does nothing by default. // Does nothing by default.
} }

View file

@ -34,6 +34,8 @@ private:
// Rml::EventListener overrides. // Rml::EventListener overrides.
void ProcessEvent(Rml::Event &event) override final; void ProcessEvent(Rml::Event &event) override final;
protected: 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 void process_event(const Event &e);
public: public:
// Used for backwards compatibility with legacy UI elements. // Used for backwards compatibility with legacy UI elements.

View file

@ -0,0 +1,40 @@
#include "ui_text_input.h"
#include <cassert>
namespace recompui {
void TextInput::process_event(const Event &e) {
switch (e.type) {
case EventType::Text: {
const EventText &event = std::get<EventText>(e.variant);
text = event.text;
for (const auto &function : text_changed_callbacks) {
function(text);
}
break;
}
default:
break;
}
}
TextInput::TextInput(Element *parent) : Element(parent, Events(EventType::Text), "input") {
}
void TextInput::set_text(std::string_view text) {
this->text = std::string(text);
set_attribute("value", this->text);
}
const std::string &TextInput::get_text() {
return text;
}
void TextInput::add_text_changed_callback(std::function<void(const std::string &)> callback) {
text_changed_callbacks.emplace_back(callback);
}
};

View file

@ -0,0 +1,20 @@
#pragma once
#include "ui_element.h"
namespace recompui {
class TextInput : public Element {
private:
std::string text;
std::vector<std::function<void(const std::string &)>> text_changed_callbacks;
protected:
virtual void process_event(const Event &e) override;
public:
TextInput(Element *parent);
void set_text(std::string_view text);
const std::string &get_text();
void add_text_changed_callback(std::function<void(const std::string &)> callback);
};
} // namespace recompui

View file

@ -78,14 +78,18 @@ namespace recompui {
} }
break; break;
case EventType::Hover: case EventType::Hover: {
set_style_enabled(hover_state, e.hover.active); bool hover_active = std::get<EventHover>(e.variant).active;
floater->set_style_enabled(hover_state, e.hover.active); set_style_enabled(hover_state, hover_active);
floater->set_style_enabled(hover_state, hover_active);
break; break;
case EventType::Enable: }
set_style_enabled(disabled_state, !e.enable.enable); case EventType::Enable: {
floater->set_style_enabled(disabled_state, !e.enable.enable); bool enable_active = std::get<EventEnable>(e.variant).active;
set_style_enabled(disabled_state, !enable_active);
floater->set_style_enabled(disabled_state, !enable_active);
break; break;
}
default: default:
assert(false && "Unknown event type."); assert(false && "Unknown event type.");
break; break;

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <variant>
namespace recompui { namespace recompui {
@ -23,6 +24,7 @@ namespace recompui {
Hover, Hover,
Enable, Enable,
Drag, Drag,
Text,
Count Count
}; };
@ -43,74 +45,79 @@ namespace recompui {
return Events(first) | Events(rest...); return Events(first) | Events(rest...);
} }
struct EventClick {
float x;
float y;
};
struct EventFocus {
bool active;
};
struct EventHover {
bool active;
};
struct EventEnable {
bool active;
};
struct EventDrag {
float x;
float y;
DragPhase phase;
};
struct EventText {
std::string text;
};
using EventVariant = std::variant<EventClick, EventFocus, EventHover, EventEnable, EventDrag, EventText>;
struct Event { struct Event {
struct Mouse {
float x;
float y;
};
EventType type; EventType type;
EventVariant variant;
union { // Factory methods for creating specific events
uint64_t raw;
struct {
Mouse mouse;
} click;
struct {
bool active;
} focus;
struct {
bool active;
} hover;
struct {
bool enable;
} enable;
struct {
Mouse mouse;
DragPhase phase;
} drag;
};
static Event click_event(float x, float y) { static Event click_event(float x, float y) {
Event e = {}; Event e;
e.type = EventType::Click; e.type = EventType::Click;
e.click.mouse.x = x; e.variant = EventClick{ x, y };
e.click.mouse.y = y;
return e; return e;
} }
static Event focus_event(bool active) { static Event focus_event(bool active) {
Event e = {}; Event e;
e.type = EventType::Focus; e.type = EventType::Focus;
e.focus.active = active; e.variant = EventFocus{ active };
return e; return e;
} }
static Event hover_event(bool active) { static Event hover_event(bool active) {
Event e = {}; Event e;
e.type = EventType::Hover; e.type = EventType::Hover;
e.focus.active = active; e.variant = EventHover{ active };
return e; return e;
} }
static Event enable_event(bool enable) { static Event enable_event(bool enable) {
Event e = {}; Event e;
e.type = EventType::Enable; e.type = EventType::Enable;
e.enable.enable = enable; e.variant = EventEnable{ enable };
return e; return e;
} }
static Event drag_event(float x, float y, DragPhase phase) { static Event drag_event(float x, float y, DragPhase phase) {
Event e = {}; Event e;
e.type = EventType::Drag; e.type = EventType::Drag;
e.drag.mouse.x = x; e.variant = EventDrag{ x, y, phase };
e.drag.mouse.y = y; return e;
e.drag.phase = phase; }
static Event text_event(const std::string &text) {
Event e;
e.type = EventType::Text;
e.variant = EventText{ text };
return e; return e;
} }
}; };

View file

@ -10,7 +10,7 @@ namespace recompui {
void ConfigOptionElement::process_event(const Event &e) { void ConfigOptionElement::process_event(const Event &e) {
switch (e.type) { switch (e.type) {
case EventType::Hover: case EventType::Hover:
hover_callback(this, e.hover.active); hover_callback(this, std::get<EventHover>(e.variant).active);
break; break;
default: default:
assert(false && "Unknown event type."); assert(false && "Unknown event type.");
@ -73,6 +73,22 @@ void ConfigOptionSlider::set_max_value(double v) {
slider->set_max_value(v); slider->set_max_value(v);
} }
// ConfigOptionTextInput
void ConfigOptionTextInput::text_changed(const std::string &text) {
// TODO: Hook up to whatever API Recomp exposes to set the value of the persisent configuration in mods.
printf("%s changed to %s.\n", name.c_str(), text.c_str());
}
ConfigOptionTextInput::ConfigOptionTextInput(Element *parent) : ConfigOptionElement(parent) {
text_input = get_current_context().create_element<TextInput>(this);
text_input->add_text_changed_callback(std::bind(&ConfigOptionTextInput::text_changed, this, std::placeholders::_1));
}
ConfigOptionTextInput::~ConfigOptionTextInput() {
}
// ConfigSubMenu // ConfigSubMenu
void ConfigSubMenu::back_button_pressed() { void ConfigSubMenu::back_button_pressed() {
@ -159,6 +175,11 @@ void ConfigSubMenu::add_slider_option(std::string_view name, std::string_view de
add_option(option_slider, name, description); add_option(option_slider, name, description);
} }
void ConfigSubMenu::add_text_option(std::string_view name, std::string_view description) {
ConfigOptionTextInput *option_text_input = get_current_context().create_element<ConfigOptionTextInput>(config_scroll_container);
add_option(option_text_input, name, description);
}
void ConfigSubMenu::set_enter_sub_menu_callback(std::function<void()> callback) { void ConfigSubMenu::set_enter_sub_menu_callback(std::function<void()> callback) {
enter_sub_menu_callback = callback; enter_sub_menu_callback = callback;
} }

View file

@ -8,6 +8,7 @@
#include "elements/ui_label.h" #include "elements/ui_label.h"
#include "elements/ui_scroll_container.h" #include "elements/ui_scroll_container.h"
#include "elements/ui_slider.h" #include "elements/ui_slider.h"
#include "elements/ui_text_input.h"
namespace recompui { namespace recompui {
@ -41,6 +42,16 @@ public:
void set_max_value(double v); void set_max_value(double v);
}; };
class ConfigOptionTextInput : public ConfigOptionElement {
protected:
TextInput *text_input = nullptr;
void text_changed(const std::string &text);
public:
ConfigOptionTextInput(Element *parent);
virtual ~ConfigOptionTextInput();
};
class ConfigSubMenu : public Element { class ConfigSubMenu : public Element {
private: private:
Container *header_container = nullptr; Container *header_container = nullptr;
@ -65,6 +76,7 @@ public:
void enter(std::string_view title); void enter(std::string_view title);
void clear_options(); void clear_options();
void add_slider_option(std::string_view name, std::string_view description, double min, double max); void add_slider_option(std::string_view name, std::string_view description, double min, double max);
void add_text_option(std::string_view name, std::string_view description);
void set_enter_sub_menu_callback(std::function<void()> callback); void set_enter_sub_menu_callback(std::function<void()> callback);
void set_quit_sub_menu_callback(std::function<void()> callback); void set_quit_sub_menu_callback(std::function<void()> callback);
}; };

View file

@ -100,17 +100,8 @@ void ModMenu::mod_toggled(bool enabled) {
void ModMenu::mod_configure_requested() { void ModMenu::mod_configure_requested() {
if (active_mod_index >= 0) { if (active_mod_index >= 0) {
ext_config_sub_menu->clear_options(); ext_config_sub_menu->clear_options();
ext_config_sub_menu->add_slider_option("Simple Option", "Description for simple option.", 0.0, 100.0);
ext_config_sub_menu->add_slider_option("Slider Option", "Description for slider option.", 0.0, 100.0); ext_config_sub_menu->add_slider_option("Slider Option", "Description for slider option.", 0.0, 100.0);
ext_config_sub_menu->add_slider_option("Option B", "Description for option B.", 0.0, 100.0); ext_config_sub_menu->add_text_option("Text Option", "Description for simple option.");
ext_config_sub_menu->add_slider_option("Option C", "Description for option C.", 0.0, 100.0);
ext_config_sub_menu->add_slider_option("Option D", "Description for option D.", 0.0, 100.0);
ext_config_sub_menu->add_slider_option("Option E", "Description for option E.", 0.0, 100.0);
ext_config_sub_menu->add_slider_option("Option F", "Description for option F.", 0.0, 100.0);
ext_config_sub_menu->add_slider_option("Option G", "Description for option G.", 0.0, 100.0);
ext_config_sub_menu->add_slider_option("Option H", "Description for option H.", 0.0, 100.0);
ext_config_sub_menu->add_slider_option("Option J", "Description for option J.", 0.0, 100.0);
ext_config_sub_menu->add_slider_option("Option K", "Description for option K.", 0.0, 100.0);
ext_config_sub_menu->enter(mod_details[active_mod_index].mod_id); ext_config_sub_menu->enter(mod_details[active_mod_index].mod_id);
} }
} }