#pragma once #include #include #include #include #include // para std::clamp #include "service_menu.h" // Necesitamos las enums como SettingsGroup #include "options.h" // Para acceder a las variables de configuración #include "lang.h" // Para las traducciones #include "section.h" // Para las acciones como Quit o Reset // --- Interfaz Base para todas las Opciones del Menú --- class MenuOption { public: // Enum para el comportamiento, similar al anterior pero más integrado enum class Behavior { ADJUST, SELECT }; // Constructor base MenuOption(std::string caption, ServiceMenu::SettingsGroup group, bool hidden = false) : caption_(std::move(caption)), group_(group), hidden_(hidden) {} // Destructor virtual para permitir la destrucción polimórfica correcta virtual ~MenuOption() = default; // Métodos comunes que todas las opciones deben tener const std::string &getCaption() const { return caption_; } ServiceMenu::SettingsGroup getGroup() const { return group_; } bool isHidden() const { return hidden_; } void setHidden(bool hidden) { hidden_ = hidden; } // Métodos virtuales que las clases derivadas implementarán según su naturaleza virtual Behavior getBehavior() const = 0; virtual std::string getValueAsString() const { return ""; } virtual void adjustValue(bool adjust_up) {} // Implementado por opciones ajustables virtual ServiceMenu::SettingsGroup getTargetGroup() const { return ServiceMenu::SettingsGroup::MAIN; } // Implementado por FolderOption virtual void executeAction() {} // Implementado por ActionOption protected: std::string caption_; ServiceMenu::SettingsGroup group_; bool hidden_; }; // --- Clases Derivadas --- // 1. Opción Booleana (On/Off) class BoolOption : public MenuOption { public: BoolOption(const std::string &cap, ServiceMenu::SettingsGroup grp, bool *var) : MenuOption(cap, grp), linked_variable_(var) {} Behavior getBehavior() const override { return Behavior::ADJUST; } std::string getValueAsString() const override { return *linked_variable_ ? Lang::getText("[SERVICE_MENU] ON") : Lang::getText("[SERVICE_MENU] OFF"); } void adjustValue(bool /*adjust_up*/) override { *linked_variable_ = !*linked_variable_; } private: bool *linked_variable_; }; // 2. Opción de Entero (Volumen, Tamaño Ventana, etc.) class IntOption : public MenuOption { public: IntOption(const std::string &cap, ServiceMenu::SettingsGroup grp, int *var, int min, int max, int step) : MenuOption(cap, grp), linked_variable_(var), min_value_(min), max_value_(max), step_value_(step) {} Behavior getBehavior() const override { return Behavior::ADJUST; } std::string getValueAsString() const override { return std::to_string(*linked_variable_); } void adjustValue(bool adjust_up) override { int newValue = *linked_variable_ + (adjust_up ? step_value_ : -step_value_); *linked_variable_ = std::clamp(newValue, min_value_, max_value_); } private: int *linked_variable_; int min_value_, max_value_, step_value_; }; // 3. Opción de Lista (Idioma, Dificultad) class ListOption : public MenuOption { public: ListOption(const std::string &cap, ServiceMenu::SettingsGroup grp, std::string *var, std::vector values) : MenuOption(cap, grp), linked_variable_(var), value_list_(std::move(values)), list_index_(0) {} void sync() { // Sincroniza el índice con el valor actual de la variable for (size_t i = 0; i < value_list_.size(); ++i) { std::string code; if (linked_variable_ == &Options::pending_changes.new_language) { code = Lang::getCodeFromName(value_list_[i]); } else if (linked_variable_ == &Options::pending_changes.new_difficulty) { code = Options::getDifficultyCodeFromName(value_list_[i]); } if (code == *linked_variable_) { list_index_ = i; return; } } } Behavior getBehavior() const override { return Behavior::ADJUST; } std::string getValueAsString() const override { return value_list_.empty() ? "" : value_list_[list_index_]; } void adjustValue(bool adjust_up) override { if (value_list_.empty()) return; size_t size = value_list_.size(); list_index_ = (adjust_up) ? (list_index_ + 1) % size : (list_index_ + size - 1) % size; // Actualiza la variable real y comprueba cambios pendientes if (linked_variable_ == &Options::pending_changes.new_language) { *linked_variable_ = Lang::getCodeFromName(value_list_[list_index_]); } else if (linked_variable_ == &Options::pending_changes.new_difficulty) { *linked_variable_ = Options::getDifficultyCodeFromName(value_list_[list_index_]); } Options::checkPendingChanges(); } private: std::string *linked_variable_; std::vector value_list_; size_t list_index_; }; // 4. Opción Carpeta (Navega a otro sub-menú) class FolderOption : public MenuOption { public: FolderOption(const std::string &cap, ServiceMenu::SettingsGroup grp, ServiceMenu::SettingsGroup target) : MenuOption(cap, grp), target_group_(target) {} Behavior getBehavior() const override { return Behavior::SELECT; } ServiceMenu::SettingsGroup getTargetGroup() const override { return target_group_; } private: ServiceMenu::SettingsGroup target_group_; }; // 5. Opción de Acción (Ejecuta una función) class ActionOption : public MenuOption { public: // Usamos std::function para poder pasar cualquier función/lambda ActionOption(const std::string &cap, ServiceMenu::SettingsGroup grp, std::function action, bool hidden = false) : MenuOption(cap, grp, hidden), action_(std::move(action)) {} Behavior getBehavior() const override { return Behavior::SELECT; } void executeAction() override { if (action_) action_(); } private: std::function action_; };