fix(studio): Character window — selected-row highlight uses retail bar sprite
Replaces the translucent-gold BackgroundColor tint with sprite 0x06001397 (Button state 6 — the retail dark horizontal bars) for the selected-row background. When spriteResolve is provided to Bind(), clicking a row now applies BackgroundSprite=0x06001397 + SpriteResolve on that row and clears it on all others. Falls back to HighlightBg tint when no resolver is passed (tests, or contexts without GL). UiPanel.BackgroundSprite / SpriteResolve added so any panel can host a sprite background in place of the solid BackgroundColor rect. HandleRowClick updated to accept spriteResolve and apply the sprite or tint branch depending on availability. Two new tests verify the sprite / deselect paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a236dc33ac
commit
dfb4c81133
3 changed files with 89 additions and 4 deletions
|
|
@ -410,7 +410,7 @@ public static class CharacterStatController
|
||||||
return v.ToString();
|
return v.ToString();
|
||||||
});
|
});
|
||||||
|
|
||||||
row.OnClick = () => HandleRowClick(rowIndex, sel, rows, data, allRaise1, allRaise10);
|
row.OnClick = () => HandleRowClick(rowIndex, sel, rows, spriteResolve, data, allRaise1, allRaise10);
|
||||||
rows.Add(row);
|
rows.Add(row);
|
||||||
y += RowHeight;
|
y += RowHeight;
|
||||||
}
|
}
|
||||||
|
|
@ -437,7 +437,7 @@ public static class CharacterStatController
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
row.OnClick = () => HandleRowClick(absIndex, sel, rows, data, allRaise1, allRaise10);
|
row.OnClick = () => HandleRowClick(absIndex, sel, rows, spriteResolve, data, allRaise1, allRaise10);
|
||||||
rows.Add(row);
|
rows.Add(row);
|
||||||
y += RowHeight;
|
y += RowHeight;
|
||||||
}
|
}
|
||||||
|
|
@ -453,6 +453,7 @@ public static class CharacterStatController
|
||||||
int clickedIndex,
|
int clickedIndex,
|
||||||
int[] sel,
|
int[] sel,
|
||||||
List<UiClickablePanel> rows,
|
List<UiClickablePanel> rows,
|
||||||
|
Func<uint, (uint handle, int w, int h)>? spriteResolve,
|
||||||
Func<CharacterSheet> data,
|
Func<CharacterSheet> data,
|
||||||
List<UiButton> allRaise1,
|
List<UiButton> allRaise1,
|
||||||
List<UiButton> allRaise10)
|
List<UiButton> allRaise10)
|
||||||
|
|
@ -465,8 +466,35 @@ public static class CharacterStatController
|
||||||
Console.WriteLine($"[CharacterStat] Row click: index={clickedIndex} → selected={newSel} ({rowName})");
|
Console.WriteLine($"[CharacterStat] Row click: index={clickedIndex} → selected={newSel} ({rowName})");
|
||||||
|
|
||||||
// Update highlight on all rows.
|
// Update highlight on all rows.
|
||||||
|
// Retail uses sprite 0x06001397 (Button state 6 — the dark horizontal bars)
|
||||||
|
// for the selected row background. When spriteResolve is available, apply the
|
||||||
|
// sprite; otherwise fall back to the translucent gold tint.
|
||||||
|
const uint HighlightSprite = 0x06001397u;
|
||||||
for (int i = 0; i < rows.Count; i++)
|
for (int i = 0; i < rows.Count; i++)
|
||||||
rows[i].BackgroundColor = (i == newSel) ? HighlightBg : Vector4.Zero;
|
{
|
||||||
|
var row = rows[i];
|
||||||
|
if (i == newSel)
|
||||||
|
{
|
||||||
|
if (spriteResolve is not null)
|
||||||
|
{
|
||||||
|
row.BackgroundColor = Vector4.Zero;
|
||||||
|
row.BackgroundSprite = HighlightSprite;
|
||||||
|
row.SpriteResolve = spriteResolve;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
row.BackgroundColor = HighlightBg;
|
||||||
|
row.BackgroundSprite = 0u;
|
||||||
|
row.SpriteResolve = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
row.BackgroundColor = Vector4.Zero;
|
||||||
|
row.BackgroundSprite = 0u;
|
||||||
|
row.SpriteResolve = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update raise buttons.
|
// Update raise buttons.
|
||||||
RefreshRaiseButtons(newSel, data, allRaise1, allRaise10);
|
RefreshRaiseButtons(newSel, data, allRaise1, allRaise10);
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,28 @@ public class UiPanel : UiElement
|
||||||
|
|
||||||
public float BorderThickness { get; set; } = 1f;
|
public float BorderThickness { get; set; } = 1f;
|
||||||
|
|
||||||
|
/// <summary>Optional dat RenderSurface id for the panel background sprite, drawn
|
||||||
|
/// in place of (or alongside) <see cref="BackgroundColor"/>. 0 = none.
|
||||||
|
/// When set, the sprite is stretched to fill the panel rect.
|
||||||
|
/// Used by the attribute-list selected-row highlight (sprite 0x06001397 = Button state 6).</summary>
|
||||||
|
public uint BackgroundSprite { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Resolves a dat RenderSurface id to (GL tex handle, pixel width, pixel height).
|
||||||
|
/// Required when <see cref="BackgroundSprite"/> is non-zero.</summary>
|
||||||
|
public Func<uint, (uint tex, int w, int h)>? SpriteResolve { get; set; }
|
||||||
|
|
||||||
protected override void OnDraw(UiRenderContext ctx)
|
protected override void OnDraw(UiRenderContext ctx)
|
||||||
{
|
{
|
||||||
if (BackgroundColor.W > 0f)
|
if (BackgroundSprite != 0 && SpriteResolve is { } sr)
|
||||||
|
{
|
||||||
|
var (tex, tw, th) = sr(BackgroundSprite);
|
||||||
|
if (tex != 0 && tw != 0 && th != 0)
|
||||||
|
ctx.DrawSprite(tex, 0, 0, Width, Height, 0, 0, Width / tw, Height / th, Vector4.One);
|
||||||
|
}
|
||||||
|
else if (BackgroundColor.W > 0f)
|
||||||
|
{
|
||||||
ctx.DrawRect(0, 0, Width, Height, BackgroundColor);
|
ctx.DrawRect(0, 0, Width, Height, BackgroundColor);
|
||||||
|
}
|
||||||
|
|
||||||
if (BorderColor.W > 0f && BorderThickness > 0f)
|
if (BorderColor.W > 0f && BorderThickness > 0f)
|
||||||
ctx.DrawRectOutline(0, 0, Width, Height, BorderColor, BorderThickness);
|
ctx.DrawRectOutline(0, 0, Width, Height, BorderColor, BorderThickness);
|
||||||
|
|
|
||||||
|
|
@ -433,6 +433,45 @@ public class CharacterStatControllerTests
|
||||||
Assert.Equal(0f, rows[2].BackgroundColor.W);
|
Assert.Equal(0f, rows[2].BackgroundColor.W);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RowClick_WithSpriteResolve_SelectedRowHasHighlightSprite()
|
||||||
|
{
|
||||||
|
// When spriteResolve is provided, the selected row must use sprite 0x06001397
|
||||||
|
// (retail Button-state-6 dark bar) instead of the translucent gold BackgroundColor.
|
||||||
|
var list = new UiPanel();
|
||||||
|
var layout = Fake((CharacterStatController.ListBoxId, list));
|
||||||
|
|
||||||
|
// Minimal sprite resolver — returns a fake non-zero handle so UiPanel draws it.
|
||||||
|
static (uint, int, int) FakeResolve(uint id) => (1u, 32, 8);
|
||||||
|
|
||||||
|
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||||
|
spriteResolve: FakeResolve);
|
||||||
|
|
||||||
|
var rows = list.Children.OfType<UiClickablePanel>().ToList();
|
||||||
|
rows[2].OnClick!();
|
||||||
|
|
||||||
|
Assert.Equal(0x06001397u, rows[2].BackgroundSprite); // selected → sprite
|
||||||
|
Assert.Equal(0f, rows[2].BackgroundColor.W); // no tint
|
||||||
|
Assert.Equal(0u, rows[0].BackgroundSprite); // others cleared
|
||||||
|
Assert.Equal(0u, rows[1].BackgroundSprite);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RowClick_WithSpriteResolve_Deselect_ClearsSprite()
|
||||||
|
{
|
||||||
|
var list = new UiPanel();
|
||||||
|
var layout = Fake((CharacterStatController.ListBoxId, list));
|
||||||
|
static (uint, int, int) FakeResolve(uint id) => (1u, 32, 8);
|
||||||
|
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||||
|
spriteResolve: FakeResolve);
|
||||||
|
|
||||||
|
var rows = list.Children.OfType<UiClickablePanel>().ToList();
|
||||||
|
rows[2].OnClick!(); // select
|
||||||
|
rows[2].OnClick!(); // deselect
|
||||||
|
|
||||||
|
Assert.Equal(0u, rows[2].BackgroundSprite);
|
||||||
|
}
|
||||||
|
|
||||||
// ── Pass 2: Raise button affordability ───────────────────────────────────
|
// ── Pass 2: Raise button affordability ───────────────────────────────────
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue