@@ -34,6 +34,42 @@ namespace ECS::Util
3434{
3535 namespace UI
3636 {
37+ entt::entity FindOwningCanvas (entt::registry* registry, entt::entity entity)
38+ {
39+ if (entity == entt::null)
40+ return entt::null;
41+
42+ auto * widget = registry->try_get <ECS ::Components::UI ::Widget>(entity);
43+ if (!widget)
44+ return entt::null;
45+
46+ if (widget->type == ECS ::Components::UI ::WidgetType::Canvas)
47+ return entity;
48+
49+ if (widget->scriptWidget )
50+ return widget->scriptWidget ->canvasEntity ;
51+
52+ return entt::null;
53+ }
54+
55+ void MarkCanvasSortDirty (entt::registry* registry, entt::entity canvasEntity)
56+ {
57+ if (canvasEntity == entt::null)
58+ return ;
59+ registry->emplace_or_replace <ECS ::Components::UI ::DirtyCanvasSort>(canvasEntity);
60+ }
61+
62+ void MarkAllCanvasSortDirty (entt::registry* registry)
63+ {
64+ registry->view <ECS ::Components::UI ::Canvas>().each ([&](entt::entity canvasEntity, auto &)
65+ {
66+ registry->emplace_or_replace <ECS ::Components::UI ::DirtyCanvasSort>(canvasEntity);
67+ });
68+ // The canvas SET changed -> canvasOrder ranking is stale; gates the (relatively
69+ // expensive) RebuildCanvasOrder pass next time CanvasRenderer::Update runs.
70+ registry->ctx ().emplace <ECS ::Components::UI ::DirtyCanvasOrderFlag>();
71+ }
72+
3773 entt::entity GetOrEmplaceCanvas (Scripting::UI ::Widget*& widget, entt::registry* registry, const char * name, vec2 pos, ivec2 size, bool isRenderTexture)
3874 {
3975 ECS ::Singletons::UISingleton& uiSingleton = registry->ctx ().get <ECS ::Singletons::UISingleton>();
@@ -109,6 +145,11 @@ namespace ECS::Util
109145 registry->emplace <ECS ::Components::UI ::CanvasRenderTargetTag>(entity);
110146 }
111147
148+ // A new canvas entering the system shifts canvasOrder for everyone;
149+ // mark every canvas (including this one) so all widget sortKeys get their
150+ // canvasOrder bits refreshed on the next CanvasRenderer::Update tick.
151+ MarkAllCanvasSortDirty (registry);
152+
112153 return entity;
113154 }
114155
@@ -201,6 +242,9 @@ namespace ECS::Util
201242 eventInputInfo.onFocusEndEvent = panelTemplateComp.onFocusEndEvent ;
202243 eventInputInfo.onFocusHeldEvent = panelTemplateComp.onFocusHeldEvent ;
203244
245+ // New widget entering the tree -> owning canvas needs sort-key rebuild.
246+ MarkCanvasSortDirty (registry, FindOwningCanvas (registry, parent));
247+
204248 return entity;
205249 }
206250
@@ -285,6 +329,9 @@ namespace ECS::Util
285329 eventInputInfo.onFocusEndEvent = textTemplate.onFocusEndEvent ;
286330 eventInputInfo.onFocusHeldEvent = textTemplate.onFocusHeldEvent ;
287331
332+ // New widget entering the tree -> owning canvas needs sort-key rebuild.
333+ MarkCanvasSortDirty (registry, FindOwningCanvas (registry, parent));
334+
288335 return entity;
289336 }
290337
@@ -311,6 +358,9 @@ namespace ECS::Util
311358 widgetComp.type = ECS ::Components::UI ::WidgetType::Widget;
312359 widgetComp.scriptWidget = widget;
313360
361+ // New widget entering the tree -> owning canvas needs sort-key rebuild.
362+ MarkCanvasSortDirty (registry, FindOwningCanvas (registry, parent));
363+
314364 return entity;
315365 }
316366
@@ -319,6 +369,10 @@ namespace ECS::Util
319369 if (!registry->all_of <ECS ::Components::UI ::Widget>(entity))
320370 return false ;
321371
372+ // Widgets leaving the tree changes the sibling set in their owning canvas.
373+ // Mark it dirty BEFORE we mutate the scriptWidget or clear the parent, so FindOwningCanvas still resolves.
374+ MarkCanvasSortDirty (registry, FindOwningCanvas (registry, entity));
375+
322376 auto & transform2DSystem = Transform2DSystem::Get (*registry);
323377 transform2DSystem.ClearParent (entity);
324378
@@ -382,6 +436,10 @@ namespace ECS::Util
382436 CallLuaEvent (eventInputInfo->onFocusBeginEvent , Scripting::UI ::UIInputEvent::FocusBegin, widget.scriptWidget );
383437 }
384438 }
439+
440+ // Focus affects sortKey (priority bits), so both the previously focused and the newly focused widget's canvases need their sortKeys rebuilt.
441+ MarkCanvasSortDirty (registry, FindOwningCanvas (registry, oldFocus));
442+ MarkCanvasSortDirty (registry, FindOwningCanvas (registry, entity));
385443 }
386444
387445 entt::entity GetFocusedWidgetEntity (entt::registry* registry)
0 commit comments