diff --git a/HellionChat/Plugin.cs b/HellionChat/Plugin.cs index 713b7f0..c117d0c 100755 --- a/HellionChat/Plugin.cs +++ b/HellionChat/Plugin.cs @@ -109,6 +109,9 @@ public sealed class Plugin : IAsyncDalamudPlugin internal static InputPreview InputPreview { get; private set; } = null!; internal CommandHelpWindow CommandHelpWindow { get; private set; } = null!; public SeStringDebugger SeStringDebugger { get; private set; } = null!; +#if DEBUG + internal Ui.Windows.WidgetGalleryWindow WidgetGallery { get; private set; } = null!; +#endif public FirstRunWizard FirstRunWizard { get; private set; } = null!; internal DebuggerWindow DebuggerWindow { get; private set; } = null!; @@ -365,6 +368,9 @@ public sealed class Plugin : IAsyncDalamudPlugin InputPreview = _host.Services.GetRequiredService(); CommandHelpWindow = _host.Services.GetRequiredService(); SeStringDebugger = _host.Services.GetRequiredService(); +#if DEBUG + WidgetGallery = _host.Services.GetRequiredService(); +#endif DebuggerWindow = _host.Services.GetRequiredService(); FirstRunWizard = _host.Services.GetRequiredService(); ChannelPopoutPool = _host.Services.GetRequiredService(); @@ -925,6 +931,13 @@ public sealed class Plugin : IAsyncDalamudPlugin SettingsWindow.Toggle(); return; } +#if DEBUG + if (arg.Equals("widgets", StringComparison.OrdinalIgnoreCase)) + { + WidgetGallery.Toggle(); + return; + } +#endif if (arg.Equals("reset", StringComparison.OrdinalIgnoreCase)) { // Recovery path documented in the v2.x master spec — drops a diff --git a/HellionChat/PluginHostFactory.cs b/HellionChat/PluginHostFactory.cs index d700eaf..794d132 100644 --- a/HellionChat/PluginHostFactory.cs +++ b/HellionChat/PluginHostFactory.cs @@ -340,6 +340,12 @@ internal static class PluginHostFactory sp.GetRequiredService>() )); services.AddSingleton(sp => new SeStringDebugger(sp.GetRequiredService())); +#if DEBUG + services.AddSingleton(sp => new Ui.Windows.WidgetGalleryWindow( + sp.GetRequiredService(), + sp.GetRequiredService() + )); +#endif services.AddSingleton(sp => new DebuggerWindow( sp.GetRequiredService(), sp.GetRequiredService() diff --git a/HellionChat/PluginLifecycle.cs b/HellionChat/PluginLifecycle.cs index 369bd24..e0a27df 100644 --- a/HellionChat/PluginLifecycle.cs +++ b/HellionChat/PluginLifecycle.cs @@ -64,6 +64,9 @@ internal sealed class PluginLifecycle : IAsyncDisposable plugin.WindowSystem.AddWindow(Plugin.InputPreview); plugin.WindowSystem.AddWindow(plugin.CommandHelpWindow); plugin.WindowSystem.AddWindow(plugin.SeStringDebugger); +#if DEBUG + plugin.WindowSystem.AddWindow(plugin.WidgetGallery); +#endif plugin.WindowSystem.AddWindow(plugin.DebuggerWindow); plugin.WindowSystem.AddWindow(plugin.FirstRunWizard); diff --git a/HellionChat/Ui/Windows/WidgetGalleryWindow.cs b/HellionChat/Ui/Windows/WidgetGalleryWindow.cs new file mode 100644 index 0000000..ba17a31 --- /dev/null +++ b/HellionChat/Ui/Windows/WidgetGalleryWindow.cs @@ -0,0 +1,196 @@ +#if DEBUG +using System.Numerics; +using Dalamud.Bindings.ImGui; +using Dalamud.Interface; +using Dalamud.Interface.Utility.Raii; +using Dalamud.Interface.Windowing; +using HellionChat.Themes; +using HellionChat.Ui.StyleEngine; +using HellionChat.Ui.StyleEngine.Widgets; + +namespace HellionChat.Ui.Windows; + +// Every widget in Ui/StyleEngine/Widgets shown in its states, so they can be +// checked one at a time before they land in real components. The v2.x style +// engine grew three primitives that were never wired to a call site +// (DrawGlowBorder, DrawSlipPolygon, DrawHonorificHeader) -- this is the cheap +// way to notice that before a cycle closes. +// +// DEBUG-only, like SeStringDebugger: it is a verification aid, not a feature. +internal sealed class WidgetGalleryWindow : Window +{ + private readonly Plugin _plugin; + private readonly WidgetPalette _palette; + + private int _badgeCount = 3; + private bool _rowActive = true; + + internal WidgetGalleryWindow(Plugin plugin, TokenResolver resolver) + : base("Widget Gallery###hellion-widget-gallery") + { + _plugin = plugin; + _palette = new WidgetPalette(resolver); + Size = new Vector2(460, 560); + SizeCondition = ImGuiCond.FirstUseEver; + } + + public override void Draw() + { + var c = _plugin.ThemeRegistry.Active.Colors; + + ImGui.TextDisabled( + $"GlobalScale {Metrics.Scale:0.00} · hover entries {HoverState.TrackedCount}" + ); + ImGui.Separator(); + + DrawRowSection(c); + DrawBadgeSection(c); + DrawPillSection(c); + DrawIconButtonSection(c); + DrawDividerSection(c); + } + + private void DrawRowSection(ThemeColors c) + { + ImGui.TextUnformatted("Row"); + ImGui.Checkbox("active##row", ref _rowActive); + + var width = ImGui.GetContentRegionAvail().X; + var height = Metrics.SidebarRowHeight; + + for (var i = 0; i < 3; i++) + { + var origin = ImGui.GetCursorScreenPos(); + var id = ImGui.GetID($"gallery.row.{i}"); + ImGui.InvisibleButton($"##gallery-row-{i}", new Vector2(width, height)); + var hovered = ImGui.IsItemHovered(); + + Row.Draw( + origin, + new Vector2(width, height), + new RowVisualState + { + IsActive = _rowActive && i == 1, + HoverAmount = HoverState.Query(id, hovered), + SurfaceAbgr = _palette.Abgr(Token.SurfaceBase, c), + SurfaceHoverAbgr = _palette.Abgr(Token.SurfaceHover, c), + SurfaceActiveAbgr = _palette.Abgr(Token.SurfaceActive, c), + AccentAbgr = _palette.Abgr(Token.AccentPrimary, c), + BorderAbgr = _palette.Abgr(Token.Border, c), + } + ); + + ImGui + .GetWindowDrawList() + .AddText( + origin + new Vector2(12f * Metrics.Scale, Metrics.CenterY(height)), + _palette.Abgr(Token.Text, c), + $"Row {i}" + ); + } + + ImGui.Spacing(); + } + + private void DrawBadgeSection(ThemeColors c) + { + ImGui.TextUnformatted("Badge"); + ImGui.SliderInt("count##badge", ref _badgeCount, 0, 150); + + int[] samples = [1, 9, _badgeCount, 120]; + var origin = ImGui.GetCursorScreenPos(); + var x = origin.X; + foreach (var n in samples) + { + Badge.Draw( + new Vector2(x, origin.Y), + n, + _palette.Abgr(Token.AccentEmber, c), + _palette.Abgr(Token.Text, c) + ); + x += Badge.CalcSize(n).X + 8f * Metrics.Scale; + } + + ImGui.Dummy(new Vector2(0, Badge.CalcSize(1).Y + 8f * Metrics.Scale)); + ImGui.Spacing(); + } + + private void DrawPillSection(ThemeColors c) + { + ImGui.TextUnformatted("Pill"); + + var origin = ImGui.GetCursorScreenPos(); + var x = origin.X; + + Pill.Draw( + new Vector2(x, origin.Y), + "filled", + _palette.Abgr(Token.SurfaceRaised, c), + _palette.Abgr(Token.Text, c) + ); + x += Pill.CalcSize("filled", withDot: false).X + 8f * Metrics.Scale; + + Pill.Draw( + new Vector2(x, origin.Y), + "with dot", + _palette.Abgr(Token.SurfaceRaised, c), + _palette.Abgr(Token.Text, c), + _palette.Abgr(Token.AccentPrimary, c) + ); + x += Pill.CalcSize("with dot", withDot: true).X + 8f * Metrics.Scale; + + Pill.Draw( + new Vector2(x, origin.Y), + "outlined", + _palette.Abgr(Token.AccentPrimary, c), + _palette.Abgr(Token.TextMuted, c), + styleOverride: new PillStyle { Outlined = true } + ); + + ImGui.Dummy(new Vector2(0, Pill.CalcSize("x", false).Y + 8f * Metrics.Scale)); + ImGui.Spacing(); + } + + private void DrawIconButtonSection(ThemeColors c) + { + ImGui.TextUnformatted("IconButton"); + + var size = new Vector2(Metrics.SidebarPopOutHitWidth, Metrics.SidebarRowHeight); + FontAwesomeIcon[] glyphs = + [ + FontAwesomeIcon.ArrowUpRightFromSquare, + FontAwesomeIcon.Check, + FontAwesomeIcon.CheckCircle, + ]; + + for (var i = 0; i < glyphs.Length; i++) + { + if (i > 0) + ImGui.SameLine(); + + IconButton.Draw( + ImGui.GetID($"gallery.icon.{i}"), + size, + glyphs[i], + _palette.Abgr(Token.TextMuted, c), + _palette.Abgr(Token.SurfaceHover, c), + _plugin.FontManager.FontAwesome + ); + } + + ImGui.Spacing(); + } + + private void DrawDividerSection(ThemeColors c) + { + ImGui.TextUnformatted("LineDivider"); + + LineDivider.Draw( + "Section (2)", + _palette.Abgr(Token.Border, c), + _palette.Abgr(Token.TextMuted, c) + ); + LineDivider.Draw(null, _palette.Abgr(Token.Border, c), _palette.Abgr(Token.TextMuted, c)); + } +} +#endif