From 1b2b40bc6eb18d44a2451d1a9c8f5128b3765382 Mon Sep 17 00:00:00 2001
From: thecozies <79979276+thecozies@users.noreply.github.com>
Date: Tue, 9 Sep 2025 08:23:28 -0500
Subject: [PATCH] changes up to swapping to recompfrontend library
---
CMakeLists.txt | 12 +-
assets/icons/Question.svg | 5 +
include/banjo_config.h | 4 +-
include/banjo_render.h | 3 +-
include/recomp_input.h | 11 +-
include/recomp_ui.h | 43 +-
lib/N64ModernRuntime | 2 +-
patches/recompui_event_structs.h | 19 +-
src/game/config.cpp | 23 +-
src/game/controls.cpp | 3 +
src/game/input.cpp | 60 +-
src/main/rt64_render_context.cpp | 15 +-
src/ui/config/ui_config_common.h | 72 +++
src/ui/config/ui_config_option.cpp | 293 ++++++++++
src/ui/config/ui_config_option.h | 131 +++++
.../{ => config}/ui_config_page_controls.cpp | 106 +++-
src/ui/{ => config}/ui_config_page_controls.h | 35 +-
src/ui/config/ui_config_page_options_menu.cpp | 307 ++++++++++
src/ui/config/ui_config_page_options_menu.h | 71 +++
src/ui/config/ui_config_tab_controls.cpp | 29 +
src/ui/config/ui_config_tab_controls.h | 16 +
src/ui/config/ui_config_tab_graphics.cpp | 385 +++++++++++++
src/ui/config/ui_config_tab_graphics.h | 19 +
src/ui/config/ui_config_tab_manifest.cpp | 109 ++++
src/ui/config/ui_config_tab_manifest.h | 22 +
src/ui/core/ui_context.cpp | 39 ++
src/ui/core/ui_context.h | 2 +
src/ui/elements/ui_binding_button.cpp | 30 +-
src/ui/elements/ui_binding_button.h | 1 +
src/ui/elements/ui_button.cpp | 4 +
src/ui/elements/ui_clickable.cpp | 8 +-
src/ui/elements/ui_config_page.cpp | 25 +-
src/ui/elements/ui_config_page.h | 5 +-
src/ui/elements/ui_element.cpp | 524 +++++++++++++++++-
src/ui/elements/ui_element.h | 53 ++
src/ui/elements/ui_icon_button.cpp | 5 +
src/ui/elements/ui_label.cpp | 31 +-
src/ui/elements/ui_label.h | 4 +-
src/ui/elements/ui_modal.cpp | 272 +++++++++
src/ui/elements/ui_modal.h | 81 +++
src/ui/elements/ui_pseudo_border.cpp | 43 ++
src/ui/elements/ui_pseudo_border.h | 22 +
src/ui/elements/ui_radio.cpp | 75 ++-
src/ui/elements/ui_radio.h | 1 +
src/ui/elements/ui_slider.cpp | 13 +-
src/ui/elements/ui_slider.h | 3 +
src/ui/elements/ui_style.cpp | 16 +
src/ui/elements/ui_style.h | 2 +
src/ui/elements/ui_tab_set.cpp | 168 ++++++
src/ui/elements/ui_tab_set.h | 52 ++
src/ui/elements/ui_text_input.cpp | 10 +-
src/ui/elements/ui_text_input.h | 1 +
src/ui/elements/ui_theme.cpp | 38 ++
src/ui/elements/ui_theme.h | 30 +-
src/ui/elements/ui_toggle.cpp | 118 +++-
src/ui/elements/ui_toggle.h | 25 +-
src/ui/elements/ui_types.h | 24 +-
src/ui/ui_api_events.cpp | 6 +
src/ui/ui_color_element.cpp | 32 ++
src/ui/ui_color_element.h | 19 +
src/ui/ui_config.cpp | 18 +-
src/ui/ui_config_modal.cpp | 238 ++++++++
src/ui/ui_config_modal.h | 14 +
src/ui/ui_config_page_controls_element.cpp | 12 +-
src/ui/ui_config_page_controls_element.h | 4 +-
src/ui/ui_elements.cpp | 1 +
src/ui/ui_elements.h | 1 +
src/ui/ui_launcher.cpp | 6 +-
src/ui/ui_mod_installer.cpp | 2 +-
src/ui/ui_mod_menu.cpp | 36 +-
src/ui/ui_mod_menu.h | 2 +-
src/ui/ui_state.cpp | 94 +++-
72 files changed, 3756 insertions(+), 249 deletions(-)
create mode 100644 assets/icons/Question.svg
create mode 100644 src/ui/config/ui_config_common.h
create mode 100644 src/ui/config/ui_config_option.cpp
create mode 100644 src/ui/config/ui_config_option.h
rename src/ui/{ => config}/ui_config_page_controls.cpp (80%)
rename src/ui/{ => config}/ui_config_page_controls.h (76%)
create mode 100644 src/ui/config/ui_config_page_options_menu.cpp
create mode 100644 src/ui/config/ui_config_page_options_menu.h
create mode 100644 src/ui/config/ui_config_tab_controls.cpp
create mode 100644 src/ui/config/ui_config_tab_controls.h
create mode 100644 src/ui/config/ui_config_tab_graphics.cpp
create mode 100644 src/ui/config/ui_config_tab_graphics.h
create mode 100644 src/ui/config/ui_config_tab_manifest.cpp
create mode 100644 src/ui/config/ui_config_tab_manifest.h
create mode 100644 src/ui/elements/ui_modal.cpp
create mode 100644 src/ui/elements/ui_modal.h
create mode 100644 src/ui/elements/ui_pseudo_border.cpp
create mode 100644 src/ui/elements/ui_pseudo_border.h
create mode 100644 src/ui/elements/ui_tab_set.cpp
create mode 100644 src/ui/elements/ui_tab_set.h
create mode 100644 src/ui/ui_color_element.cpp
create mode 100644 src/ui/ui_color_element.h
create mode 100644 src/ui/ui_config_modal.cpp
create mode 100644 src/ui/ui_config_modal.h
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