feat(D.2b): chat polish — typing fix, opacity, scrollbar 3-slice, retail channel menu Visual-iteration batch (decomp-grounded), each fix verified against the retail screenshots: - typing: UiElement.HitTest aborted on ClickThrough BEFORE walking children, so the ClickThrough UiDatElement panels blocked hit-testing to the input/transcript inside them. Check ClickThrough AFTER the child walk (it only gates whether THIS element claims the hit). Restores input focus + typing. - opacity: UiElement.Opacity + a UiRenderContext alpha stack applied to sprite/rect draws (text bypasses it, stays sharp); chat frame Opacity=0.75 → translucent chat. - brown sliver: grow the transcript panel up 9px to cover the dropped resize-bar strip. - scrollbar: real 3-slice thumb (caps 0x06004C60/66 + tiled mid) + tiled track. - max/min: shifted one button-width left of the scrollbar (dat right-anchors collide). - system text now green (retail ChatMessageType 5; was yellow). - word-wrap: transcript lines wrap to the panel width (greedy, ports GlyphList::Recalculate). - channel menu reworked to retail gmMainChatUI::InitTalkFocusMenu: "Chat" button + a TWO-COLUMN popup of the 14 talk-focus items (Squelch, Tell to Selected, Chat to All, Tell to Fellows, ...) on a tan panel; channel items set the active outbound channel. Build + 392 App tests green. Visual confirmation in progress. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> @
100 lines
3.6 KiB
C#
100 lines
3.6 KiB
C#
using System.Linq;
|
|
using AcDream.App.UI;
|
|
using AcDream.UI.Abstractions;
|
|
|
|
namespace AcDream.App.Tests.UI;
|
|
|
|
public class UiChannelMenuTests
|
|
{
|
|
[Fact]
|
|
public void Items_HasExpected14Entries()
|
|
{
|
|
// Retail gmMainChatUI::InitTalkFocusMenu: squelch + tell-selected + 12 channels.
|
|
Assert.Equal(14, UiChannelMenu.Items.Length);
|
|
}
|
|
|
|
[Fact]
|
|
public void Items_FirstEntry_IsSquelch_Special()
|
|
{
|
|
Assert.Equal("Squelch (ignore)", UiChannelMenu.Items[0].Label);
|
|
Assert.Null(UiChannelMenu.Items[0].Channel); // special item, no channel
|
|
}
|
|
|
|
[Fact]
|
|
public void Items_LastEntry_IsOlthoi()
|
|
{
|
|
var last = UiChannelMenu.Items[^1];
|
|
Assert.Equal("Tell to Olthoi Chat", last.Label);
|
|
Assert.Equal(ChatChannelKind.Olthoi, last.Channel);
|
|
}
|
|
|
|
[Fact]
|
|
public void Items_ContainAll12ChannelKinds()
|
|
{
|
|
var kinds = new HashSet<ChatChannelKind>(
|
|
UiChannelMenu.Items.Where(i => i.Channel is not null).Select(i => i.Channel!.Value));
|
|
foreach (var k in new[]
|
|
{
|
|
ChatChannelKind.Say, ChatChannelKind.General, ChatChannelKind.Trade, ChatChannelKind.Lfg,
|
|
ChatChannelKind.Fellowship, ChatChannelKind.Allegiance, ChatChannelKind.Patron,
|
|
ChatChannelKind.Vassals, ChatChannelKind.Monarch, ChatChannelKind.Roleplay,
|
|
ChatChannelKind.Society, ChatChannelKind.Olthoi,
|
|
})
|
|
Assert.Contains(k, kinds);
|
|
}
|
|
|
|
[Fact]
|
|
public void DefaultSelected_IsSay()
|
|
{
|
|
var menu = new UiChannelMenu();
|
|
Assert.Equal(ChatChannelKind.Say, menu.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()
|
|
{
|
|
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 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);
|
|
}
|
|
|
|
[Fact]
|
|
public void Select_SpecialItem_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++;
|
|
|
|
// "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
|
|
}
|
|
}
|