57b6ead003
Bumps csproj, yaml, repo.json, CHANGELOG, ROADMAP and README in lock-step to 1.5.4. Forge-post DE-body added with the Polish & Motion versionsnatur. Slim-rule applied to the yaml and repo.json changelog blocks (keeps v1.5.4 + v1.5.3 + v1.5.2 + v1.5.1, drops v1.5.0). A csharpier reflow of two v1.5.4 source files (ChatLogWindow, HellionStyle) is folded in. preflight.sh blocks A-F all green.
162 lines
6.7 KiB
C#
162 lines
6.7 KiB
C#
using Dalamud.Bindings.ImGui;
|
|
using Dalamud.Interface.Utility.Raii;
|
|
using HellionChat.Themes;
|
|
using HellionChat.Util;
|
|
|
|
namespace HellionChat.Ui;
|
|
|
|
// Theme-driven ImGui style override. PushGlobal is pushed once per frame
|
|
// in Plugin.Draw and drives every Hellion-rendered window.
|
|
internal static class HellionStyle
|
|
{
|
|
// Local color stack for the active theme. Use inside a
|
|
// `using var _ = HellionStyle.Push(theme);` block.
|
|
internal static IDisposable Push(Theme theme)
|
|
{
|
|
var a = theme.AbgrCache;
|
|
var stack = new StackHandle();
|
|
stack.PushColorAbgr(ImGuiCol.Button, a.Primary);
|
|
stack.PushColorAbgr(ImGuiCol.ButtonHovered, a.PrimaryLight);
|
|
stack.PushColorAbgr(ImGuiCol.ButtonActive, a.PrimaryDark);
|
|
stack.PushColorAbgr(ImGuiCol.FrameBg, a.FrameBg);
|
|
stack.PushColorAbgr(ImGuiCol.FrameBgHovered, a.SurfaceHover);
|
|
stack.PushColorAbgr(ImGuiCol.FrameBgActive, a.Surface);
|
|
stack.PushColorAbgr(ImGuiCol.Border, a.Border);
|
|
stack.PushColorAbgr(ImGuiCol.Header, a.Surface);
|
|
stack.PushColorAbgr(ImGuiCol.HeaderHovered, a.SurfaceHover);
|
|
stack.PushColorAbgr(ImGuiCol.HeaderActive, a.Identity);
|
|
stack.PushColorAbgr(ImGuiCol.CheckMark, a.Primary);
|
|
stack.PushColorAbgr(ImGuiCol.SliderGrab, a.Primary);
|
|
stack.PushColorAbgr(ImGuiCol.SliderGrabActive, a.PrimaryLight);
|
|
return stack;
|
|
}
|
|
|
|
// Global color and style stack pushed once per frame.
|
|
// windowOpacity: window background alpha (0.5-1.0).
|
|
internal static IDisposable PushGlobal(
|
|
Theme theme,
|
|
ThemeRegistry registry,
|
|
float windowOpacity = 1.0f
|
|
)
|
|
{
|
|
var c = theme.Colors;
|
|
var l = theme.Layout;
|
|
|
|
// Crossfade: PM-1 reads a lerped snapshot during the 300ms window
|
|
// following a Switch (TryGetActiveCrossfade returns false outside
|
|
// the window or while ReduceMotion is on). Only the ABGR-slot path
|
|
// crossfades -- WindowBg/ChildBg RGBA stays bound to the user's
|
|
// per-window opacity override and must not fade. See
|
|
// feedback_dalamud_pinning_override.
|
|
ThemeAbgrCache a;
|
|
if (!Plugin.Config.ReduceMotion && registry.TryGetActiveCrossfade(out var lerped))
|
|
{
|
|
a = lerped;
|
|
}
|
|
else
|
|
{
|
|
a = theme.AbgrCache;
|
|
}
|
|
|
|
var stack = new StackHandle();
|
|
|
|
var alphaByte = (uint)Math.Clamp((int)(windowOpacity * 255f), 0x55, 0xFF);
|
|
var windowBgWithAlpha = (c.WindowBg & 0xFFFFFF00u) | alphaByte;
|
|
|
|
// ChildBg alpha resolution lives in HellionStyleHelpers so the
|
|
// threshold logic can be covered by a pure-helper test in the
|
|
// build suite.
|
|
var childBgWithAlpha = HellionStyleHelpers.ResolveChildBgAlpha(c.ChildBg, windowOpacity);
|
|
|
|
// Layout
|
|
stack.PushStyleVar(ImGuiStyleVar.WindowRounding, l.WindowRounding);
|
|
stack.PushStyleVar(ImGuiStyleVar.ChildRounding, l.ChildRounding);
|
|
stack.PushStyleVar(ImGuiStyleVar.PopupRounding, l.PopupRounding);
|
|
stack.PushStyleVar(ImGuiStyleVar.FrameRounding, l.FrameRounding);
|
|
stack.PushStyleVar(ImGuiStyleVar.GrabRounding, l.GrabRounding);
|
|
stack.PushStyleVar(ImGuiStyleVar.TabRounding, l.TabRounding);
|
|
stack.PushStyleVar(ImGuiStyleVar.ScrollbarRounding, l.ScrollbarRounding);
|
|
stack.PushStyleVar(ImGuiStyleVar.WindowBorderSize, l.WindowBorderSize);
|
|
stack.PushStyleVar(ImGuiStyleVar.FrameBorderSize, l.FrameBorderSize);
|
|
|
|
// Surfaces — WindowBg/ChildBg use opacity-modulated values (RGBA path);
|
|
// everything else reads from the pre-computed ABGR cache.
|
|
stack.PushColor(ImGuiCol.WindowBg, windowBgWithAlpha);
|
|
stack.PushColor(ImGuiCol.ChildBg, childBgWithAlpha);
|
|
stack.PushColorAbgr(ImGuiCol.PopupBg, a.ChildBg);
|
|
stack.PushColorAbgr(ImGuiCol.Border, a.Border);
|
|
stack.PushColorAbgr(ImGuiCol.BorderShadow, 0u);
|
|
|
|
// Frames
|
|
stack.PushColorAbgr(ImGuiCol.FrameBg, a.FrameBg);
|
|
stack.PushColorAbgr(ImGuiCol.FrameBgHovered, a.SurfaceHover);
|
|
stack.PushColorAbgr(ImGuiCol.FrameBgActive, a.Surface);
|
|
|
|
// Title bars
|
|
stack.PushColorAbgr(ImGuiCol.TitleBg, a.WindowBg);
|
|
stack.PushColorAbgr(ImGuiCol.TitleBgActive, a.Identity);
|
|
stack.PushColorAbgr(ImGuiCol.TitleBgCollapsed, a.WindowBg);
|
|
|
|
// Buttons
|
|
stack.PushColorAbgr(ImGuiCol.Button, a.Primary);
|
|
stack.PushColorAbgr(ImGuiCol.ButtonHovered, a.PrimaryLight);
|
|
stack.PushColorAbgr(ImGuiCol.ButtonActive, a.PrimaryDark);
|
|
|
|
// Headers / selectables
|
|
stack.PushColorAbgr(ImGuiCol.Header, a.Surface);
|
|
stack.PushColorAbgr(ImGuiCol.HeaderHovered, a.SurfaceHover);
|
|
stack.PushColorAbgr(ImGuiCol.HeaderActive, a.Identity);
|
|
|
|
// Tabs
|
|
stack.PushColorAbgr(ImGuiCol.Tab, a.FrameBg);
|
|
stack.PushColorAbgr(ImGuiCol.TabHovered, a.PrimaryLight);
|
|
stack.PushColorAbgr(ImGuiCol.TabActive, a.Identity);
|
|
stack.PushColorAbgr(ImGuiCol.TabUnfocused, a.ChildBg);
|
|
stack.PushColorAbgr(ImGuiCol.TabUnfocusedActive, a.PrimaryDark);
|
|
|
|
// Scrollbar
|
|
stack.PushColorAbgr(ImGuiCol.ScrollbarBg, a.WindowBg);
|
|
stack.PushColorAbgr(ImGuiCol.ScrollbarGrab, a.Surface);
|
|
stack.PushColorAbgr(ImGuiCol.ScrollbarGrabHovered, a.AccentLight);
|
|
stack.PushColorAbgr(ImGuiCol.ScrollbarGrabActive, a.Accent);
|
|
|
|
// Resize grip
|
|
stack.PushColorAbgr(ImGuiCol.ResizeGrip, a.FrameBg);
|
|
stack.PushColorAbgr(ImGuiCol.ResizeGripHovered, a.AccentLight);
|
|
stack.PushColorAbgr(ImGuiCol.ResizeGripActive, a.Accent);
|
|
|
|
// Check mark + slider grab
|
|
stack.PushColorAbgr(ImGuiCol.CheckMark, a.Primary);
|
|
stack.PushColorAbgr(ImGuiCol.SliderGrab, a.Primary);
|
|
stack.PushColorAbgr(ImGuiCol.SliderGrabActive, a.PrimaryLight);
|
|
|
|
// Separator
|
|
stack.PushColorAbgr(ImGuiCol.Separator, a.Border);
|
|
stack.PushColorAbgr(ImGuiCol.SeparatorHovered, a.PrimaryLight);
|
|
stack.PushColorAbgr(ImGuiCol.SeparatorActive, a.Primary);
|
|
|
|
return stack;
|
|
}
|
|
|
|
private sealed class StackHandle : IDisposable
|
|
{
|
|
private readonly List<IDisposable> _items = new(64);
|
|
|
|
internal void PushColor(ImGuiCol slot, uint rgba) =>
|
|
_items.Add(ImRaii.PushColor(slot, ColourUtil.RgbaToAbgr(rgba)));
|
|
|
|
internal void PushColorAbgr(ImGuiCol slot, uint abgr) =>
|
|
_items.Add(ImRaii.PushColor(slot, abgr));
|
|
|
|
internal void PushStyleVar(ImGuiStyleVar var, float value) =>
|
|
_items.Add(ImRaii.PushStyle(var, value));
|
|
|
|
public void Dispose()
|
|
{
|
|
for (var i = _items.Count - 1; i >= 0; i--)
|
|
_items[i].Dispose();
|
|
_items.Clear();
|
|
}
|
|
}
|
|
}
|