From 9c7be4106d6e0b0ab9dd084e8ebdb60b228b1856 Mon Sep 17 00:00:00 2001 From: Jon Kazama Date: Tue, 18 Aug 2026 19:09:40 +0200 Subject: [PATCH] feat(popouts): bring the pop-out windows up to the rest Three things, all visible in one screenshot. The tab name was drawn twice. The pop-out has a title bar carrying the tab name and a header row underneath repeating it -- the same string, one line apart. The header now only draws when the title bar is off, which is the case it was written for. The close button was ImGui.Button, so it took the theme's button colours. On several themes that is a bright magenta plate sitting next to plain text, making the way out of the window the loudest thing in it. It uses the plugin's own icon button now: glyph contrast-checked against the surface, danger colour on hover only. And the message area gets the same floor as the main log, with the same restraint -- no accent wash, motes at a tenth. Pop-outs were the last surface still sitting on flat background while every other window had depth. --- HellionChat/PluginHostFactory.cs | 5 +- HellionChat/Ui/Windows/ChannelPopoutWindow.cs | 65 +++++++++++++++---- 2 files changed, 57 insertions(+), 13 deletions(-) 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(); } }