#include "ProjectPanelSupport.h" namespace XCEngine::UI::Editor::App { using namespace ProjectPanelSupport; ProjectPanel::Layout ProjectPanel::BuildLayout(const UIRect& bounds) const { Layout layout = {}; const auto& assetEntries = m_browserModel.GetAssetEntries(); const std::vector breadcrumbSegments = m_browserModel.BuildBreadcrumbSegments(); const float dividerThickness = ResolveUIEditorDockHostMetrics().splitterMetrics.thickness; layout.bounds = UIRect( bounds.x, bounds.y, ClampNonNegative(bounds.width), ClampNonNegative(bounds.height)); const float leftWidth = ClampNavigationWidth(m_navigationWidth, layout.bounds.width); layout.leftPaneRect = UIRect( layout.bounds.x, layout.bounds.y, leftWidth, layout.bounds.height); layout.dividerRect = UIRect( layout.leftPaneRect.x + layout.leftPaneRect.width, layout.bounds.y, dividerThickness, layout.bounds.height); layout.rightPaneRect = UIRect( layout.dividerRect.x + layout.dividerRect.width, layout.bounds.y, ClampNonNegative(layout.bounds.width - layout.leftPaneRect.width - layout.dividerRect.width), layout.bounds.height); layout.treeRect = UIRect( layout.leftPaneRect.x, layout.leftPaneRect.y + kTreeTopPadding, layout.leftPaneRect.width, ClampNonNegative(layout.leftPaneRect.height - kTreeTopPadding)); layout.browserHeaderRect = UIRect( layout.rightPaneRect.x, layout.rightPaneRect.y, layout.rightPaneRect.width, (std::min)(kBrowserHeaderHeight, layout.rightPaneRect.height)); layout.browserBodyRect = UIRect( layout.rightPaneRect.x, layout.browserHeaderRect.y + layout.browserHeaderRect.height, layout.rightPaneRect.width, ClampNonNegative(layout.rightPaneRect.height - layout.browserHeaderRect.height)); layout.gridRect = UIRect( layout.browserBodyRect.x + kGridInsetX, layout.browserBodyRect.y + kGridInsetY, ClampNonNegative(layout.browserBodyRect.width - kGridInsetX * 2.0f), ClampNonNegative(layout.browserBodyRect.height - kGridInsetY * 2.0f)); const float breadcrumbRowHeight = kHeaderFontSize + kBreadcrumbItemPaddingY * 2.0f; const float breadcrumbY = layout.browserHeaderRect.y + std::floor((layout.browserHeaderRect.height - breadcrumbRowHeight) * 0.5f); const float headerRight = layout.browserHeaderRect.x + layout.browserHeaderRect.width - kHeaderHorizontalPadding; float nextItemX = layout.browserHeaderRect.x + kHeaderHorizontalPadding; for (std::size_t index = 0u; index < breadcrumbSegments.size(); ++index) { if (index > 0u) { const float separatorWidth = MeasureTextWidth(m_textMeasurer, ">", kHeaderFontSize); if (nextItemX < headerRight && separatorWidth > 0.0f) { layout.breadcrumbItems.push_back({ ">", {}, UIRect( nextItemX, breadcrumbY, ClampNonNegative((std::min)(separatorWidth, headerRight - nextItemX)), breadcrumbRowHeight), true, false, false }); } nextItemX += separatorWidth + kBreadcrumbSpacing; } const ProjectBrowserModel::BreadcrumbSegment& segment = breadcrumbSegments[index]; const float labelWidth = MeasureTextWidth(m_textMeasurer, segment.label, kHeaderFontSize); const float itemWidth = labelWidth + kBreadcrumbItemPaddingX * 2.0f; const float availableWidth = headerRight - nextItemX; if (availableWidth <= 0.0f) { break; } layout.breadcrumbItems.push_back({ segment.label, segment.targetFolderId, UIRect( nextItemX, breadcrumbY, ClampNonNegative((std::min)(itemWidth, availableWidth)), breadcrumbRowHeight), false, !segment.current, segment.current }); nextItemX += itemWidth + kBreadcrumbSpacing; } const float effectiveTileWidth = kGridTileWidth + kGridTileGapX; int columnCount = effectiveTileWidth > 0.0f ? static_cast((layout.gridRect.width + kGridTileGapX) / effectiveTileWidth) : 1; if (columnCount < 1) { columnCount = 1; } layout.assetTiles.reserve(assetEntries.size()); for (std::size_t index = 0; index < assetEntries.size(); ++index) { const int column = static_cast(index % static_cast(columnCount)); const int row = static_cast(index / static_cast(columnCount)); const float tileX = layout.gridRect.x + static_cast(column) * (kGridTileWidth + kGridTileGapX); const float tileY = layout.gridRect.y + static_cast(row) * (kGridTileHeight + kGridTileGapY); AssetTileLayout tile = {}; tile.itemIndex = index; tile.tileRect = UIRect(tileX, tileY, kGridTileWidth, kGridTileHeight); tile.previewRect = UIRect( tile.tileRect.x + (tile.tileRect.width - kGridPreviewWidth) * 0.5f, tile.tileRect.y + 6.0f, kGridPreviewWidth, kGridPreviewHeight); tile.labelRect = UIRect( tile.tileRect.x + 4.0f, tile.previewRect.y + tile.previewRect.height + 8.0f, tile.tileRect.width - 8.0f, 18.0f); layout.assetTiles.push_back(tile); } return layout; } std::size_t ProjectPanel::HitTestBreadcrumbItem(const UIPoint& point) const { for (std::size_t index = 0u; index < m_layout.breadcrumbItems.size(); ++index) { const BreadcrumbItemLayout& item = m_layout.breadcrumbItems[index]; if (!item.separator && ContainsPoint(item.rect, point)) { return index; } } return kInvalidLayoutIndex; } std::size_t ProjectPanel::HitTestAssetTile(const UIPoint& point) const { for (const AssetTileLayout& tile : m_layout.assetTiles) { if (ContainsPoint(tile.tileRect, point)) { return tile.itemIndex; } } return kInvalidLayoutIndex; } } // namespace XCEngine::UI::Editor::App