diff --git a/HellionChat/PluginHostFactory.cs b/HellionChat/PluginHostFactory.cs index 9c02edc..d36659c 100644 --- a/HellionChat/PluginHostFactory.cs +++ b/HellionChat/PluginHostFactory.cs @@ -324,7 +324,10 @@ internal static class PluginHostFactory sp.GetRequiredService() ), sp.GetRequiredService>(), - sp.GetRequiredService() + sp.GetRequiredService(), + sp.GetRequiredService(), + sp.GetRequiredService(), + sp.GetRequiredService() ) ); services.AddSingleton(sp => new Ui.Windows.ChannelPopoutPool( diff --git a/HellionChat/Ui/Windows/ChannelPopoutWindow.cs b/HellionChat/Ui/Windows/ChannelPopoutWindow.cs index a7fa4e1..8bcdb3f 100644 --- a/HellionChat/Ui/Windows/ChannelPopoutWindow.cs +++ b/HellionChat/Ui/Windows/ChannelPopoutWindow.cs @@ -3,7 +3,10 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; +using HellionChat.Themes; using HellionChat.Ui.Components; +using HellionChat.Ui.StyleEngine.Widgets; +using HellionChat.Util; using Microsoft.Extensions.Logging; namespace HellionChat.Ui.Windows; @@ -20,13 +23,19 @@ internal sealed class ChannelPopoutWindow : Window, IFocusableChatWindow private readonly InputBar _input; private readonly ILogger _logger; private readonly FontManager _fonts; + private readonly Ui.StyleEngine.SurfaceBackdrop _backdrop; + private readonly ThemeRegistry _themes; + private readonly Ui.StyleEngine.TokenResolver _resolver; public ChannelPopoutWindow( int slotIndex, MessageList messages, InputBar input, ILogger logger, - FontManager fonts + FontManager fonts, + Ui.StyleEngine.SurfaceBackdrop backdrop, + ThemeRegistry themes, + Ui.StyleEngine.TokenResolver resolver ) : base($"{Plugin.PluginName}###hellion_popout_{slotIndex}") { @@ -35,6 +44,9 @@ internal sealed class ChannelPopoutWindow : Window, IFocusableChatWindow _input = input; _logger = logger; _fonts = fonts; + _backdrop = backdrop; + _themes = themes; + _resolver = resolver; IsOpen = false; RespectCloseHotkey = false; ShowCloseButton = false; @@ -103,7 +115,11 @@ internal sealed class ChannelPopoutWindow : Window, IFocusableChatWindow if (Bound is null) return; - DrawHeader(Bound); + // Only when the window has no title bar of its own. With the bar on, + // this row repeated the tab name directly underneath it -- the same + // string twice, one line apart. + if (!Plugin.Config.ShowPopOutTitleBar) + DrawHeader(Bound); // The header close button can unbind us mid-frame (CloseRequested -> // pool.TryClose -> Unbind nulls Bound). Re-check before the body so we @@ -125,7 +141,13 @@ internal sealed class ChannelPopoutWindow : Window, IFocusableChatWindow ) { if (body.Success) + { + // Same floor as the main window's log, and the same reasoning: + // no accent wash and barely any motes, because a chat log is read + // line by line. + _backdrop.Draw(accentWashHeight: 0f, moteIntensity: 0.10f, strength: 0.45f); _messages.Draw(Bound); + } } _input.Draw(Bound); @@ -137,18 +159,37 @@ internal sealed class ChannelPopoutWindow : Window, IFocusableChatWindow // close button is the canonical "send the tab back" affordance for v1.8.0. // PartnerHonorific is deferred (HonorificService has no per-target title, // plan §D / Sub-Spec WARN-8) — no honorific row here. + var colors = _themes.Active.Colors; + var text = ColourUtil.RgbaToAbgr(_resolver.Resolve(Ui.StyleEngine.Token.Text, colors)); + var surface = ColourUtil.RgbaToAbgr( + _resolver.Resolve(Ui.StyleEngine.Token.SurfaceBase, colors) + ); + var danger = ColourUtil.RgbaToAbgr( + _resolver.Resolve(Ui.StyleEngine.Token.StatusDanger, colors) + ); + ImGui.TextUnformatted(tab.Name); - ImGui.SameLine(); - using (_fonts.FontAwesome.Push()) + + // The plugin's own icon button rather than ImGui.Button. The stock one + // took the theme's button colours, which on several themes is a bright + // magenta plate next to plain text -- the loudest thing in the window + // being the way out of it. + var size = ImGui.GetFrameHeight(); + ImGui.SameLine(ImGui.GetContentRegionAvail().X - size); + var (clicked, _) = IconButton.Draw( + ImGui.GetID($"popout.close.{_slotIndex}"), + new Vector2(size, size), + FontAwesomeIcon.Times, + ColourUtil.EnsureContrast(text, surface, 3f), + danger, + _fonts.FontAwesome + ); + + if (clicked) { - ImGui.SameLine(ImGui.GetContentRegionAvail().X - ImGui.GetFrameHeight()); - if (ImGui.Button($"{FontAwesomeIcon.Times.ToIconString()}##popin-{_slotIndex}")) - { - // Pop-In: release the slot via the pool (not a bare Unbind, which - // would orphan the slot — the pool owns the slot bookkeeping). - CloseRequested?.Invoke(tab.Identifier); - } + // Pop-In: release the slot via the pool (not a bare Unbind, which + // would orphan the slot — the pool owns the slot bookkeeping). + CloseRequested?.Invoke(tab.Identifier); } - ImGui.Separator(); } }