fix(D.2b): Character window — tab bar sprites on root + footer State-A all 3 lines
BUG 1 (tab bar): Tab group elements (0x10000228/229/538) are UiText with
ConsumesDatChildren=true so their 3 button children are consumed at import.
Fix: inject 3 sprite UiTexts per tab as CHILDREN OF LAYOUT ROOT at absolute
tab rects, ZOrder=8/9 so they draw over dat-imported UiTexts (ZOrder=1-3).
Original tab groups hidden. Active tab (Attributes) gold; inactive parchment.
BUG 2 (footer): Three root causes, all fixed.
(a) _byId stores LAST registered copy per id: stateA (0x10000240) was
the Titles-page copy, hidden by the page-visibility pass. Fixed by
walking root.Children to find the Attributes page (contains NameId)
then FindInSubtree for stateA within that subtree.
(b) Attributes-page stateB/stateC siblings (stacked at y=545) were still
Visible=True, drawing over stateA line-1/line-2. Fixed with
HideAllById walking the Attributes page subtree for ids 241/247.
(c) Footer label elements (H=17-18px, Padding=4f) were routed through
UiTexts scroll path: bottom-pinned baseY ended above the top clip
boundary, silently blanking all text. Fixed: LabelProvider sets
Padding=0f for directly-bound footer single-line labels.
UiDatElement.ElementId exposes _info.Id for subtree id-based walks.
676 tests pass, vitals panel unaffected (regression screenshot clean).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
99291595bb
commit
5aa65dbd43
3 changed files with 236 additions and 111 deletions
|
|
@ -514,71 +514,72 @@ public class CharacterStatControllerTests
|
|||
}
|
||||
|
||||
// ── Pass 2: Tab button states ─────────────────────────────────────────────
|
||||
// Tab groups are UiText (Type 12) with ConsumesDatChildren=true; their button
|
||||
// children are consumed at import time. AddTabSprites() injects 3 UiText
|
||||
// sprite-children per group when a spriteResolve is provided.
|
||||
// Tab sprites are added to layout.Root (NOT to the tab group elements), so
|
||||
// the tab groups keep Children.Count==0 and survive the page-visibility pass.
|
||||
// AddTabSpritesToRoot() adds 3 sprite UiTexts + 1 label UiText per tab to the
|
||||
// root when a spriteResolve is provided; nothing is added when spriteResolve=null.
|
||||
|
||||
[Fact]
|
||||
public void TabButtons_NoSpriteResolve_AddsNoSpriteChildren()
|
||||
public void TabButtons_NoSpriteResolve_AddsNoSpriteChildrenToRoot()
|
||||
{
|
||||
// When spriteResolve is null, AddTabSprites returns early — no children added.
|
||||
var tabGroup = new UiText();
|
||||
var layout = Fake((CharacterStatController.TabAttribId, tabGroup));
|
||||
// When spriteResolve is null, AddTabSpritesToRoot is not called — no sprites added.
|
||||
var layout = Fake(); // empty fake layout with just the root UiPanel
|
||||
int rootChildCountBefore = layout.Root.Children.Count;
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter, spriteResolve: null);
|
||||
|
||||
Assert.Empty(tabGroup.Children);
|
||||
// No extra children added to root when spriteResolve is null.
|
||||
Assert.Equal(rootChildCountBefore, layout.Root.Children.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TabButtons_AttributesGroup_AddsThreeOpenSpriteChildren()
|
||||
public void TabButtons_AttributesGroup_AddsOpenSpriteIdsToRoot()
|
||||
{
|
||||
// Attributes tab (isOpen=true): three UiText sprite children with Open sprite ids.
|
||||
var tabGroup = new UiText();
|
||||
var layout = Fake((CharacterStatController.TabAttribId, tabGroup));
|
||||
// Attributes tab (isOpen=true): 3 sprite children with Open sprite ids on ROOT.
|
||||
// The tab group element itself has 0 children (sprites go to root, not the group).
|
||||
var layout = Fake(); // minimal fake
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16));
|
||||
|
||||
var sprites = tabGroup.Children.OfType<UiText>().ToList();
|
||||
Assert.Equal(3, sprites.Count);
|
||||
Assert.Equal(0x06005D92u, sprites[0].BackgroundSprite); // Open left-cap
|
||||
Assert.Equal(0x06005D94u, sprites[1].BackgroundSprite); // Open center
|
||||
Assert.Equal(0x06005D96u, sprites[2].BackgroundSprite); // Open right-cap
|
||||
// Root should contain the Open sprite ids among all tab sprite children.
|
||||
var sprites = layout.Root.Children.OfType<UiText>()
|
||||
.Where(t => t.BackgroundSprite != 0u).ToList();
|
||||
Assert.Contains(sprites, t => t.BackgroundSprite == 0x06005D92u); // Open left-cap
|
||||
Assert.Contains(sprites, t => t.BackgroundSprite == 0x06005D94u); // Open center
|
||||
Assert.Contains(sprites, t => t.BackgroundSprite == 0x06005D96u); // Open right-cap
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TabButtons_SkillsGroup_AddsThreeClosedSpriteChildren()
|
||||
public void TabButtons_SkillsAndTitles_AddClosedSpriteIdsToRoot()
|
||||
{
|
||||
// Skills tab (isOpen=false): three UiText sprite children with Closed sprite ids.
|
||||
var tabGroup = new UiText();
|
||||
var layout = Fake((CharacterStatController.TabSkillsId, tabGroup));
|
||||
// Skills + Titles tabs (isOpen=false): Closed sprite ids appear on root.
|
||||
var layout = Fake();
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16));
|
||||
|
||||
var sprites = tabGroup.Children.OfType<UiText>().ToList();
|
||||
Assert.Equal(3, sprites.Count);
|
||||
Assert.Equal(0x06005D93u, sprites[0].BackgroundSprite); // Closed left-cap
|
||||
Assert.Equal(0x06005D95u, sprites[1].BackgroundSprite); // Closed center
|
||||
Assert.Equal(0x06005D97u, sprites[2].BackgroundSprite); // Closed right-cap
|
||||
var sprites = layout.Root.Children.OfType<UiText>()
|
||||
.Where(t => t.BackgroundSprite != 0u).ToList();
|
||||
Assert.Contains(sprites, t => t.BackgroundSprite == 0x06005D93u); // Closed left-cap
|
||||
Assert.Contains(sprites, t => t.BackgroundSprite == 0x06005D95u); // Closed center
|
||||
Assert.Contains(sprites, t => t.BackgroundSprite == 0x06005D97u); // Closed right-cap
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TabButtons_TitlesGroup_AddsThreeClosedSpriteChildren()
|
||||
public void TabButtons_WithSpriteResolve_AddsAllThreeTabsToRoot()
|
||||
{
|
||||
// Titles tab (isOpen=false): three UiText sprite children with Closed sprite ids.
|
||||
var tabGroup = new UiText();
|
||||
var layout = Fake((CharacterStatController.TabTitlesId, tabGroup));
|
||||
// With spriteResolve: all 3 tabs inject 4 children each (3 sprites + 1 label)
|
||||
// = 12 sprite children total across 3 tabs on the root.
|
||||
var layout = Fake();
|
||||
|
||||
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||
spriteResolve: id => (id, 16, 16));
|
||||
|
||||
var sprites = tabGroup.Children.OfType<UiText>().ToList();
|
||||
Assert.Equal(3, sprites.Count);
|
||||
Assert.Equal(0x06005D93u, sprites[0].BackgroundSprite); // Closed left-cap
|
||||
Assert.Equal(0x06005D95u, sprites[1].BackgroundSprite); // Closed center
|
||||
Assert.Equal(0x06005D97u, sprites[2].BackgroundSprite); // Closed right-cap
|
||||
// 3 tabs × 3 sprites = 9 sprite UiTexts on root.
|
||||
var sprites = layout.Root.Children.OfType<UiText>()
|
||||
.Where(t => t.BackgroundSprite != 0u).ToList();
|
||||
Assert.Equal(9, sprites.Count);
|
||||
}
|
||||
|
||||
// ── Affordability helpers (GetRaiseCost) ──────────────────────────────────
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue