219 lines
7.1 KiB
C++
219 lines
7.1 KiB
C++
#include "define_buttons.h"
|
|
|
|
#include <algorithm> // Para __all_of_fn, all_of
|
|
#include <functional> // Para identity
|
|
#include <memory> // Para allocator, unique_ptr, shared_ptr, make_unique, operator==
|
|
|
|
#include "color.h" // Para Color
|
|
#include "input.h" // Para Input
|
|
#include "input_types.h" // Para InputAction
|
|
#include "lang.h" // Para getText
|
|
#include "options.h" // Para Gamepad
|
|
#include "param.h" // Para Param, ParamGame, param
|
|
#include "resource.h" // Para Resource
|
|
#include "ui/window_message.h" // Para WindowMessage
|
|
#include "utils.h" // Para Zone
|
|
|
|
DefineButtons::DefineButtons()
|
|
: input_(Input::get()) {
|
|
clearButtons();
|
|
|
|
auto gamepads = input_->getGamepads();
|
|
for (auto gamepad : gamepads) {
|
|
controller_names_.emplace_back(Input::getControllerName(gamepad));
|
|
}
|
|
|
|
// Crear la ventana de mensaje
|
|
WindowMessage::Config config;
|
|
config.bg_color = Color{20, 30, 50, 240}; // Fondo azul oscuro semi-transparente
|
|
config.border_color = Color{100, 150, 200, 255}; // Borde azul claro
|
|
config.title_color = Color{100, 150, 200, 255}; // Titulo azul claro
|
|
config.text_color = Color{220, 220, 220, 255}; // Texto gris claro
|
|
config.padding = 15.0F;
|
|
config.line_spacing = 5.0F;
|
|
config.title_separator_spacing = 15;
|
|
config.min_width = 250.0F;
|
|
config.text_safety_margin = 15.0F;
|
|
config.min_width = 100;
|
|
config.min_height = 32;
|
|
config.animation_duration = 0.3F;
|
|
|
|
auto text_renderer = Resource::get()->getText("04b_25_flat");
|
|
window_message_ = std::make_unique<WindowMessage>(
|
|
text_renderer,
|
|
Lang::getText("[DEFINE_BUTTONS] TITLE"),
|
|
config);
|
|
window_message_->setPosition(param.game.game_area.center_x, param.game.game_area.center_y, WindowMessage::PositionMode::CENTERED);
|
|
}
|
|
|
|
void DefineButtons::render() {
|
|
if (enabled_ && window_message_) {
|
|
window_message_->render();
|
|
}
|
|
}
|
|
|
|
void DefineButtons::update() {
|
|
if (!enabled_) {
|
|
return;
|
|
}
|
|
|
|
// Actualizar la ventana siempre
|
|
if (window_message_) {
|
|
window_message_->update();
|
|
}
|
|
|
|
// Manejar la secuencia de cierre si ya terminamos
|
|
if (finished_ && message_shown_) {
|
|
message_timer_++;
|
|
|
|
// Después del delay, iniciar animación de cierre (solo una vez)
|
|
if (message_timer_ > MESSAGE_DISPLAY_FRAMES && !closing_) {
|
|
if (window_message_) {
|
|
window_message_->hide(); // Iniciar animación de cierre
|
|
}
|
|
closing_ = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DefineButtons::handleEvents(const SDL_Event &event) {
|
|
if (enabled_) {
|
|
switch (event.type) {
|
|
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
|
doControllerButtonDown(event.gbutton);
|
|
break;
|
|
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
|
checkEnd();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
auto DefineButtons::enable(Options::Gamepad *options_gamepad) -> bool {
|
|
if (options_gamepad != nullptr) {
|
|
options_gamepad_ = options_gamepad;
|
|
enabled_ = true;
|
|
finished_ = false;
|
|
index_button_ = 0;
|
|
message_shown_ = false;
|
|
closing_ = false;
|
|
clearButtons();
|
|
updateWindowMessage();
|
|
|
|
if (window_message_) {
|
|
window_message_->autoSize();
|
|
window_message_->show();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void DefineButtons::disable() {
|
|
enabled_ = false;
|
|
finished_ = false;
|
|
message_shown_ = false;
|
|
closing_ = false;
|
|
|
|
if (window_message_) {
|
|
window_message_->hide();
|
|
}
|
|
}
|
|
|
|
void DefineButtons::doControllerButtonDown(const SDL_GamepadButtonEvent &event) {
|
|
auto gamepad = input_->getGamepad(event.which);
|
|
|
|
if (!gamepad || gamepad != options_gamepad_->instance) {
|
|
return;
|
|
}
|
|
|
|
const auto BUTTON = static_cast<SDL_GamepadButton>(event.button);
|
|
if (checkButtonNotInUse(BUTTON)) {
|
|
buttons_.at(index_button_).button = BUTTON;
|
|
incIndexButton();
|
|
updateWindowMessage();
|
|
}
|
|
}
|
|
|
|
void DefineButtons::bindButtons(Options::Gamepad *options_gamepad) {
|
|
for (const auto &button : buttons_) {
|
|
Input::bindGameControllerButton(options_gamepad->instance, button.action, button.button);
|
|
}
|
|
|
|
Input::bindGameControllerButton(options_gamepad->instance, Input::Action::SM_SELECT, Input::Action::FIRE_LEFT);
|
|
Input::bindGameControllerButton(options_gamepad->instance, Input::Action::SM_BACK, Input::Action::FIRE_CENTER);
|
|
}
|
|
|
|
void DefineButtons::incIndexButton() {
|
|
if (index_button_ < buttons_.size() - 1) {
|
|
++index_button_;
|
|
} else {
|
|
finished_ = true;
|
|
}
|
|
}
|
|
|
|
auto DefineButtons::checkButtonNotInUse(SDL_GamepadButton button) -> bool {
|
|
return std::ranges::all_of(buttons_, [button](const auto &b) {
|
|
return b.button != button;
|
|
});
|
|
}
|
|
|
|
void DefineButtons::clearButtons() {
|
|
buttons_.clear();
|
|
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_LEFT"), Input::Action::FIRE_LEFT, SDL_GAMEPAD_BUTTON_INVALID);
|
|
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_UP"), Input::Action::FIRE_CENTER, SDL_GAMEPAD_BUTTON_INVALID);
|
|
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_RIGHT"), Input::Action::FIRE_RIGHT, SDL_GAMEPAD_BUTTON_INVALID);
|
|
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] START"), Input::Action::START, SDL_GAMEPAD_BUTTON_INVALID);
|
|
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] SERVICE_MENU"), Input::Action::SERVICE, SDL_GAMEPAD_BUTTON_INVALID);
|
|
}
|
|
|
|
void DefineButtons::checkEnd() {
|
|
if (finished_ && !message_shown_) {
|
|
bindButtons(options_gamepad_);
|
|
input_->saveGamepadConfigFromGamepad(options_gamepad_->instance);
|
|
input_->resetInputStates();
|
|
|
|
// Mostrar mensaje de finalización
|
|
if (window_message_) {
|
|
window_message_->clearTexts();
|
|
window_message_->addText(Lang::getText("[DEFINE_BUTTONS] CONFIGURATION_COMPLETE"));
|
|
}
|
|
|
|
// Solo marcar que ya mostramos el mensaje
|
|
message_shown_ = true;
|
|
message_timer_ = 0;
|
|
}
|
|
}
|
|
|
|
auto DefineButtons::isReadyToClose() const -> bool {
|
|
// Solo está listo para cerrar si:
|
|
// 1. Terminó
|
|
// 2. Ya mostró el mensaje
|
|
// 3. Está cerrando
|
|
// 4. La ventana ya no está visible (animación terminada)
|
|
return finished_ && message_shown_ && closing_ &&
|
|
(!window_message_ || !window_message_->isVisible());
|
|
}
|
|
|
|
void DefineButtons::updateWindowMessage() {
|
|
if (!window_message_ || (options_gamepad_ == nullptr)) {
|
|
return;
|
|
}
|
|
|
|
// Configurar título
|
|
std::string title = Lang::getText("[DEFINE_BUTTONS] CONFIGURING") + ": " + options_gamepad_->name;
|
|
window_message_->setTitle(title);
|
|
|
|
// Limpiar textos anteriores
|
|
window_message_->clearTexts();
|
|
|
|
if (index_button_ < buttons_.size()) {
|
|
// Instrucción actual
|
|
std::string instruction = Lang::getText("[DEFINE_BUTTONS] PRESS_BUTTON_FOR") + ":";
|
|
window_message_->addText(instruction);
|
|
window_message_->addText(buttons_.at(index_button_).label);
|
|
}
|
|
} |