mirror of
https://github.com/Zelda64Recomp/Zelda64Recomp
synced 2026-07-04 21:35:51 -04:00
WIP mod menu, fix some warnings
This commit is contained in:
@@ -123,7 +123,7 @@ void ElementConfigGroup::OnAttributeChange(const Rml::ElementAttributes& changed
|
||||
|
||||
const nlohmann::json& options = get_options(config_key);
|
||||
|
||||
for (int i = 0; i < options.size(); i++) {
|
||||
for (size_t i = 0; i < options.size(); i++) {
|
||||
const auto &el = options[i];
|
||||
AddConfigOptionElement(el);
|
||||
}
|
||||
|
||||
@@ -132,7 +132,6 @@ void ElementConfigOption::OnAttributeChange(const Rml::ElementAttributes& change
|
||||
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());
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "ElementModDetailsPanel.h"
|
||||
#include "presets.h"
|
||||
#include "librecomp/mods.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
#define MOD_DETAILS_BEM "mod-details"
|
||||
|
||||
namespace recompui {
|
||||
|
||||
static const std::string cls_base = BLOCK(MOD_DETAILS_BEM);
|
||||
static const std::string cls_header = EL(MOD_DETAILS_BEM, "header");
|
||||
static const std::string cls_thumbnail_container = EL(MOD_DETAILS_BEM, "thumbnail-container");
|
||||
static const std::string cls_thumbnail = EL(MOD_DETAILS_BEM, "thumbnail");
|
||||
static const std::string cls_header_details = EL(MOD_DETAILS_BEM, "header-details");
|
||||
static const std::string cls_title = EL(MOD_DETAILS_BEM, "title");
|
||||
static const std::string cls_version = EL(MOD_DETAILS_BEM, "version");
|
||||
static const std::string cls_body = EL(MOD_DETAILS_BEM, "body");
|
||||
static const std::string cls_authors = EL(MOD_DETAILS_BEM, "authors");
|
||||
static const std::string cls_description = EL(MOD_DETAILS_BEM, "description");
|
||||
|
||||
ElementModDetailsPanel::ElementModDetailsPanel(const Rml::String& tag) : Rml::Element(tag)
|
||||
{
|
||||
SetAttribute("recomp-store-element", true);
|
||||
Rml::ElementDocument *doc = GetOwnerDocument();
|
||||
SetClass(cls_base, true);
|
||||
|
||||
{
|
||||
Rml::Element *header_el = add_div_with_class(doc, this, cls_header);
|
||||
{
|
||||
Rml::Element *thumbnail_container_el = add_div_with_class(doc, header_el, cls_thumbnail_container);
|
||||
{
|
||||
Rml::Element *thumbnail_el = add_div_with_class(doc, thumbnail_container_el, cls_thumbnail);
|
||||
} // thumbnail_container_el
|
||||
|
||||
Rml::Element *header_details_el = add_div_with_class(doc, header_el, cls_header_details);
|
||||
{
|
||||
title_el = add_div_with_class(doc, header_details_el, cls_title);
|
||||
version_el = add_div_with_class(doc, header_details_el, cls_version);
|
||||
} // header_details_el
|
||||
}
|
||||
Rml::Element* body_el = add_div_with_class(doc, this, cls_body);
|
||||
{
|
||||
description_el = add_div_with_class(doc, body_el, cls_description);
|
||||
authors_el = add_div_with_class(doc, body_el, cls_authors);
|
||||
} // body_el
|
||||
}
|
||||
}
|
||||
|
||||
ElementModDetailsPanel::~ElementModDetailsPanel()
|
||||
{
|
||||
}
|
||||
|
||||
void ElementModDetailsPanel::SetModDetails(const recomp::mods::ModDetails& details) {
|
||||
cur_details = details;
|
||||
|
||||
title_el->SetInnerRML(cur_details.mod_id);
|
||||
version_el->SetInnerRML(cur_details.version.to_string());
|
||||
|
||||
std::string authors_str = "<i>Authors</i>:";
|
||||
bool first = true;
|
||||
for (const std::string& author : details.authors) {
|
||||
authors_str += (first ? " " : ", ") + author;
|
||||
first = false;
|
||||
}
|
||||
authors_el->SetInnerRML(authors_str);
|
||||
description_el->SetInnerRML("Placeholder description. Some long text to make sure that wrapping is working correctly. Yet more text and so on.");
|
||||
|
||||
DirtyLayout();
|
||||
}
|
||||
|
||||
} // namespace Rml
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef RECOMPUI_ELEMENT_MOD_DETAILS_PANEL_H
|
||||
#define RECOMPUI_ELEMENT_MOD_DETAILS_PANEL_H
|
||||
|
||||
#include "common.h"
|
||||
#include "librecomp/mods.hpp"
|
||||
|
||||
namespace recompui {
|
||||
|
||||
class ElementModDetailsPanel : public Rml::Element {
|
||||
public:
|
||||
ElementModDetailsPanel(const Rml::String& tag);
|
||||
virtual ~ElementModDetailsPanel();
|
||||
void SetModDetails(const recomp::mods::ModDetails& details);
|
||||
private:
|
||||
recomp::mods::ModDetails cur_details;
|
||||
Rml::Element* thumbnail_el;
|
||||
Rml::Element* title_el;
|
||||
Rml::Element* authors_el;
|
||||
Rml::Element* version_el;
|
||||
Rml::Element* description_el;
|
||||
};
|
||||
|
||||
} // namespace recompui
|
||||
#endif
|
||||
@@ -1,65 +1,160 @@
|
||||
#include "ElementModMenu.h"
|
||||
#include "ElementModDetailsPanel.h"
|
||||
#include "presets.h"
|
||||
#include "librecomp/mods.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
#define MOD_MENU_BEM "mod-menu"
|
||||
|
||||
namespace recompui {
|
||||
|
||||
static const BEM mod_menu_bem("mod-menu");
|
||||
static const std::string cls_base = BLOCK(MOD_MENU_BEM);
|
||||
static const std::string cls_modal_wrapper = EL(MOD_MENU_BEM, "modal-wrapper");
|
||||
static const std::string cls_modal_header = EL(MOD_MENU_BEM, "modal-header");
|
||||
static const std::string cls_modal_body = EL(MOD_MENU_BEM, "modal-body");
|
||||
static const std::string cls_list = EL(MOD_MENU_BEM, "list");
|
||||
static const std::string cls_list_scroll = EL(MOD_MENU_BEM, "list-scroll");
|
||||
static const std::string cls_list_entry = EL(MOD_MENU_BEM, "list-entry");
|
||||
static const std::string cls_list_entry_thumbnail = EL(MOD_MENU_BEM, "list-entry-thumbnail");
|
||||
static const std::string cls_list_entry_body = EL(MOD_MENU_BEM, "list-entry-body");
|
||||
static const std::string cls_list_entry_name = EL(MOD_MENU_BEM, "list-entry-name");
|
||||
static const std::string cls_list_entry_description = EL(MOD_MENU_BEM, "list-entry-description");
|
||||
|
||||
static const std::string cls_base = mod_menu_bem.get_block();
|
||||
static const std::string cls_modal_wrapper = mod_menu_bem.el("modal-wrapper");
|
||||
static const std::string cls_modal_header = mod_menu_bem.el("modal-header");
|
||||
static const std::string cls_modal_body = mod_menu_bem.el("modal-body");
|
||||
static const std::string cls_list = mod_menu_bem.el("list");
|
||||
static const std::string cls_list_scroll = mod_menu_bem.el("list-scroll");
|
||||
static const std::string cls_details = mod_menu_bem.el("details");
|
||||
void ElementModMenu::ProcessEvent(Rml::Event& event) {
|
||||
Rml::Element* event_element = event.GetCurrentElement();
|
||||
Rml::EventId event_id = event.GetId();
|
||||
switch (event_id) {
|
||||
// Click event handlers.
|
||||
case Rml::EventId::Click:
|
||||
// Refresh
|
||||
if (event_element == refresh_button) {
|
||||
RefreshMods();
|
||||
}
|
||||
// Close
|
||||
else if (event_element == close_button) {
|
||||
|
||||
static Rml::Element *add_div_with_class(Rml::ElementDocument *doc, Rml::Element *parent_el, const std::string& cls) {
|
||||
Rml::Element *el = parent_el->AppendChild(doc->CreateElement("div"));
|
||||
el->SetClass(cls.c_str(), true);
|
||||
return el;
|
||||
}
|
||||
break;
|
||||
case Rml::EventId::Focus:
|
||||
{
|
||||
size_t mod_index;
|
||||
Rml::Variant *val = event_element->GetAttribute("mod_index");
|
||||
if (val->GetInto(mod_index) && mod_index < mod_details.size()) {
|
||||
details_el->SetModDetails(mod_details[mod_index]);
|
||||
}
|
||||
if (active_list_entry_el != nullptr) {
|
||||
active_list_entry_el->RemoveAttribute("is_selected");
|
||||
}
|
||||
event_element->SetAttribute("is_selected", true);
|
||||
active_list_entry_el = event_element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ElementModMenu::ElementModMenu(const Rml::String& tag) : Rml::Element(tag)
|
||||
{
|
||||
Rml::ElementPtr ElementModMenu::CreateModListEntry(const recomp::mods::ModDetails& details, size_t index) {
|
||||
Rml::ElementDocument *doc = GetOwnerDocument();
|
||||
|
||||
Rml::ElementPtr mod_el = doc->CreateElement("div");
|
||||
mod_el->SetClass(cls_list_entry, true);
|
||||
mod_el->SetAttribute("mod_index", index);
|
||||
{
|
||||
Rml::Element* thumbnail_el = add_div_with_class(doc, mod_el.get(), cls_list_entry_thumbnail);
|
||||
Rml::Element *body_el = add_div_with_class(doc, mod_el.get(), cls_list_entry_body);
|
||||
{
|
||||
Rml::Element *name_el = add_div_with_class(doc, body_el, cls_list_entry_name);
|
||||
name_el->SetInnerRML(details.mod_id);
|
||||
|
||||
Rml::Element *description_el = add_div_with_class(doc, body_el, cls_list_entry_description);
|
||||
description_el->SetInnerRML("Short description of mod here.");
|
||||
} // body_el
|
||||
} // mod_el
|
||||
|
||||
return mod_el;
|
||||
}
|
||||
|
||||
void ElementModMenu::CreateModList() {
|
||||
Rml::ElementDocument *doc = GetOwnerDocument();
|
||||
|
||||
// Clear the contents of the list scroll.
|
||||
list_el_scroll->SetInnerRML("");
|
||||
Rml::Element* prev_el = refresh_button;
|
||||
active_list_entry_el = nullptr;
|
||||
|
||||
bool first = true;
|
||||
|
||||
// Create the child elements for the list scroll.
|
||||
for (size_t mod_index = 0; mod_index < mod_details.size(); mod_index++) {
|
||||
const recomp::mods::ModDetails& details = mod_details[mod_index];
|
||||
Rml::Element *mod_el = list_el_scroll->AppendChild(CreateModListEntry(details, mod_index));
|
||||
mod_el->SetAttribute("mod_index", mod_index);
|
||||
mod_el->AddEventListener(Rml::EventId::Focus, this, false);
|
||||
mod_el->SetId("mod-list-entry-" + std::to_string(mod_index));
|
||||
|
||||
mod_el->SetProperty("nav-up", "#" + prev_el->GetId());
|
||||
prev_el->SetProperty("nav-down", "#" + mod_el->GetId());
|
||||
|
||||
if (first) {
|
||||
active_list_entry_el = mod_el;
|
||||
}
|
||||
first = false;
|
||||
|
||||
prev_el = mod_el;
|
||||
}
|
||||
|
||||
active_list_entry_el->SetAttribute("is_selected", true);
|
||||
|
||||
DirtyLayout();
|
||||
}
|
||||
|
||||
void ElementModMenu::RefreshMods() {
|
||||
recomp::mods::scan_mods();
|
||||
mod_details = recomp::mods::get_mod_details(game_mod_id);
|
||||
|
||||
details_el->SetModDetails(mod_details[0]);
|
||||
|
||||
CreateModList();
|
||||
}
|
||||
|
||||
ElementModMenu::ElementModMenu(const Rml::String& tag) : Rml::Element(tag) {
|
||||
game_mod_id = "mm";
|
||||
SetAttribute("recomp-store-element", true);
|
||||
Rml::ElementDocument *doc = GetOwnerDocument();
|
||||
SetClass(mod_menu_bem.block, true);
|
||||
SetClass(cls_base, true);
|
||||
|
||||
{
|
||||
Rml::Element *modal_wrapper_el = add_div_with_class(doc, this, cls_modal_wrapper);
|
||||
{
|
||||
Rml::Element *header_el = add_div_with_class(doc, modal_wrapper_el, cls_modal_header);
|
||||
{
|
||||
add_button(doc, header_el, "Refresh", ButtonVariant::Primary);
|
||||
add_icon_button(doc, header_el, "icons/X.svg", ButtonVariant::Tertiary);
|
||||
}
|
||||
refresh_button = add_button(doc, header_el, "Refresh", ButtonVariant::Primary);
|
||||
refresh_button->AddEventListener(Rml::EventId::Click, this, false);
|
||||
refresh_button->SetId("refresh-button");
|
||||
close_button = add_icon_button(doc, header_el, "icons/X.svg", ButtonVariant::Tertiary);
|
||||
close_button->AddEventListener(Rml::EventId::Click, this, false);
|
||||
close_button->SetId("close-button");
|
||||
|
||||
refresh_button->SetProperty("nav-right", "#" + close_button->GetId());
|
||||
close_button->SetProperty("nav-left", "#" + refresh_button->GetId());
|
||||
} // header_el
|
||||
|
||||
Rml::Element *body_el = add_div_with_class(doc, modal_wrapper_el, cls_modal_body);
|
||||
{
|
||||
Rml::Element *list_el = add_div_with_class(doc, body_el, cls_list);
|
||||
list_el = add_div_with_class(doc, body_el, cls_list);
|
||||
{
|
||||
Rml::Element *list_el_scroll = add_div_with_class(doc, list_el, cls_list_scroll);
|
||||
{
|
||||
std::vector<recomp::mods::ModDetails> mods = recomp::mods::get_mod_details("mm");
|
||||
for (auto& mod : mods) {
|
||||
Rml::Element *mod_el = list_el_scroll->AppendChild(doc->CreateElement("div"));
|
||||
mod_el->SetInnerRML(mod.mod_id);
|
||||
}
|
||||
} // list_el_scroll
|
||||
list_el_scroll = add_div_with_class(doc, list_el, cls_list_scroll);
|
||||
} // list_el
|
||||
|
||||
Rml::Element *details_el = add_div_with_class(doc, body_el, cls_details);
|
||||
details_el->SetInnerRML("two");
|
||||
}
|
||||
}
|
||||
details_el =
|
||||
static_cast<ElementModDetailsPanel*>(body_el->AppendChild(doc->CreateElement("recomp-mod-details-panel")));
|
||||
} // body_el
|
||||
} // modal_wrapper_el
|
||||
}
|
||||
|
||||
RefreshMods();
|
||||
}
|
||||
|
||||
ElementModMenu::~ElementModMenu()
|
||||
{
|
||||
ElementModMenu::~ElementModMenu() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,13 +2,28 @@
|
||||
#define RECOMPUI_ELEMENT_MOD_MENU_H
|
||||
|
||||
#include "common.h"
|
||||
#include "librecomp/mods.hpp"
|
||||
#include "ElementModDetailsPanel.h"
|
||||
|
||||
namespace recompui {
|
||||
|
||||
class ElementModMenu : public Rml::Element {
|
||||
class ElementModMenu : public Rml::Element, public Rml::EventListener {
|
||||
public:
|
||||
ElementModMenu(const Rml::String& tag);
|
||||
virtual ~ElementModMenu();
|
||||
void ProcessEvent(Rml::Event& event) final;
|
||||
private:
|
||||
void RefreshMods();
|
||||
void CreateModList();
|
||||
Rml::ElementPtr CreateModListEntry(const recomp::mods::ModDetails& details, size_t index);
|
||||
Rml::Element *refresh_button;
|
||||
Rml::Element *close_button;
|
||||
Rml::Element *list_el; // The root mod list element.
|
||||
Rml::Element *list_el_scroll; // The scroll within the root mod list element.
|
||||
ElementModDetailsPanel *details_el; // The details panel.
|
||||
Rml::Element *active_list_entry_el = nullptr;
|
||||
std::vector<recomp::mods::ModDetails> mod_details{};
|
||||
std::string game_mod_id;
|
||||
};
|
||||
|
||||
} // namespace recompui
|
||||
|
||||
@@ -46,7 +46,7 @@ ElementOptionTypeColor::ElementOptionTypeColor(const Rml::String& tag) : Rml::El
|
||||
|
||||
Rml::Element *hsv_wrapper = preview_wrapper->AppendChild(doc->CreateElement("div"));
|
||||
hsv_wrapper->SetClass(cls_color_hsv_wrapper, true);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
const auto &label = hsv_label[i];
|
||||
|
||||
Rml::Element *range_wrapper = hsv_wrapper->AppendChild(doc->CreateElement("div"));
|
||||
@@ -88,7 +88,7 @@ ElementOptionTypeColor::~ElementOptionTypeColor()
|
||||
{
|
||||
Rml::ElementList elements;
|
||||
GetElementsByTagName(elements, "input");
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
for (size_t i = 0; i < elements.size(); i++) {
|
||||
Rml::Element *el = elements[i];
|
||||
el->RemoveEventListener(Rml::EventId::Click, this, false);
|
||||
}
|
||||
@@ -144,7 +144,7 @@ void ElementOptionTypeColor::init_option(std::string& _config_key) {
|
||||
|
||||
set_preview_block_rgb(col);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
const auto &label = hsv_label[i];
|
||||
|
||||
Rml::ElementFormControlInput *range = (Rml::ElementFormControlInput *)GetElementById(range_input_id + label);
|
||||
|
||||
@@ -48,7 +48,7 @@ void ElementOptionTypeDropdown::init_option(std::string& _config_key) {
|
||||
|
||||
auto select_el = get_select();
|
||||
|
||||
for (int i = 0; i < opt_array.size(); i++) {
|
||||
for (size_t i = 0; i < opt_array.size(); i++) {
|
||||
const auto &j_opt = opt_array[i];
|
||||
const std::string opt_val = j_opt.get<std::string>();
|
||||
const std::string opt_id = select_option_id + config_key + "--" + opt_val;
|
||||
|
||||
@@ -19,7 +19,7 @@ ElementOptionTypeRadioTabs::~ElementOptionTypeRadioTabs()
|
||||
{
|
||||
Rml::ElementList elements;
|
||||
GetElementsByTagName(elements, "input");
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
for (size_t i = 0; i < elements.size(); i++) {
|
||||
Rml::Element *el = elements[i];
|
||||
el->RemoveEventListener(Rml::EventId::Click, this, false);
|
||||
}
|
||||
@@ -28,9 +28,9 @@ ElementOptionTypeRadioTabs::~ElementOptionTypeRadioTabs()
|
||||
void ElementOptionTypeRadioTabs::set_cur_option(int opt) {
|
||||
Rml::ElementList elements;
|
||||
GetElementsByTagName(elements, "input");
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
for (size_t i = 0; i < elements.size(); i++) {
|
||||
Rml::Element *el = elements[i];
|
||||
if (i == opt) {
|
||||
if (static_cast<int>(i) == opt) {
|
||||
SetAttribute("checked", true);
|
||||
el->SetAttribute("checked", true);
|
||||
} else {
|
||||
@@ -48,7 +48,7 @@ void ElementOptionTypeRadioTabs::init_option(std::string& _config_key) {
|
||||
int opt = recomp::config::get_config_store_value<int>(config_key);
|
||||
const json& opt_array = option_json["values"];
|
||||
|
||||
for (int i = 0; i < opt_array.size(); i++) {
|
||||
for (size_t i = 0; i < opt_array.size(); i++) {
|
||||
const auto &j_opt = opt_array[i];
|
||||
const std::string opt_val = j_opt.get<std::string>();
|
||||
const std::string opt_id = radio_input_id + config_key + "--" + opt_val;
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
#include "presets.h"
|
||||
|
||||
#define BUTTON_BEM "button"
|
||||
#define ICON_BUTTON_BEM "icon-button"
|
||||
|
||||
namespace recompui {
|
||||
|
||||
static const BEM button_bem("button");
|
||||
Rml::Element *add_button(Rml::ElementDocument *doc, Rml::Element *parent_el, const Rml::String contents, ButtonVariant variant, bool isLarge) {
|
||||
Rml::Element *button = parent_el->AppendChild(doc->CreateElement("button"));
|
||||
|
||||
button->SetClass(button_bem.get_block(), true);
|
||||
button->SetClass(BLOCK(BUTTON_BEM), true);
|
||||
|
||||
button->SetClass(button_bem.mod(button_variants.at(variant)), true);
|
||||
button->SetClass(MOD_DYN(BUTTON_BEM, button_variants.at(variant)), true);
|
||||
if (isLarge) {
|
||||
button->SetClass(button_bem.mod("large"), true);
|
||||
button->SetClass(MOD(BUTTON_BEM, "large"), true);
|
||||
}
|
||||
|
||||
if (contents != "") {
|
||||
@@ -20,16 +22,15 @@ Rml::Element *add_button(Rml::ElementDocument *doc, Rml::Element *parent_el, con
|
||||
return button;
|
||||
}
|
||||
|
||||
static const BEM icon_button_bem("icon-button");
|
||||
Rml::Element *add_icon_button(Rml::ElementDocument *doc, Rml::Element *parent_el, const std::string &svg_src, ButtonVariant variant) {
|
||||
Rml::Element *button = parent_el->AppendChild(doc->CreateElement("button"));
|
||||
|
||||
button->SetClass(icon_button_bem.get_block(), true);
|
||||
button->SetClass(icon_button_bem.mod(button_variants.at(variant)), true);
|
||||
button->SetClass(BLOCK(ICON_BUTTON_BEM), true);
|
||||
button->SetClass(MOD_DYN(ICON_BUTTON_BEM, button_variants.at(variant)), true);
|
||||
|
||||
{
|
||||
Rml::Element *icon = button->AppendChild(doc->CreateElement("svg"));
|
||||
icon->SetClass(icon_button_bem.el("icon"), true);
|
||||
icon->SetClass(EL(ICON_BUTTON_BEM, "icon"), true);
|
||||
icon->SetAttribute("src", svg_src);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,12 @@
|
||||
namespace recompui {
|
||||
Rml::Element *add_button(Rml::ElementDocument *doc, Rml::Element *parent_el, const Rml::String contents = "", ButtonVariant variant = ButtonVariant::Primary, bool isLarge = false);
|
||||
Rml::Element *add_icon_button(Rml::ElementDocument *doc, Rml::Element *parent_el, const std::string &svg_src, ButtonVariant variant = ButtonVariant::Tertiary);
|
||||
|
||||
inline Rml::Element *add_div_with_class(Rml::ElementDocument *doc, Rml::Element *parent_el, const std::string& cls) {
|
||||
Rml::Element *el = parent_el->AppendChild(doc->CreateElement("div"));
|
||||
el->SetClass(cls, true);
|
||||
return el;
|
||||
}
|
||||
} // namespace recompui
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user