#pragma once #include "HierarchyPanel.h" #include "Rendering/Assets/BuiltInIcons.h" #include "UI/Styles/EditorTreeViewStyle.h" #include #include #include #include #include namespace XCEngine::UI::Editor::App::HierarchyPanelSupport { using ::XCEngine::UI::UIColor; using ::XCEngine::UI::UIDrawList; using ::XCEngine::UI::UIInputEvent; using ::XCEngine::UI::UIInputEventType; using ::XCEngine::UI::UIPoint; using ::XCEngine::UI::UIPointerButton; using ::XCEngine::UI::UIRect; using Widgets::AppendUIEditorTreeViewBackground; using Widgets::AppendUIEditorTreeViewForeground; using Widgets::DoesUIEditorTreeViewItemHaveChildren; using Widgets::HitTestUIEditorTreeView; using Widgets::IsUIEditorTreeViewPointInside; using Widgets::UIEditorTreeViewHitTarget; using Widgets::UIEditorTreeViewHitTargetKind; using Widgets::UIEditorTreeViewInvalidIndex; inline constexpr std::string_view kHierarchyPanelId = "hierarchy"; inline constexpr float kDragThreshold = 4.0f; inline constexpr UIColor kDragPreviewColor(0.92f, 0.92f, 0.92f, 0.42f); inline bool ContainsPoint(const UIRect& rect, const UIPoint& point) { return point.x >= rect.x && point.x <= rect.x + rect.width && point.y >= rect.y && point.y <= rect.y + rect.height; } inline float ComputeSquaredDistance(const UIPoint& lhs, const UIPoint& rhs) { const float dx = lhs.x - rhs.x; const float dy = lhs.y - rhs.y; return dx * dx + dy * dy; } inline ::XCEngine::UI::UITextureHandle ResolveGameObjectIcon(const BuiltInIcons* icons) { return icons != nullptr ? icons->Resolve(BuiltInIconKind::GameObject) : ::XCEngine::UI::UITextureHandle {}; } inline std::vector FilterHierarchyInputEvents( const UIRect& bounds, const std::vector& inputEvents, bool allowInteraction, bool panelActive, bool captureActive) { if (!allowInteraction && !captureActive) { return {}; } std::vector filteredEvents = {}; filteredEvents.reserve(inputEvents.size()); for (const UIInputEvent& event : inputEvents) { switch (event.type) { case UIInputEventType::PointerMove: case UIInputEventType::PointerButtonDown: case UIInputEventType::PointerButtonUp: case UIInputEventType::PointerWheel: if (captureActive || ContainsPoint(bounds, event.position)) { filteredEvents.push_back(event); } break; case UIInputEventType::PointerLeave: filteredEvents.push_back(event); break; case UIInputEventType::FocusGained: case UIInputEventType::FocusLost: if (panelActive || captureActive) { filteredEvents.push_back(event); } break; case UIInputEventType::KeyDown: case UIInputEventType::KeyUp: case UIInputEventType::Character: if (panelActive) { filteredEvents.push_back(event); } break; default: break; } } return filteredEvents; } inline const Widgets::UIEditorTreeViewItem* ResolveHitItem( const Widgets::UIEditorTreeViewLayout& layout, const std::vector& items, const UIPoint& point, UIEditorTreeViewHitTarget* hitTargetOutput = nullptr) { const UIEditorTreeViewHitTarget hitTarget = HitTestUIEditorTreeView(layout, point); if (hitTargetOutput != nullptr) { *hitTargetOutput = hitTarget; } if (hitTarget.itemIndex >= items.size()) { return nullptr; } return &items[hitTarget.itemIndex]; } inline std::size_t FindVisibleIndexForItemId( const Widgets::UIEditorTreeViewLayout& layout, const std::vector& items, std::string_view itemId) { for (std::size_t visibleIndex = 0u; visibleIndex < layout.visibleItemIndices.size(); ++visibleIndex) { const std::size_t itemIndex = layout.visibleItemIndices[visibleIndex]; if (itemIndex < items.size() && items[itemIndex].itemId == itemId) { return visibleIndex; } } return UIEditorTreeViewInvalidIndex; } } // namespace XCEngine::UI::Editor::App::HierarchyPanelSupport