@
feat(D.2b): data-driven channel menu chrome + greying + scroll-arrow fix Investigation found the menu popup is fully dat-driven (UIElement_Menu::MakePopup @0x46d310 reads LayoutDesc 0x21000006 elements 0x1000001C/1D/1E — the "stray" top-level elements). Render the popup from the real sprites instead of a flat rect: - panel 0x0600124C, item row 0x0600124E, selected row 0x0600124D; 191x17 rows, 2 cols. - drawing rows as SPRITES also fixes the z-order (a DrawRect bg composited OVER the labels; sprites share the labels submission bucket so text lands on top). - item greying: available channels white, unavailable salmon (colorPink) — static approximation (Say/General/Trade/LFG) with an AvailabilityProvider hook for live TurbineChat state; unavailable items are inert on click. Ports ResetAllTalkFocusMenuButtons. - scroll arrows: both dat sprites point down (export-confirmed); V-flip the top button so it points up. Tabs confirmed to have NO digits in retail (blank gold frames) — acdream already matches. Build + 392 App tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> @
This commit is contained in:
parent
7094a1c847
commit
bb983ae850
4 changed files with 155 additions and 64 deletions
|
|
@ -6,10 +6,13 @@ namespace AcDream.App.Tests.UI;
|
|||
|
||||
public class UiChannelMenuTests
|
||||
{
|
||||
// PopupH = Rows(7) * ItemH(17) = 119; popup opens upward so top = -119.
|
||||
// Item idx -> col = idx/7, row = idx%7; row band y in [top+row*17, top+(row+1)*17).
|
||||
// Right column needs lx >= ColW(191).
|
||||
|
||||
[Fact]
|
||||
public void Items_HasExpected14Entries()
|
||||
{
|
||||
// Retail gmMainChatUI::InitTalkFocusMenu: squelch + tell-selected + 12 channels.
|
||||
Assert.Equal(14, UiChannelMenu.Items.Length);
|
||||
}
|
||||
|
||||
|
|
@ -17,7 +20,7 @@ public class UiChannelMenuTests
|
|||
public void Items_FirstEntry_IsSquelch_Special()
|
||||
{
|
||||
Assert.Equal("Squelch (ignore)", UiChannelMenu.Items[0].Label);
|
||||
Assert.Null(UiChannelMenu.Items[0].Channel); // special item, no channel
|
||||
Assert.Null(UiChannelMenu.Items[0].Channel);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -46,30 +49,11 @@ public class UiChannelMenuTests
|
|||
[Fact]
|
||||
public void DefaultSelected_IsSay()
|
||||
{
|
||||
var menu = new UiChannelMenu();
|
||||
Assert.Equal(ChatChannelKind.Say, menu.Selected);
|
||||
Assert.Equal(ChatChannelKind.Say, new UiChannelMenu().Selected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Select_LeftColumnItem_FiresChannel()
|
||||
{
|
||||
var menu = new UiChannelMenu { Width = 80f, Height = 18f };
|
||||
var openEvt = new UiEvent(0, menu, UiEventType.MouseDown, 0, 10, 5); // open
|
||||
Assert.True(menu.OnEvent(openEvt));
|
||||
|
||||
ChatChannelKind? fired = null;
|
||||
menu.OnChannelChanged = k => fired = k;
|
||||
|
||||
// PopupH = 7*16 = 112, top = -112. "Chat to All" (Say) is index 2 = left col, row 2:
|
||||
// y in [-112+32, -112+48) = [-80,-64). Click (lx=10 < ColW, ly=-72) → idx 2 → Say.
|
||||
var selEvt = new UiEvent(0, menu, UiEventType.MouseDown, 0, 10, -72);
|
||||
Assert.True(menu.OnEvent(selEvt));
|
||||
Assert.Equal(ChatChannelKind.Say, fired);
|
||||
Assert.Equal(ChatChannelKind.Say, menu.Selected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Select_RightColumnItem_FiresChannel()
|
||||
public void Select_AvailableLeftColumnItem_FiresChannel()
|
||||
{
|
||||
var menu = new UiChannelMenu { Width = 80f, Height = 18f };
|
||||
Assert.True(menu.OnEvent(new UiEvent(0, menu, UiEventType.MouseDown, 0, 10, 5))); // open
|
||||
|
|
@ -77,11 +61,25 @@ public class UiChannelMenuTests
|
|||
ChatChannelKind? fired = null;
|
||||
menu.OnChannelChanged = k => fired = k;
|
||||
|
||||
// "Tell to Monarch" is index 7 = right col (lx >= ColW 150), row 0:
|
||||
// y in [-112, -96). Click (lx=160, ly=-104) → col 1, row 0 → idx 7 → Monarch.
|
||||
Assert.True(menu.OnEvent(new UiEvent(0, menu, UiEventType.MouseDown, 0, 160, -104)));
|
||||
Assert.Equal(ChatChannelKind.Monarch, fired);
|
||||
Assert.Equal(ChatChannelKind.Monarch, menu.Selected);
|
||||
// "Chat to All" (Say) is index 2 = left col, row 2: y in [-85,-68). Say is available.
|
||||
Assert.True(menu.OnEvent(new UiEvent(0, menu, UiEventType.MouseDown, 0, 10, -76)));
|
||||
Assert.Equal(ChatChannelKind.Say, fired);
|
||||
Assert.Equal(ChatChannelKind.Say, menu.Selected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Select_AvailableRightColumnItem_FiresChannel()
|
||||
{
|
||||
var menu = new UiChannelMenu { Width = 80f, Height = 18f };
|
||||
Assert.True(menu.OnEvent(new UiEvent(0, menu, UiEventType.MouseDown, 0, 10, 5))); // open
|
||||
|
||||
ChatChannelKind? fired = null;
|
||||
menu.OnChannelChanged = k => fired = k;
|
||||
|
||||
// "Tell to Trade Chat" (Trade) is index 11 = right col (lx>=191), row 4: y in [-51,-34).
|
||||
Assert.True(menu.OnEvent(new UiEvent(0, menu, UiEventType.MouseDown, 0, 200, -42)));
|
||||
Assert.Equal(ChatChannelKind.Trade, fired);
|
||||
Assert.Equal(ChatChannelKind.Trade, menu.Selected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -89,12 +87,39 @@ public class UiChannelMenuTests
|
|||
{
|
||||
var menu = new UiChannelMenu { Width = 80f, Height = 18f };
|
||||
Assert.True(menu.OnEvent(new UiEvent(0, menu, UiEventType.MouseDown, 0, 10, 5))); // open
|
||||
|
||||
int fired = 0;
|
||||
menu.OnChannelChanged = _ => fired++;
|
||||
|
||||
// "Squelch (ignore)" is index 0 = left col, row 0: y in [-112, -96). No channel.
|
||||
Assert.True(menu.OnEvent(new UiEvent(0, menu, UiEventType.MouseDown, 0, 10, -104)));
|
||||
Assert.Equal(0, fired); // special item is a no-op
|
||||
// "Squelch (ignore)" is index 0 = left col, row 0 (null channel): y in [-119,-102).
|
||||
Assert.True(menu.OnEvent(new UiEvent(0, menu, UiEventType.MouseDown, 0, 10, -110)));
|
||||
Assert.Equal(0, fired);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Select_UnavailableChannel_DoesNotFire()
|
||||
{
|
||||
var menu = new UiChannelMenu { Width = 80f, Height = 18f };
|
||||
Assert.True(menu.OnEvent(new UiEvent(0, menu, UiEventType.MouseDown, 0, 10, 5))); // open
|
||||
int fired = 0;
|
||||
menu.OnChannelChanged = _ => fired++;
|
||||
|
||||
// "Tell to Fellows" (Fellowship) is index 3 = left col, row 3: y in [-68,-51).
|
||||
// Fellowship is unavailable by the default static gate, so the click is inert.
|
||||
Assert.True(menu.OnEvent(new UiEvent(0, menu, UiEventType.MouseDown, 0, 10, -60)));
|
||||
Assert.Equal(0, fired);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AvailabilityProvider_Overrides_DefaultGate()
|
||||
{
|
||||
var menu = new UiChannelMenu { Width = 80f, Height = 18f, AvailabilityProvider = _ => true };
|
||||
Assert.True(menu.OnEvent(new UiEvent(0, menu, UiEventType.MouseDown, 0, 10, 5))); // open
|
||||
|
||||
ChatChannelKind? fired = null;
|
||||
menu.OnChannelChanged = k => fired = k;
|
||||
|
||||
// With every channel available, "Tell to Fellows" (idx 3, row 3) now fires.
|
||||
Assert.True(menu.OnEvent(new UiEvent(0, menu, UiEventType.MouseDown, 0, 10, -60)));
|
||||
Assert.Equal(ChatChannelKind.Fellowship, fired);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue