docs(ui): Fix 4 — dat UIState model has no Group visibility encoding; CharacterStatController hacks are correct

Investigation (2026-06-26): the character footer three sibling groups (0x10000240/241/247)
all carry DefaultState=0x10000011 (StatManagement_Footer_Default) — the dat does NOT
differentiate them by visibility.  Parent 0x1000022F has States {Default, Text, Meter}
with PassToChildren=true, but each child group registers all three states with
IncorporationFlags=None and Media=0, so state-propagation produces no visual change
on any group.  Retail gmStatManagementUI uses hardcoded element-id dispatch for
0x10000240/241/247 — the groups are never hidden/shown via the dat state mechanism
(decomp gmStatManagementUI::GetFooterTitleLabel @0x004f0170).

Tab-page containers (0x1000022B/22C/10000539) have DefaultState=Undef — no visibility
encoding.  Tab visibility is managed purely at runtime by gmTabUI.

IncorporationFlags (DatReaderWriter): {None, PassToChildren, X, Y, Width, Height,
ZLevel} — no Visible flag.  The importer cannot set initial Group visibility from
the dat; the controller is the correct and only place.  CharacterStatController
HideAllById footer pass and ContainsWidget page-visibility walk are retail-faithful
and must be kept.

No logic changes — comment-only documentation.  Build green, 710 App tests green.
Studio screenshots: character footer shows State-A by default with no overlap;
vitals and toolbar unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-26 11:19:03 +02:00
parent ed626f4250
commit 1b9dd6c7a8
2 changed files with 38 additions and 0 deletions

View file

@ -186,6 +186,25 @@ public static class LayoutImporter
/// Dat shell: load the LayoutDesc, resolve inheritance for every top-level
/// element, and build the widget tree. Returns null if the layout is absent
/// from the dats.
///
/// <para>
/// <b>Dat UIState visibility model (2026-06-26 audit):</b>
/// The dat's <c>ElementDesc.DefaultState</c> field specifies which SPRITE/MEDIA
/// state an element starts in (e.g., <c>Normal</c>, <c>Minimized</c>). It does
/// NOT encode visibility of sibling Group containers. The <c>StateDesc</c>'s
/// <see cref="DatReaderWriter.Enums.IncorporationFlags"/> contains X/Y/Width/Height/
/// ZLevel/PassToChildren — there is no Visible flag.
/// </para>
///
/// <para>
/// Windows that display multiple sibling Group containers at the same position
/// (the character footer's three state-groups; the tab-page content areas) manage
/// visibility purely at runtime via C++ controller code. Retail uses
/// <c>UIElement::SetState(stateId)</c> on the parent to propagate state, then
/// C++ getters access the right sub-group by element id. All groups are shipped
/// as visible in the imported widget tree; the relevant controllers
/// (<see cref="CharacterStatController"/>) perform the initial show/hide.
/// </para>
/// </summary>
/// <param name="fontResolve">Optional per-element font resolver (see
/// <see cref="Build"/> for details). Null = original single-font behavior.</param>