22
33#include " Game-Lib/ECS/Components/Name.h"
44#include " Game-Lib/ECS/Components/UI/BoundingRect.h"
5+ #include " Game-Lib/ECS/Components/UI/Canvas.h"
56#include " Game-Lib/ECS/Components/UI/EventInputInfo.h"
7+ #include " Game-Lib/ECS/Components/UI/Panel.h"
68#include " Game-Lib/ECS/Components/UI/Widget.h"
79#include " Game-Lib/ECS/Singletons/UISingleton.h"
810#include " Game-Lib/ECS/Util/UIUtil.h"
@@ -135,7 +137,7 @@ namespace ECS::Systems::UI
135137 if (eventInputInfo->onMouseUpEvent != -1 )
136138 {
137139 auto & rect = registry.get <Components::UI::BoundingRect>(uiSingleton.clickedEntity );
138- bool isWithin = IsWithin (mousePos, rect.min , rect.max );
140+ bool isWithin = IsWithin (mousePos, rect.hoveredMin , rect.hoveredMax );
139141 if (isWithin)
140142 {
141143 auto & widget = registry.get <Components::UI::Widget>(uiSingleton.clickedEntity );
@@ -243,7 +245,7 @@ namespace ECS::Systems::UI
243245 if (eventInputInfo->onMouseUpEvent != -1 )
244246 {
245247 auto & rect = registry.get <Components::UI::BoundingRect>(uiSingleton.clickedEntity );
246- bool isWithin = IsWithin (mousePos, rect.min , rect.max );
248+ bool isWithin = IsWithin (mousePos, rect.hoveredMin , rect.hoveredMax );
247249 if (isWithin)
248250 {
249251 auto & widget = registry.get <Components::UI::Widget>(uiSingleton.clickedEntity );
@@ -379,6 +381,75 @@ namespace ECS::Systems::UI
379381 });
380382 }
381383
384+ // This function is called on a canvas to find all hovered entities within it
385+ // It's recursive because we can have Panels with a RenderTarget canvas as a texture
386+ // When it finds one of those we need to offset the panel position and call this function again on the nested canvas
387+ void RecursivelyFindHoveredInCanvas (entt::registry& registry, entt::entity entity, const vec2& mousePos, std::map<u64 , entt::entity>& allHoveredEntities, const vec2& parentMin, const vec2& parentMax)
388+ {
389+ auto & transform2DSystem = ECS::Transform2DSystem::Get (registry);
390+ // auto& boundingRect = registry.get<Components::UI::BoundingRect>(entity);
391+ // bool isWithin = IsWithin(mousePos, boundingRect.min, boundingRect.max);
392+
393+ // Loop over children recursively (depth first)
394+ transform2DSystem.IterateChildrenRecursiveDepth (entity, [&](auto childEntity)
395+ {
396+ auto & widget = registry.get <Components::UI::Widget>(childEntity);
397+
398+ if (!widget.IsVisible ())
399+ return false ;
400+
401+ if (!widget.IsInteractable ())
402+ return true ;
403+
404+ if (widget.type == Components::UI::WidgetType::Canvas) // For now we don't let canvas consume input
405+ return true ;
406+
407+ auto * rect = registry.try_get <Components::UI::BoundingRect>(childEntity);
408+ if (rect == nullptr )
409+ {
410+ return true ;
411+ }
412+
413+ // Offset the rect by the parents position
414+ vec2 min = rect->min + parentMin;
415+ vec2 max = rect->max + parentMin;
416+
417+ // Cap it so we can't go outside the parent max and interact with clipped children
418+ max = glm::min (max, parentMax);
419+
420+ // Update hoveredMin and hoveredMax
421+ rect->hoveredMin = min;
422+ rect->hoveredMax = max;
423+
424+ bool isWithin = IsWithin (mousePos, min, max);
425+
426+ if (isWithin)
427+ {
428+ Components::Transform2D& transform = registry.get <Components::Transform2D>(childEntity);
429+
430+ vec2 middlePoint = (min + max) * 0 .5f ;
431+
432+ u16 numParents = std::numeric_limits<u16 >::max () - static_cast <u16 >(transform.GetHierarchyDepth ());
433+ u16 layer = std::numeric_limits<u16 >::max () - static_cast <u16 >(transform.GetLayer ());
434+ u32 distanceToMouse = static_cast <u32 >(glm::distance (middlePoint, mousePos)); // Distance in pixels
435+
436+ u64 key = (static_cast <u64 >(numParents) << 48 ) | (static_cast <u64 >(layer) << 32 ) | distanceToMouse;
437+ allHoveredEntities[key] = childEntity;
438+ }
439+
440+ if (widget.type == Components::UI::WidgetType::Panel)
441+ {
442+ auto & panelTemplate = registry.get <Components::UI::PanelTemplate>(childEntity);
443+ if (panelTemplate.setFlags .backgroundRT )
444+ {
445+ RecursivelyFindHoveredInCanvas (registry, panelTemplate.backgroundRTEntity , mousePos, allHoveredEntities, min, max);
446+ }
447+ }
448+
449+ return true ;
450+ });
451+ }
452+
382453 void HandleInput::Update (entt::registry& registry, f32 deltaTime)
383454 {
384455 auto & ctx = registry.ctx ();
@@ -404,9 +475,10 @@ namespace ECS::Systems::UI
404475 // Loop over widget roots
405476 if (!inputManager->IsCursorVirtual ())
406477 {
407- registry.view <Components::UI::WidgetRoot>( ).each ([&](auto entity)
478+ registry.view <Components::UI::Canvas>(entt::exclude<Components::UI::CanvasRenderTargetTag> ).each ([&](auto entity, auto & canvas )
408479 {
409- // Loop over children recursively (depth first)
480+ RecursivelyFindHoveredInCanvas (registry, entity, mousePos, uiSingleton.allHoveredEntities , vec2 (0 ,0 ), renderSize);
481+ /* // Loop over children recursively (depth first)
410482 transform2DSystem.IterateChildrenRecursiveDepth(entity, [&](auto childEntity)
411483 {
412484 auto& widget = registry.get<Components::UI::Widget>(childEntity);
@@ -442,7 +514,7 @@ namespace ECS::Systems::UI
442514 uiSingleton.allHoveredEntities[key] = childEntity;
443515 }
444516 return true;
445- });
517+ });*/
446518 });
447519 }
448520
0 commit comments