acdream/src/AcDream.App/UI/IUiDatStateful.cs
Erik 7d09821fdc fix(chargen): Campaign CC gate round 1 Batch B — authored selection states, label state, zoom/swatch feedback
GF-1/GF-8: UiButton now recognizes retail's custom Unselected/Selected
radio-pair (0x10000016/0x10000017), bypassing the standard Normal/
Highlight machine that never admitted those state names — .Selected now
lights the heritage/template/gender/Face-Clothes rows it was always a
no-op for.

AP-222/GF-11b: per-state label color/outline (dat 0x1B/0x21) now applies
off the REQUESTED retail state id, not the art-gated committed
ActiveState — resolves the Appearance spins' current-part highlight
(text recolors even though no Highlight art exists on either client) and
the Town caption's Normal-to-white swap.

GF-11c: UiButton.LabelBox lets a lifted caption with its own authored
rect draw there instead of the face-relative offset that's only correct
when the label is authored directly on the button (heritage/template
family, unchanged).

GF-9: wires the real nine companion overlay elements (SetColor's
SetVisible mechanism) that swatch clicks were always meant to drive,
retiring AP-215 item 1 (the swatch.Selected substitution was a permanent
no-op — swatches author no Highlight media at all).

GF-10: zoom buttons now set the retail-mirrored mutual-exclusive
Highlight/Normal pair on click; InitializePage carries no initial
SetState for either button, so both stay at "Normal" until first click.

Register: AP-222 retired (mechanism identified and ported), AP-215
narrowed (item 1 retired, item 2 unrelated and unchanged), row count
recount corrected 164 (was already one high before this batch).

App suite 5282/3 (was 5266/3), Runtime 1735/0 unchanged. Fixture + live-
DAT tests only — no graphical client launch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 11:37:09 +02:00

83 lines
3.1 KiB
C#

namespace AcDream.App.UI;
/// <summary>
/// Narrow numeric-state bridge for widgets imported from retail LayoutDesc data.
/// Controllers use retail state ids without knowing how names/media are stored.
/// </summary>
public interface IUiDatStateful
{
uint ActiveRetailStateId { get; }
bool TrySetRetailState(uint stateId);
}
public static class RetailUiStateIds
{
public const uint Closed = 11u;
public const uint Open = 12u;
public const uint HideDetail = 0x10000006u;
public const uint ShowDetail = 0x10000007u;
public const uint ObjectSelected = 0x1000000Bu;
public const uint StackedItemSelected = 0x1000000Cu;
public const uint ItemSlotEmpty = 0x1000001Cu;
public const uint Maximized = 0x10000047u;
public const uint Minimized = 0x10000048u;
public const uint LockedUi = 0x10000063u;
public const uint UnlockedUi = 0x10000064u;
/// <summary>
/// Campaign CC gate round 1 Batch B (GF-1/GF-8): retail's custom
/// radio-selection state pair, live-DAT-probe-confirmed on the Heritage
/// row (<c>0x100003BF</c>), Profession template (<c>0x100003D9</c>),
/// Appearance Face/Clothes sub-tabs (<c>0x100003A9</c>/<c>0x100003AA</c>),
/// and gender buttons (<c>0x100003A7</c>/<c>0x100003A8</c>). Named
/// <c>UiStateInfo.Name</c> strings, not media file ids — the buttons
/// author their state DESCRIPTORS under these two ids, with the actual
/// per-state art living either directly on the button (gender) or on a
/// single stateful face-segment child (heritage/template/sub-tabs).
/// See <see cref="AcDream.App.UI.UiButton"/>'s custom-selection-pair
/// bypass in <c>UpdateVisualState</c>.
/// </summary>
public const uint Unselected = 0x10000016u;
public const uint Selected = 0x10000017u;
public static string StateName(uint stateId)
=> stateId switch
{
Closed => "Closed",
Open => "Open",
HideDetail => "HideDetail",
ShowDetail => "ShowDetail",
ObjectSelected => "ObjectSelected",
StackedItemSelected => "StackedItemSelected",
ItemSlotEmpty => "ItemSlot_Empty",
Maximized => "Maximized",
Minimized => "Minimized",
LockedUi => "LockedUI",
UnlockedUi => "UnlockedUI",
Unselected => "Unselected",
Selected => "Selected",
_ => "",
};
public static bool TryStateId(string stateName, out uint stateId)
{
stateId = stateName switch
{
"Closed" => Closed,
"Open" => Open,
"HideDetail" => HideDetail,
"ShowDetail" => ShowDetail,
"ObjectSelected" => ObjectSelected,
"StackedItemSelected" => StackedItemSelected,
"ItemSlot_Empty" => ItemSlotEmpty,
"Maximized" => Maximized,
"Minimized" => Minimized,
"LockedUI" => LockedUi,
"UnlockedUI" => UnlockedUi,
"Unselected" => Unselected,
"Selected" => Selected,
_ => 0u,
};
return stateId != 0;
}
}