#pragma once #include #include #include #include #include #include #include #include #include #include #include namespace XCEngine::UI::Editor::App { class ProductProjectPanel { public: enum class CursorKind : std::uint8_t { Arrow = 0, ResizeEW }; void Initialize(const std::filesystem::path& repoRoot); void SetTextMeasurer(const ::XCEngine::UI::Editor::UIEditorTextMeasurer* textMeasurer); void Update( const UIEditorPanelContentHostFrame& contentHostFrame, const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents, bool allowInteraction, bool panelActive); void Append(::XCEngine::UI::UIDrawList& drawList) const; CursorKind GetCursorKind() const; bool WantsHostPointerCapture() const; bool WantsHostPointerRelease() const; bool HasActivePointerCapture() const; private: struct FolderEntry { std::string itemId = {}; std::filesystem::path absolutePath = {}; }; struct AssetEntry { std::string itemId = {}; std::filesystem::path absolutePath = {}; std::string displayName = {}; bool directory = false; }; struct BreadcrumbItemLayout { std::string label = {}; std::string targetFolderId = {}; ::XCEngine::UI::UIRect rect = {}; bool separator = false; bool clickable = false; bool current = false; }; struct AssetTileLayout { std::size_t itemIndex = static_cast(-1); ::XCEngine::UI::UIRect tileRect = {}; ::XCEngine::UI::UIRect previewRect = {}; ::XCEngine::UI::UIRect labelRect = {}; }; struct Layout { ::XCEngine::UI::UIRect bounds = {}; ::XCEngine::UI::UIRect leftPaneRect = {}; ::XCEngine::UI::UIRect treeRect = {}; ::XCEngine::UI::UIRect dividerRect = {}; ::XCEngine::UI::UIRect rightPaneRect = {}; ::XCEngine::UI::UIRect browserHeaderRect = {}; ::XCEngine::UI::UIRect browserBodyRect = {}; ::XCEngine::UI::UIRect gridRect = {}; std::vector breadcrumbItems = {}; std::vector assetTiles = {}; }; const FolderEntry* FindFolderEntry(std::string_view itemId) const; const UIEditorPanelContentHostPanelState* FindMountedProjectPanel( const UIEditorPanelContentHostFrame& contentHostFrame) const; Layout BuildLayout(const ::XCEngine::UI::UIRect& bounds) const; std::size_t HitTestBreadcrumbItem(const ::XCEngine::UI::UIPoint& point) const; std::size_t HitTestAssetTile(const ::XCEngine::UI::UIPoint& point) const; void RefreshFolderTree(); void RefreshAssetList(); void EnsureValidCurrentFolder(); void ExpandFolderAncestors(std::string_view itemId); void SyncCurrentFolderSelection(); void NavigateToFolder(std::string_view itemId); void ResetTransientFrames(); std::filesystem::path m_assetsRootPath = {}; std::vector m_folderEntries = {}; std::vector m_treeItems = {}; std::vector m_assetEntries = {}; const ::XCEngine::UI::Editor::UIEditorTextMeasurer* m_textMeasurer = nullptr; ::XCEngine::UI::Widgets::UISelectionModel m_folderSelection = {}; ::XCEngine::UI::Widgets::UIExpansionModel m_folderExpansion = {}; ::XCEngine::UI::Widgets::UISelectionModel m_assetSelection = {}; UIEditorTreeViewInteractionState m_treeInteractionState = {}; UIEditorTreeViewInteractionFrame m_treeFrame = {}; Layout m_layout = {}; std::string m_currentFolderId = {}; std::string m_hoveredAssetItemId = {}; std::string m_lastPrimaryClickedAssetId = {}; float m_navigationWidth = 248.0f; std::uint64_t m_lastPrimaryClickTimeMs = 0u; std::size_t m_hoveredBreadcrumbIndex = static_cast(-1); std::size_t m_pressedBreadcrumbIndex = static_cast(-1); bool m_visible = false; bool m_splitterHovered = false; bool m_splitterDragging = false; bool m_requestPointerCapture = false; bool m_requestPointerRelease = false; }; } // namespace XCEngine::UI::Editor::App