Zelda64Recomp/src/ui/elements/ElementConfigOption.cpp
2024-12-04 18:46:39 -05:00

156 lines
5.5 KiB
C++

#include "ElementConfigOption.h"
#include "../ui_elements.h"
#include <string>
using json = nlohmann::json;
using ConfigOptionType = recomp::config::ConfigOptionType;
namespace recompui {
static const std::string option_type_wrapper_id = "checkbox__input";
static const std::string config_option_base_class = "config-option";
static const std::string config_option_base_class_hz = config_option_base_class + "--hz";
static const std::string config_option_title_class = config_option_base_class + "__title";
static const std::string config_option_wrapper = config_option_base_class + "__list"; // TODO: move hz listing to radio tabs, make this container dumber
ElementConfigOption::ElementConfigOption(const Rml::String& tag) : Rml::Element(tag)
{
Rml::ElementDocument *doc = GetOwnerDocument();
SetAttribute("recomp-store-element", true);
SetClass(config_option_base_class, true);
{
Rml::Element *label_el = AppendChild(doc->CreateElement("label"));
label_el->SetClass(config_option_title_class, true);
{
Rml::Element *label_text_el = label_el->AppendChild(doc->CreateTextNode("Unknown"));
label_text_el->SetAttribute("id", "config-opt-label");
} // label_el
Rml::Element *option_type_wrapper = AppendChild(doc->CreateElement("div"));
option_type_wrapper->SetId(option_type_wrapper_id);
option_type_wrapper->SetClass(config_option_wrapper, true);
} // base element
AddEventListener(Rml::EventId::Mouseover, this, true);
}
ElementConfigOption::~ElementConfigOption()
{
RemoveEventListener(Rml::EventId::Mouseover, this, true);
}
Rml::Element *ElementConfigOption::GetLabel() {
Rml::ElementText *text_label = (Rml::ElementText *)GetElementById("config-opt-label");
return text_label->GetParentNode();
}
void ElementConfigOption::SetTextLabel(const std::string& s) {
Rml::ElementText *text_label = (Rml::ElementText *)GetElementById("config-opt-label");
text_label->SetText(s);
DirtyLayout();
}
Rml::Element *ElementConfigOption::GetOptionTypeWrapper() {
return GetElementById(option_type_wrapper_id);
}
template <typename T>
static void add_option_el(Rml::ElementDocument *doc, Rml::Element *wrapper, const std::string& tag, std::string& config_key) {
T *opt = (T *)wrapper->AppendChild(recompui::create_custom_element(doc, tag));
opt->init_option(config_key);
}
void ElementConfigOption::AddOptionTypeElement() {
ConfigOptionType el_option_type = ConfigOptionType::Label;
const json& option_json = recomp::config::get_json_from_key(config_key);
recomp::config::from_json(option_json["type"], el_option_type);
Rml::Element *wrapper = GetOptionTypeWrapper();
Rml::ElementDocument *doc = GetOwnerDocument();
switch (el_option_type) {
default:
printf("No option type element exists for type '%d'\n", el_option_type);
return;
case ConfigOptionType::Checkbox: {
add_option_el<ElementOptionTypeCheckbox>(doc, wrapper, "recomp-option-type-checkbox", config_key);
break;
}
case ConfigOptionType::Color: {
add_option_el<ElementOptionTypeColor>(doc, wrapper, "recomp-option-type-color", config_key);
break;
}
case ConfigOptionType::Dropdown: {
add_option_el<ElementOptionTypeDropdown>(doc, wrapper, "recomp-option-type-dropdown", config_key);
break;
}
case ConfigOptionType::RadioTabs: {
add_option_el<ElementOptionTypeRadioTabs>(doc, wrapper, "recomp-option-type-radio-tabs", config_key);
break;
}
case ConfigOptionType::Range: {
add_option_el<ElementOptionTypeRange>(doc, wrapper, "recomp-option-type-range", config_key);
break;
}
}
}
void ElementConfigOption::OnAttributeChange(const Rml::ElementAttributes& changed_attributes)
{
// Call through to the base element's OnAttributeChange().
Rml::Element::OnAttributeChange(changed_attributes);
bool dirty_layout = false;
auto config_store_key_attr = changed_attributes.find("recomp-data");
if (config_store_key_attr != changed_attributes.end() && config_store_key_attr->second.GetType() == Rml::Variant::STRING) {
config_key = config_store_key_attr->second.Get<Rml::String>();
if (in_checkbox_group) {
SetClass(config_option_base_class_hz, true);
}
Rml::Element *label = GetLabel();
label->SetAttribute("for", "input__" + config_key);
try {
auto value = recomp::config::get_config_store_value<std::string>("translations/" + config_key);
SetTextLabel(value);
printf("found type and translation\n");
AddOptionTypeElement();
} catch (const std::runtime_error& e) {
SetTextLabel(e.what());
}
dirty_layout = true;
}
if (dirty_layout) {
DirtyLayout();
}
}
void ElementConfigOption::ProcessEvent(Rml::Event& event)
{
// Set description key
if (event == Rml::EventId::Mouseover)
{
if (event.GetPhase() == Rml::EventPhase::Capture || event.GetPhase() == Rml::EventPhase::Target)
{
Rml::ElementList elements;
Rml::ElementDocument *doc = GetOwnerDocument();
GetElementsByTagName(elements, "input");
doc->GetElementsByTagName(elements, "recomp-description");
for (size_t i = 0; i < elements.size(); i++) {
Rml::Element *el = elements[i];
el->SetAttribute("recomp-data", config_key);
}
}
}
}
} // namespace Rml