#ifndef YAZE_APP_EDITOR_SYSTEM_EDITOR_CARD_REGISTRY_H_ #define YAZE_APP_EDITOR_SYSTEM_EDITOR_CARD_REGISTRY_H_ #include #include #include #include #include #include "imgui/imgui.h" namespace yaze { namespace editor { // Forward declaration class EditorCard; /** * @struct CardInfo * @brief Metadata for an editor card * * Describes a registerable UI card that can be shown/hidden, * organized by category, and controlled programmatically. */ struct CardInfo { std::string card_id; // Unique identifier (e.g., "dungeon.room_selector") std::string display_name; // Human-readable name (e.g., "Room Selector") std::string icon; // Material icon std::string category; // Category (e.g., "Dungeon", "Graphics", "Palette") std::string shortcut_hint; // Display hint (e.g., "Ctrl+Shift+R") bool* visibility_flag; // Pointer to bool controlling visibility EditorCard* card_instance; // Pointer to actual card (optional) std::function on_show; // Callback when card is shown std::function on_hide; // Callback when card is hidden int priority; // Display priority for menus (lower = higher) }; /** * @class EditorCardRegistry * @brief Central registry for all editor cards with session awareness and dependency injection * * This class combines the functionality of EditorCardManager (global card management) * and SessionCardRegistry (session-aware prefixing) into a single, dependency-injected * component that can be passed to editors. * * Design Philosophy: * - Dependency injection (no singleton pattern) * - Session-aware card ID prefixing for multi-session support * - Centralized visibility management * - View menu integration * - Workspace preset system * - No direct GUI dependency in registration logic * * Session-Aware Card IDs: * - Single session: "dungeon.room_selector" * - Multiple sessions: "s0.dungeon.room_selector", "s1.dungeon.room_selector" * * Usage: * ```cpp * // In EditorManager: * EditorCardRegistry card_registry; * EditorDependencies deps; * deps.card_registry = &card_registry; * * // In Editor: * deps.card_registry->RegisterCard(deps.session_id, { * .card_id = "dungeon.room_selector", * .display_name = "Room Selector", * .icon = ICON_MD_LIST, * .category = "Dungeon", * .on_show = []() { } * }); * * // Programmatic control: * deps.card_registry->ShowCard(deps.session_id, "dungeon.room_selector"); * ``` */ class EditorCardRegistry { public: EditorCardRegistry() = default; ~EditorCardRegistry() = default; // Non-copyable, non-movable (manages pointers and callbacks) EditorCardRegistry(const EditorCardRegistry&) = delete; EditorCardRegistry& operator=(const EditorCardRegistry&) = delete; EditorCardRegistry(EditorCardRegistry&&) = delete; EditorCardRegistry& operator=(EditorCardRegistry&&) = delete; // ============================================================================ // Session Lifecycle Management // ============================================================================ /** * @brief Register a new session in the registry * @param session_id Unique session identifier * * Creates internal tracking structures for the session. * Must be called before registering cards for a session. */ void RegisterSession(size_t session_id); /** * @brief Unregister a session and all its cards * @param session_id Session identifier to remove * * Automatically unregisters all cards associated with the session. */ void UnregisterSession(size_t session_id); /** * @brief Set the currently active session * @param session_id Session to make active * * Used for determining whether to apply card ID prefixing. */ void SetActiveSession(size_t session_id); // ============================================================================ // Card Registration // ============================================================================ /** * @brief Register a card for a specific session * @param session_id Session this card belongs to * @param base_info Card metadata (ID will be automatically prefixed if needed) * * The card_id in base_info should be the unprefixed ID. This method * automatically applies session prefixing when multiple sessions exist. */ void RegisterCard(size_t session_id, const CardInfo& base_info); /** * @brief Register a card with inline parameters (convenience method) */ void RegisterCard(size_t session_id, const std::string& card_id, const std::string& display_name, const std::string& icon, const std::string& category, const std::string& shortcut_hint = "", int priority = 50, std::function on_show = nullptr, std::function on_hide = nullptr, bool visible_by_default = false); /** * @brief Unregister a specific card * @param session_id Session the card belongs to * @param base_card_id Unprefixed card ID */ void UnregisterCard(size_t session_id, const std::string& base_card_id); /** * @brief Unregister all cards with a given prefix * @param prefix Prefix to match (e.g., "s0" or "s1.dungeon") * * Useful for cleaning up session cards or category cards. */ void UnregisterCardsWithPrefix(const std::string& prefix); /** * @brief Remove all registered cards (use with caution) */ void ClearAllCards(); // ============================================================================ // Card Control (Programmatic, No GUI) // ============================================================================ /** * @brief Show a card programmatically * @param session_id Session the card belongs to * @param base_card_id Unprefixed card ID * @return true if card was found and shown */ bool ShowCard(size_t session_id, const std::string& base_card_id); /** * @brief Hide a card programmatically */ bool HideCard(size_t session_id, const std::string& base_card_id); /** * @brief Toggle a card's visibility */ bool ToggleCard(size_t session_id, const std::string& base_card_id); /** * @brief Check if a card is currently visible */ bool IsCardVisible(size_t session_id, const std::string& base_card_id) const; /** * @brief Get visibility flag pointer for a card * @return Pointer to bool controlling card visibility (for passing to EditorCard::Begin) */ bool* GetVisibilityFlag(size_t session_id, const std::string& base_card_id); // ============================================================================ // Batch Operations // ============================================================================ /** * @brief Show all cards in a specific session */ void ShowAllCardsInSession(size_t session_id); /** * @brief Hide all cards in a specific session */ void HideAllCardsInSession(size_t session_id); /** * @brief Show all cards in a category for a session */ void ShowAllCardsInCategory(size_t session_id, const std::string& category); /** * @brief Hide all cards in a category for a session */ void HideAllCardsInCategory(size_t session_id, const std::string& category); /** * @brief Show only one card, hiding all others in its category */ void ShowOnlyCard(size_t session_id, const std::string& base_card_id); // ============================================================================ // Query Methods // ============================================================================ /** * @brief Get all cards registered for a session * @return Vector of prefixed card IDs */ std::vector GetCardsInSession(size_t session_id) const; /** * @brief Get cards in a specific category for a session */ std::vector GetCardsInCategory(size_t session_id, const std::string& category) const; /** * @brief Get all categories for a session */ std::vector GetAllCategories(size_t session_id) const; /** * @brief Get card metadata * @param session_id Session the card belongs to * @param base_card_id Unprefixed card ID */ const CardInfo* GetCardInfo(size_t session_id, const std::string& base_card_id) const; /** * @brief Get all registered categories across all sessions */ std::vector GetAllCategories() const; // ============================================================================ // View Menu Integration // ============================================================================ /** * @brief Draw view menu section for a category */ void DrawViewMenuSection(size_t session_id, const std::string& category); /** * @brief Draw all categories as view menu submenus */ void DrawViewMenuAll(size_t session_id); // ============================================================================ // VSCode-Style Sidebar // ============================================================================ /** * @brief Draw sidebar for a category with session filtering */ void DrawSidebar(size_t session_id, const std::string& category, const std::vector& active_categories = {}, std::function on_category_switch = nullptr, std::function on_collapse = nullptr); static constexpr float GetSidebarWidth() { return 48.0f; } // ============================================================================ // Compact Controls for Menu Bar // ============================================================================ /** * @brief Draw compact card control for active editor's cards */ void DrawCompactCardControl(size_t session_id, const std::string& category); /** * @brief Draw minimal inline card toggles */ void DrawInlineCardToggles(size_t session_id, const std::string& category); // ============================================================================ // Card Browser UI // ============================================================================ /** * @brief Draw visual card browser/toggler */ void DrawCardBrowser(size_t session_id, bool* p_open); // ============================================================================ // Workspace Presets // ============================================================================ struct WorkspacePreset { std::string name; std::vector visible_cards; // Card IDs std::string description; }; void SavePreset(const std::string& name, const std::string& description = ""); bool LoadPreset(const std::string& name); void DeletePreset(const std::string& name); std::vector GetPresets() const; // ============================================================================ // Quick Actions // ============================================================================ void ShowAll(size_t session_id); void HideAll(size_t session_id); void ResetToDefaults(size_t session_id); // ============================================================================ // Statistics // ============================================================================ size_t GetCardCount() const { return cards_.size(); } size_t GetVisibleCardCount(size_t session_id) const; size_t GetSessionCount() const { return session_count_; } // ============================================================================ // Session Prefixing Utilities // ============================================================================ /** * @brief Generate session-aware card ID * @param session_id Session identifier * @param base_id Unprefixed card ID * @return Prefixed ID if multiple sessions, otherwise base ID * * Examples: * - Single session: "dungeon.room_selector" → "dungeon.room_selector" * - Multi-session: "dungeon.room_selector" → "s0.dungeon.room_selector" */ std::string MakeCardId(size_t session_id, const std::string& base_id) const; /** * @brief Check if card IDs should be prefixed * @return true if session_count > 1 */ bool ShouldPrefixCards() const { return session_count_ > 1; } // ============================================================================ // Convenience Methods (for EditorManager direct usage without session_id) // ============================================================================ /** * @brief Register card for active session (convenience) */ void RegisterCard(const CardInfo& base_info) { RegisterCard(active_session_, base_info); } /** * @brief Show card in active session (convenience) */ bool ShowCard(const std::string& base_card_id) { return ShowCard(active_session_, base_card_id); } /** * @brief Hide card in active session (convenience) */ bool HideCard(const std::string& base_card_id) { return HideCard(active_session_, base_card_id); } /** * @brief Check if card is visible in active session (convenience) */ bool IsCardVisible(const std::string& base_card_id) const { return IsCardVisible(active_session_, base_card_id); } /** * @brief Hide all cards in category for active session (convenience) */ void HideAllCardsInCategory(const std::string& category) { HideAllCardsInCategory(active_session_, category); } /** * @brief Draw card browser for active session (convenience) */ void DrawCardBrowser(bool* p_open) { DrawCardBrowser(active_session_, p_open); } /** * @brief Get active category (for sidebar) */ std::string GetActiveCategory() const { return active_category_; } /** * @brief Set active category (for sidebar) */ void SetActiveCategory(const std::string& category) { active_category_ = category; } /** * @brief Show all cards in category for active session (convenience) */ void ShowAllCardsInCategory(const std::string& category) { ShowAllCardsInCategory(active_session_, category); } /** * @brief Get visibility flag for active session (convenience) */ bool* GetVisibilityFlag(const std::string& base_card_id) { return GetVisibilityFlag(active_session_, base_card_id); } /** * @brief Show all cards for active session (convenience) */ void ShowAll() { ShowAll(active_session_); } /** * @brief Hide all cards for active session (convenience) */ void HideAll() { HideAll(active_session_); } /** * @brief Draw sidebar for active session (convenience) */ void DrawSidebar(const std::string& category, const std::vector& active_categories = {}, std::function on_category_switch = nullptr, std::function on_collapse = nullptr) { DrawSidebar(active_session_, category, active_categories, on_category_switch, on_collapse); } private: // Core card storage (prefixed IDs → CardInfo) std::unordered_map cards_; // Centralized visibility flags for cards without external flags std::unordered_map centralized_visibility_; // Session tracking size_t session_count_ = 0; size_t active_session_ = 0; // Maps session_id → vector of prefixed card IDs registered for that session std::unordered_map> session_cards_; // Maps session_id → (base_card_id → prefixed_card_id) std::unordered_map> session_card_mapping_; // Workspace presets std::unordered_map presets_; // Active category tracking std::string active_category_; std::vector recent_categories_; static constexpr size_t kMaxRecentCategories = 5; // Helper methods void UpdateSessionCount(); std::string GetPrefixedCardId(size_t session_id, const std::string& base_id) const; void UnregisterSessionCards(size_t session_id); void SavePresetsToFile(); void LoadPresetsFromFile(); // UI drawing helpers (internal) void DrawCardMenuItem(const CardInfo& info); void DrawCardInSidebar(const CardInfo& info, bool is_active); }; } // namespace editor } // namespace yaze #endif // YAZE_APP_EDITOR_SYSTEM_EDITOR_CARD_REGISTRY_H_