diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c834c8..b6c985e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,8 +169,9 @@ set (SOURCES ${CMAKE_SOURCE_DIR}/src/ui/ui_launcher.cpp ${CMAKE_SOURCE_DIR}/src/ui/ui_config.cpp ${CMAKE_SOURCE_DIR}/src/ui/ui_assign_players_modal.cpp + ${CMAKE_SOURCE_DIR}/src/ui/ui_color_element.cpp + ${CMAKE_SOURCE_DIR}/src/ui/ui_config_modal.cpp ${CMAKE_SOURCE_DIR}/src/ui/ui_config_page_example.cpp - ${CMAKE_SOURCE_DIR}/src/ui/ui_config_page_controls.cpp ${CMAKE_SOURCE_DIR}/src/ui/ui_config_page_controls_element.cpp ${CMAKE_SOURCE_DIR}/src/ui/ui_prompt.cpp ${CMAKE_SOURCE_DIR}/src/ui/ui_player_card.cpp @@ -186,6 +187,12 @@ set (SOURCES ${CMAKE_SOURCE_DIR}/src/ui/ui_api_images.cpp ${CMAKE_SOURCE_DIR}/src/ui/ui_utils.cpp ${CMAKE_SOURCE_DIR}/src/ui/util/hsv.cpp + ${CMAKE_SOURCE_DIR}/src/ui/config/ui_config_page_options_menu.cpp + ${CMAKE_SOURCE_DIR}/src/ui/config/ui_config_page_controls.cpp + ${CMAKE_SOURCE_DIR}/src/ui/config/ui_config_tab_controls.cpp + ${CMAKE_SOURCE_DIR}/src/ui/config/ui_config_tab_graphics.cpp + ${CMAKE_SOURCE_DIR}/src/ui/config/ui_config_tab_manifest.cpp + ${CMAKE_SOURCE_DIR}/src/ui/config/ui_config_option.cpp ${CMAKE_SOURCE_DIR}/src/ui/core/ui_context.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_binding_button.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_button.cpp @@ -196,7 +203,9 @@ set (SOURCES ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_element.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_image.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_label.cpp + ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_modal.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_pill_button.cpp + ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_pseudo_border.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_radio.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_scroll_container.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_select.cpp @@ -204,6 +213,7 @@ set (SOURCES ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_span.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_style.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_svg.cpp + ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_tab_set.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_text_input.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_theme.cpp ${CMAKE_SOURCE_DIR}/src/ui/elements/ui_toggle.cpp diff --git a/assets/icons/Question.svg b/assets/icons/Question.svg new file mode 100644 index 0000000..9fdcaf3 --- /dev/null +++ b/assets/icons/Question.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/include/banjo_config.h b/include/banjo_config.h index a8e089a..ff7009b 100644 --- a/include/banjo_config.h +++ b/include/banjo_config.h @@ -13,7 +13,9 @@ namespace banjo { // TODO: Move loading configs to the runtime once we have a way to allow per-project customization. void load_config(); void save_config(); - + bool read_json_with_backups(const std::filesystem::path& path, nlohmann::json& json_out); + bool save_json_with_backups(const std::filesystem::path& path, const nlohmann::json& json_data); + void reset_input_bindings(); void reset_cont_input_bindings(int profile_index); void reset_kb_input_bindings(int profile_index); diff --git a/include/banjo_render.h b/include/banjo_render.h index b73b48b..800fce9 100644 --- a/include/banjo_render.h +++ b/include/banjo_render.h @@ -6,6 +6,7 @@ #include "common/rt64_user_configuration.h" #include "ultramodern/renderer_context.hpp" +#include "librecomp/config.hpp" #include "librecomp/mods.hpp" namespace RT64 { @@ -54,7 +55,7 @@ namespace banjo { // Texture pack enable option. Must be an enum with two options. // The first option is treated as disabled and the second option is treated as enabled. - bool is_texture_pack_enable_config_option(const recomp::mods::ConfigOption& option, bool show_errors); + bool is_texture_pack_enable_config_option(const recomp::config::ConfigOption& option, bool show_errors); } } diff --git a/include/recomp_input.h b/include/recomp_input.h index fafa0ae..fdc0517 100644 --- a/include/recomp_input.h +++ b/include/recomp_input.h @@ -45,7 +45,10 @@ namespace recomp { #define DEFINE_RECOMP_UI_INPUTS() \ DEFINE_INPUT(TOGGLE_MENU, 0, "Toggle Menu") \ DEFINE_INPUT(ACCEPT_MENU, 0, "Accept (Menu)") \ - DEFINE_INPUT(APPLY_MENU, 0, "Apply (Menu)") + DEFINE_INPUT(BACK_MENU, 0, "Back (Menu)") \ + DEFINE_INPUT(APPLY_MENU, 0, "Apply (Menu)") \ + DEFINE_INPUT(TAB_LEFT_MENU, 0, "Tab Left (Menu)") \ + DEFINE_INPUT(TAB_RIGHT_MENU, 0, "Tab Right (Menu)") #define DEFINE_ALL_INPUTS() \ DEFINE_N64_BUTTON_INPUTS() \ @@ -130,7 +133,10 @@ namespace recomp { std::vector toggle_menu; std::vector accept_menu; + std::vector back_menu; std::vector apply_menu; + std::vector tab_left_menu; + std::vector tab_right_menu; }; inline const std::vector& get_default_mapping_for_input(const DefaultN64Mappings& defaults, const GameInput input) { @@ -156,7 +162,10 @@ namespace recomp { case GameInput::Y_AXIS_NEG: return defaults.analog_down; case GameInput::TOGGLE_MENU: return defaults.toggle_menu; case GameInput::ACCEPT_MENU: return defaults.accept_menu; + case GameInput::BACK_MENU: return defaults.back_menu; case GameInput::APPLY_MENU: return defaults.apply_menu; + case GameInput::TAB_LEFT_MENU: return defaults.tab_left_menu; + case GameInput::TAB_RIGHT_MENU: return defaults.tab_right_menu; default: return empty_input_field; } } diff --git a/include/recomp_ui.h b/include/recomp_ui.h index 1856ab0..f0246f8 100644 --- a/include/recomp_ui.h +++ b/include/recomp_ui.h @@ -10,11 +10,13 @@ #include "SDL.h" #include "RmlUi/Core.h" +#include "recomp_input.h" #include "../src/ui/util/hsv.h" #include "../src/ui/util/bem.h" #include "../src/ui/elements/ui_button.h" #include "../src/ui/elements/ui_theme.h" +#include "../src/ui/elements/ui_types.h" #include "../src/ui/core/ui_context.h" @@ -61,7 +63,7 @@ namespace recompui { ContextId get_config_context_id(); ContextId get_config_sub_menu_context_id(); - enum class ConfigTab { + enum class ConfigTabId { General, Controls, Graphics, @@ -70,8 +72,8 @@ namespace recompui { Debug, }; - void set_config_tab(ConfigTab tab); - int config_tab_to_index(ConfigTab tab); + void set_config_tab(ConfigTabId tab); + int config_tab_to_index(ConfigTabId tab); Rml::ElementTabSet* get_config_tabset(); Rml::Element* get_mod_tab(); void set_config_tabset_mod_nav(); @@ -133,6 +135,41 @@ namespace recompui { void release_image(const std::string &src); void drop_files(const std::list &file_list); + void report_removed_element(Rml::Element* element); + + namespace menu_action_mapping { + struct key_map { + // End result menu action + const MenuAction action; + // Mapped input from controller + const recomp::GameInput input; + // SDL key code from controller -> keyboard + const int sdl; + // RML key identifier passed to rmlui + const Rml::Input::KeyIdentifier rml; + }; + + static const key_map accept = { MenuAction::Accept, recomp::GameInput::ACCEPT_MENU, SDLK_RETURN, Rml::Input::KI_RETURN }; + static const key_map apply = { MenuAction::Apply, recomp::GameInput::APPLY_MENU, SDLK_f, Rml::Input::KI_F }; + static const key_map back = { MenuAction::Back, recomp::GameInput::BACK_MENU, SDLK_F15, Rml::Input::KI_F15 }; + static const key_map toggle = { MenuAction::Toggle, recomp::GameInput::TOGGLE_MENU, SDLK_ESCAPE, Rml::Input::KI_ESCAPE }; + static const key_map tab_left = { MenuAction::TabLeft, recomp::GameInput::TAB_LEFT_MENU, SDLK_F16, Rml::Input::KI_F16 }; + static const key_map tab_right = { MenuAction::TabRight, recomp::GameInput::TAB_RIGHT_MENU, SDLK_F17, Rml::Input::KI_F17 }; + + static const std::unordered_map rml_key_to_action { + { accept.rml, accept }, + { apply.rml, apply }, + { back.rml, back }, + { toggle.rml, toggle }, + { tab_left.rml, tab_left }, + { tab_right.rml, tab_right } + }; + + MenuAction menu_action_from_rml_key(const Rml::Input::KeyIdentifier& key); + }; + + // Constant that represents an input that doesn't have a promptfont icon associated with it. + extern const std::string unknown_input; } #endif diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index c5e268a..d46ed00 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit c5e268aa0f71cf06a10a001da981dc3e02e7dff0 +Subproject commit d46ed007a56d6ad1d6c9d687889ffc9acab1eb19 diff --git a/patches/recompui_event_structs.h b/patches/recompui_event_structs.h index 914160d..5495081 100644 --- a/patches/recompui_event_structs.h +++ b/patches/recompui_event_structs.h @@ -1,7 +1,7 @@ #ifndef __UI_FUNCS_H__ #define __UI_FUNCS_H__ -// These two enums must be kept in sync with src/ui/elements/ui_types.h! +// These three enums must be kept in sync with src/ui/elements/ui_types.h! typedef enum { UI_EVENT_NONE, UI_EVENT_CLICK, @@ -11,6 +11,9 @@ typedef enum { UI_EVENT_DRAG, UI_EVENT_RESERVED1, // Would be UI_EVENT_TEXT but text events aren't usable in mods currently UI_EVENT_UPDATE, + UI_EVENT_NAVIGATE, + UI_EVENT_MOUSE_BUTTON, + UI_EVENT_MENU_ACTION, UI_EVENT_COUNT } RecompuiEventType; @@ -21,6 +24,16 @@ typedef enum { UI_DRAG_END } RecompuiDragPhase; +typedef enum { + UI_MENU_ACTION_NONE, + UI_MENU_ACTION_ACCEPT, + UI_MENU_ACTION_APPLY, + UI_MENU_ACTION_BACK, + UI_MENU_ACTION_TOGGLE, + UI_MENU_ACTION_TAB_LEFT, + UI_MENU_ACTION_TAB_RIGHT +} RecompuiMenuAction; + typedef struct { RecompuiEventType type; union { @@ -46,6 +59,10 @@ typedef struct { float y; RecompuiDragPhase phase; } drag; + + struct { + RecompuiMenuAction action; + } menu_action; } data; } RecompuiEventData; diff --git a/src/game/config.cpp b/src/game/config.cpp index 3cedec3..5d58ff6 100644 --- a/src/game/config.cpp +++ b/src/game/config.cpp @@ -213,7 +213,7 @@ bool read_json(std::ifstream input_file, nlohmann::json& json_out) { return true; } -bool read_json_with_backups(const std::filesystem::path& path, nlohmann::json& json_out) { +bool banjo::read_json_with_backups(const std::filesystem::path& path, nlohmann::json& json_out) { // Try reading and parsing the base file. if (read_json(std::ifstream{path}, json_out)) { return true; @@ -228,7 +228,7 @@ bool read_json_with_backups(const std::filesystem::path& path, nlohmann::json& j return false; } -bool save_json_with_backups(const std::filesystem::path& path, const nlohmann::json& json_data) { +bool banjo::save_json_with_backups(const std::filesystem::path& path, const nlohmann::json& json_data) { { std::ofstream output_file = recomp::open_output_file_with_backup(path); if (!output_file.good()) { @@ -253,7 +253,7 @@ bool save_general_config(const std::filesystem::path& path) { config_json["analog_camera_invert_mode"] = banjo::get_analog_camera_invert_mode(); config_json["debug_mode"] = banjo::get_debug_mode_enabled(); - return save_json_with_backups(path, config_json); + return banjo::save_json_with_backups(path, config_json); } void set_general_settings_from_json(const nlohmann::json& config_json) { @@ -270,7 +270,7 @@ void set_general_settings_from_json(const nlohmann::json& config_json) { bool load_general_config(const std::filesystem::path& path) { nlohmann::json config_json{}; - if (!read_json_with_backups(path, config_json)) { + if (!banjo::read_json_with_backups(path, config_json)) { return false; } @@ -318,7 +318,10 @@ void assign_all_mappings(int profile_index, const recomp::DefaultN64Mappings& va assign_mapping_complete(profile_index, recomp::GameInput::TOGGLE_MENU, values.toggle_menu); assign_mapping_complete(profile_index, recomp::GameInput::ACCEPT_MENU, values.accept_menu); + assign_mapping_complete(profile_index, recomp::GameInput::BACK_MENU, values.back_menu); assign_mapping_complete(profile_index, recomp::GameInput::APPLY_MENU, values.apply_menu); + assign_mapping_complete(profile_index, recomp::GameInput::TAB_LEFT_MENU, values.tab_left_menu); + assign_mapping_complete(profile_index, recomp::GameInput::TAB_RIGHT_MENU, values.tab_right_menu); }; void banjo::reset_input_bindings() { @@ -365,12 +368,12 @@ void reset_graphics_options() { bool save_graphics_config(const std::filesystem::path& path) { nlohmann::json config_json{}; ultramodern::to_json(config_json, ultramodern::renderer::get_graphics_config()); - return save_json_with_backups(path, config_json); + return banjo::save_json_with_backups(path, config_json); } bool load_graphics_config(const std::filesystem::path& path) { nlohmann::json config_json{}; - if (!read_json_with_backups(path, config_json)) { + if (!banjo::read_json_with_backups(path, config_json)) { return false; } @@ -420,7 +423,7 @@ bool save_controls_config(const std::filesystem::path& path) { controller["profile"] = recomp::get_input_profile_key(recomp::get_controller_profile_index(i)); } - return save_json_with_backups(path, config_json); + return banjo::save_json_with_backups(path, config_json); } bool load_input_device_from_json(const nlohmann::json& config_json, int profile_index, recomp::InputDevice device, const std::string& key) { @@ -466,7 +469,7 @@ bool load_input_device_from_json(const nlohmann::json& config_json, int profile_ bool load_controls_config(const std::filesystem::path& path) { nlohmann::json config_json{}; - if (!read_json_with_backups(path, config_json)) { + if (!banjo::read_json_with_backups(path, config_json)) { return false; } @@ -526,12 +529,12 @@ bool save_sound_config(const std::filesystem::path& path) { config_json["main_volume"] = banjo::get_main_volume(); config_json["bgm_volume"] = banjo::get_bgm_volume(); - return save_json_with_backups(path, config_json); + return banjo::save_json_with_backups(path, config_json); } bool load_sound_config(const std::filesystem::path& path) { nlohmann::json config_json{}; - if (!read_json_with_backups(path, config_json)) { + if (!banjo::read_json_with_backups(path, config_json)) { return false; } diff --git a/src/game/controls.cpp b/src/game/controls.cpp index d99bbbf..5b39b81 100644 --- a/src/game/controls.cpp +++ b/src/game/controls.cpp @@ -389,7 +389,10 @@ void clear_all_mappings(int profile_index) { clear_mapping(profile_index, recomp::GameInput::TOGGLE_MENU); clear_mapping(profile_index, recomp::GameInput::ACCEPT_MENU); + clear_mapping(profile_index, recomp::GameInput::BACK_MENU); clear_mapping(profile_index, recomp::GameInput::APPLY_MENU); + clear_mapping(profile_index, recomp::GameInput::TAB_LEFT_MENU); + clear_mapping(profile_index, recomp::GameInput::TAB_RIGHT_MENU); }; void recomp::initialize_input_bindings() { diff --git a/src/game/input.cpp b/src/game/input.cpp index 4d4dc22..89826a1 100644 --- a/src/game/input.cpp +++ b/src/game/input.cpp @@ -601,8 +601,17 @@ const recomp::DefaultN64Mappings recomp::default_n64_keyboard_mappings = { .accept_menu = { {.input_type = InputType::Keyboard, .input_id = SDL_SCANCODE_RETURN} }, + .back_menu = { + {.input_type = InputType::Keyboard, .input_id = SDL_SCANCODE_F15} + }, .apply_menu = { {.input_type = InputType::Keyboard, .input_id = SDL_SCANCODE_F} + }, + .tab_left_menu = { + {.input_type = InputType::Keyboard, .input_id = SDL_SCANCODE_F16} + }, + .tab_right_menu = { + {.input_type = InputType::Keyboard, .input_id = SDL_SCANCODE_F17} } }; @@ -671,9 +680,18 @@ const recomp::DefaultN64Mappings recomp::default_n64_controller_mappings = { .accept_menu = { {.input_type = InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_SOUTH}, }, - .apply_menu = { + .back_menu = { {.input_type = InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_WEST}, + }, + .apply_menu = { + {.input_type = InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_NORTH}, {.input_type = InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_START} + }, + .tab_left_menu = { + {.input_type = InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_LEFTSHOULDER} + }, + .tab_right_menu = { + {.input_type = InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER} } }; @@ -976,6 +994,8 @@ void recomp::set_single_controller_mode(bool single_controller) { InputState.single_controller = single_controller; } +const std::string recompui::unknown_input = "UNKNOWN"; + std::string controller_button_to_string(SDL_GameControllerButton button) { switch (button) { case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_A: @@ -1008,20 +1028,20 @@ std::string controller_button_to_string(SDL_GameControllerButton button) { return PF_DPAD_LEFT; case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_RIGHT: return PF_DPAD_RIGHT; - // case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_MISC1: - // return ""; - // case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE1: - // return ""; - // case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE2: - // return ""; - // case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE3: - // return ""; - // case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE4: - // return ""; + case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_MISC1: + return PF_STEAM_OPTIONS; + case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE1: + return PF_GAMEPAD_L4; + case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE2: + return PF_GAMEPAD_R4; + case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE3: + return PF_GAMEPAD_L5; + case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE4: + return PF_GAMEPAD_R5; case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_TOUCHPAD: return PF_SONY_TOUCHPAD; default: - return "Button " + std::to_string(button); + return recompui::unknown_input; } } @@ -1080,6 +1100,18 @@ std::unordered_map scancode_codepoints{ {SDL_SCANCODE_F10, PF_KEYBOARD_F10}, {SDL_SCANCODE_F11, PF_KEYBOARD_F11}, {SDL_SCANCODE_F12, PF_KEYBOARD_F12}, + {SDL_SCANCODE_F13, "F13"}, + {SDL_SCANCODE_F14, "F14"}, + {SDL_SCANCODE_F15, "F15"}, + {SDL_SCANCODE_F16, "F16"}, + {SDL_SCANCODE_F17, "F17"}, + {SDL_SCANCODE_F18, "F18"}, + {SDL_SCANCODE_F19, "F19"}, + {SDL_SCANCODE_F20, "F20"}, + {SDL_SCANCODE_F21, "F21"}, + {SDL_SCANCODE_F22, "F22"}, + {SDL_SCANCODE_F23, "F23"}, + {SDL_SCANCODE_F24, "F24"}, {SDL_SCANCODE_PRINTSCREEN, PF_KEYBOARD_PRINT_SCREEN}, {SDL_SCANCODE_SCROLLLOCK, PF_KEYBOARD_SCROLL_LOCK}, {SDL_SCANCODE_PAUSE, PF_KEYBOARD_PAUSE}, @@ -1103,7 +1135,7 @@ std::string keyboard_input_to_string(SDL_Scancode key) { if (scancode_codepoints.find(key) != scancode_codepoints.end()) { return scancode_codepoints[key]; } - return std::to_string(key); + return recompui::unknown_input; } std::string controller_axis_to_string(int axis) { @@ -1138,6 +1170,6 @@ std::string recomp::InputField::to_string() const { case InputType::Keyboard: return keyboard_input_to_string((SDL_Scancode)input_id); default: - return std::to_string((uint32_t)input_type) + "," + std::to_string(input_id); + return recompui::unknown_input; } } diff --git a/src/main/rt64_render_context.cpp b/src/main/rt64_render_context.cpp index 1dcf2d5..00d9f60 100644 --- a/src/main/rt64_render_context.cpp +++ b/src/main/rt64_render_context.cpp @@ -14,6 +14,7 @@ #include "banjo_render.h" #include "recomp_ui.h" #include "concurrentqueue.h" +#include "../ui/config/ui_config_tab_graphics.h" static RT64::UserConfiguration::Antialiasing device_max_msaa = RT64::UserConfiguration::Antialiasing::None; static bool sample_positions_supported = false; @@ -326,6 +327,8 @@ banjo::renderer::RT64Context::RT64Context(uint8_t* rdram, ultramodern::renderer: sample_positions_supported = false; } + recompui::update_msaa_supported(sample_positions_supported); + high_precision_fb_enabled = app->shaderLibrary->usesHDR; } @@ -482,13 +485,13 @@ void banjo::renderer::enable_texture_pack(const recomp::mods::ModContext& contex texture_pack_action_queue.enqueue(TexturePackEnableAction{mod.manifest.mod_id}); // Check for the texture pack enabled config option. - const recomp::mods::ConfigSchema& config_schema = context.get_mod_config_schema(mod.manifest.mod_id); + const recomp::config::ConfigSchema& config_schema = context.get_mod_config_schema(mod.manifest.mod_id); auto find_it = config_schema.options_by_id.find(banjo::renderer::special_option_texture_pack_enabled); if (find_it != config_schema.options_by_id.end()) { - const recomp::mods::ConfigOption& config_option = config_schema.options[find_it->second]; + const recomp::config::ConfigOption& config_option = config_schema.options[find_it->second]; if (is_texture_pack_enable_config_option(config_option, false)) { - recomp::mods::ConfigValueVariant value_variant = context.get_mod_config_value(mod.manifest.mod_id, config_option.id); + recomp::config::ConfigValueVariant value_variant = context.get_mod_config_value(mod.manifest.mod_id, config_option.id); uint32_t value; if (uint32_t* value_ptr = std::get_if(&value_variant)) { value = *value_ptr; @@ -522,16 +525,16 @@ void banjo::renderer::secondary_disable_texture_pack(const std::string& mod_id) // HD texture enable option. Must be an enum with two options. // The first option is treated as disabled and the second option is treated as enabled. -bool banjo::renderer::is_texture_pack_enable_config_option(const recomp::mods::ConfigOption& option, bool show_errors) { +bool banjo::renderer::is_texture_pack_enable_config_option(const recomp::config::ConfigOption& option, bool show_errors) { if (option.id == banjo::renderer::special_option_texture_pack_enabled) { - if (option.type != recomp::mods::ConfigOptionType::Enum) { + if (option.type != recomp::config::ConfigOptionType::Enum) { if (show_errors) { recompui::message_box(("Mod has the special config option id for enabling an HD texture pack (\"" + banjo::renderer::special_option_texture_pack_enabled + "\"), but the config option is not an enum.").c_str()); } return false; } - const recomp::mods::ConfigOptionEnum &option_enum = std::get(option.variant); + const recomp::config::ConfigOptionEnum &option_enum = std::get(option.variant); if (option_enum.options.size() != 2) { if (show_errors) { recompui::message_box(("Mod has the special config option id for enabling an HD texture pack (\"" + banjo::renderer::special_option_texture_pack_enabled + "\"), but the config option doesn't have exactly 2 values.").c_str()); diff --git a/src/ui/config/ui_config_common.h b/src/ui/config/ui_config_common.h new file mode 100644 index 0000000..80ff2e6 --- /dev/null +++ b/src/ui/config/ui_config_common.h @@ -0,0 +1,72 @@ +#pragma once +#include "librecomp/config.hpp" +#include "librecomp/mods.hpp" + +namespace recompui { + // Callbacks for render updates relating to config option changes. + using get_config_option_updates_callback = std::function()>; + using clear_config_option_updates_callback = std::function; + using check_page_dirty_callback = std::function; + + using set_option_value_callback = std::function; + // Callbacks for various config option properties + using get_option_value_callback = std::function; + using get_option_name_callback = std::function; + using get_option_description_callback = std::function; + using get_option_disabled_callback = std::function; + using get_option_hidden_callback = std::function; + using get_option_configuration_callback = std::function; + + // Text that displays on the right side of the options + using get_enum_option_details_callback = std::function; + // Fetches if an individual enum option is disabled + using get_enum_option_disabled_callback = std::function; + + using on_option_hover_callback = std::function; + + class ConfigOptionPropertyCallbacks { + // private: + // const get_option_configuration_callback get_configuration; + public: + const get_option_configuration_callback get_configuration; + const get_option_value_callback get_value; + const get_option_name_callback get_name; + const get_option_description_callback get_description; + const get_option_hidden_callback get_hidden; + const get_option_disabled_callback get_disabled = nullptr; + + const get_enum_option_details_callback get_enum_option_details = nullptr; + const get_enum_option_disabled_callback get_enum_option_disabled = nullptr; + + ConfigOptionPropertyCallbacks( + get_option_configuration_callback get_configuration, + get_option_value_callback get_value, + get_option_name_callback get_name, + get_option_description_callback get_description, + get_option_hidden_callback get_hidden, + get_option_disabled_callback get_disabled = nullptr, + get_enum_option_details_callback get_enum_option_details = nullptr, + get_enum_option_disabled_callback get_enum_option_disabled = nullptr + ) : + get_configuration(get_configuration), + get_value(get_value), + get_name(get_name), + get_description(get_description), + get_hidden(get_hidden), + get_disabled(get_disabled), + get_enum_option_details(get_enum_option_details), + get_enum_option_disabled(get_enum_option_disabled) {} + + ConfigOptionPropertyCallbacks(const ConfigOptionPropertyCallbacks&) = default; + + recomp::config::ConfigOptionEnum get_enum_configuration(const std::string &option_id) { + return std::get(get_configuration(option_id)); + } + recomp::config::ConfigOptionNumber get_number_configuration(const std::string &option_id) { + return std::get(get_configuration(option_id)); + } + recomp::config::ConfigOptionString get_string_configuration(const std::string &option_id) { + return std::get(get_configuration(option_id)); + } + }; +}; diff --git a/src/ui/config/ui_config_option.cpp b/src/ui/config/ui_config_option.cpp new file mode 100644 index 0000000..a063460 --- /dev/null +++ b/src/ui/config/ui_config_option.cpp @@ -0,0 +1,293 @@ +#include "ui_config_option.h" + +namespace recompui { + +constexpr float config_option_element_margin_vertical = 12.0f; +NovaConfigOptionElement::NovaConfigOptionElement( + Element *parent, + std::string option_id, + size_t option_index, + ConfigOptionPropertyCallbacks *callbacks, + set_option_value_callback set_option_value, + on_option_hover_callback on_hover +) : + Element(parent, Events(EventType::Hover, EventType::Focus), "div", false), + option_id(option_id), + option_index(option_index), + callbacks(callbacks), + set_option_value(set_option_value), + on_hover(on_hover) +{ + set_display(Display::Flex); + set_position(Position::Relative); + set_flex_direction(FlexDirection::Column); + set_align_items(AlignItems::FlexStart); + set_justify_content(JustifyContent::FlexStart); + set_padding_top(config_option_element_margin_vertical); + set_padding_left(12.0f); + set_padding_right(12.0f); + set_padding_bottom(config_option_element_margin_vertical); + set_height_auto(); + set_width(100.0f, Unit::Percent); + set_as_navigation_container(NavigationType::Auto); + + ContextId context = recompui::get_current_context(); + auto name_text = callbacks->get_name(option_id); + if (!name_text.empty()) { + name_label = context.create_element