feat(style-engine): add PushStack as ImRaii bridge

DI-singleton that pairs Token lookups with ImRaii's tracked push/pop
machinery. Begin() returns a disposable PushScope with fluent Color, Style
(float/Vector2) and Font methods; reverse-order dispose runs through the
collected IDisposables. Counter-symmetry and exception-safety come from
ImRaii, this layer just handles the token → ImGuiCol resolution and the
RGBA → ABGR conversion at the ImGui boundary.
This commit is contained in:
2026-05-23 16:36:01 +02:00
parent d89540de52
commit b8299a90ca
2 changed files with 74 additions and 0 deletions
+3
View File
@@ -93,6 +93,9 @@ internal static class PluginHostFactory
)); ));
services.AddSingleton(_ => new Ui.StyleEngine.TokenResolver()); services.AddSingleton(_ => new Ui.StyleEngine.TokenResolver());
services.AddSingleton(sp => new Ui.StyleEngine.PushStack(
sp.GetRequiredService<Ui.StyleEngine.TokenResolver>()
));
services.AddSingleton(sp => new GameFunctions.GameFunctions( services.AddSingleton(sp => new GameFunctions.GameFunctions(
sp.GetRequiredService<Plugin>(), sp.GetRequiredService<Plugin>(),
+71
View File
@@ -0,0 +1,71 @@
using System.Numerics;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface.ManagedFontAtlas;
using Dalamud.Interface.Utility.Raii;
using HellionChat.Themes;
using HellionChat.Util;
namespace HellionChat.Ui.StyleEngine;
// Token-aware bridge over Dalamud's ImRaii. Couples semantic Token lookups
// to the already-tracked push/pop machinery so callers express style intent
// instead of raw ImGuiCol slots. Counter-symmetry and exception-safety come
// from ImRaii, not from this class.
internal sealed class PushStack
{
private readonly TokenResolver _resolver;
public PushStack(TokenResolver resolver)
{
_resolver = resolver;
}
public PushScope Begin() => new(_resolver);
// Disposable scope handed to the using-block. Each Push.* call is a thin
// delegate to ImRaii / IFontHandle.Push with the token resolve in front;
// disposes in reverse order via the captured IDisposables.
internal sealed class PushScope : IDisposable
{
private readonly List<IDisposable> _items = new(32);
private readonly TokenResolver _resolver;
internal PushScope(TokenResolver resolver)
{
_resolver = resolver;
}
public PushScope Color(Token token, Theme theme)
{
var slot = TokenMap.ToImGuiCol(token);
var rgba = _resolver.Resolve(token, theme.Colors);
_items.Add(ImRaii.PushColor(slot, ColourUtil.RgbaToAbgr(rgba)));
return this;
}
public PushScope Style(ImGuiStyleVar var, float value)
{
_items.Add(ImRaii.PushStyle(var, value));
return this;
}
public PushScope Style(ImGuiStyleVar var, Vector2 value)
{
_items.Add(ImRaii.PushStyle(var, value));
return this;
}
public PushScope Font(IFontHandle font)
{
_items.Add(font.Push());
return this;
}
public void Dispose()
{
for (var i = _items.Count - 1; i >= 0; i--)
_items[i].Dispose();
_items.Clear();
}
}
}