mirror of
https://github.com/BanjoRecomp/BanjoRecomp
synced 2026-05-24 23:01:28 -04:00
controls page multi vs single views
This commit is contained in:
+6
-1
@@ -10,6 +10,7 @@
|
||||
#include "promptfont.h"
|
||||
#include "GamepadMotion.hpp"
|
||||
#include "../ui/ui_assign_players_modal.h"
|
||||
#include "../ui/ui_config_page_controls_element.h"
|
||||
|
||||
constexpr float axis_threshold = 0.5f;
|
||||
|
||||
@@ -146,6 +147,10 @@ void process_player_assignment(SDL_Event* event) {
|
||||
if (queue_close_player_assignment_modal) {
|
||||
recompui::assign_players_modal->close();
|
||||
queue_close_player_assignment_modal = false;
|
||||
if (recompui::controls_page != nullptr) {
|
||||
recompui::controls_page->force_update();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player_assignment_state.is_assigning) {
|
||||
@@ -1099,4 +1104,4 @@ std::string recomp::InputField::to_string() const {
|
||||
default:
|
||||
return std::to_string((uint32_t)input_type) + "," + std::to_string(input_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +113,10 @@ namespace recompui {
|
||||
return header;
|
||||
}
|
||||
|
||||
void ConfigPage::hide_header() {
|
||||
header->set_visibility(Visibility::Hidden);
|
||||
}
|
||||
|
||||
ConfigHeaderFooter* ConfigPage::add_footer() {
|
||||
footer->set_visibility(Visibility::Visible);
|
||||
set_border_bottom_left_radius(0);
|
||||
@@ -120,6 +124,10 @@ namespace recompui {
|
||||
return footer;
|
||||
}
|
||||
|
||||
|
||||
void ConfigPage::hide_footer() {
|
||||
footer->set_visibility(Visibility::Hidden);
|
||||
set_border_bottom_left_radius(theme::border::radius_lg);
|
||||
set_border_bottom_right_radius(theme::border::radius_lg);
|
||||
}
|
||||
|
||||
} // namespace recompui
|
||||
|
||||
@@ -39,7 +39,9 @@ namespace recompui {
|
||||
public:
|
||||
ConfigPage(Element *parent);
|
||||
ConfigHeaderFooter *add_header();
|
||||
void hide_header();
|
||||
ConfigHeaderFooter *add_footer();
|
||||
void hide_footer();
|
||||
ConfigHeaderFooter *get_header() { return header; };
|
||||
ConfigBody *get_body() { return body; };
|
||||
ConfigHeaderFooter *get_footer() { return footer; };
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "elements/ui_toggle.h"
|
||||
#include "elements/ui_container.h"
|
||||
#include "elements/ui_binding_button.h"
|
||||
#include "elements/ui_select.h"
|
||||
|
||||
namespace recompui {
|
||||
|
||||
@@ -125,70 +126,179 @@ ConfigPageControls::ConfigPageControls(
|
||||
int num_players,
|
||||
std::vector<GameInputContext> game_input_contexts,
|
||||
std::vector<PlayerBindings> game_input_bindings,
|
||||
std::vector<bool> player_keyboard_enabled,
|
||||
on_player_bind_callback on_player_bind,
|
||||
set_player_keyboard_enabled_callback set_player_keyboard_enabled
|
||||
on_player_bind_callback on_player_bind
|
||||
) : ConfigPage(parent) {
|
||||
this->on_player_bind = on_player_bind;
|
||||
this->game_input_contexts = game_input_contexts;
|
||||
this->num_players = num_players;
|
||||
this->game_input_bindings = game_input_bindings;
|
||||
this->player_keyboard_enabled = player_keyboard_enabled;
|
||||
this->multiplayer_enabled = num_players > 1;
|
||||
|
||||
multiplayer_view_mappings = !multiplayer_enabled;
|
||||
|
||||
set_selected_player(selected_player);
|
||||
|
||||
recompui::ContextId context = get_current_context();
|
||||
|
||||
render_all();
|
||||
}
|
||||
|
||||
void ConfigPageControls::process_event(const Event &e) {
|
||||
switch (e.type) {
|
||||
case EventType::Update:
|
||||
if (last_update_index != update_index) {
|
||||
last_update_index = update_index;
|
||||
render_all();
|
||||
}
|
||||
queue_update();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigPageControls::force_update() {
|
||||
update_index++;
|
||||
}
|
||||
|
||||
void ConfigPageControls::render_all() {
|
||||
render_header();
|
||||
render_body();
|
||||
render_footer();
|
||||
}
|
||||
|
||||
void ConfigPageControls::render_header() {
|
||||
if (!multiplayer_enabled) {
|
||||
hide_header();
|
||||
return;
|
||||
}
|
||||
|
||||
recompui::ContextId context = get_current_context();
|
||||
add_header();
|
||||
|
||||
// header left
|
||||
{
|
||||
auto header_left = header->get_left();
|
||||
for (uint8_t i = 0; i < num_players; i++) {
|
||||
std::string player_text = "P" + std::to_string(i + 1);
|
||||
auto player_button = context.create_element<PillButton>(header_left, player_text, "icons/Cont.svg", ButtonStyle::Basic, PillButtonSize::XLarge);
|
||||
player_elements.push_back(player_button);
|
||||
player_button->add_pressed_callback([this, i]() {
|
||||
set_selected_player(i);
|
||||
update_control_mappings();
|
||||
header_left->clear_children();
|
||||
if (multiplayer_view_mappings) {
|
||||
auto profile_name = context.create_element<Label>(header_left, "Editing: Name of da profile", LabelStyle::Normal);
|
||||
} else {
|
||||
// Nothing rendered here as of now.. maybe single player toggle
|
||||
}
|
||||
}
|
||||
|
||||
// header right
|
||||
{
|
||||
auto header_right = header->get_right();
|
||||
header_right->clear_children();
|
||||
|
||||
if (multiplayer_view_mappings) {
|
||||
Button* go_back_button = context.create_element<Button>(header_right, "Go back", ButtonStyle::Tertiary);
|
||||
go_back_button->add_pressed_callback([this]() {
|
||||
this->multiplayer_view_mappings = false;
|
||||
this->render_all();
|
||||
});
|
||||
} else {
|
||||
Button* assign_players_button = context.create_element<Button>(header_right, "Assign players", ButtonStyle::Primary);
|
||||
assign_players_button->add_pressed_callback([]() {
|
||||
recompui::assign_players_modal->open();
|
||||
recompinput::start_player_assignment();
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
auto header_right = header->get_right();
|
||||
Button* assign_players_button = context.create_element<Button>(header_right, "Assign players", ButtonStyle::Primary);
|
||||
assign_players_button->add_pressed_callback([]() {
|
||||
recompui::assign_players_modal->open();
|
||||
recompinput::start_player_assignment();
|
||||
});
|
||||
}
|
||||
|
||||
void ConfigPageControls::render_body() {
|
||||
bool show_mappings = (multiplayer_enabled && multiplayer_view_mappings) || !multiplayer_enabled;
|
||||
|
||||
recompui::ContextId context = get_current_context();
|
||||
|
||||
if (show_mappings) {
|
||||
body->get_right()->set_display(Display::Flex);
|
||||
render_body_mappings();
|
||||
} else {
|
||||
body->get_right()->set_display(Display::None);
|
||||
render_body_players();
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigPageControls::render_body_mappings() {
|
||||
recompui::ContextId context = get_current_context();
|
||||
|
||||
// left side
|
||||
{
|
||||
render_control_mappings();
|
||||
}
|
||||
|
||||
// right side
|
||||
{
|
||||
description_container = context.create_element<Element>(body->get_right(), 0, "p", true);
|
||||
description_container->set_text(
|
||||
"Sometimes, the windows combine with the seams in a way\n"
|
||||
"That twitches on a peak at the place where the spirit was slain\n"
|
||||
"Hey, one foot leads to another\n"
|
||||
"Night's for sleep, blue curtains, covers, sequins in the eyes\n"
|
||||
"That's a fine time to dine\n"
|
||||
"Divine who's circling, feeding the cards to the midwives"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigPageControls::render_body_players() {
|
||||
recompui::ContextId context = get_current_context();
|
||||
|
||||
auto body_left = body->get_left();
|
||||
body_left->clear_children();
|
||||
|
||||
auto player_grid = context.create_element<Element>(body_left, 0, "div", false);
|
||||
player_grid->set_display(Display::Flex);
|
||||
player_grid->set_flex_direction(FlexDirection::Row);
|
||||
player_grid->set_flex_wrap(FlexWrap::Wrap);
|
||||
player_grid->set_justify_content(JustifyContent::SpaceBetween);
|
||||
player_grid->set_align_items(AlignItems::Center);
|
||||
player_grid->set_width(100.0f, Unit::Percent);
|
||||
player_grid->set_height_auto();
|
||||
player_grid->set_gap(64.0f);
|
||||
|
||||
for (int i = 0; i < num_players; i++) {
|
||||
auto player_card = context.create_element<PlayerCard>(
|
||||
player_grid,
|
||||
i,
|
||||
false
|
||||
);
|
||||
player_cards.push_back(player_card);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigPageControls::render_footer() {
|
||||
if (multiplayer_enabled && !multiplayer_view_mappings) {
|
||||
hide_footer();
|
||||
return;
|
||||
}
|
||||
|
||||
recompui::ContextId context = get_current_context();
|
||||
|
||||
add_footer();
|
||||
{
|
||||
auto footer_left = footer->get_left();
|
||||
keyboard_toggle = context.create_element<Toggle>(footer_left);
|
||||
keyboard_toggle->set_checked(player_keyboard_enabled[selected_player]);
|
||||
keyboard_toggle->add_checked_callback([this, set_player_keyboard_enabled](bool checked) {
|
||||
set_player_keyboard_enabled(this->selected_player, checked);
|
||||
update_control_mappings();
|
||||
});
|
||||
auto kb_label = context.create_element<Label>(footer_left, "Enable keyboard", LabelStyle::Normal);
|
||||
kb_label->set_margin_left(12.0f);
|
||||
footer_left->clear_children();
|
||||
if (!multiplayer_enabled) {
|
||||
keyboard_toggle = context.create_element<Toggle>(footer_left);
|
||||
keyboard_toggle->set_checked(single_player_show_keyboard_mappings);
|
||||
keyboard_toggle->add_checked_callback([this](bool checked) {
|
||||
this->single_player_show_keyboard_mappings = checked;
|
||||
this->update_control_mappings();
|
||||
});
|
||||
Label *kb_label = context.create_element<Label>(footer_left, "Enable keyboard", LabelStyle::Normal);
|
||||
kb_label->set_margin_left(12.0f);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto footer_right = footer->get_right();
|
||||
footer_right->clear_children();
|
||||
context.create_element<Button>(footer_right, "Reset to defaults", ButtonStyle::Warning);
|
||||
// TODO: Add reset to defaults callback
|
||||
}
|
||||
|
||||
description_container = context.create_element<Element>(body->get_right(), 0, "p", true);
|
||||
description_container->set_text(
|
||||
"Sometimes, the windows combine with the seams in a way\n"
|
||||
"That twitches on a peak at the place where the spirit was slain\n"
|
||||
"Hey, one foot leads to another\n"
|
||||
"Night's for sleep, blue curtains, covers, sequins in the eyes\n"
|
||||
"That's a fine time to dine\n"
|
||||
"Divine who's circling, feeding the cards to the midwives"
|
||||
);
|
||||
|
||||
set_selected_player(selected_player);
|
||||
render_control_mappings();
|
||||
}
|
||||
|
||||
void ConfigPageControls::render_control_mappings() {
|
||||
@@ -240,29 +350,7 @@ void ConfigPageControls::on_bind_click(recompinput::GameInput game_input, int in
|
||||
}
|
||||
|
||||
void ConfigPageControls::set_selected_player(int player) {
|
||||
static const std::array<theme::color, 8> player_colors = {
|
||||
theme::color::Player1,
|
||||
theme::color::Player2,
|
||||
theme::color::Player3,
|
||||
theme::color::Player4,
|
||||
theme::color::Player5,
|
||||
theme::color::Player6,
|
||||
theme::color::Player7,
|
||||
theme::color::Player8
|
||||
};
|
||||
|
||||
selected_player = player;
|
||||
for (uint8_t i = 0; i < num_players; i++) {
|
||||
auto player_button = player_elements[i];
|
||||
theme::color player_color = player_colors[i % player_colors.size()];
|
||||
if (i == selected_player) {
|
||||
player_button->apply_theme_style(player_color, false, true);
|
||||
} else {
|
||||
player_button->apply_theme_style(player_color, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
keyboard_toggle->set_checked(player_keyboard_enabled[selected_player]);
|
||||
}
|
||||
|
||||
void ConfigPageControls::on_option_hover(uint8_t index) {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "elements/ui_binding_button.h"
|
||||
#include "elements/ui_pill_button.h"
|
||||
#include "elements/ui_toggle.h"
|
||||
#include "ui_player_card.h"
|
||||
|
||||
// TODO: remove after moving to recompinput
|
||||
namespace recompinput {
|
||||
@@ -61,41 +62,52 @@ public:
|
||||
|
||||
using PlayerBindings = std::map<recompinput::GameInput, BindingList>;
|
||||
|
||||
// Sets if keyboard should be enabled, first arg player index, second is a bool to enable/disable
|
||||
using set_player_keyboard_enabled_callback = std::function<void(int, bool)>;
|
||||
|
||||
class ConfigPageControls : public ConfigPage {
|
||||
protected:
|
||||
// for tracking forced updates to entire page (major changes like player reassignment or singleplayer mode)
|
||||
int last_update_index = 0;
|
||||
int update_index = 0;
|
||||
|
||||
int selected_player = 0;
|
||||
int num_players;
|
||||
|
||||
bool multiplayer_enabled;
|
||||
bool multiplayer_view_mappings;
|
||||
|
||||
bool single_player_show_keyboard_mappings = false;
|
||||
|
||||
std::vector<GameInputContext> game_input_contexts;
|
||||
std::vector<PlayerBindings> game_input_bindings;
|
||||
std::vector<bool> player_keyboard_enabled;
|
||||
|
||||
std::vector<PillButton*> player_elements;
|
||||
std::vector<PlayerCard*> player_cards;
|
||||
std::vector<GameInputRow*> game_input_rows;
|
||||
Toggle *keyboard_toggle;
|
||||
Element *description_container = nullptr;
|
||||
on_player_bind_callback on_player_bind;
|
||||
|
||||
virtual void process_event(const Event &e) override;
|
||||
std::string_view get_type_name() override { return "ConfigPageControls"; }
|
||||
private:
|
||||
void on_option_hover(uint8_t index);
|
||||
void on_bind_click(recompinput::GameInput game_input, int input_index);
|
||||
|
||||
void render_all();
|
||||
void render_header();
|
||||
void render_body();
|
||||
void render_body_players();
|
||||
void render_body_mappings();
|
||||
void render_footer();
|
||||
public:
|
||||
ConfigPageControls(
|
||||
Element *parent,
|
||||
int num_players,
|
||||
std::vector<GameInputContext> game_input_contexts,
|
||||
std::vector<PlayerBindings> game_input_bindings,
|
||||
std::vector<bool> player_keyboard_enabled,
|
||||
on_player_bind_callback on_player_bind,
|
||||
set_player_keyboard_enabled_callback set_player_keyboard_enabled
|
||||
on_player_bind_callback on_player_bind
|
||||
);
|
||||
virtual ~ConfigPageControls();
|
||||
|
||||
|
||||
void force_update();
|
||||
void render_control_mappings();
|
||||
void update_control_mappings();
|
||||
void set_selected_player(int player);
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace recompinput {
|
||||
|
||||
namespace recompui {
|
||||
|
||||
ConfigPageControls *config_page;
|
||||
ConfigPageControls *controls_page = nullptr;
|
||||
|
||||
static bool is_multiplayer_enabled() {
|
||||
return true;
|
||||
@@ -64,27 +64,6 @@ static void temp_on_bind_player(int player_index, recompinput::GameInput game_in
|
||||
temp_binding_info.is_scanning = true;
|
||||
}
|
||||
|
||||
static uint8_t get_num_players() {
|
||||
return temp_local_player_bindings.size();
|
||||
}
|
||||
|
||||
static std::vector<bool> temp_local_player_has_keyboard_enabled = {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
};
|
||||
|
||||
static void temp_set_keyboard_player_enabled(uint8_t player, bool enabled) {
|
||||
temp_local_player_has_keyboard_enabled[player] = enabled;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ElementConfigPageControls::ElementConfigPageControls(const Rml::String& tag) : Rml::Element(tag) {
|
||||
SetProperty(Rml::PropertyId::Display, Rml::Style::Display::Block);
|
||||
SetProperty("width", "100%");
|
||||
@@ -96,14 +75,12 @@ ElementConfigPageControls::ElementConfigPageControls(const Rml::String& tag) : R
|
||||
// TODO: remove temp stores
|
||||
temp_set_all_defaults();
|
||||
|
||||
config_page = context.create_element<ConfigPageControls>(
|
||||
controls_page = context.create_element<ConfigPageControls>(
|
||||
&this_compat,
|
||||
get_num_players(),
|
||||
recompinput::get_num_players(),
|
||||
temp_game_input_contexts,
|
||||
temp_local_player_bindings,
|
||||
temp_local_player_has_keyboard_enabled,
|
||||
temp_on_bind_player,
|
||||
temp_set_keyboard_player_enabled
|
||||
temp_on_bind_player
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace recompui {
|
||||
|
||||
extern ConfigPageControls *config_page;
|
||||
extern ConfigPageControls *controls_page;
|
||||
|
||||
class ElementConfigPageControls : public Rml::Element {
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user