#ifndef YAZE_APP_GUI_CANVAS_CANVAS_MENU_H #define YAZE_APP_GUI_CANVAS_CANVAS_MENU_H #include #include #include #include #include "imgui/imgui.h" namespace yaze { namespace gui { /** * @brief Menu section priority for controlling rendering order * * Lower values render first in the context menu: * - Editor-specific items (0) appear at the top * - Bitmap/palette operations (10) in the middle * - Canvas properties (20) near the bottom * - Debug/performance (30) at the bottom */ enum class MenuSectionPriority { kEditorSpecific = 0, // Highest priority - editor-specific actions kBitmapPalette = 10, // Medium priority - bitmap/palette operations kCanvasProperties = 20, // Low priority - canvas settings kDebug = 30 // Lowest priority - debug/performance }; /** * @brief Declarative popup definition for menu items * * Links a menu item to a persistent popup that should open when the menu * item is selected. This separates popup definition from popup rendering. */ struct CanvasPopupDefinition { // Unique popup identifier for ImGui std::string popup_id; // Callback that renders the popup content (should call ImGui::BeginPopup/EndPopup) std::function render_callback; // Whether to automatically open the popup when menu item is selected bool auto_open_on_select = true; // Whether the popup should persist across frames until explicitly closed bool persist_across_frames = true; // Default constructor CanvasPopupDefinition() = default; // Constructor for simple popups CanvasPopupDefinition(const std::string& id, std::function callback) : popup_id(id), render_callback(std::move(callback)) {} }; /** * @brief Declarative menu item definition * * Pure data structure representing a menu item with optional popup linkage. * Can be composed into hierarchical menus via subitems. */ struct CanvasMenuItem { // Display label for the menu item std::string label; // Optional icon (Material Design icon name or Unicode glyph) std::string icon; // Optional keyboard shortcut display (e.g., "Ctrl+S") std::string shortcut; // Callback invoked when menu item is selected std::function callback; // Optional popup definition - if present, popup will be managed automatically std::optional popup; // Condition to determine if menu item is enabled std::function enabled_condition = []() { return true; }; // Condition to determine if menu item is visible std::function visible_condition = []() { return true; }; // Nested submenu items std::vector subitems; // Color for the menu item label ImVec4 color = ImVec4(1, 1, 1, 1); // Whether to show a separator after this item bool separator_after = false; // Default constructor CanvasMenuItem() = default; // Simple menu item constructor CanvasMenuItem(const std::string& lbl, std::function cb) : label(lbl), callback(std::move(cb)) {} // Menu item with icon CanvasMenuItem(const std::string& lbl, const std::string& ico, std::function cb) : label(lbl), icon(ico), callback(std::move(cb)) {} // Menu item with icon and shortcut CanvasMenuItem(const std::string& lbl, const std::string& ico, std::function cb, const std::string& sc) : label(lbl), icon(ico), callback(std::move(cb)), shortcut(sc) {} // Helper to create a disabled menu item static CanvasMenuItem Disabled(const std::string& lbl) { CanvasMenuItem item; item.label = lbl; item.enabled_condition = []() { return false; }; return item; } // Helper to create a conditional menu item static CanvasMenuItem Conditional(const std::string& lbl, std::function cb, std::function condition) { CanvasMenuItem item; item.label = lbl; item.callback = std::move(cb); item.enabled_condition = std::move(condition); return item; } // Helper to create a menu item with popup static CanvasMenuItem WithPopup(const std::string& lbl, const std::string& popup_id, std::function render_callback) { CanvasMenuItem item; item.label = lbl; item.popup = CanvasPopupDefinition(popup_id, std::move(render_callback)); return item; } }; /** * @brief Menu section grouping related menu items * * Provides visual organization of menu items with optional section titles. * Sections are rendered in priority order. */ struct CanvasMenuSection { // Optional section title (rendered as colored text) std::string title; // Color for section title ImVec4 title_color = ImVec4(0.7f, 0.7f, 0.7f, 1.0f); // Menu items in this section std::vector items; // Whether to show a separator after this section bool separator_after = true; // Priority for ordering sections (lower values render first) MenuSectionPriority priority = MenuSectionPriority::kEditorSpecific; // Default constructor CanvasMenuSection() = default; // Constructor with title explicit CanvasMenuSection(const std::string& t) : title(t) {} // Constructor with title and items CanvasMenuSection(const std::string& t, const std::vector& its) : title(t), items(its) {} // Constructor with title, items, and priority CanvasMenuSection(const std::string& t, const std::vector& its, MenuSectionPriority prio) : title(t), items(its), priority(prio) {} }; /** * @brief Complete menu definition * * Aggregates menu sections for a complete context menu or popup menu. */ struct CanvasMenuDefinition { // Menu sections (rendered in order) std::vector sections; // Whether the menu is enabled bool enabled = true; // Default constructor CanvasMenuDefinition() = default; // Constructor with sections explicit CanvasMenuDefinition(const std::vector& secs) : sections(secs) {} // Add a section void AddSection(const CanvasMenuSection& section) { sections.push_back(section); } // Add items without a section title void AddItems(const std::vector& items) { CanvasMenuSection section; section.items = items; section.separator_after = false; sections.push_back(section); } }; // ==================== Free Function API ==================== /** * @brief Render a single menu item * * Handles visibility, enabled state, subitems, and popup linkage. * * @param item Menu item to render * @param popup_opened_callback Optional callback invoked when popup is opened */ void RenderMenuItem(const CanvasMenuItem& item, std::function)> popup_opened_callback = nullptr); /** * @brief Render a menu section * * Renders section title (if present), all items, and separator. * * @param section Menu section to render * @param popup_opened_callback Optional callback invoked when popup is opened */ void RenderMenuSection(const CanvasMenuSection& section, std::function)> popup_opened_callback = nullptr); /** * @brief Render a complete menu definition * * Renders all sections in order. Does not handle ImGui::BeginPopup/EndPopup - * caller is responsible for popup context. * * @param menu Menu definition to render * @param popup_opened_callback Optional callback invoked when popup is opened */ void RenderCanvasMenu(const CanvasMenuDefinition& menu, std::function)> popup_opened_callback = nullptr); } // namespace gui } // namespace yaze #endif // YAZE_APP_GUI_CANVAS_CANVAS_MENU_H