#pragma once #include // Para max, clamp #include // Para size_t #include // Para function #include // Para allocator, string, basic_string, to_string, operator==, char_traits #include // Para move #include // Para vector #include "lang.h" // Para getText #include "text.h" // Para Text #include "ui/service_menu.h" // Para ServiceMenu // --- Clase MenuOption: interfaz base para todas las opciones del menú --- class MenuOption { public: // --- Enums --- enum class Behavior { ADJUST, // Solo puede ajustar valor (como IntOption, BoolOption, ListOption) SELECT, // Solo puede ejecutar acción (como ActionOption, FolderOption) BOTH // Puede tanto ajustar como ejecutar acción (como ActionListOption) }; // --- Constructor y destructor --- MenuOption(std::string caption, ServiceMenu::SettingsGroup group, bool hidden = false) : caption_(std::move(caption)), group_(group), hidden_(hidden) {} virtual ~MenuOption() = default; // --- Getters --- [[nodiscard]] auto getCaption() const -> const std::string & { return caption_; } [[nodiscard]] auto getGroup() const -> ServiceMenu::SettingsGroup { return group_; } [[nodiscard]] auto isHidden() const -> bool { return hidden_; } void setHidden(bool hidden) { hidden_ = hidden; } [[nodiscard]] virtual auto getBehavior() const -> Behavior = 0; [[nodiscard]] virtual auto getValueAsString() const -> std::string { return ""; } virtual void adjustValue(bool adjust_up) {} [[nodiscard]] virtual auto getTargetGroup() const -> ServiceMenu::SettingsGroup { return ServiceMenu::SettingsGroup::MAIN; } virtual void executeAction() {} virtual auto getMaxValueWidth(Text *text_renderer) const -> int { return 0; } // Método virtual para que cada opción calcule el ancho de su valor más largo protected: // --- Variables --- std::string caption_; ServiceMenu::SettingsGroup group_; bool hidden_; }; // --- Clases Derivadas --- class BoolOption : public MenuOption { public: BoolOption(const std::string &cap, ServiceMenu::SettingsGroup grp, bool *var) : MenuOption(cap, grp), linked_variable_(var) {} [[nodiscard]] auto getBehavior() const -> Behavior override { return Behavior::ADJUST; } [[nodiscard]] auto getValueAsString() const -> std::string override { return *linked_variable_ ? Lang::getText("[SERVICE_MENU] ON") : Lang::getText("[SERVICE_MENU] OFF"); } void adjustValue(bool /*adjust_up*/) override { *linked_variable_ = !*linked_variable_; } auto getMaxValueWidth(Text *text_renderer) const -> int override { return std::max( text_renderer->length(Lang::getText("[SERVICE_MENU] ON"), -2), text_renderer->length(Lang::getText("[SERVICE_MENU] OFF"), -2)); } private: bool *linked_variable_; }; 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) {} [[nodiscard]] auto getBehavior() const -> Behavior override { return Behavior::ADJUST; } [[nodiscard]] auto getValueAsString() const -> std::string override { return std::to_string(*linked_variable_); } void adjustValue(bool adjust_up) override { int new_value = *linked_variable_ + (adjust_up ? step_value_ : -step_value_); *linked_variable_ = std::clamp(new_value, min_value_, max_value_); } auto getMaxValueWidth(Text *text_renderer) const -> int override { int max_width = 0; // Iterar por todos los valores posibles en el rango for (int value = min_value_; value <= max_value_; value += step_value_) { int width = text_renderer->length(std::to_string(value), -2); max_width = std::max(max_width, width); } return max_width; } private: int *linked_variable_; int min_value_, max_value_, step_value_; }; class ListOption : public MenuOption { public: ListOption(const std::string &cap, ServiceMenu::SettingsGroup grp, std::vector values, std::function current_value_getter, std::function new_value_setter) : MenuOption(cap, grp), value_list_(std::move(values)), getter_(std::move(current_value_getter)), setter_(std::move(new_value_setter)) { sync(); } void sync() { std::string current_value = getter_(); for (size_t i = 0; i < value_list_.size(); ++i) { if (value_list_[i] == current_value) { list_index_ = i; return; } } } [[nodiscard]] auto getBehavior() const -> Behavior override { return Behavior::ADJUST; } [[nodiscard]] auto getValueAsString() const -> std::string 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; setter_(value_list_[list_index_]); } auto getMaxValueWidth(Text *text_renderer) const -> int override { int max_w = 0; for (const auto &val : value_list_) { max_w = std::max(max_w, text_renderer->length(val, -2)); } return max_w; } private: std::vector value_list_; std::function getter_; std::function setter_; size_t list_index_{0}; }; class FolderOption : public MenuOption { public: FolderOption(const std::string &cap, ServiceMenu::SettingsGroup grp, ServiceMenu::SettingsGroup target) : MenuOption(cap, grp), target_group_(target) {} [[nodiscard]] auto getBehavior() const -> Behavior override { return Behavior::SELECT; } [[nodiscard]] auto getTargetGroup() const -> ServiceMenu::SettingsGroup override { return target_group_; } private: ServiceMenu::SettingsGroup target_group_; }; class ActionOption : public MenuOption { public: ActionOption(const std::string &cap, ServiceMenu::SettingsGroup grp, std::function action, bool hidden = false) : MenuOption(cap, grp, hidden), action_(std::move(action)) {} [[nodiscard]] auto getBehavior() const -> Behavior override { return Behavior::SELECT; } void executeAction() override { if (action_) { action_(); } } private: std::function action_; }; // Opción de lista con acción class ActionListOption : public MenuOption { public: using ValueGetter = std::function; using ValueSetter = std::function; using ActionExecutor = std::function; ActionListOption(const std::string &caption, ServiceMenu::SettingsGroup group, std::vector options, ValueGetter getter, ValueSetter setter, ActionExecutor action_executor, bool hidden = false) : MenuOption(caption, group, hidden), options_(std::move(options)), value_getter_(std::move(getter)), value_setter_(std::move(setter)), action_executor_(std::move(action_executor)) { updateCurrentIndex(); } [[nodiscard]] auto getBehavior() const -> Behavior override { return Behavior::BOTH; } [[nodiscard]] auto getValueAsString() const -> std::string override; [[nodiscard]] auto getMaxValueWidth(Text *text) const -> int override; void adjustValue(bool up) override; void executeAction() override; void sync(); // Sincroniza con el valor actual private: std::vector options_; ValueGetter value_getter_; ValueSetter value_setter_; ActionExecutor action_executor_; size_t current_index_{0}; void updateCurrentIndex(); [[nodiscard]] auto findCurrentIndex() const -> size_t; };