mirror of
https://github.com/Zelda64Recomp/Zelda64Recomp.git
synced 2025-10-30 08:03:03 +00:00
Split config sub menu into separate context and fix configure button, prevent infinite loop when looking for autofocus element
This commit is contained in:
parent
590273c070
commit
0a596746a7
17 changed files with 197 additions and 57 deletions
|
|
@ -96,7 +96,6 @@
|
||||||
<svg src="icons/X.svg" />
|
<svg src="icons/X.svg" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<recomp-config-sub-menu id="config_sub_menu" />
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="centered-page__controls"
|
class="centered-page__controls"
|
||||||
|
|
|
||||||
70
assets/config_sub_menu.rml
Normal file
70
assets/config_sub_menu.rml
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
<rml>
|
||||||
|
<head>
|
||||||
|
<link type="text/rcss" href="rml.rcss"/>
|
||||||
|
<link type="text/rcss" href="recomp.rcss"/>
|
||||||
|
<title>Inventory</title>
|
||||||
|
<style>
|
||||||
|
body
|
||||||
|
{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide the window icon. */
|
||||||
|
div#title_bar div#icon
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.flex-grid {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.col {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="window">
|
||||||
|
<!-- <handle move_target="#document"> -->
|
||||||
|
<div id="window" class="rmlui-window" style="display:flex; flex-flow: column; background-color:rgba(0,0,0,0)" onkeydown="config_keydown">
|
||||||
|
<div class="centered-page" onclick="close_config_menu_backdrop">
|
||||||
|
<div class="centered-page__modal">
|
||||||
|
<div class="config__icon-buttons">
|
||||||
|
<button
|
||||||
|
class="icon-button"
|
||||||
|
onclick="open_quit_game_prompt"
|
||||||
|
id="config__quit-game-button"
|
||||||
|
>
|
||||||
|
<svg src="icons/Quit.svg" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="icon-button"
|
||||||
|
onclick="close_config_menu"
|
||||||
|
id="config__close-menu-button"
|
||||||
|
>
|
||||||
|
<svg src="icons/X.svg" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<recomp-config-sub-menu id="config_sub_menu" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="centered-page__controls"
|
||||||
|
data-model="nav_help_model"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<span>Navigate</span>
|
||||||
|
<span class="prompt-font-sm">{{nav_help__navigate}}</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span>Accept</span>
|
||||||
|
<span class="prompt-font-sm">{{nav_help__accept}}</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span>Exit</span>
|
||||||
|
<span class="prompt-font-sm">{{nav_help__exit}}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</rml>
|
||||||
|
|
@ -54,6 +54,7 @@ namespace recompui {
|
||||||
|
|
||||||
ContextId get_launcher_context_id();
|
ContextId get_launcher_context_id();
|
||||||
ContextId get_config_context_id();
|
ContextId get_config_context_id();
|
||||||
|
ContextId get_config_sub_menu_context_id();
|
||||||
ContextId get_close_prompt_context_id();
|
ContextId get_close_prompt_context_id();
|
||||||
|
|
||||||
enum class ButtonVariant {
|
enum class ButtonVariant {
|
||||||
|
|
@ -95,6 +96,7 @@ namespace recompui {
|
||||||
void set_render_hooks();
|
void set_render_hooks();
|
||||||
|
|
||||||
Rml::ElementPtr create_custom_element(Rml::Element* parent, std::string tag);
|
Rml::ElementPtr create_custom_element(Rml::Element* parent, std::string tag);
|
||||||
|
Rml::ElementDocument* load_document(const std::filesystem::path& path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -153,13 +153,13 @@ recompui::ContextId create_context_impl(Rml::ElementDocument* document) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
recompui::ContextId recompui::create_context(Rml::Context* rml_context, const std::filesystem::path& path) {
|
recompui::ContextId recompui::create_context(const std::filesystem::path& path) {
|
||||||
ContextId new_context = create_context_impl(nullptr);
|
ContextId new_context = create_context_impl(nullptr);
|
||||||
|
|
||||||
auto workingdir = std::filesystem::current_path();
|
auto workingdir = std::filesystem::current_path();
|
||||||
|
|
||||||
new_context.open();
|
new_context.open();
|
||||||
Rml::ElementDocument* doc = rml_context->LoadDocument(path.string());
|
Rml::ElementDocument* doc = recompui::load_document(path.string());
|
||||||
opened_context->document = doc;
|
opened_context->document = doc;
|
||||||
opened_context->root_element.base = doc;
|
opened_context->root_element.base = doc;
|
||||||
new_context.close();
|
new_context.close();
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "RmlUi/Core.h"
|
#include "RmlUi/Core.h"
|
||||||
|
|
||||||
|
|
@ -48,7 +49,7 @@ namespace recompui {
|
||||||
bool takes_input() { return true; }
|
bool takes_input() { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
ContextId create_context(Rml::Context*, const std::filesystem::path& path);
|
ContextId create_context(const std::filesystem::path& path);
|
||||||
ContextId create_context(Rml::ElementDocument* document);
|
ContextId create_context(Rml::ElementDocument* document);
|
||||||
void destroy_context(ContextId id);
|
void destroy_context(ContextId id);
|
||||||
ContextId get_current_context();
|
ContextId get_current_context();
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ namespace recompui {
|
||||||
set_font_weight(700);
|
set_font_weight(700);
|
||||||
set_cursor(Cursor::Pointer);
|
set_cursor(Cursor::Pointer);
|
||||||
set_color(Color{ 204, 204, 204, 255 });
|
set_color(Color{ 204, 204, 204, 255 });
|
||||||
|
set_tab_index(TabIndex::Auto);
|
||||||
hover_style.set_color(Color{ 242, 242, 242, 255 });
|
hover_style.set_color(Color{ 242, 242, 242, 255 });
|
||||||
|
|
||||||
const uint8_t border_opacity = 204;
|
const uint8_t border_opacity = 204;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
namespace recompui {
|
namespace recompui {
|
||||||
class Element : public Style, public Rml::EventListener {
|
class Element : public Style, public Rml::EventListener {
|
||||||
friend ContextId create_context(Rml::Context* rml_context, const std::filesystem::path& path);
|
friend ContextId create_context(const std::filesystem::path& path);
|
||||||
private:
|
private:
|
||||||
Rml::Element *base = nullptr;
|
Rml::Element *base = nullptr;
|
||||||
Rml::ElementPtr base_owning = {};
|
Rml::ElementPtr base_owning = {};
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,18 @@ namespace recompui {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Rml::Style::TabIndex to_rml(TabIndex tab_index) {
|
||||||
|
switch (tab_index) {
|
||||||
|
case TabIndex::None:
|
||||||
|
return Rml::Style::TabIndex::None;
|
||||||
|
case TabIndex::Auto:
|
||||||
|
return Rml::Style::TabIndex::Auto;
|
||||||
|
default:
|
||||||
|
assert(false && "Unknown tab index.");
|
||||||
|
return Rml::Style::TabIndex::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Style::set_property(Rml::PropertyId property_id, const Rml::Property &property, Animation) {
|
void Style::set_property(Rml::PropertyId property_id, const Rml::Property &property, Animation) {
|
||||||
property_map[property_id] = property;
|
property_map[property_id] = property;
|
||||||
}
|
}
|
||||||
|
|
@ -459,4 +471,8 @@ namespace recompui {
|
||||||
set_property(Rml::PropertyId::Drag, to_rml(drag), Animation());
|
set_property(Rml::PropertyId::Drag, to_rml(drag), Animation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Style::set_tab_index(TabIndex tab_index) {
|
||||||
|
set_property(Rml::PropertyId::TabIndex, to_rml(tab_index), Animation());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace recompui
|
} // namespace recompui
|
||||||
|
|
@ -83,6 +83,7 @@ namespace recompui {
|
||||||
void set_row_gap(float size, Unit unit = Unit::Dp, Animation animation = Animation());
|
void set_row_gap(float size, Unit unit = Unit::Dp, Animation animation = Animation());
|
||||||
void set_column_gap(float size, Unit unit = Unit::Dp, Animation animation = Animation());
|
void set_column_gap(float size, Unit unit = Unit::Dp, Animation animation = Animation());
|
||||||
void set_drag(Drag drag);
|
void set_drag(Drag drag);
|
||||||
|
void set_tab_index(TabIndex focus);
|
||||||
virtual bool is_element() { return false; }
|
virtual bool is_element() { return false; }
|
||||||
ResourceId get_resource_id() { return resource_id; }
|
ResourceId get_resource_id() { return resource_id; }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -197,6 +197,11 @@ namespace recompui {
|
||||||
Clone
|
Clone
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class TabIndex {
|
||||||
|
None,
|
||||||
|
Auto
|
||||||
|
};
|
||||||
|
|
||||||
struct Animation {
|
struct Animation {
|
||||||
AnimationType type = AnimationType::None;
|
AnimationType type = AnimationType::None;
|
||||||
float duration = 0.0f;
|
float duration = 0.0f;
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,15 @@ void recomp::config_menu_set_cont_or_kb(bool cont_interacted) {
|
||||||
void close_config_menu_impl() {
|
void close_config_menu_impl() {
|
||||||
zelda64::save_config();
|
zelda64::save_config();
|
||||||
|
|
||||||
recompui::hide_context(recompui::get_config_context_id());
|
recompui::ContextId config_context = recompui::get_config_context_id();
|
||||||
|
recompui::ContextId sub_menu_context = recompui::get_config_sub_menu_context_id();
|
||||||
|
|
||||||
|
if (recompui::is_context_open(sub_menu_context)) {
|
||||||
|
recompui::hide_context(sub_menu_context);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
recompui::hide_context(config_context);
|
||||||
|
}
|
||||||
|
|
||||||
if (!ultramodern::is_game_started()) {
|
if (!ultramodern::is_game_started()) {
|
||||||
recompui::show_context(recompui::get_launcher_context_id(), "");
|
recompui::show_context(recompui::get_launcher_context_id(), "");
|
||||||
|
|
@ -435,7 +443,8 @@ public:
|
||||||
|
|
||||||
}
|
}
|
||||||
Rml::ElementDocument* load_document(Rml::Context* context) override {
|
Rml::ElementDocument* load_document(Rml::Context* context) override {
|
||||||
config_context = recompui::create_context(context, zelda64::get_asset_path("config_menu.rml"));
|
(void)context;
|
||||||
|
config_context = recompui::create_context(zelda64::get_asset_path("config_menu.rml"));
|
||||||
Rml::ElementDocument* ret = config_context.get_document();
|
Rml::ElementDocument* ret = config_context.get_document();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
#include "ui_config_sub_menu.h"
|
#include "ui_config_sub_menu.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include "recomp_ui.h"
|
||||||
|
|
||||||
namespace recompui {
|
namespace recompui {
|
||||||
|
|
||||||
|
|
@ -91,9 +94,12 @@ ConfigOptionRadio::ConfigOptionRadio(const std::vector<std::string> &options, El
|
||||||
// ConfigSubMenu
|
// ConfigSubMenu
|
||||||
|
|
||||||
void ConfigSubMenu::back_button_pressed() {
|
void ConfigSubMenu::back_button_pressed() {
|
||||||
if (quit_sub_menu_callback != nullptr) {
|
// Hide the config sub menu and show the config menu.
|
||||||
quit_sub_menu_callback();
|
ContextId config_context = recompui::get_config_context_id();
|
||||||
}
|
ContextId sub_menu_context = recompui::get_config_sub_menu_context_id();
|
||||||
|
|
||||||
|
recompui::hide_context(sub_menu_context);
|
||||||
|
recompui::show_context(config_context, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigSubMenu::option_hovered(ConfigOptionElement *option, bool active) {
|
void ConfigSubMenu::option_hovered(ConfigOptionElement *option, bool active) {
|
||||||
|
|
@ -113,6 +119,8 @@ void ConfigSubMenu::option_hovered(ConfigOptionElement *option, bool active) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigSubMenu::ConfigSubMenu(Element *parent) : Element(parent) {
|
ConfigSubMenu::ConfigSubMenu(Element *parent) : Element(parent) {
|
||||||
|
using namespace std::string_view_literals;
|
||||||
|
|
||||||
set_display(Display::Flex);
|
set_display(Display::Flex);
|
||||||
set_flex(1, 1, 100.0f, Unit::Percent);
|
set_flex(1, 1, 100.0f, Unit::Percent);
|
||||||
set_flex_direction(FlexDirection::Column);
|
set_flex_direction(FlexDirection::Column);
|
||||||
|
|
@ -148,10 +156,6 @@ ConfigSubMenu::~ConfigSubMenu() {
|
||||||
|
|
||||||
void ConfigSubMenu::enter(std::string_view title) {
|
void ConfigSubMenu::enter(std::string_view title) {
|
||||||
title_label->set_text(title);
|
title_label->set_text(title);
|
||||||
|
|
||||||
if (enter_sub_menu_callback != nullptr) {
|
|
||||||
enter_sub_menu_callback();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigSubMenu::clear_options() {
|
void ConfigSubMenu::clear_options() {
|
||||||
|
|
@ -182,18 +186,10 @@ void ConfigSubMenu::add_radio_option(std::string_view name, std::string_view des
|
||||||
add_option(option_radio, name, description);
|
add_option(option_radio, name, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigSubMenu::set_enter_sub_menu_callback(std::function<void()> callback) {
|
|
||||||
enter_sub_menu_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigSubMenu::set_quit_sub_menu_callback(std::function<void()> callback) {
|
|
||||||
quit_sub_menu_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ElementConfigSubMenu
|
// ElementConfigSubMenu
|
||||||
|
|
||||||
ElementConfigSubMenu::ElementConfigSubMenu(const Rml::String &tag) : Rml::Element(tag) {
|
ElementConfigSubMenu::ElementConfigSubMenu(const Rml::String &tag) : Rml::Element(tag) {
|
||||||
SetProperty(Rml::PropertyId::Display, Rml::Style::Display::None);
|
SetProperty(Rml::PropertyId::Display, Rml::Style::Display::Flex);
|
||||||
SetProperty("width", "100%");
|
SetProperty("width", "100%");
|
||||||
SetProperty("height", "100%");
|
SetProperty("height", "100%");
|
||||||
|
|
||||||
|
|
@ -210,14 +206,6 @@ void ElementConfigSubMenu::set_display(bool display) {
|
||||||
SetProperty(Rml::PropertyId::Display, display ? Rml::Style::Display::Block : Rml::Style::Display::None);
|
SetProperty(Rml::PropertyId::Display, display ? Rml::Style::Display::Block : Rml::Style::Display::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ElementConfigSubMenu::set_enter_sub_menu_callback(std::function<void()> callback) {
|
|
||||||
config_sub_menu->set_enter_sub_menu_callback(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ElementConfigSubMenu::set_quit_sub_menu_callback(std::function<void()> callback) {
|
|
||||||
config_sub_menu->set_quit_sub_menu_callback(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
ConfigSubMenu *ElementConfigSubMenu::get_config_sub_menu_element() const {
|
ConfigSubMenu *ElementConfigSubMenu::get_config_sub_menu_element() const {
|
||||||
return config_sub_menu;
|
return config_sub_menu;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,6 @@ private:
|
||||||
Label *description_label = nullptr;
|
Label *description_label = nullptr;
|
||||||
Container *config_container = nullptr;
|
Container *config_container = nullptr;
|
||||||
ScrollContainer *config_scroll_container = nullptr;
|
ScrollContainer *config_scroll_container = nullptr;
|
||||||
std::function<void()> enter_sub_menu_callback = nullptr;
|
|
||||||
std::function<void()> quit_sub_menu_callback = nullptr;
|
|
||||||
std::vector<ConfigOptionElement *> config_option_elements;
|
std::vector<ConfigOptionElement *> config_option_elements;
|
||||||
std::unordered_set<ConfigOptionElement *> hover_option_elements;
|
std::unordered_set<ConfigOptionElement *> hover_option_elements;
|
||||||
|
|
||||||
|
|
@ -83,8 +81,6 @@ public:
|
||||||
void add_slider_option(std::string_view name, std::string_view description, double min, double max, double step, bool percent);
|
void add_slider_option(std::string_view name, std::string_view description, double min, double max, double step, bool percent);
|
||||||
void add_text_option(std::string_view name, std::string_view description);
|
void add_text_option(std::string_view name, std::string_view description);
|
||||||
void add_radio_option(std::string_view name, std::string_view description, const std::vector<std::string> &options);
|
void add_radio_option(std::string_view name, std::string_view description, const std::vector<std::string> &options);
|
||||||
void set_enter_sub_menu_callback(std::function<void()> callback);
|
|
||||||
void set_quit_sub_menu_callback(std::function<void()> callback);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ElementConfigSubMenu : public Rml::Element {
|
class ElementConfigSubMenu : public Rml::Element {
|
||||||
|
|
@ -92,8 +88,6 @@ public:
|
||||||
ElementConfigSubMenu(const Rml::String &tag);
|
ElementConfigSubMenu(const Rml::String &tag);
|
||||||
virtual ~ElementConfigSubMenu();
|
virtual ~ElementConfigSubMenu();
|
||||||
void set_display(bool display);
|
void set_display(bool display);
|
||||||
void set_enter_sub_menu_callback(std::function<void()> callback);
|
|
||||||
void set_quit_sub_menu_callback(std::function<void()> callback);
|
|
||||||
ConfigSubMenu *get_config_sub_menu_element() const;
|
ConfigSubMenu *get_config_sub_menu_element() const;
|
||||||
private:
|
private:
|
||||||
ConfigSubMenu *config_sub_menu;
|
ConfigSubMenu *config_sub_menu;
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,8 @@ public:
|
||||||
|
|
||||||
}
|
}
|
||||||
Rml::ElementDocument* load_document(Rml::Context* context) override {
|
Rml::ElementDocument* load_document(Rml::Context* context) override {
|
||||||
launcher_context = recompui::create_context(context, zelda64::get_asset_path("launcher.rml"));
|
(void)context;
|
||||||
|
launcher_context = recompui::create_context(zelda64::get_asset_path("launcher.rml"));
|
||||||
Rml::ElementDocument* ret = launcher_context.get_document();
|
Rml::ElementDocument* ret = launcher_context.get_document();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "ui_mod_menu.h"
|
#include "ui_mod_menu.h"
|
||||||
|
#include "recomp_ui.h"
|
||||||
|
|
||||||
#include "librecomp/mods.hpp"
|
#include "librecomp/mods.hpp"
|
||||||
|
|
||||||
|
|
@ -80,10 +81,6 @@ void ModMenu::set_active_mod(int32_t mod_index) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModMenu::set_config_sub_menu(ConfigSubMenu *config_sub_menu) {
|
|
||||||
ext_config_sub_menu = config_sub_menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModMenu::refresh_mods() {
|
void ModMenu::refresh_mods() {
|
||||||
recomp::mods::scan_mods();
|
recomp::mods::scan_mods();
|
||||||
mod_details = recomp::mods::get_mod_details(game_mod_id);
|
mod_details = recomp::mods::get_mod_details(game_mod_id);
|
||||||
|
|
@ -96,25 +93,38 @@ void ModMenu::mod_toggled(bool enabled) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO remove this once this is migrated to the new system.
|
||||||
|
ContextId sub_menu_context;
|
||||||
|
|
||||||
|
ContextId get_config_sub_menu_context_id() {
|
||||||
|
return sub_menu_context;
|
||||||
|
}
|
||||||
|
|
||||||
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();
|
// Record the context that was open when this function was called and close it.
|
||||||
|
ContextId prev_context = recompui::get_current_context();
|
||||||
|
prev_context.close();
|
||||||
|
|
||||||
|
// Open the sub menu context and set up the element.
|
||||||
|
sub_menu_context.open();
|
||||||
|
config_sub_menu->clear_options();
|
||||||
|
|
||||||
const recomp::mods::ConfigSchema &config_schema = recomp::mods::get_mod_config_schema(mod_details[active_mod_index].mod_id);
|
const recomp::mods::ConfigSchema &config_schema = recomp::mods::get_mod_config_schema(mod_details[active_mod_index].mod_id);
|
||||||
for (const recomp::mods::ConfigOption &option : config_schema.options) {
|
for (const recomp::mods::ConfigOption &option : config_schema.options) {
|
||||||
switch (option.type) {
|
switch (option.type) {
|
||||||
case recomp::mods::ConfigOptionType::Enum: {
|
case recomp::mods::ConfigOptionType::Enum: {
|
||||||
const recomp::mods::ConfigOptionEnum &option_enum = std::get<recomp::mods::ConfigOptionEnum>(option.variant);
|
const recomp::mods::ConfigOptionEnum &option_enum = std::get<recomp::mods::ConfigOptionEnum>(option.variant);
|
||||||
ext_config_sub_menu->add_radio_option(option.name, option.description, option_enum.options);
|
config_sub_menu->add_radio_option(option.name, option.description, option_enum.options);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case recomp::mods::ConfigOptionType::Number: {
|
case recomp::mods::ConfigOptionType::Number: {
|
||||||
const recomp::mods::ConfigOptionNumber &option_number = std::get<recomp::mods::ConfigOptionNumber>(option.variant);
|
const recomp::mods::ConfigOptionNumber &option_number = std::get<recomp::mods::ConfigOptionNumber>(option.variant);
|
||||||
ext_config_sub_menu->add_slider_option(option.name, option.description, option_number.min, option_number.max, option_number.step, option_number.percent);
|
config_sub_menu->add_slider_option(option.name, option.description, option_number.min, option_number.max, option_number.step, option_number.percent);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case recomp::mods::ConfigOptionType::String: {
|
case recomp::mods::ConfigOptionType::String: {
|
||||||
ext_config_sub_menu->add_text_option(option.name, option.description);
|
config_sub_menu->add_text_option(option.name, option.description);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
@ -123,7 +133,15 @@ void ModMenu::mod_configure_requested() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ext_config_sub_menu->enter(mod_details[active_mod_index].mod_id);
|
config_sub_menu->enter(mod_details[active_mod_index].mod_id);
|
||||||
|
sub_menu_context.close();
|
||||||
|
|
||||||
|
// Reopen the context that was open when this function was called.
|
||||||
|
prev_context.open();
|
||||||
|
|
||||||
|
// Hide the config menu and show the sub menu.
|
||||||
|
recompui::hide_context(recompui::get_config_context_id());
|
||||||
|
recompui::show_context(sub_menu_context, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,6 +212,18 @@ ModMenu::ModMenu(Element *parent) : Element(parent) {
|
||||||
} // this
|
} // this
|
||||||
|
|
||||||
refresh_mods();
|
refresh_mods();
|
||||||
|
|
||||||
|
context.close();
|
||||||
|
|
||||||
|
sub_menu_context = recompui::create_context("assets/config_sub_menu.rml");
|
||||||
|
sub_menu_context.open();
|
||||||
|
Rml::ElementDocument* sub_menu_doc = sub_menu_context.get_document();
|
||||||
|
Rml::Element* config_sub_menu_generic = sub_menu_doc->GetElementById("config_sub_menu");
|
||||||
|
ElementConfigSubMenu* config_sub_menu_element = rmlui_dynamic_cast<ElementConfigSubMenu*>(config_sub_menu_generic);
|
||||||
|
config_sub_menu = config_sub_menu_element->get_config_sub_menu_element();
|
||||||
|
sub_menu_context.close();
|
||||||
|
|
||||||
|
context.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
ModMenu::~ModMenu() {
|
ModMenu::~ModMenu() {
|
||||||
|
|
@ -214,8 +244,4 @@ ElementModMenu::~ElementModMenu() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ElementModMenu::set_config_sub_menu(ConfigSubMenu *config_sub_menu) {
|
|
||||||
mod_menu->set_config_sub_menu(config_sub_menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace recompui
|
} // namespace recompui
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ public:
|
||||||
ModMenu(Element *parent);
|
ModMenu(Element *parent);
|
||||||
virtual ~ModMenu();
|
virtual ~ModMenu();
|
||||||
void set_active_mod(int32_t mod_index);
|
void set_active_mod(int32_t mod_index);
|
||||||
void set_config_sub_menu(ConfigSubMenu *config_sub_menu);
|
|
||||||
private:
|
private:
|
||||||
void refresh_mods();
|
void refresh_mods();
|
||||||
void mod_toggled(bool enabled);
|
void mod_toggled(bool enabled);
|
||||||
|
|
@ -43,18 +42,18 @@ private:
|
||||||
ModDetailsPanel *mod_details_panel = nullptr;
|
ModDetailsPanel *mod_details_panel = nullptr;
|
||||||
Container *footer_container = nullptr;
|
Container *footer_container = nullptr;
|
||||||
Button *refresh_button = nullptr;
|
Button *refresh_button = nullptr;
|
||||||
ConfigSubMenu *ext_config_sub_menu = nullptr;
|
|
||||||
int32_t active_mod_index = -1;
|
int32_t active_mod_index = -1;
|
||||||
std::vector<ModEntry *> mod_entries;
|
std::vector<ModEntry *> mod_entries;
|
||||||
std::vector<recomp::mods::ModDetails> mod_details{};
|
std::vector<recomp::mods::ModDetails> mod_details{};
|
||||||
std::string game_mod_id;
|
std::string game_mod_id;
|
||||||
|
|
||||||
|
ConfigSubMenu *config_sub_menu;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ElementModMenu : public Rml::Element {
|
class ElementModMenu : public Rml::Element {
|
||||||
public:
|
public:
|
||||||
ElementModMenu(const Rml::String& tag);
|
ElementModMenu(const Rml::String& tag);
|
||||||
virtual ~ElementModMenu();
|
virtual ~ElementModMenu();
|
||||||
void set_config_sub_menu(ConfigSubMenu *config_sub_menu);
|
|
||||||
private:
|
private:
|
||||||
ModMenu *mod_menu;
|
ModMenu *mod_menu;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
#include "recomp_input.h"
|
#include "recomp_input.h"
|
||||||
#include "librecomp/game.hpp"
|
#include "librecomp/game.hpp"
|
||||||
#include "zelda_config.h"
|
#include "zelda_config.h"
|
||||||
|
#include "zelda_support.h"
|
||||||
#include "ui_rml_hacks.hpp"
|
#include "ui_rml_hacks.hpp"
|
||||||
#include "ui_elements.h"
|
#include "ui_elements.h"
|
||||||
#include "ui_mod_menu.h"
|
#include "ui_mod_menu.h"
|
||||||
|
|
@ -124,12 +125,24 @@ void recompui::register_event(UiEventListenerInstancer& listener, const std::str
|
||||||
|
|
||||||
Rml::Element* find_autofocus_element(Rml::Element* start) {
|
Rml::Element* find_autofocus_element(Rml::Element* start) {
|
||||||
Rml::Element* cur_element = start;
|
Rml::Element* cur_element = start;
|
||||||
|
Rml::Element* first_found = nullptr;
|
||||||
|
|
||||||
while (cur_element) {
|
while (cur_element) {
|
||||||
if (cur_element->HasAttribute("autofocus")) {
|
if (cur_element->HasAttribute("autofocus")) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cur_element = RecompRml::FindNextTabElement(cur_element, true);
|
cur_element = RecompRml::FindNextTabElement(cur_element, true);
|
||||||
|
// Track the first element that was found to know when we've wrapped around.
|
||||||
|
if (!first_found) {
|
||||||
|
first_found = cur_element;
|
||||||
|
}
|
||||||
|
// Stop searching if we found the first element again.
|
||||||
|
else {
|
||||||
|
if (cur_element == first_found) {
|
||||||
|
// Return the first tab element as there was nothing marked with autofocus.
|
||||||
|
return first_found;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cur_element;
|
return cur_element;
|
||||||
|
|
@ -151,7 +164,6 @@ public:
|
||||||
bool mouse_is_active_initialized = false;
|
bool mouse_is_active_initialized = false;
|
||||||
bool mouse_is_active = false;
|
bool mouse_is_active = false;
|
||||||
bool cont_is_active = false;
|
bool cont_is_active = false;
|
||||||
bool submenu_is_active = false;
|
|
||||||
bool await_stick_return_x = false;
|
bool await_stick_return_x = false;
|
||||||
bool await_stick_return_y = false;
|
bool await_stick_return_y = false;
|
||||||
int last_active_mouse_position[2] = {0, 0};
|
int last_active_mouse_position[2] = {0, 0};
|
||||||
|
|
@ -218,7 +230,9 @@ public:
|
||||||
Rml::LoadFontFace(font.string(), face.fallback_face);
|
Rml::LoadFontFace(font.string(), face.fallback_face);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_documents() {
|
||||||
launcher_menu_controller->load_document(context);
|
launcher_menu_controller->load_document(context);
|
||||||
config_menu_controller->load_document(context);
|
config_menu_controller->load_document(context);
|
||||||
}
|
}
|
||||||
|
|
@ -279,7 +293,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cont_is_active || non_mouse_interacted) {
|
if (cont_is_active || non_mouse_interacted) {
|
||||||
if (non_mouse_interacted && !submenu_is_active) {
|
if (non_mouse_interacted) {
|
||||||
auto focusedEl = current_document->GetFocusLeafNode();
|
auto focusedEl = current_document->GetFocusLeafNode();
|
||||||
if (focusedEl == nullptr || RecompRml::CanFocusElement(focusedEl) != RecompRml::CanFocus::Yes) {
|
if (focusedEl == nullptr || RecompRml::CanFocusElement(focusedEl) != RecompRml::CanFocus::Yes) {
|
||||||
Rml::Element* element = find_autofocus_element(current_document);
|
Rml::Element* element = find_autofocus_element(current_document);
|
||||||
|
|
@ -335,6 +349,13 @@ public:
|
||||||
.takes_input = takes_input
|
.takes_input = takes_input
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// auto& on_show = context.on_show;
|
||||||
|
// if (on_show) {
|
||||||
|
// context.open();
|
||||||
|
// on_show();
|
||||||
|
// context.close();
|
||||||
|
// }
|
||||||
|
|
||||||
document->PullToFront();
|
document->PullToFront();
|
||||||
document->Show();
|
document->Show();
|
||||||
}
|
}
|
||||||
|
|
@ -403,6 +424,7 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
||||||
std::locale::global(std::locale::classic());
|
std::locale::global(std::locale::classic());
|
||||||
#endif
|
#endif
|
||||||
ui_state = std::make_unique<UIState>(window, interface, device);
|
ui_state = std::make_unique<UIState>(window, interface, device);
|
||||||
|
ui_state->load_documents();
|
||||||
}
|
}
|
||||||
|
|
||||||
moodycamel::ConcurrentQueue<SDL_Event> ui_event_queue{};
|
moodycamel::ConcurrentQueue<SDL_Event> ui_event_queue{};
|
||||||
|
|
@ -523,7 +545,7 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
|
||||||
bool cont_interacted = false;
|
bool cont_interacted = false;
|
||||||
bool kb_interacted = false;
|
bool kb_interacted = false;
|
||||||
|
|
||||||
bool config_was_open = recompui::is_context_open(recompui::get_config_context_id());
|
bool config_was_open = recompui::is_context_open(recompui::get_config_context_id()) || recompui::is_context_open(recompui::get_config_sub_menu_context_id());
|
||||||
|
|
||||||
while (recompui::try_deque_event(cur_event)) {
|
while (recompui::try_deque_event(cur_event)) {
|
||||||
bool context_taking_input = recompui::is_context_taking_input();
|
bool context_taking_input = recompui::is_context_taking_input();
|
||||||
|
|
@ -742,3 +764,9 @@ bool recompui::is_any_context_open() {
|
||||||
return ui_state->is_any_context_open();
|
return ui_state->is_any_context_open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rml::ElementDocument* recompui::load_document(const std::filesystem::path& path) {
|
||||||
|
std::lock_guard lock{ui_state_mutex};
|
||||||
|
|
||||||
|
return ui_state->context->LoadDocument(path.string());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue