fix(ui): #375 residual — activate the Configure Keyboard screen's own tab control
The gate-3 screenshot flight showed the keyboard list still rendering as overlapping text after the string-resolver + parked-prototype fixes: all SIX ActionClass pages were visible simultaneously (six stacked ListBoxes — 'EmotesterSettings' is the Emote and CharacterSettings pages interleaved) with six dead tab buttons above them. Root cause: OP8's Bind built every page's rows but never called ActivateTabBehavior() on the screen's own Type-8 tab host (0x1000049B), so no authored click bindings were wired and no default-entry switch ran. The authored table marks Movement (0x1000049D) IsDefault=true — activation now performs the same default switch OptionsPanelController runs on ITS host, hiding the other five pages and making the six tabs live. Regressed by Bind_ActivatesTheTabControl_MovementDefaultShown_OtherPagesHidden (fixture-driven: BehaviorActive, Movement visible, five pages hidden, SwitchTo flips exclusivity). Full Release suite: 13,087 passed / 4 skipped / 0 failed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
3441a71833
commit
a8ce010d02
2 changed files with 71 additions and 0 deletions
|
|
@ -161,6 +161,11 @@ public sealed class KeyboardConfigController
|
||||||
private const int HeaderTemplateIndex = 0;
|
private const int HeaderTemplateIndex = 0;
|
||||||
private const int RowTemplateIndex = 1;
|
private const int RowTemplateIndex = 1;
|
||||||
|
|
||||||
|
/// <summary>The screen's own Type-8 tab control hosting the six ActionClass
|
||||||
|
/// pages (class doc §"Six ActionClass list boxes"). Its authored tab table
|
||||||
|
/// (dat property 0x2E) marks Movement (0x1000049D) as the default entry.</summary>
|
||||||
|
private const uint TabHostElementId = 0x1000049Bu;
|
||||||
|
|
||||||
// The row template's 3 key-button children, in "Mapping 1/2/3" column order.
|
// The row template's 3 key-button children, in "Mapping 1/2/3" column order.
|
||||||
private static readonly uint[] KeyButtonIds = { 0x10000030u, 0x10000031u, 0x10000032u };
|
private static readonly uint[] KeyButtonIds = { 0x10000030u, 0x10000031u, 0x10000032u };
|
||||||
|
|
||||||
|
|
@ -291,6 +296,25 @@ public sealed class KeyboardConfigController
|
||||||
|
|
||||||
WireScreenButtons(layout, controller, bindings);
|
WireScreenButtons(layout, controller, bindings);
|
||||||
|
|
||||||
|
// Gate-2 screenshot finding (#375 residual): OP8 built all six pages
|
||||||
|
// but never ACTIVATED the screen's own tab control, so every page
|
||||||
|
// stayed Visible simultaneously — six stacked ListBoxes reading as
|
||||||
|
// "overlapping text", with six dead tab buttons above them.
|
||||||
|
// ActivateTabBehavior wires the authored tab clicks and performs the
|
||||||
|
// authored default-entry switch (Movement, IsDefault=true in the DAT
|
||||||
|
// table), hiding the other five pages — the exact same call
|
||||||
|
// OptionsPanelController makes on ITS Type-8 host at construction.
|
||||||
|
if (layout.FindElement(TabHostElementId) is UiTabPanel tabHost)
|
||||||
|
{
|
||||||
|
tabHost.ActivateTabBehavior();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine(
|
||||||
|
$"[D.2b] KeyboardConfigController: tab host 0x{TabHostElementId:X8} not found "
|
||||||
|
+ "(or not a UiTabPanel) — all six ActionClass pages will render stacked.");
|
||||||
|
}
|
||||||
|
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,53 @@ public sealed class KeyboardConfigControllerTests
|
||||||
Assert.Equal(3, controller.Page.Rows.Count);
|
Assert.Equal(3, controller.Page.Rows.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Bind_ActivatesTheTabControl_MovementDefaultShown_OtherPagesHidden()
|
||||||
|
{
|
||||||
|
// Gate-2 screenshot finding (#375 residual): OP8 never activated the
|
||||||
|
// screen's own Type-8 tab control, so all six ActionClass pages stayed
|
||||||
|
// Visible simultaneously — six stacked ListBoxes reading as
|
||||||
|
// "overlapping text", with dead tab buttons. Bind must run the
|
||||||
|
// authored default-entry switch (Movement, IsDefault=true) exactly
|
||||||
|
// like OptionsPanelController does for its own host.
|
||||||
|
var snapshot = new RetailActionMapSnapshot(new[]
|
||||||
|
{
|
||||||
|
Row(0x4, 0x29, RetailActionClass.Movement),
|
||||||
|
Row(0x5, 0x33, RetailActionClass.Camera),
|
||||||
|
});
|
||||||
|
|
||||||
|
ImportedLayout layout = FixtureLoader.LoadKeyboardConfig();
|
||||||
|
var fake = new FakeBindings();
|
||||||
|
KeyboardConfigController controller = KeyboardConfigController.Bind(
|
||||||
|
layout, snapshot, MakeTemplateResolver(), (_, _) => null, fake.ToBindings())!;
|
||||||
|
Assert.NotNull(controller);
|
||||||
|
|
||||||
|
UiTabPanel tabHost = Assert.IsType<UiTabPanel>(layout.FindElement(0x1000049Bu));
|
||||||
|
Assert.True(tabHost.BehaviorActive);
|
||||||
|
Assert.Equal(0x1000049Du, tabHost.ActivePageElementId); // Movement, the authored default
|
||||||
|
|
||||||
|
// Exactly one page visible: Movement; the other five hidden.
|
||||||
|
foreach ((uint pageId, bool expectVisible) in new[]
|
||||||
|
{
|
||||||
|
(0x1000049Du, true), // Movement
|
||||||
|
(0x1000049Fu, false), // Camera
|
||||||
|
(0x100004A1u, false), // Combat
|
||||||
|
(0x100004A3u, false), // UI
|
||||||
|
(0x10000211u, false), // CharacterSettings
|
||||||
|
(0x100004A5u, false), // Emote
|
||||||
|
})
|
||||||
|
{
|
||||||
|
UiElement? page = UiElement.FindDescendant(tabHost, pageId);
|
||||||
|
Assert.NotNull(page);
|
||||||
|
Assert.Equal(expectVisible, page!.Visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The tab buttons are live: switching to Camera flips exclusivity.
|
||||||
|
tabHost.SwitchTo(0x1000049Fu);
|
||||||
|
Assert.False(UiElement.FindDescendant(tabHost, 0x1000049Du)!.Visible);
|
||||||
|
Assert.True(UiElement.FindDescendant(tabHost, 0x1000049Fu)!.Visible);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Bind_MapsKnownActionsAndLeavesUnknownOnesUnmapped()
|
public void Bind_MapsKnownActionsAndLeavesUnknownOnesUnmapped()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue