controls page multi vs single views

This commit is contained in:
thecozies
2025-07-28 09:55:20 -05:00
parent 261ed2b44b
commit 9fa9602772
7 changed files with 192 additions and 100 deletions
+6 -1
View File
@@ -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);
}
}
}
+9 -1
View File
@@ -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
+2
View File
@@ -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; };
+149 -61
View File
@@ -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) {
+21 -9
View File
@@ -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);
+4 -27
View File
@@ -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
);
}
+1 -1
View File
@@ -6,7 +6,7 @@
namespace recompui {
extern ConfigPageControls *config_page;
extern ConfigPageControls *controls_page;
class ElementConfigPageControls : public Rml::Element {
public: