Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 25 additions & 25 deletions recompinput/include/recompinput/input_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,41 @@

namespace recompinput {
#define DEFINE_N64_BUTTON_INPUTS() \
DEFINE_INPUT(A, 0x8000, "A") \
DEFINE_INPUT(B, 0x4000, "B") \
DEFINE_INPUT(Z, 0x2000, "Z") \
DEFINE_INPUT(L, 0x0020, "L") \
DEFINE_INPUT(R, 0x0010, "R") \
DEFINE_INPUT(START, 0x1000, "Start") \
DEFINE_INPUT(C_UP, 0x0008, "C Up") \
DEFINE_INPUT(C_DOWN, 0x0004, "C Down") \
DEFINE_INPUT(C_LEFT, 0x0002, "C Left") \
DEFINE_INPUT(C_RIGHT, 0x0001, "C Right") \
DEFINE_INPUT(DPAD_UP, 0x0800, "D-Pad Up") \
DEFINE_INPUT(DPAD_DOWN, 0x0400, "D-Pad Down") \
DEFINE_INPUT(DPAD_LEFT, 0x0200, "D-Pad Left") \
DEFINE_INPUT(DPAD_RIGHT, 0x0100, "D-Pad Right")
DEFINE_INPUT(A, 0x8000, "A", "") \
DEFINE_INPUT(B, 0x4000, "B", "") \
DEFINE_INPUT(Z, 0x2000, "Z", "") \
DEFINE_INPUT(L, 0x0020, "L", "") \
DEFINE_INPUT(R, 0x0010, "R", "") \
DEFINE_INPUT(START, 0x1000, "Start", "") \
DEFINE_INPUT(C_UP, 0x0008, "C Up", "") \
DEFINE_INPUT(C_DOWN, 0x0004, "C Down", "") \
DEFINE_INPUT(C_LEFT, 0x0002, "C Left", "") \
DEFINE_INPUT(C_RIGHT, 0x0001, "C Right", "") \
DEFINE_INPUT(DPAD_UP, 0x0800, "D-Pad Up", "") \
DEFINE_INPUT(DPAD_DOWN, 0x0400, "D-Pad Down", "") \
DEFINE_INPUT(DPAD_LEFT, 0x0200, "D-Pad Left", "") \
DEFINE_INPUT(DPAD_RIGHT, 0x0100, "D-Pad Right", "")

#define DEFINE_N64_AXIS_INPUTS() \
DEFINE_INPUT(Y_AXIS_POS, 0, "Up") \
DEFINE_INPUT(Y_AXIS_NEG, 0, "Down") \
DEFINE_INPUT(X_AXIS_NEG, 0, "Left") \
DEFINE_INPUT(X_AXIS_POS, 0, "Right") \
DEFINE_INPUT(Y_AXIS_POS, 0, "Up", "") \
DEFINE_INPUT(Y_AXIS_NEG, 0, "Down", "") \
DEFINE_INPUT(X_AXIS_NEG, 0, "Left", "") \
DEFINE_INPUT(X_AXIS_POS, 0, "Right", "") \

#define DEFINE_RECOMP_UI_INPUTS() \
DEFINE_INPUT(TOGGLE_MENU, 0, "Toggle Menu") \
DEFINE_INPUT(ACCEPT_MENU, 0, "Accept (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_INPUT(TOGGLE_MENU, 0, "Toggle Menu", "Open or close this configuration menu from in game.") \
DEFINE_INPUT(ACCEPT_MENU, 0, "Accept (Menu)", "In the recomp interface, performs the action for the currently highlighted item. Like pressing a button, or toggling a switch.") \
DEFINE_INPUT(BACK_MENU, 0, "Back (Menu)", "In the recomp interface, returns to the header or backs out to a previous menu.") \
DEFINE_INPUT(APPLY_MENU, 0, "Apply (Menu)", "In the recomp interface, if changes are made to a configuration that requires applying your settings, this will apply the current changes.") \
DEFINE_INPUT(TAB_LEFT_MENU, 0, "Tab Left (Menu)", "In the recomp interface, switches the active tab to the one on the left of the current tab.") \
DEFINE_INPUT(TAB_RIGHT_MENU, 0, "Tab Right (Menu)", "In the recomp interface, switches the active tab to the one on the right of the current tab.")

#define DEFINE_ALL_INPUTS() \
DEFINE_N64_AXIS_INPUTS() \
DEFINE_N64_BUTTON_INPUTS() \
DEFINE_RECOMP_UI_INPUTS()

#define DEFINE_INPUT(name, value, readable) name,
#define DEFINE_INPUT(name, value, readable, description) name,
// - Enum containing every recomp input.
// - Includes inputs that are specific to menu navigation.
// - This represents what any controller/keyboard can bind to.
Expand Down
1 change: 1 addition & 0 deletions recompinput/include/recompinput/recompinput.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "SDL.h"
#include "chrono"
#include <string>

namespace recompinput {
constexpr size_t max_num_players_supported = 128;
Expand Down
27 changes: 8 additions & 19 deletions recompinput/src/input_types.cpp
Original file line number Diff line number Diff line change
@@ -1,35 +1,24 @@
#include "recompinput.h"
#include <string>
#include <array>
#include <unordered_map>
#include <unordered_set>
#include "recompinput.h"

namespace recompinput {

#define DEFINE_INPUT(name, value, readable) readable,
#define DEFINE_INPUT(name, value, readable, description) readable,
static std::array<std::string, num_game_inputs> game_input_names = {
DEFINE_ALL_INPUTS()
};
#undef DEFINE_INPUT

constexpr std::array<std::string, num_game_inputs> get_default_game_input_descriptions() {
#define DEFINE_INPUT(name, value, readable) "",
std::array<std::string, num_game_inputs> descriptions = {
DEFINE_ALL_INPUTS()
};
descriptions[static_cast<size_t>(GameInput::TOGGLE_MENU)] = "Open or close this configuration menu from in game.";
descriptions[static_cast<size_t>(GameInput::ACCEPT_MENU)] = "In the recomp interface, performs the action for the currently highlighted item. Like pressing a button, or toggling a switch.";
descriptions[static_cast<size_t>(GameInput::BACK_MENU)] = "In the recomp interface, returns to the header or backs out to a previous menu.";
descriptions[static_cast<size_t>(GameInput::APPLY_MENU)] = "In the recomp interface, if changes are made to a configuration that requires applying your settings, this will apply the current changes.";
descriptions[static_cast<size_t>(GameInput::TAB_LEFT_MENU)] = "In the recomp interface, switches the active tab to the one on the left of the current tab.";
descriptions[static_cast<size_t>(GameInput::TAB_RIGHT_MENU)] = "In the recomp interface, switches the active tab to the one on the right of the current tab.";
static std::array<std::string, num_game_inputs> game_input_descriptions = {
#define DEFINE_INPUT(_1, _2, _3, description) description,
DEFINE_ALL_INPUTS()
#undef DEFINE_INPUT
return descriptions;
}

static std::array<std::string, num_game_inputs> game_input_descriptions = get_default_game_input_descriptions();
};

#define DEFINE_INPUT(name, value, readable) #name,
#define DEFINE_INPUT(name, value, readable, description) #name,
static const std::array<std::string, num_game_inputs> game_input_enum_names = {
DEFINE_ALL_INPUTS()
};
Expand Down Expand Up @@ -70,7 +59,7 @@ bool get_game_input_clearable(GameInput input) {
}

bool get_game_input_is_menu(GameInput input) {
#define DEFINE_INPUT(name, value, readable) case GameInput::name: return true;
#define DEFINE_INPUT(name, value, readable, description) case GameInput::name: return true;

switch (input) {
DEFINE_RECOMP_UI_INPUTS()
Expand Down
2 changes: 1 addition & 1 deletion recompinput/src/profiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ static const std::string keyboard_mp_profile_key = "keyboard_mp_player_"; // + p
static const std::string keyboard_mp_profile_name = "Keyboard "; // + "(player number)"

// Make the button value array, which maps a button index to its bit field.
#define DEFINE_INPUT(name, value, readable) uint16_t(value##u),
#define DEFINE_INPUT(name, value, readable, description) uint16_t(value##u),
static const std::array n64_button_values = {
DEFINE_N64_BUTTON_INPUTS()
};
Expand Down
3 changes: 1 addition & 2 deletions recompui/src/api/ui_api_events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
#include "librecomp/overlays.hpp"
#include "librecomp/helpers.hpp"

// TODO: Forced game includes
#include "../../../../../patches/ui_funcs.h"
#include "event_structs.h"

struct QueuedCallback {
recompui::ResourceId resource;
Expand Down
11 changes: 11 additions & 0 deletions recompui/src/base/ui_game_option.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ namespace recompui {
}

void GameOption::process_event(const Event &e) {
if (event_callback != nullptr) {
bool cancel = event_callback(e);
if (cancel) {
return;
}
}

switch (e.type) {
case EventType::Click:
if (is_enabled()) {
Expand Down Expand Up @@ -116,4 +123,8 @@ namespace recompui {
void GameOption::set_callback(std::function<void()> new_callback) {
callback = new_callback;
}

void GameOption::set_event_callback(std::function<bool(const Event& e)> new_callback) {
event_callback = new_callback;
}
}
2 changes: 2 additions & 0 deletions recompui/src/base/ui_game_option.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace recompui {
private:
std::string title;
std::function<void()> callback;
std::function<bool(const Event& e)> event_callback = nullptr;
protected:
Label *label;
void set_styles();
Expand All @@ -19,6 +20,7 @@ namespace recompui {
GameOption(ResourceId rid, Element* parent, const std::string& title, std::function<void()> callback, GameOptionsMenuLayout layout);
void set_title(const std::string& new_title);
void set_callback(std::function<void()> new_callback);
void set_event_callback(std::function<bool(const Event& e)> new_callback);
Label* get_label() { return label; }
// These are public so you can modify them.
Style hover_style;
Expand Down
3 changes: 3 additions & 0 deletions recompui/src/composites/ui_mod_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,9 @@ void update_mod_list(bool scan_mods) {
}

void update_game_mod_id(const std::string &game_mod_id) {
if (current_game_mod_id != "" && game_mod_id != current_game_mod_id && mod_menu) {
mod_menu->set_mods_dirty(false);
}
current_game_mod_id = game_mod_id;
}

Expand Down
100 changes: 57 additions & 43 deletions recompui/src/elements/ui_element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -671,11 +671,6 @@ Element *Element::get_nav_parent() {
void Element::set_as_navigation_container(NavigationType nav_type) {
is_nav_container = true;
this->nav_type = nav_type;

Element *parent_nav = get_nav_parent();
if (parent_nav != nullptr) {
parent_nav->nav_children.push_back(this);
}
}

void Element::set_nav_wrapping(bool wrapping) {
Expand Down Expand Up @@ -710,53 +705,72 @@ Element::CanFocus Element::is_focusable() {
return CanFocus::No;
}

void Element::get_all_focusable_children(Element *nav_parent) {
for (auto child : children) {
CanFocus res = child->is_focusable();
if (res == CanFocus::Yes) {
nav_parent->nav_children.push_back(child);
} else if (res == CanFocus::NoAndNoChildren) {
continue; // Skip this child, it has no focusable children.
} else {
child->get_all_focusable_children(nav_parent);
}
}
}

// Dive into the hierarchy to build a list of focusable elements and navigation containers.
bool Element::is_distant_parent_of(Element *el) {
if (el == nullptr) {
return false;
}
Element *cur_parent = el->parent;
while (cur_parent != nullptr) {
if (this == cur_parent) {
return true;
}
cur_parent = cur_parent->parent;
}
return false;
}

/**
* - Element should be visible in order for it or any of its children to be considered for navigation.
* - The current focused element is always treated as a valid element. No need to dive into it. If it was focused,
* it is not a nav container.
* - The document calls this function with nav_parent being itself
* - Nav containers' nav_children dont need to be direct descendants, but once you hit a child that:
* - isnt visible
* - focus is NoAndNoChildren
* - is either focusable OR a nav container
* then you stop/continue. if focusable or a nav container, push it to the nav_parent's children
* - One exception, if this element is a parent or distant parent (like mine), then continue diving into that tree.
*/
void Element::build_navigation(Element *nav_parent, Element *cur_focus_element) {
if (!base->IsVisible()) {
return;
bool is_visible = base->IsVisible();
bool is_current_focus = cur_focus_element ? this->id == cur_focus_element->id : false;
bool is_doc = this->get_type_name() == "Document";

if (nav_children.size() > 0) {
nav_children.clear();
}

for (auto &child : children) {
if (child == cur_focus_element) {
nav_parent->nav_children.push_back(child);
continue;
Element::CanFocus can_focus = Element::CanFocus::No;
if (!is_doc) {
// Current focused element doesn't need to be visible or
// focusable, it could have changed either way.
if (is_current_focus) {
nav_parent->nav_children.push_back(this);
return;
}
if (!child->base->IsVisible() || !child->enabled) {
continue;
can_focus = is_focusable();
// All other elements that aren't visible should be skipped.
if (can_focus == Element::CanFocus::NoAndNoChildren && !is_distant_parent_of(cur_focus_element)) {
return;
}
}

if ((child->is_focusable() == CanFocus::Yes) || child->is_nav_container) {
nav_parent->nav_children.push_back(child);
if (can_focus == Element::CanFocus::Yes) {
nav_parent->nav_children.push_back(this);
} else if (is_nav_container) {
// Add nav children recursively to self.
for (auto &child : children) {
child->build_navigation(this, cur_focus_element);
}

if (child->is_nav_container) {
child->nav_children.clear();
child->build_navigation(child, cur_focus_element);

// didn't find any nav children, check for focus elements
if (child->nav_children.size() == 0) {
child->get_all_focusable_children(child);
}

// didn't find any focus elements
if (child->nav_children.size() == 0) {
nav_parent->nav_children.pop_back();
}
// Only give the nav parent this nav container if it has any focusable elements.
if (nav_children.size() > 0) {
nav_parent->nav_children.push_back(this);
}
else {
} else {
// This isn't focusable or a nav container, so iter children recursively from the
// current nav_parent.
for (auto &child : children) {
child->build_navigation(nav_parent, cur_focus_element);
}
}
Expand Down
2 changes: 1 addition & 1 deletion recompui/src/elements/ui_element.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ class Element : public Style, public Rml::EventListener {
void ProcessEvent(Rml::Event &event) override final;

Element *get_nav_parent();
void get_all_focusable_children(Element *nav_parent);
void build_navigation(Element *nav_parent, Element *cur_focus_element);
bool is_distant_parent_of(Element *el);
protected:
// Use of this method in inherited classes is discouraged unless it's necessary.
void set_attribute(const Rml::String &attribute_key, const Rml::String &attribute_value);
Expand Down
4 changes: 3 additions & 1 deletion recompui/src/elements/ui_modal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ void TabbedModal::open() {
if (tabs != nullptr) {
tabs->focus_on_active_tab();
on_tab_change(tabs->get_active_tab());
refresh_tab = true;
}
}

Expand Down Expand Up @@ -334,12 +335,13 @@ TabbedModal::TabbedModal(
void TabbedModal::process_event(const Event &e) {
switch (e.type) {
case EventType::Update: {
if (previous_tab_index != current_tab_index) {
if (refresh_tab || previous_tab_index != current_tab_index) {
body->clear_children();
if (current_tab_index >= 0 && current_tab_index < tab_contexts.size()) {
tab_contexts[current_tab_index].create_contents(modal_root_context, body);
}
previous_tab_index = current_tab_index;
refresh_tab = false;
}
queue_update();
break;
Expand Down
1 change: 1 addition & 0 deletions recompui/src/elements/ui_modal.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ namespace recompui {
TabSet *tabs = nullptr;
int previous_tab_index = -1;
int current_tab_index = -1;
bool refresh_tab = false;
virtual void process_event(const Event &e) override;
std::string_view get_type_name() override { return "TabbedModal"; }
void on_tab_change(int tab_index);
Expand Down
Loading