mirror of
				https://github.com/Zelda64Recomp/Zelda64Recomp.git
				synced 2025-10-30 08:03:03 +00:00 
			
		
		
		
	Manual navigation in UI framework and WIP mod menu navigation
This commit is contained in:
		
							parent
							
								
									6166fffc99
								
							
						
					
					
						commit
						afc880521c
					
				
					 23 changed files with 128 additions and 12 deletions
				
			
		|  | @ -466,6 +466,8 @@ recompui::Style* recompui::ContextId::add_resource_impl(std::unique_ptr<Style>&& | |||
|     auto key = opened_context->resources.emplace(std::move(resource)); | ||||
| 
 | ||||
|     if (is_element) { | ||||
|         Element* element_ptr = static_cast<Element*>(resource_ptr); | ||||
|         element_ptr->set_id(std::string{element_ptr->get_type_name()} + "-" + std::to_string(key.raw)); | ||||
|         key.set_tag(static_cast<uint8_t>(SlotTag::Element)); | ||||
|         // Send one update to the element.
 | ||||
|         opened_context->to_update.emplace(ResourceId{ key.raw }); | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ namespace recompui { | |||
| 
 | ||||
|         // Element overrides.
 | ||||
|         virtual void process_event(const Event &e) override; | ||||
|         std::string_view get_type_name() override { return "Button"; } | ||||
|     public: | ||||
|         Button(Element *parent, const std::string &text, ButtonStyle style); | ||||
|         void add_pressed_callback(std::function<void()> callback); | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ namespace recompui { | |||
| 
 | ||||
|         // Element overrides.
 | ||||
|         virtual void process_event(const Event &e) override; | ||||
|         std::string_view get_type_name() override { return "Clickable"; } | ||||
|     public: | ||||
|         Clickable(Element *parent, bool draggable = false); | ||||
|         void add_pressed_callback(std::function<void(float, float)> callback); | ||||
|  |  | |||
|  | @ -5,6 +5,8 @@ | |||
| namespace recompui { | ||||
| 
 | ||||
|     class Container : public Element { | ||||
|     protected: | ||||
|         std::string_view get_type_name() override { return "Container"; } | ||||
|     public: | ||||
|         Container(Element* parent, FlexDirection direction, JustifyContent justify_content); | ||||
|     }; | ||||
|  |  | |||
|  | @ -147,6 +147,11 @@ void Element::handle_event(const Event& event) { | |||
|     process_event(event); | ||||
| } | ||||
| 
 | ||||
| void Element::set_id(const std::string& new_id) { | ||||
|     id = new_id; | ||||
|     base->SetId(new_id); | ||||
| } | ||||
| 
 | ||||
| void Element::ProcessEvent(Rml::Event &event) { | ||||
|     ContextId prev_context = recompui::try_close_current_context(); | ||||
|     ContextId context = ContextId::null(); | ||||
|  |  | |||
|  | @ -33,6 +33,7 @@ private: | |||
|     std::unordered_multimap<std::string_view, uint32_t> style_name_index_map; | ||||
|     std::vector<UICallback> callbacks; | ||||
|     std::vector<Element *> children; | ||||
|     std::string id; | ||||
|     bool shim = false; | ||||
|     bool enabled = true; | ||||
|     bool disabled_attribute = false; | ||||
|  | @ -44,6 +45,7 @@ private: | |||
|     void apply_style(Style *style); | ||||
|     void propagate_disabled(bool disabled); | ||||
|     void handle_event(const Event &e); | ||||
|     void set_id(const std::string& new_id); | ||||
| 
 | ||||
|     // Style overrides.
 | ||||
|     virtual void set_property(Rml::PropertyId property_id, const Rml::Property &property) override; | ||||
|  | @ -56,6 +58,7 @@ protected: | |||
|     virtual void process_event(const Event &e); | ||||
|     virtual ElementValue get_element_value() { return std::monostate{}; } | ||||
|     virtual void set_input_value(const ElementValue&) {} | ||||
|     virtual std::string_view get_type_name() { return "Element"; } | ||||
| public: | ||||
|     // Used for backwards compatibility with legacy UI elements.
 | ||||
|     Element(Rml::Element *base); | ||||
|  | @ -94,6 +97,7 @@ public: | |||
|     void set_input_value_u32(uint32_t val) { set_input_value(val); } | ||||
|     void set_input_value_float(float val) { set_input_value(val); } | ||||
|     void set_input_value_double(double val) { set_input_value(val); } | ||||
|     const std::string& get_id() { return id; } | ||||
| }; | ||||
| 
 | ||||
| void queue_ui_callback(recompui::ResourceId resource, const Event& e, const UICallback& callback); | ||||
|  |  | |||
|  | @ -5,6 +5,8 @@ | |||
| namespace recompui { | ||||
| 
 | ||||
|     class Image : public Element { | ||||
|     protected: | ||||
|         std::string_view get_type_name() override { return "ImageView"; } | ||||
|     public: | ||||
|         Image(Element *parent, std::string_view src); | ||||
|     }; | ||||
|  |  | |||
|  | @ -12,6 +12,8 @@ namespace recompui { | |||
|     }; | ||||
| 
 | ||||
|     class Label : public Element { | ||||
|     protected: | ||||
|         std::string_view get_type_name() override { return "Label"; } | ||||
|     public: | ||||
|         Label(Element *parent, LabelStyle label_style); | ||||
|         Label(Element *parent, const std::string &text, LabelStyle label_style); | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ namespace recompui { | |||
|         uint32_t index = 0; | ||||
|     protected: | ||||
|         virtual void process_event(const Event &e) override; | ||||
|         std::string_view get_type_name() override { return "LabelRadioOption"; } | ||||
|     public: | ||||
|         RadioOption(Element *parent, std::string_view name, uint32_t index); | ||||
|         void set_pressed_callback(std::function<void(uint32_t)> callback); | ||||
|  | @ -29,6 +30,8 @@ namespace recompui { | |||
|         void option_selected(uint32_t index); | ||||
|         void set_input_value(const ElementValue& val) override; | ||||
|         ElementValue get_element_value() override { return get_index(); } | ||||
|     protected: | ||||
|         std::string_view get_type_name() override { return "LabelRadio"; } | ||||
|     public: | ||||
|         Radio(Element *parent); | ||||
|         virtual ~Radio(); | ||||
|  |  | |||
|  | @ -10,6 +10,8 @@ namespace recompui { | |||
|     }; | ||||
| 
 | ||||
|     class ScrollContainer : public Element { | ||||
|     protected: | ||||
|         std::string_view get_type_name() override { return "ScrollContainer"; } | ||||
|     public: | ||||
|         ScrollContainer(Element *parent, ScrollDirection direction); | ||||
|     }; | ||||
|  |  | |||
|  | @ -36,6 +36,7 @@ namespace recompui { | |||
| 
 | ||||
|     protected: | ||||
|         virtual void process_event(const Event &e) override; | ||||
|         std::string_view get_type_name() override { return "Slider"; } | ||||
| 
 | ||||
|     public: | ||||
|         Slider(Element *parent, SliderType type); | ||||
|  |  | |||
|  | @ -6,6 +6,8 @@ | |||
| namespace recompui { | ||||
| 
 | ||||
|     class Span : public Element { | ||||
|     protected: | ||||
|         std::string_view get_type_name() override { return "Span"; } | ||||
|     public: | ||||
|         Span(Element *parent); | ||||
|         Span(Element *parent, const std::string &text); | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| #include "ui_style.h" | ||||
| #include "ui_element.h" | ||||
| 
 | ||||
| #include <cassert> | ||||
| 
 | ||||
|  | @ -587,6 +588,14 @@ namespace recompui { | |||
|         set_property(nav_to_property(dir), Rml::Style::Nav::None); | ||||
|     } | ||||
| 
 | ||||
|     void Style::set_nav(NavDirection dir, Element* element) { | ||||
|         set_property(nav_to_property(dir), Rml::Property(Rml::String{ "#" + element->get_id() }, Rml::Unit::STRING)); | ||||
|     } | ||||
| 
 | ||||
|     void Style::set_nav_manual(NavDirection dir, const std::string& target) { | ||||
|         set_property(nav_to_property(dir), Rml::Property(target, Rml::Unit::STRING)); | ||||
|     } | ||||
| 
 | ||||
|     void Style::set_tab_index_auto() { | ||||
|         set_property(Rml::PropertyId::TabIndex, Rml::Style::Nav::Auto); | ||||
|     } | ||||
|  |  | |||
|  | @ -94,9 +94,10 @@ namespace recompui { | |||
|         void set_drag(Drag drag); | ||||
|         void set_tab_index(TabIndex focus); | ||||
|         void set_font_family(std::string_view family); | ||||
|         // TODO set_nav with Element*
 | ||||
|         void set_nav_auto(NavDirection dir); | ||||
|         void set_nav_none(NavDirection dir); | ||||
|         void set_nav(NavDirection dir, Element* element); | ||||
|         void set_nav_manual(NavDirection dir, const std::string& target); | ||||
|         void set_tab_index_auto(); | ||||
|         void set_tab_index_none(); | ||||
|         virtual bool is_element() { return false; } | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ namespace recompui { | |||
|         std::vector<std::function<void(const std::string &)>> text_changed_callbacks; | ||||
|     protected: | ||||
|         virtual void process_event(const Event &e) override; | ||||
|         std::string_view get_type_name() override { return "TextInput"; } | ||||
|     public: | ||||
|         TextInput(Element *parent, bool text_visible = true); | ||||
|         void set_text(std::string_view text); | ||||
|  |  | |||
|  | @ -6,9 +6,9 @@ | |||
| 
 | ||||
| namespace recompui { | ||||
| 
 | ||||
|     Toggle::Toggle(Element *parent) : Element(parent, Events(EventType::Click, EventType::Hover, EventType::Enable), "button") { | ||||
|     Toggle::Toggle(Element *parent) : Element(parent, Events(EventType::Click, EventType::Focus, EventType::Hover, EventType::Enable), "button") { | ||||
|         enable_focus(); | ||||
|          | ||||
| 
 | ||||
|         set_width(162.0f); | ||||
|         set_height(72.0f); | ||||
|         set_border_radius(36.0f); | ||||
|  | @ -20,13 +20,19 @@ namespace recompui { | |||
|         checked_style.set_border_color(Color{ 34, 177, 76, 255 }); | ||||
|         hover_style.set_border_color(Color{ 177, 76, 34, 255 }); | ||||
|         hover_style.set_background_color(Color{ 206, 120, 68, 76 }); | ||||
|         focus_style.set_border_color(Color{ 177, 76, 34, 255 }); | ||||
|         focus_style.set_background_color(Color{ 206, 120, 68, 76 }); | ||||
|         checked_hover_style.set_border_color(Color{ 34, 177, 76, 255 }); | ||||
|         checked_hover_style.set_background_color(Color{ 68, 206, 120, 76 }); | ||||
|         checked_focus_style.set_border_color(Color{ 34, 177, 76, 255 }); | ||||
|         checked_focus_style.set_background_color(Color{ 68, 206, 120, 76 }); | ||||
|         disabled_style.set_border_color(Color{ 177, 76, 34, 128 }); | ||||
|         checked_disabled_style.set_border_color(Color{ 34, 177, 76, 128 }); | ||||
|         add_style(&checked_style, checked_state); | ||||
|         add_style(&hover_style, hover_state); | ||||
|         add_style(&focus_style, focus_state); | ||||
|         add_style(&checked_hover_style, { checked_state, hover_state }); | ||||
|         add_style(&checked_focus_style, { checked_state, focus_state }); | ||||
|         add_style(&disabled_style, disabled_state); | ||||
|         add_style(&checked_disabled_style, { checked_state, disabled_state }); | ||||
| 
 | ||||
|  | @ -92,6 +98,11 @@ namespace recompui { | |||
|             floater->set_style_enabled(hover_state, hover_active); | ||||
|             break; | ||||
|         } | ||||
|         case EventType::Focus: { | ||||
|             bool focus_active = std::get<EventFocus>(e.variant).active; | ||||
|             set_style_enabled(focus_state, focus_active); | ||||
|             break; | ||||
|         } | ||||
|         case EventType::Enable: { | ||||
|             bool enable_active = std::get<EventEnable>(e.variant).active; | ||||
|             set_style_enabled(disabled_state, !enable_active); | ||||
|  |  | |||
|  | @ -12,7 +12,9 @@ namespace recompui { | |||
|         std::list<std::function<void(bool)>> checked_callbacks; | ||||
|         Style checked_style; | ||||
|         Style hover_style; | ||||
|         Style focus_style; | ||||
|         Style checked_hover_style; | ||||
|         Style checked_focus_style; | ||||
|         Style disabled_style; | ||||
|         Style checked_disabled_style; | ||||
|         Style floater_checked_style; | ||||
|  | @ -25,6 +27,7 @@ namespace recompui { | |||
| 
 | ||||
|         // Element overrides.
 | ||||
|         virtual void process_event(const Event &e) override; | ||||
|         std::string_view get_type_name() override { return "Toggle"; } | ||||
|     public: | ||||
|         Toggle(Element *parent); | ||||
|         void set_checked(bool checked); | ||||
|  |  | |||
|  | @ -36,8 +36,8 @@ ConfigOptionElement::~ConfigOptionElement() { | |||
| 
 | ||||
| } | ||||
| 
 | ||||
| void ConfigOptionElement::set_id(std::string_view id) { | ||||
|     this->id = id; | ||||
| void ConfigOptionElement::set_option_id(std::string_view id) { | ||||
|     this->option_id = id; | ||||
| } | ||||
| 
 | ||||
| void ConfigOptionElement::set_name(std::string_view name) { | ||||
|  | @ -60,7 +60,7 @@ const std::string &ConfigOptionElement::get_description() const { | |||
| // ConfigOptionSlider
 | ||||
| 
 | ||||
| void ConfigOptionSlider::slider_value_changed(double v) { | ||||
|     callback(id, v); | ||||
|     callback(option_id, v); | ||||
| } | ||||
| 
 | ||||
| ConfigOptionSlider::ConfigOptionSlider(Element *parent, double value, double min_value, double max_value, double step_value, bool percent, std::function<void(const std::string &, double)> callback) : ConfigOptionElement(parent) { | ||||
|  | @ -78,7 +78,7 @@ ConfigOptionSlider::ConfigOptionSlider(Element *parent, double value, double min | |||
| // ConfigOptionTextInput
 | ||||
| 
 | ||||
| void ConfigOptionTextInput::text_changed(const std::string &text) { | ||||
|     callback(id, text); | ||||
|     callback(option_id, text); | ||||
| } | ||||
| 
 | ||||
| ConfigOptionTextInput::ConfigOptionTextInput(Element *parent, std::string_view value, std::function<void(const std::string &, const std::string &)> callback) : ConfigOptionElement(parent) { | ||||
|  | @ -93,7 +93,7 @@ ConfigOptionTextInput::ConfigOptionTextInput(Element *parent, std::string_view v | |||
| // ConfigOptionRadio
 | ||||
| 
 | ||||
| void ConfigOptionRadio::index_changed(uint32_t index) { | ||||
|     callback(id, index); | ||||
|     callback(option_id, index); | ||||
| } | ||||
| 
 | ||||
| ConfigOptionRadio::ConfigOptionRadio(Element *parent, uint32_t value, const std::vector<std::string> &options, std::function<void(const std::string &, uint32_t)> callback) : ConfigOptionElement(parent) { | ||||
|  | @ -189,7 +189,7 @@ void ConfigSubMenu::clear_options() { | |||
| } | ||||
| 
 | ||||
| void ConfigSubMenu::add_option(ConfigOptionElement *option, std::string_view id, std::string_view name, std::string_view description) { | ||||
|     option->set_id(id); | ||||
|     option->set_option_id(id); | ||||
|     option->set_name(name); | ||||
|     option->set_description(description); | ||||
|     option->set_hover_callback([this](ConfigOptionElement *option, bool active){ option_hovered(option, active); }); | ||||
|  |  | |||
|  | @ -16,16 +16,17 @@ namespace recompui { | |||
| class ConfigOptionElement : public Element { | ||||
| protected: | ||||
|     Label *name_label = nullptr; | ||||
|     std::string id; | ||||
|     std::string option_id; | ||||
|     std::string name; | ||||
|     std::string description; | ||||
|     std::function<void(ConfigOptionElement *, bool)> hover_callback = nullptr; | ||||
| 
 | ||||
|     virtual void process_event(const Event &e) override; | ||||
|     std::string_view get_type_name() override { return "ConfigOptionElement"; } | ||||
| public: | ||||
|     ConfigOptionElement(Element *parent); | ||||
|     virtual ~ConfigOptionElement(); | ||||
|     void set_id(std::string_view id); | ||||
|     void set_option_id(std::string_view id); | ||||
|     void set_name(std::string_view name); | ||||
|     void set_description(std::string_view description); | ||||
|     void set_hover_callback(std::function<void(ConfigOptionElement *, bool)> callback); | ||||
|  | @ -38,6 +39,7 @@ protected: | |||
|     std::function<void(const std::string &, double)> callback; | ||||
| 
 | ||||
|     void slider_value_changed(double v); | ||||
|     std::string_view get_type_name() override { return "ConfigOptionSlider"; } | ||||
| public: | ||||
|     ConfigOptionSlider(Element *parent, double value, double min_value, double max_value, double step_value, bool percent, std::function<void(const std::string &, double)> callback); | ||||
| }; | ||||
|  | @ -48,6 +50,7 @@ protected: | |||
|     std::function<void(const std::string &, const std::string &)> callback; | ||||
| 
 | ||||
|     void text_changed(const std::string &text); | ||||
|     std::string_view get_type_name() override { return "ConfigOptionTextInput"; } | ||||
| public: | ||||
|     ConfigOptionTextInput(Element *parent, std::string_view value, std::function<void(const std::string &, const std::string &)> callback); | ||||
| }; | ||||
|  | @ -58,6 +61,7 @@ protected: | |||
|     std::function<void(const std::string &, uint32_t)> callback; | ||||
| 
 | ||||
|     void index_changed(uint32_t index); | ||||
|     std::string_view get_type_name() override { return "ConfigOptionRadio"; } | ||||
| public: | ||||
|     ConfigOptionRadio(Element *parent, uint32_t value, const std::vector<std::string> &options, std::function<void(const std::string &, uint32_t)> callback); | ||||
| }; | ||||
|  | @ -77,7 +81,8 @@ private: | |||
|     void back_button_pressed(); | ||||
|     void option_hovered(ConfigOptionElement *option, bool active); | ||||
|     void add_option(ConfigOptionElement *option, std::string_view id, std::string_view name, std::string_view description); | ||||
| 
 | ||||
| protected: | ||||
|     std::string_view get_type_name() override { return "ConfigSubMenu"; } | ||||
| public: | ||||
|     ConfigSubMenu(Element *parent); | ||||
|     virtual ~ConfigSubMenu(); | ||||
|  |  | |||
|  | @ -4,6 +4,8 @@ | |||
| 
 | ||||
| namespace recompui { | ||||
| 
 | ||||
| extern const std::string mod_tab_id; | ||||
| 
 | ||||
| ModDetailsPanel::ModDetailsPanel(Element *parent) : Element(parent) { | ||||
|     set_flex(1.0f, 1.0f, 200.0f); | ||||
|     set_height(100.0f, Unit::Percent); | ||||
|  | @ -63,13 +65,16 @@ ModDetailsPanel::ModDetailsPanel(Element *parent) : Element(parent) { | |||
|         { | ||||
|             enable_toggle = context.create_element<Toggle>(enable_container); | ||||
|             enable_toggle->add_checked_callback([this](bool checked){ enable_toggle_checked(checked); }); | ||||
|             enable_toggle->set_nav_manual(NavDirection::Up, mod_tab_id); | ||||
| 
 | ||||
|             enable_label = context.create_element<Label>(enable_container, "A currently enabled mod requires this mod", LabelStyle::Annotation); | ||||
|         } | ||||
| 
 | ||||
|         configure_button = context.create_element<Button>(buttons_container, "Configure", recompui::ButtonStyle::Secondary); | ||||
|         configure_button->add_pressed_callback([this](){ configure_button_pressed(); }); | ||||
|         configure_button->set_nav_manual(NavDirection::Up, mod_tab_id); | ||||
|     } | ||||
|     clear_mod_navigation(); | ||||
| } | ||||
| 
 | ||||
| ModDetailsPanel::~ModDetailsPanel() { | ||||
|  | @ -110,6 +115,14 @@ void ModDetailsPanel::set_mod_configure_pressed_callback(std::function<void()> c | |||
|     mod_configure_pressed_callback = callback; | ||||
| } | ||||
| 
 | ||||
| void ModDetailsPanel::setup_mod_navigation(Element* nav_target) { | ||||
|     enable_toggle->set_nav(NavDirection::Left, nav_target); | ||||
| } | ||||
| 
 | ||||
| void ModDetailsPanel::clear_mod_navigation() { | ||||
|     enable_toggle->set_nav_none(NavDirection::Left); | ||||
| } | ||||
| 
 | ||||
| void ModDetailsPanel::enable_toggle_checked(bool checked) { | ||||
|     if (mod_toggled_callback != nullptr) { | ||||
|         mod_toggled_callback(checked); | ||||
|  |  | |||
|  | @ -18,7 +18,13 @@ public: | |||
|     void set_mod_details(const recomp::mods::ModDetails& details, const std::string &thumbnail, bool toggle_checked, bool toggle_enabled, bool toggle_label_visible, bool configure_enabled); | ||||
|     void set_mod_toggled_callback(std::function<void(bool)> callback); | ||||
|     void set_mod_configure_pressed_callback(std::function<void()> callback); | ||||
|     void setup_mod_navigation(Element* nav_target); | ||||
|     void clear_mod_navigation(); | ||||
|     Toggle* get_enable_toggle() { return enable_toggle; } | ||||
|     Button* get_configure_button() { return configure_button; } | ||||
|     void disable_toggle(); | ||||
| protected: | ||||
|     std::string_view get_type_name() override { return "ModDetailsPanel"; } | ||||
| private: | ||||
|     recomp::mods::ModDetails cur_details; | ||||
|     Container *thumbnail_container = nullptr; | ||||
|  |  | |||
|  | @ -32,6 +32,9 @@ static bool is_mod_enabled_or_auto(const std::string &mod_id) { | |||
| constexpr float modEntryHeight = 120.0f; | ||||
| constexpr float modEntryPadding = 4.0f; | ||||
| 
 | ||||
| extern const std::string mod_tab_id; | ||||
| const std::string mod_tab_id = "#tab_mods"; | ||||
| 
 | ||||
| ModEntryView::ModEntryView(Element *parent) : Element(parent) { | ||||
|     ContextId context = get_current_context(); | ||||
| 
 | ||||
|  | @ -283,6 +286,22 @@ void ModMenu::mod_selected(uint32_t mod_index) { | |||
|         bool configure_enabled = !config_schema.options.empty(); | ||||
|         mod_details_panel->set_mod_details(mod_details[mod_index], thumbnail_src, toggle_checked, toggle_enabled, auto_enabled, configure_enabled); | ||||
|         mod_entry_buttons[active_mod_index]->set_selected(true); | ||||
| 
 | ||||
|         mod_details_panel->setup_mod_navigation(mod_entry_buttons[mod_index]); | ||||
|         if (configure_enabled) { | ||||
|             Button* configure_button = mod_details_panel->get_configure_button(); | ||||
|             refresh_button->set_nav(NavDirection::Up, configure_button); | ||||
|             mods_folder_button->set_nav(NavDirection::Up, configure_button); | ||||
|         } | ||||
|         else if (toggle_enabled) { | ||||
|             Toggle* enable_toggle = mod_details_panel->get_enable_toggle(); | ||||
|             refresh_button->set_nav(NavDirection::Up, enable_toggle); | ||||
|             mods_folder_button->set_nav(NavDirection::Up, enable_toggle); | ||||
|         } | ||||
|         else { | ||||
|             refresh_button->set_nav_manual(NavDirection::Up, mod_tab_id); | ||||
|             mods_folder_button->set_nav_manual(NavDirection::Up, mod_tab_id); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -495,6 +514,8 @@ void ModMenu::create_mod_list() { | |||
|     mod_entry_buttons.clear(); | ||||
|     mod_entry_spacers.clear(); | ||||
| 
 | ||||
|     Toggle* enable_toggle = mod_details_panel->get_enable_toggle(); | ||||
| 
 | ||||
|     // Create the child elements for the list scroll.
 | ||||
|     for (size_t mod_index = 0; mod_index < mod_details.size(); mod_index++) { | ||||
|         const std::vector<char> &thumbnail = recomp::mods::get_mod_thumbnail(mod_details[mod_index].mod_id); | ||||
|  | @ -513,6 +534,13 @@ void ModMenu::create_mod_list() { | |||
|         mod_entry->set_mod_details(mod_details[mod_index]); | ||||
|         mod_entry->set_mod_thumbnail(thumbnail_name); | ||||
|         mod_entry->set_mod_enabled(is_mod_enabled_or_auto(mod_details[mod_index].mod_id)); | ||||
|         mod_entry->set_nav(NavDirection::Right, enable_toggle); | ||||
|         if (mod_index == 0) { | ||||
|             mod_entry->set_nav_manual(NavDirection::Up, mod_tab_id); | ||||
|         } | ||||
|         if (mod_index == mod_details.size() - 1) { | ||||
|             mod_entry->set_nav(NavDirection::Down, install_mods_button); | ||||
|         } | ||||
|         mod_entry_buttons.emplace_back(mod_entry); | ||||
|     } | ||||
| 
 | ||||
|  | @ -605,17 +633,23 @@ ModMenu::ModMenu(Element *parent) : Element(parent) { | |||
|         footer_container->set_border_bottom_left_radius(16.0f); | ||||
|         footer_container->set_border_bottom_right_radius(16.0f); | ||||
|         { | ||||
|             Toggle* enable_toggle = mod_details_panel->get_enable_toggle(); | ||||
|             Button* configure_button = mod_details_panel->get_configure_button(); | ||||
|             install_mods_button = context.create_element<Button>(footer_container, "Install Mods", recompui::ButtonStyle::Primary); | ||||
|             install_mods_button->add_pressed_callback([this](){ open_install_dialog(); }); | ||||
|             install_mods_button->set_nav_manual(NavDirection::Up, mod_tab_id); | ||||
| 
 | ||||
|             Element* footer_spacer = context.create_element<Element>(footer_container); | ||||
|             footer_spacer->set_flex(1.0f, 0.0f); | ||||
| 
 | ||||
|             refresh_button = context.create_element<Button>(footer_container, "Refresh", recompui::ButtonStyle::Primary); | ||||
|             refresh_button->add_pressed_callback([this](){ recomp::mods::scan_mods(); refresh_mods(); }); | ||||
|             refresh_button->set_nav_manual(NavDirection::Up, mod_tab_id); | ||||
| 
 | ||||
|             mods_folder_button = context.create_element<Button>(footer_container, "Open Mods Folder", recompui::ButtonStyle::Primary); | ||||
|             mods_folder_button->add_pressed_callback([this](){ open_mods_folder(); }); | ||||
|             mods_folder_button->set_nav(NavDirection::Up, configure_button); | ||||
|             mods_folder_button->set_nav_manual(NavDirection::Up, mod_tab_id); | ||||
|         } // footer_container
 | ||||
|     } // this
 | ||||
|      | ||||
|  |  | |||
|  | @ -18,6 +18,8 @@ public: | |||
|     void set_mod_thumbnail(const std::string &thumbnail); | ||||
|     void set_mod_enabled(bool enabled); | ||||
|     void set_selected(bool selected); | ||||
| protected: | ||||
|     std::string_view get_type_name() override { return "ModEntryView"; } | ||||
| private: | ||||
|     Image *thumbnail_image = nullptr; | ||||
|     Element *body_container = nullptr; | ||||
|  | @ -40,6 +42,7 @@ public: | |||
|     void set_selected(bool selected); | ||||
| protected: | ||||
|     virtual void process_event(const Event &e) override; | ||||
|     std::string_view get_type_name() override { return "ModEntryButton"; } | ||||
| private: | ||||
|     uint32_t mod_index = 0; | ||||
|     ModEntryView *view = nullptr; | ||||
|  | @ -56,6 +59,7 @@ private: | |||
|     void check_height_distance(); | ||||
| protected: | ||||
|     virtual void process_event(const Event &e) override; | ||||
|     std::string_view get_type_name() override { return "ModEntrySpacer"; } | ||||
| public: | ||||
|     ModEntrySpacer(Element *parent); | ||||
|     void set_target_height(float target_height, bool animate_to_target); | ||||
|  | @ -66,6 +70,8 @@ public: | |||
|     ModMenu(Element *parent); | ||||
|     virtual ~ModMenu(); | ||||
|     void set_mods_dirty() { mods_dirty = true; } | ||||
| protected: | ||||
|     std::string_view get_type_name() override { return "ModMenu"; } | ||||
| private: | ||||
|     void refresh_mods(); | ||||
|     void open_mods_folder(); | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Mr-Wiseguy
						Mr-Wiseguy