using System;
using System.Numerics;
using AcDream.UI.Abstractions;
namespace AcDream.App.UI;
///
/// Chat channel selector (the "Chat ▸" button). Port of retail
/// UIElement_Menu as used by gmMainChatUI::InitTalkFocusMenu @0x4cdc50:
/// a button whose label is the active channel; clicking opens a popup of channels;
/// selecting one calls SetTalkFocus (here: ).
///
public sealed class UiChannelMenu : UiElement
{
public readonly record struct Item(string Label, ChatChannelKind Channel);
/// Retail talk-focus channels (subset acdream's ChatInputParser routes).
public static readonly Item[] Channels =
{
new("Say", ChatChannelKind.Say),
new("General", ChatChannelKind.General),
new("Trade", ChatChannelKind.Trade),
new("LFG", ChatChannelKind.Lfg),
new("Fellowship", ChatChannelKind.Fellowship),
new("Allegiance", ChatChannelKind.Allegiance),
new("Patron", ChatChannelKind.Patron),
new("Vassals", ChatChannelKind.Vassals),
new("Monarch", ChatChannelKind.Monarch),
new("Roleplay", ChatChannelKind.Roleplay),
new("Society", ChatChannelKind.Society),
new("Olthoi", ChatChannelKind.Olthoi),
};
public ChatChannelKind Selected { get; private set; } = ChatChannelKind.Say;
public Action? OnChannelChanged { get; set; }
public UiDatFont? DatFont { get; set; }
public AcDream.App.Rendering.BitmapFont? Font { get; set; }
public Func? SpriteResolve { get; set; }
public uint NormalSprite { get; set; }
public uint PressedSprite { get; set; }
public Vector4 TextColor { get; set; } = new(1f, 0.85f, 0.4f, 1f);
private bool _open;
private const float ItemH = 16f;
private const float PopupW = 90f;
public UiChannelMenu() { CapturesPointerDrag = true; }
private string Label => FindLabel(Selected);
private static string FindLabel(ChatChannelKind k)
{
foreach (var it in Channels) if (it.Channel == k) return it.Label;
return "Chat";
}
protected override void OnDraw(UiRenderContext ctx)
{
if (SpriteResolve is { } resolve)
{
var (tex, _, _) = resolve(_open ? PressedSprite : NormalSprite);
if (tex != 0) ctx.DrawSprite(tex, 0, 0, Width, Height, 0f, 0f, 1f, 1f, Vector4.One);
}
DrawLabel(ctx, Label + " >", 2f, (Height - LineH()) * 0.5f);
if (_open)
{
float h = Channels.Length * ItemH;
float top = -h; // popup opens UPWARD (chat sits at screen bottom)
ctx.DrawRect(0, top, MathF.Max(Width, PopupW), h, new(0f, 0f, 0f, 0.85f));
for (int i = 0; i < Channels.Length; i++)
DrawLabel(ctx, Channels[i].Label, 2f, top + i * ItemH);
}
}
private float LineH() => DatFont?.LineHeight ?? Font?.LineHeight ?? 14f;
private void DrawLabel(UiRenderContext ctx, string s, float x, float y)
{
if (DatFont is { } df) ctx.DrawStringDat(df, s, x, y, TextColor);
else ctx.DrawString(s, x, y, TextColor, Font);
}
protected override bool OnHitTest(float lx, float ly)
=> _open ? (lx >= 0 && lx < MathF.Max(Width, PopupW)
&& ly >= -Channels.Length * ItemH && ly < Height)
: base.OnHitTest(lx, ly);
public override bool OnEvent(in UiEvent e)
{
if (e.Type == UiEventType.MouseDown)
{
float ly = e.Data2;
if (_open && ly < 0)
{
int idx = (int)((ly + Channels.Length * ItemH) / ItemH);
if (idx >= 0 && idx < Channels.Length)
{
Selected = Channels[idx].Channel;
OnChannelChanged?.Invoke(Selected);
}
_open = false;
return true;
}
_open = !_open;
return true;
}
return false;
}
}