mirror of
https://github.com/Zelda64Recomp/Zelda64Recomp.git
synced 2026-04-26 20:21:38 +00:00
Text input.
This commit is contained in:
parent
de88b5de46
commit
0a33cf03ef
12 changed files with 189 additions and 69 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.");
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
40
src/ui/elements/ui_text_input.cpp
Normal file
40
src/ui/elements/ui_text_input.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
20
src/ui/elements/ui_text_input.h
Normal file
20
src/ui/elements/ui_text_input.h
Normal 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
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue