pub fn resolve_layout_direction(
commands: Commands<'_, '_>,
default_dir: Option<Res<'_, DefaultLayoutDirection>>,
dirs: Query<'_, '_, &LayoutDirection>,
parents: Query<'_, '_, &ChildOf>,
all: Query<'_, '_, Entity, Without<IsResource>>,
resolved_q: Query<'_, '_, &ResolvedDirection>,
changed_inputs: Query<'_, '_, (), Or<(Changed<LayoutDirection>, Changed<ChildOf>)>>,
unstamped: Query<'_, '_, (), Without<ResolvedDirection>>,
removed_dirs: RemovedComponents<'_, '_, LayoutDirection>,
removed_parents: RemovedComponents<'_, '_, ChildOf>,
)Expand description
Resolve every entity’s LayoutDirection (defaulting to
LayoutDirection::Auto when the component is absent) against its
ancestor chain and stamp the answer into ResolvedDirection.
Roots whose direction is Auto fall back to the
DefaultLayoutDirection resource. Runs in
crate::tick::TickStage::LayoutSync before the layout backend
reads ResolvedDirection.
Algorithm: one pass over every entity. For each entity, walk
ChildOf to the nearest ancestor that either (a) has an explicit
Ltr / Rtl direction, or (b) is the root. Honour the override or
the resource default. Time is O(depth) per entity; with shallow
UI trees (<= 16 levels) this is cheap and avoids any allocation.
D9: the pass is gated on its actual inputs - an explicit
LayoutDirection changing / appearing / disappearing, a hierarchy
edit (ChildOf changed or removed), the DefaultLayoutDirection
resource changing, or entities that have never been stamped. Steady
ticks cost a handful of empty-query checks. When the pass does run,
ResolvedDirection is only (re)inserted when the value actually
differs, so Changed<ResolvedDirection> downstream (the layout
backend’s D8 hook) fires exclusively on real flips.