feat(themes): wire theme engine into plugin draw pipeline + migrate v13→v14
HellionStyle.PushGlobal nimmt jetzt eine Theme-Instance + Window-Opacity und liest alle Color- und Style-Slots aus dem aktiven Theme statt aus einer fixen Konstanten-Tabelle. Plugin hält die ThemeRegistry und schaltet beim Init auf das in Config.Theme gespeicherte Slug. Configuration v13 → v14: - Neue Felder Theme (slug), WindowOpacity, ReduceMotion, UseCompactDensity, ShowThemeQuickPicker - HellionThemeEnabled und HellionThemeWindowOpacity sind ab v14 [Obsolete] und bleiben bis v1.2.0 als JSON-Safety-Net erhalten - Migration setzt alle Bestandsuser auf hellion-arctic; chat2-classic bleibt im Themes-Tab als Upstream-Look wählbar - WindowOpacity übernimmt den Wert von HellionThemeWindowOpacity, alte HellionThemeEnabled-Flag entfällt funktional (Theme-Engine ist immer aktiv) Konsumenten der alten Felder (ChatLogWindow.BgAlpha, Popout.BgAlpha) lesen jetzt das neue WindowOpacity. Die Settings-UI in Appearance.cs schreibt übergangsweise weiter in die Obsolete-Felder; Phase J ersetzt diesen Block durch den dedizierten Themes-Tab. CS0612/CS0618 sind dort gezielt mit pragma gekapselt.
This commit is contained in:
@@ -34,10 +34,23 @@ public class ConfigKeyBind
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class Configuration : IPluginConfiguration
|
public class Configuration : IPluginConfiguration
|
||||||
{
|
{
|
||||||
private const int LatestVersion = 13;
|
private const int LatestVersion = 14;
|
||||||
|
|
||||||
public int Version { get; set; } = LatestVersion;
|
public int Version { get; set; } = LatestVersion;
|
||||||
|
|
||||||
|
// v1.1.0 — Theme-Engine. Slug-basiert; ThemeRegistry liefert das Objekt.
|
||||||
|
public string Theme = "hellion-arctic";
|
||||||
|
|
||||||
|
// v1.1.0 — Globale Window-Opacity, theme-übergreifend. Migration aus
|
||||||
|
// HellionThemeWindowOpacity beim Bump v13 → v14.
|
||||||
|
public float WindowOpacity = 0.85f;
|
||||||
|
|
||||||
|
// v1.1.0 — Felder für künftige UI-Toggles (v1.2.0 / v1.3.0). Werden
|
||||||
|
// vorab angelegt, damit später keine Migration nötig ist.
|
||||||
|
public bool ReduceMotion;
|
||||||
|
public bool UseCompactDensity;
|
||||||
|
public bool ShowThemeQuickPicker;
|
||||||
|
|
||||||
// Hellion Chat — Privacy filter (DSGVO Art. 25 Privacy by Default).
|
// Hellion Chat — Privacy filter (DSGVO Art. 25 Privacy by Default).
|
||||||
// Master-switch defaults to true; set false to restore upstream behavior.
|
// Master-switch defaults to true; set false to restore upstream behavior.
|
||||||
public bool PrivacyFilterEnabled = true;
|
public bool PrivacyFilterEnabled = true;
|
||||||
@@ -70,12 +83,14 @@ public class Configuration : IPluginConfiguration
|
|||||||
// Hellion Chat global ImGui theme — applied to every plugin window in
|
// Hellion Chat global ImGui theme — applied to every plugin window in
|
||||||
// Plugin.Draw. Default ON; users who prefer the upstream Dalamud look
|
// Plugin.Draw. Default ON; users who prefer the upstream Dalamud look
|
||||||
// can flip this off in the Privacy tab.
|
// can flip this off in the Privacy tab.
|
||||||
|
[Obsolete("Replaced by Theme slug + WindowOpacity in v14")]
|
||||||
public bool HellionThemeEnabled = true;
|
public bool HellionThemeEnabled = true;
|
||||||
|
|
||||||
// Window background opacity, 0.5–1.0. Lower values make the plugin
|
// Window background opacity, 0.5–1.0. Lower values make the plugin
|
||||||
// panes more glass-like so the game shines through. Default 0.5
|
// panes more glass-like so the game shines through. Default 0.5
|
||||||
// matches the maintainer's daily-driver preference; users who want
|
// matches the maintainer's daily-driver preference; users who want
|
||||||
// a less translucent look bump it up in Aussehen → Theme.
|
// a less translucent look bump it up in Aussehen → Theme.
|
||||||
|
[Obsolete("Replaced by WindowOpacity in v14")]
|
||||||
public float HellionThemeWindowOpacity = 0.5f;
|
public float HellionThemeWindowOpacity = 0.5f;
|
||||||
|
|
||||||
// Use the bundled Exo 2 font (OFL-1.1) for the regular plugin font
|
// Use the bundled Exo 2 font (OFL-1.1) for the regular plugin font
|
||||||
@@ -321,10 +336,19 @@ public class Configuration : IPluginConfiguration
|
|||||||
RetentionLastRunAt = other.RetentionLastRunAt;
|
RetentionLastRunAt = other.RetentionLastRunAt;
|
||||||
|
|
||||||
FirstRunCompleted = other.FirstRunCompleted;
|
FirstRunCompleted = other.FirstRunCompleted;
|
||||||
|
#pragma warning disable CS0612, CS0618 // Obsolete-Felder bleiben bis v1.2.0 als JSON-Safety-Net erhalten
|
||||||
HellionThemeEnabled = other.HellionThemeEnabled;
|
HellionThemeEnabled = other.HellionThemeEnabled;
|
||||||
HellionThemeWindowOpacity = other.HellionThemeWindowOpacity;
|
HellionThemeWindowOpacity = other.HellionThemeWindowOpacity;
|
||||||
|
#pragma warning restore CS0612, CS0618
|
||||||
UseHellionFont = other.UseHellionFont;
|
UseHellionFont = other.UseHellionFont;
|
||||||
|
|
||||||
|
// v1.1.0 theme engine fields
|
||||||
|
Theme = other.Theme;
|
||||||
|
WindowOpacity = other.WindowOpacity;
|
||||||
|
ReduceMotion = other.ReduceMotion;
|
||||||
|
UseCompactDensity = other.UseCompactDensity;
|
||||||
|
ShowThemeQuickPicker = other.ShowThemeQuickPicker;
|
||||||
|
|
||||||
EnableAutoTellTabs = other.EnableAutoTellTabs;
|
EnableAutoTellTabs = other.EnableAutoTellTabs;
|
||||||
AutoTellTabsLimit = other.AutoTellTabsLimit;
|
AutoTellTabsLimit = other.AutoTellTabsLimit;
|
||||||
AutoTellTabsCompactDisplay = other.AutoTellTabsCompactDisplay;
|
AutoTellTabsCompactDisplay = other.AutoTellTabsCompactDisplay;
|
||||||
|
|||||||
+32
-7
@@ -63,6 +63,7 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
internal ExtraChat ExtraChat { get; }
|
internal ExtraChat ExtraChat { get; }
|
||||||
internal TypingIpc TypingIpc { get; }
|
internal TypingIpc TypingIpc { get; }
|
||||||
internal FontManager FontManager { get; }
|
internal FontManager FontManager { get; }
|
||||||
|
internal Themes.ThemeRegistry ThemeRegistry { get; private set; } = null!;
|
||||||
|
|
||||||
internal int DeferredSaveFrames = -1;
|
internal int DeferredSaveFrames = -1;
|
||||||
|
|
||||||
@@ -237,6 +238,27 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hellion Chat v13 → v14 — theme-engine migration. Alle User landen
|
||||||
|
// auf "hellion-arctic" als neues Default-Theme; die alte
|
||||||
|
// HellionThemeEnabled-Flag wird deprecated und nur noch ein Release
|
||||||
|
// als Safety-Net im JSON behalten. Window-Opacity wandert von
|
||||||
|
// HellionThemeWindowOpacity in das neue WindowOpacity-Feld.
|
||||||
|
if (Config.Version < 14)
|
||||||
|
{
|
||||||
|
Config.Theme = "hellion-arctic";
|
||||||
|
#pragma warning disable CS0612, CS0618 // Obsolete: HellionThemeWindowOpacity bleibt readable bis v1.2.0
|
||||||
|
Config.WindowOpacity = Config.HellionThemeWindowOpacity;
|
||||||
|
#pragma warning restore CS0612, CS0618
|
||||||
|
Config.ReduceMotion = false;
|
||||||
|
Config.UseCompactDensity = false;
|
||||||
|
Config.ShowThemeQuickPicker = false;
|
||||||
|
Config.Version = 14;
|
||||||
|
SaveConfig();
|
||||||
|
Log.Information(
|
||||||
|
"Migrated config v13 → v14: theme engine introduced, all users land on hellion-arctic; " +
|
||||||
|
"pick chat2-classic in Settings → Themes for the upstream look");
|
||||||
|
}
|
||||||
|
|
||||||
// Hellion v1.0.0 default tab layout. Five thematically separated
|
// Hellion v1.0.0 default tab layout. Five thematically separated
|
||||||
// tabs: General catches the immediate-surroundings public chat
|
// tabs: General catches the immediate-surroundings public chat
|
||||||
// (Say/Yell/Shout) only; System absorbs the rest of the technical
|
// (Say/Yell/Shout) only; System absorbs the rest of the technical
|
||||||
@@ -266,6 +288,12 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
ExtraChat = new ExtraChat();
|
ExtraChat = new ExtraChat();
|
||||||
FontManager = new FontManager();
|
FontManager = new FontManager();
|
||||||
|
|
||||||
|
// v1.1.0 — Theme-Engine init. Custom-Themes liegen in
|
||||||
|
// pluginConfigs/HellionChat/themes/, lazy geladen beim ersten Get.
|
||||||
|
var customThemesDir = Path.Combine(Interface.ConfigDirectory.FullName, "themes");
|
||||||
|
ThemeRegistry = new Themes.ThemeRegistry(customThemesDir);
|
||||||
|
ThemeRegistry.Switch(Config.Theme);
|
||||||
|
|
||||||
MessageManager = new MessageManager(this); // Does it require UI?
|
MessageManager = new MessageManager(this); // Does it require UI?
|
||||||
|
|
||||||
// Hellion Chat — Auto-Tell-Tabs service. Subscribes to the
|
// Hellion Chat — Auto-Tell-Tabs service. Subscribes to the
|
||||||
@@ -559,13 +587,10 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
|
|
||||||
private void Draw()
|
private void Draw()
|
||||||
{
|
{
|
||||||
// Hellion theme is pushed once per frame here so every plugin window
|
// Theme-Engine ist ab v14 immer aktiv; Klassik ist jetzt ein eigenes
|
||||||
// (chat log, settings, viewers, wizard, file dialog) renders with
|
// Theme statt einem deaktivierten Hellion-Theme. Active wird einmal
|
||||||
// the same palette. Skipping the push leaves the upstream Dalamud
|
// pro Frame aus der Registry gelesen.
|
||||||
// look untouched for users who flipped the toggle off.
|
using IDisposable _style = HellionStyle.PushGlobal(ThemeRegistry.Active, Config.WindowOpacity);
|
||||||
using IDisposable? _style = Config.HellionThemeEnabled
|
|
||||||
? HellionStyle.PushGlobal(Config.HellionThemeWindowOpacity)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
ChatLogWindow.BeginFrame();
|
ChatLogWindow.BeginFrame();
|
||||||
|
|
||||||
|
|||||||
@@ -494,9 +494,7 @@ public sealed class ChatLogWindow : Window
|
|||||||
Flags |= ImGuiWindowFlags.NoTitleBar;
|
Flags |= ImGuiWindowFlags.NoTitleBar;
|
||||||
|
|
||||||
if (LastViewport == ImGuiHelpers.MainViewport.Handle && !WasDocked)
|
if (LastViewport == ImGuiHelpers.MainViewport.Handle && !WasDocked)
|
||||||
BgAlpha = Plugin.Config.HellionThemeEnabled
|
BgAlpha = Plugin.Config.WindowOpacity;
|
||||||
? Plugin.Config.HellionThemeWindowOpacity
|
|
||||||
: Plugin.Config.WindowAlpha / 100f;
|
|
||||||
|
|
||||||
LastViewport = ImGui.GetWindowViewport().Handle;
|
LastViewport = ImGui.GetWindowViewport().Handle;
|
||||||
WasDocked = ImGui.IsWindowDocked();
|
WasDocked = ImGui.IsWindowDocked();
|
||||||
|
|||||||
+86
-173
@@ -1,3 +1,4 @@
|
|||||||
|
using HellionChat.Themes;
|
||||||
using HellionChat.Util;
|
using HellionChat.Util;
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Interface.Utility.Raii;
|
using Dalamud.Interface.Utility.Raii;
|
||||||
@@ -5,207 +6,119 @@ using Dalamud.Interface.Utility.Raii;
|
|||||||
namespace HellionChat.Ui;
|
namespace HellionChat.Ui;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ImGui style override for Hellion Chat. Industrial HUD palette with three
|
/// ImGui style override for Hellion Chat. v1.1.0 ist die Engine
|
||||||
/// distinct accents — cyan-teal as the primary action color, industrial
|
/// theme-getrieben: PushGlobal nimmt eine Theme-Instance + Window-
|
||||||
/// amber for active state highlights, slate-violet for title bars and
|
/// Opacity, die gesamten Color- und Style-Slots werden aus dem Theme
|
||||||
/// active tabs — on a deep-slate frame background with steel borders.
|
/// gelesen statt aus einer fixen Konstanten-Tabelle.
|
||||||
///
|
|
||||||
/// Two entry points:
|
|
||||||
/// Push — local color stack, scoped via using-block. Use inside
|
|
||||||
/// Hellion-only surfaces (Privacy tab, first-run wizard).
|
|
||||||
/// PushGlobal — full color + style variable stack. Pushed once per frame
|
|
||||||
/// in Plugin.Draw so every Hellion-rendered window inherits
|
|
||||||
/// the look. Cheap to pop because ImGui keeps its own stack.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class HellionStyle
|
internal static class HellionStyle
|
||||||
{
|
{
|
||||||
// Encoded as 0xRRGGBBAA, matching ChatTwo convention (see Settings.cs
|
|
||||||
// Ko-fi buttons). RgbaToAbgr handles the byte swap to the format ImGui
|
|
||||||
// expects. Hex values are sourced from the Hellion Online Media brand
|
|
||||||
// guide ("Arctic Cyan + Ember Glow", BRANDING.md in the website repo).
|
|
||||||
|
|
||||||
// Primary — Arctic Cyan, used for every interactive control (buttons,
|
|
||||||
// checks, sliders, separators when hovered). Three brand stages plus a
|
|
||||||
// hover that lifts to brand-color-light and a press that drops to
|
|
||||||
// brand-color-dark.
|
|
||||||
private const uint PrimaryRgba = 0x00BED2FF; // brand-color
|
|
||||||
private const uint PrimaryHoverRgba = 0x4DD9E8FF; // brand-color-light
|
|
||||||
private const uint PrimaryActiveRgba = 0x0097A7FF; // brand-color-dark
|
|
||||||
|
|
||||||
// Identity — brand-color-dark teal for window title bars and the
|
|
||||||
// active tab. Sits visibly below the primary cyan on buttons so the
|
|
||||||
// user sees "where am I" (deep teal) versus "what can I click"
|
|
||||||
// (brand cyan) without leaving the cyan family.
|
|
||||||
private const uint IdentityRgba = 0x0097A7FF; // brand-color-dark
|
|
||||||
private const uint IdentityHoverRgba = 0x4DD9E8FF; // brand-color-light
|
|
||||||
private const uint IdentityDeepRgba = 0x005670FF; // dimmer teal for unfocused-active tab
|
|
||||||
|
|
||||||
// Accent — Ember Orange for warm highlights on grips and scrollbar
|
|
||||||
// pulls. Replaces the previous industrial amber so the plugin matches
|
|
||||||
// the website's CTA palette. AccentActive is reserved for any future
|
|
||||||
// pressed-state on accent surfaces; the current slots only need
|
|
||||||
// AccentRgba and AccentHoverRgba.
|
|
||||||
private const uint AccentRgba = 0xF97316FF; // accent-color
|
|
||||||
private const uint AccentHoverRgba = 0xFB923CFF; // accent-color-light
|
|
||||||
|
|
||||||
// Surfaces — Hellion brand background ladder. Window darkest, frame
|
|
||||||
// hover ladder climbs into surface tones. Matches the website's
|
|
||||||
// background / background-medium / background-light / surface vars.
|
|
||||||
private const uint WindowBgRgba = 0x070B12FF; // background
|
|
||||||
private const uint ChildBgRgba = 0x0C1220FF; // background-medium
|
|
||||||
private const uint PopupBgRgba = 0x0C1220FF; // background-medium
|
|
||||||
private const uint FrameBgRgba = 0x141E30FF; // background-light
|
|
||||||
private const uint FrameBgHoverRgba = 0x1A2538FF; // surface
|
|
||||||
private const uint FrameBgActiveRgba = 0x22303FFF; // surface-hover
|
|
||||||
// Cyan-tinted border — matches website --border-brand (cyan @ 40% α).
|
|
||||||
private const uint BorderRgba = 0x00BED266;
|
|
||||||
private const uint BorderShadowRgba = 0x00000000;
|
|
||||||
|
|
||||||
// Headers / collapsing-headers / tree nodes / selectables — same
|
|
||||||
// surface ladder as frames so panels feel consistent.
|
|
||||||
private const uint HeaderRgba = 0x141E30FF;
|
|
||||||
private const uint HeaderHoverRgba = 0x1A2538FF;
|
|
||||||
private const uint HeaderActiveRgba = 0x22303FFF;
|
|
||||||
|
|
||||||
// Title bars — Identity teal on active so the focused window reads
|
|
||||||
// as "yours" without using accent or primary slots.
|
|
||||||
private const uint TitleBgRgba = 0x070B12FF;
|
|
||||||
private const uint TitleBgActiveRgba = IdentityRgba;
|
|
||||||
private const uint TitleBgCollapsedRgba = 0x05080EFF;
|
|
||||||
|
|
||||||
// Tabs — neutral inactive, Identity-light on hover, Identity teal on
|
|
||||||
// active. Unfocused-active uses the deeper Identity stage so an
|
|
||||||
// unfocused window's active tab still reads but does not pull focus.
|
|
||||||
private const uint TabRgba = 0x141E30FF;
|
|
||||||
private const uint TabHoveredRgba = IdentityHoverRgba;
|
|
||||||
private const uint TabActiveRgba = IdentityRgba;
|
|
||||||
private const uint TabUnfocusedRgba = 0x0C1220FF;
|
|
||||||
private const uint TabUnfocusedActiveRgba = IdentityDeepRgba;
|
|
||||||
|
|
||||||
// Scrollbar — Ember on grab so the pull stands out without competing
|
|
||||||
// with the cyan action buttons. Idle grab is a subtle surface tone,
|
|
||||||
// hover/active climb into accent.
|
|
||||||
private const uint ScrollbarBgRgba = 0x070B12FF;
|
|
||||||
private const uint ScrollbarGrabRgba = 0x22303FFF; // surface-hover
|
|
||||||
private const uint ScrollbarGrabHoveredRgba = AccentHoverRgba;
|
|
||||||
private const uint ScrollbarGrabActiveRgba = AccentRgba;
|
|
||||||
|
|
||||||
// Resize grip — same Ember treatment as the scrollbar.
|
|
||||||
private const uint ResizeGripRgba = 0x141E30FF;
|
|
||||||
private const uint ResizeGripHoveredRgba = AccentHoverRgba;
|
|
||||||
private const uint ResizeGripActiveRgba = AccentRgba;
|
|
||||||
|
|
||||||
// Separator and check mark / slider follow the primary cyan.
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Local color stack for Hellion-only surfaces. Cheap. Use inside a
|
/// Local color stack auf Basis des aktiven Themes. Cheap. Use inside a
|
||||||
/// `using var _ = HellionStyle.Push();` block.
|
/// `using var _ = HellionStyle.Push(theme);` block.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static IDisposable Push()
|
internal static IDisposable Push(Theme theme)
|
||||||
{
|
{
|
||||||
|
var c = theme.Colors;
|
||||||
var stack = new StackHandle();
|
var stack = new StackHandle();
|
||||||
stack.PushColor(ImGuiCol.Button, PrimaryRgba);
|
stack.PushColor(ImGuiCol.Button, c.Primary);
|
||||||
stack.PushColor(ImGuiCol.ButtonHovered, PrimaryHoverRgba);
|
stack.PushColor(ImGuiCol.ButtonHovered, c.PrimaryLight);
|
||||||
stack.PushColor(ImGuiCol.ButtonActive, PrimaryActiveRgba);
|
stack.PushColor(ImGuiCol.ButtonActive, c.PrimaryDark);
|
||||||
stack.PushColor(ImGuiCol.FrameBg, FrameBgRgba);
|
stack.PushColor(ImGuiCol.FrameBg, c.FrameBg);
|
||||||
stack.PushColor(ImGuiCol.FrameBgHovered, FrameBgHoverRgba);
|
stack.PushColor(ImGuiCol.FrameBgHovered, c.SurfaceHover);
|
||||||
stack.PushColor(ImGuiCol.FrameBgActive, FrameBgActiveRgba);
|
stack.PushColor(ImGuiCol.FrameBgActive, c.Surface);
|
||||||
stack.PushColor(ImGuiCol.Border, BorderRgba);
|
stack.PushColor(ImGuiCol.Border, c.Border);
|
||||||
stack.PushColor(ImGuiCol.Header, HeaderRgba);
|
stack.PushColor(ImGuiCol.Header, c.Surface);
|
||||||
stack.PushColor(ImGuiCol.HeaderHovered, HeaderHoverRgba);
|
stack.PushColor(ImGuiCol.HeaderHovered, c.SurfaceHover);
|
||||||
stack.PushColor(ImGuiCol.HeaderActive, HeaderActiveRgba);
|
stack.PushColor(ImGuiCol.HeaderActive, c.Identity);
|
||||||
stack.PushColor(ImGuiCol.CheckMark, PrimaryRgba);
|
stack.PushColor(ImGuiCol.CheckMark, c.Primary);
|
||||||
stack.PushColor(ImGuiCol.SliderGrab, PrimaryRgba);
|
stack.PushColor(ImGuiCol.SliderGrab, c.Primary);
|
||||||
stack.PushColor(ImGuiCol.SliderGrabActive, PrimaryHoverRgba);
|
stack.PushColor(ImGuiCol.SliderGrabActive, c.PrimaryLight);
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Global color and style-variable stack pushed once per frame in
|
/// Global color and style-variable stack pushed once per frame in
|
||||||
/// Plugin.Draw. Covers every ImGui surface the plugin renders so the
|
/// Plugin.Draw. Drives every Hellion-rendered window from the active
|
||||||
/// Hellion look is consistent across upstream and Hellion tabs.
|
/// theme's palette and layout values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="windowOpacity">Window background alpha (0.5–1.0). Lower
|
/// <param name="theme">Active theme from ThemeRegistry.</param>
|
||||||
/// values let the game shine through the plugin panes.</param>
|
/// <param name="windowOpacity">Window background alpha (0.5–1.0).</param>
|
||||||
internal static IDisposable PushGlobal(float windowOpacity = 1.0f)
|
internal static IDisposable PushGlobal(Theme theme, float windowOpacity = 1.0f)
|
||||||
{
|
{
|
||||||
|
var c = theme.Colors;
|
||||||
|
var l = theme.Layout;
|
||||||
var stack = new StackHandle();
|
var stack = new StackHandle();
|
||||||
|
|
||||||
// Mix the configured opacity into both the outer window and the
|
|
||||||
// inner content child backgrounds — without ChildBg following the
|
|
||||||
// slider the chat log stays opaque inside even when the user
|
|
||||||
// wants to see the game behind it during combat. Form fields and
|
|
||||||
// popups (FrameBg, PopupBg) still stay opaque so input is readable.
|
|
||||||
var alphaByte = (uint)Math.Clamp((int)(windowOpacity * 255f), 0x55, 0xFF);
|
var alphaByte = (uint)Math.Clamp((int)(windowOpacity * 255f), 0x55, 0xFF);
|
||||||
var windowBgWithAlpha = (WindowBgRgba & 0xFFFFFF00u) | alphaByte;
|
var windowBgWithAlpha = (c.WindowBg & 0xFFFFFF00u) | alphaByte;
|
||||||
var childBgWithAlpha = (ChildBgRgba & 0xFFFFFF00u) | alphaByte;
|
var childBgWithAlpha = (c.ChildBg & 0xFFFFFF00u) | alphaByte;
|
||||||
|
|
||||||
// Layout — geometric edges, modest rounding, single-pixel borders.
|
// Layout
|
||||||
stack.PushStyleVar(ImGuiStyleVar.WindowRounding, 4f);
|
stack.PushStyleVar(ImGuiStyleVar.WindowRounding, l.WindowRounding);
|
||||||
stack.PushStyleVar(ImGuiStyleVar.ChildRounding, 3f);
|
stack.PushStyleVar(ImGuiStyleVar.ChildRounding, l.ChildRounding);
|
||||||
stack.PushStyleVar(ImGuiStyleVar.PopupRounding, 3f);
|
stack.PushStyleVar(ImGuiStyleVar.PopupRounding, l.PopupRounding);
|
||||||
stack.PushStyleVar(ImGuiStyleVar.FrameRounding, 2f);
|
stack.PushStyleVar(ImGuiStyleVar.FrameRounding, l.FrameRounding);
|
||||||
stack.PushStyleVar(ImGuiStyleVar.GrabRounding, 2f);
|
stack.PushStyleVar(ImGuiStyleVar.GrabRounding, l.GrabRounding);
|
||||||
stack.PushStyleVar(ImGuiStyleVar.TabRounding, 2f);
|
stack.PushStyleVar(ImGuiStyleVar.TabRounding, l.TabRounding);
|
||||||
stack.PushStyleVar(ImGuiStyleVar.ScrollbarRounding, 2f);
|
stack.PushStyleVar(ImGuiStyleVar.ScrollbarRounding, l.ScrollbarRounding);
|
||||||
stack.PushStyleVar(ImGuiStyleVar.WindowBorderSize, 1f);
|
stack.PushStyleVar(ImGuiStyleVar.WindowBorderSize, l.WindowBorderSize);
|
||||||
stack.PushStyleVar(ImGuiStyleVar.FrameBorderSize, 1f);
|
stack.PushStyleVar(ImGuiStyleVar.FrameBorderSize, l.FrameBorderSize);
|
||||||
|
|
||||||
// Surfaces.
|
// Surfaces
|
||||||
stack.PushColor(ImGuiCol.WindowBg, windowBgWithAlpha);
|
stack.PushColor(ImGuiCol.WindowBg, windowBgWithAlpha);
|
||||||
stack.PushColor(ImGuiCol.ChildBg, childBgWithAlpha);
|
stack.PushColor(ImGuiCol.ChildBg, childBgWithAlpha);
|
||||||
stack.PushColor(ImGuiCol.PopupBg, PopupBgRgba);
|
stack.PushColor(ImGuiCol.PopupBg, c.ChildBg);
|
||||||
stack.PushColor(ImGuiCol.Border, BorderRgba);
|
stack.PushColor(ImGuiCol.Border, c.Border);
|
||||||
stack.PushColor(ImGuiCol.BorderShadow, BorderShadowRgba);
|
stack.PushColor(ImGuiCol.BorderShadow, 0u);
|
||||||
|
|
||||||
// Frames (input fields, combos, sliders).
|
// Frames
|
||||||
stack.PushColor(ImGuiCol.FrameBg, FrameBgRgba);
|
stack.PushColor(ImGuiCol.FrameBg, c.FrameBg);
|
||||||
stack.PushColor(ImGuiCol.FrameBgHovered, FrameBgHoverRgba);
|
stack.PushColor(ImGuiCol.FrameBgHovered, c.SurfaceHover);
|
||||||
stack.PushColor(ImGuiCol.FrameBgActive, FrameBgActiveRgba);
|
stack.PushColor(ImGuiCol.FrameBgActive, c.Surface);
|
||||||
|
|
||||||
// Title bars — tertiary identity on active.
|
// Title bars
|
||||||
stack.PushColor(ImGuiCol.TitleBg, TitleBgRgba);
|
stack.PushColor(ImGuiCol.TitleBg, c.WindowBg);
|
||||||
stack.PushColor(ImGuiCol.TitleBgActive, TitleBgActiveRgba);
|
stack.PushColor(ImGuiCol.TitleBgActive, c.Identity);
|
||||||
stack.PushColor(ImGuiCol.TitleBgCollapsed, TitleBgCollapsedRgba);
|
stack.PushColor(ImGuiCol.TitleBgCollapsed, c.WindowBg);
|
||||||
|
|
||||||
// Buttons — primary cyan.
|
// Buttons
|
||||||
stack.PushColor(ImGuiCol.Button, PrimaryRgba);
|
stack.PushColor(ImGuiCol.Button, c.Primary);
|
||||||
stack.PushColor(ImGuiCol.ButtonHovered, PrimaryHoverRgba);
|
stack.PushColor(ImGuiCol.ButtonHovered, c.PrimaryLight);
|
||||||
stack.PushColor(ImGuiCol.ButtonActive, PrimaryActiveRgba);
|
stack.PushColor(ImGuiCol.ButtonActive, c.PrimaryDark);
|
||||||
|
|
||||||
// Headers / selectables — slate with subtle steps.
|
// Headers / selectables
|
||||||
stack.PushColor(ImGuiCol.Header, HeaderRgba);
|
stack.PushColor(ImGuiCol.Header, c.Surface);
|
||||||
stack.PushColor(ImGuiCol.HeaderHovered, HeaderHoverRgba);
|
stack.PushColor(ImGuiCol.HeaderHovered, c.SurfaceHover);
|
||||||
stack.PushColor(ImGuiCol.HeaderActive, HeaderActiveRgba);
|
stack.PushColor(ImGuiCol.HeaderActive, c.Identity);
|
||||||
|
|
||||||
// Tabs — tertiary identity for the active tab.
|
// Tabs
|
||||||
stack.PushColor(ImGuiCol.Tab, TabRgba);
|
stack.PushColor(ImGuiCol.Tab, c.FrameBg);
|
||||||
stack.PushColor(ImGuiCol.TabHovered, TabHoveredRgba);
|
stack.PushColor(ImGuiCol.TabHovered, c.PrimaryLight);
|
||||||
stack.PushColor(ImGuiCol.TabActive, TabActiveRgba);
|
stack.PushColor(ImGuiCol.TabActive, c.Identity);
|
||||||
stack.PushColor(ImGuiCol.TabUnfocused, TabUnfocusedRgba);
|
stack.PushColor(ImGuiCol.TabUnfocused, c.ChildBg);
|
||||||
stack.PushColor(ImGuiCol.TabUnfocusedActive, TabUnfocusedActiveRgba);
|
stack.PushColor(ImGuiCol.TabUnfocusedActive, c.PrimaryDark);
|
||||||
|
|
||||||
// Scrollbar.
|
// Scrollbar
|
||||||
stack.PushColor(ImGuiCol.ScrollbarBg, ScrollbarBgRgba);
|
stack.PushColor(ImGuiCol.ScrollbarBg, c.WindowBg);
|
||||||
stack.PushColor(ImGuiCol.ScrollbarGrab, ScrollbarGrabRgba);
|
stack.PushColor(ImGuiCol.ScrollbarGrab, c.Surface);
|
||||||
stack.PushColor(ImGuiCol.ScrollbarGrabHovered, ScrollbarGrabHoveredRgba);
|
stack.PushColor(ImGuiCol.ScrollbarGrabHovered, c.AccentLight);
|
||||||
stack.PushColor(ImGuiCol.ScrollbarGrabActive, ScrollbarGrabActiveRgba);
|
stack.PushColor(ImGuiCol.ScrollbarGrabActive, c.Accent);
|
||||||
|
|
||||||
// Resize grip — secondary amber on active.
|
// Resize grip
|
||||||
stack.PushColor(ImGuiCol.ResizeGrip, ResizeGripRgba);
|
stack.PushColor(ImGuiCol.ResizeGrip, c.FrameBg);
|
||||||
stack.PushColor(ImGuiCol.ResizeGripHovered, ResizeGripHoveredRgba);
|
stack.PushColor(ImGuiCol.ResizeGripHovered, c.AccentLight);
|
||||||
stack.PushColor(ImGuiCol.ResizeGripActive, ResizeGripActiveRgba);
|
stack.PushColor(ImGuiCol.ResizeGripActive, c.Accent);
|
||||||
|
|
||||||
// Check mark + slider grab — primary cyan.
|
// Check mark + slider grab
|
||||||
stack.PushColor(ImGuiCol.CheckMark, PrimaryRgba);
|
stack.PushColor(ImGuiCol.CheckMark, c.Primary);
|
||||||
stack.PushColor(ImGuiCol.SliderGrab, PrimaryRgba);
|
stack.PushColor(ImGuiCol.SliderGrab, c.Primary);
|
||||||
stack.PushColor(ImGuiCol.SliderGrabActive, PrimaryHoverRgba);
|
stack.PushColor(ImGuiCol.SliderGrabActive, c.PrimaryLight);
|
||||||
|
|
||||||
// Separator — primary cyan when hovered/active so the eye
|
// Separator
|
||||||
// immediately sees that splitters are interactive.
|
stack.PushColor(ImGuiCol.Separator, c.Border);
|
||||||
stack.PushColor(ImGuiCol.Separator, BorderRgba);
|
stack.PushColor(ImGuiCol.SeparatorHovered, c.PrimaryLight);
|
||||||
stack.PushColor(ImGuiCol.SeparatorHovered, PrimaryHoverRgba);
|
stack.PushColor(ImGuiCol.SeparatorActive, c.Primary);
|
||||||
stack.PushColor(ImGuiCol.SeparatorActive, PrimaryRgba);
|
|
||||||
|
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,9 +103,7 @@ internal class Popout : Window
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BgAlpha = Plugin.Config.HellionThemeEnabled
|
BgAlpha = Plugin.Config.WindowOpacity;
|
||||||
? Plugin.Config.HellionThemeWindowOpacity
|
|
||||||
: Plugin.Config.WindowAlpha / 100f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,13 @@ internal sealed class Appearance : ISettingsTab
|
|||||||
|
|
||||||
using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false))
|
using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false))
|
||||||
{
|
{
|
||||||
|
// v1.1.0 — Diese Settings-UI wird in Phase J durch den dedizierten
|
||||||
|
// Themes-Tab ersetzt. Bis dahin bleiben die alten Toggles erhalten,
|
||||||
|
// damit die Settings-Seite kompiliert; sie schreiben in die mit
|
||||||
|
// [Obsolete] markierten Felder, die bis v1.2.0 als JSON-Safety-Net
|
||||||
|
// bestehen bleiben. Das pragma unterdrückt die CS0612-Warnungen
|
||||||
|
// gezielt für diesen Übergangs-Block.
|
||||||
|
#pragma warning disable CS0612, CS0618
|
||||||
ImGui.Checkbox(HellionStrings.Theme_Enabled_Name, ref Mutable.HellionThemeEnabled);
|
ImGui.Checkbox(HellionStrings.Theme_Enabled_Name, ref Mutable.HellionThemeEnabled);
|
||||||
ImGuiUtil.HelpMarker(HellionStrings.Theme_Enabled_Description);
|
ImGuiUtil.HelpMarker(HellionStrings.Theme_Enabled_Description);
|
||||||
|
|
||||||
@@ -81,6 +88,7 @@ internal sealed class Appearance : ISettingsTab
|
|||||||
{
|
{
|
||||||
ImGuiUtil.DragFloatVertical(Language.Options_WindowOpacity_Name, ref Mutable.WindowAlpha, .25f, 0f, 100f, $"{Mutable.WindowAlpha:N2}%%", ImGuiSliderFlags.AlwaysClamp);
|
ImGuiUtil.DragFloatVertical(Language.Options_WindowOpacity_Name, ref Mutable.WindowAlpha, .25f, 0f, 100f, $"{Mutable.WindowAlpha:N2}%%", ImGuiSliderFlags.AlwaysClamp);
|
||||||
}
|
}
|
||||||
|
#pragma warning restore CS0612, CS0618
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user