feat(window): wire inactive opacity to main window focus state
This commit is contained in:
@@ -373,6 +373,7 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
||||
new SelfTests.HoverSheenAllocStep(this),
|
||||
new SelfTests.HonorificHeaderRenderStep(this),
|
||||
new SelfTests.PerformanceBaselineStep(this),
|
||||
new SelfTests.MainWindowFocusOpacityStep(this),
|
||||
]);
|
||||
|
||||
// Re-surface the wizard for existing users when a major UX
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Plugin.SelfTest;
|
||||
|
||||
namespace HellionChat.SelfTests;
|
||||
|
||||
// UI-12 focus opacity. Pins the pure ResolveBgAlpha contract (focused →
|
||||
// WindowOpacity, unfocused → WindowOpacityInactive). The PreDraw wiring
|
||||
// (BgAlpha = ResolveBgAlpha(IsFocused) behind the main-viewport/!docked guard)
|
||||
// is NOT headless-deterministic — the guard may leave BgAlpha null when
|
||||
// LastViewport is stale on a /xlperf frame — so the wiring is verified by the
|
||||
// reviewer grep (ResolveBgAlpha has a non-test caller: MainWindow.PreDraw) and
|
||||
// the visible transparency by in-game smoke, not by driving PreDraw here.
|
||||
internal sealed class MainWindowFocusOpacityStep : ISelfTestStep
|
||||
{
|
||||
private readonly Plugin plugin;
|
||||
|
||||
public MainWindowFocusOpacityStep(Plugin plugin)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public string Name => "Hellion Chat - MainWindow focus opacity";
|
||||
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
var window = this.plugin.MainWindow;
|
||||
if (window is null)
|
||||
{
|
||||
ImGui.Text("Plugin.MainWindow is null");
|
||||
return SelfTestStepResult.Fail;
|
||||
}
|
||||
|
||||
// Contract: focused returns the focused opacity, unfocused the inactive one.
|
||||
if (window.ResolveBgAlpha(true) != Plugin.Config.WindowOpacity)
|
||||
{
|
||||
ImGui.Text(
|
||||
$"ResolveBgAlpha(true) = {window.ResolveBgAlpha(true)}, expected {Plugin.Config.WindowOpacity}"
|
||||
);
|
||||
return SelfTestStepResult.Fail;
|
||||
}
|
||||
|
||||
if (window.ResolveBgAlpha(false) != Plugin.Config.WindowOpacityInactive)
|
||||
{
|
||||
ImGui.Text(
|
||||
$"ResolveBgAlpha(false) = {window.ResolveBgAlpha(false)}, expected {Plugin.Config.WindowOpacityInactive}"
|
||||
);
|
||||
return SelfTestStepResult.Fail;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
public void CleanUp() { }
|
||||
}
|
||||
@@ -37,6 +37,9 @@ internal sealed class MainWindow : Window
|
||||
public Vector2 LastWindowSize { get; private set; } = Vector2.Zero;
|
||||
internal unsafe ImGuiViewport* LastViewport;
|
||||
|
||||
// 1.5.6 viewport-guard input: tracked in Draw, read by PreDraw next frame.
|
||||
private bool _wasDocked;
|
||||
|
||||
public MainWindow(
|
||||
Components.HonorificHeader honorific,
|
||||
Components.Sidebar sidebar,
|
||||
@@ -70,6 +73,35 @@ internal sealed class MainWindow : Window
|
||||
RespectCloseHotkey = false;
|
||||
}
|
||||
|
||||
// UI-12: per-window focus-dependent opacity. ResolveBgAlpha stays guard-free
|
||||
// and pure so the self-test can drive it directly; PreDraw owns the guard +
|
||||
// wiring. 1.5.6 parity (focused → WindowOpacity, unfocused →
|
||||
// WindowOpacityInactive, ChatLogWindow.PreOpenCheck 1d3b429:724).
|
||||
internal float ResolveBgAlpha(bool isFocused) =>
|
||||
isFocused ? Plugin.Config.WindowOpacity : Plugin.Config.WindowOpacityInactive;
|
||||
|
||||
public override void PreDraw()
|
||||
{
|
||||
// Dalamud's WindowHost turns Window.BgAlpha into SetNextWindowBgAlpha
|
||||
// (WindowHost.cs:650-652), which REPLACES this one window's WindowBg
|
||||
// alpha (imgui.cpp:7229). The global GlobalStyleScope clamp is left
|
||||
// untouched, so Settings/DbViewer/popouts/wizard keep today's opacity.
|
||||
// Viewport guard (1.5.6 parity, ChatLogWindow.PreOpenCheck 1d3b429:718):
|
||||
// only drive BgAlpha while the window is on the main viewport and not
|
||||
// docked. On a floated own-viewport (Dalamud multi-viewport mode) the
|
||||
// WindowBg alpha would compose against the OS-layer alpha (double
|
||||
// transparency), so leave BgAlpha null there and let the global scope
|
||||
// govern. LastViewport/_wasDocked are last frame's values from Draw
|
||||
// (one-frame latency, accepted, matches 1.5.6).
|
||||
unsafe
|
||||
{
|
||||
if (LastViewport == ImGuiHelpers.MainViewport.Handle && !_wasDocked)
|
||||
BgAlpha = ResolveBgAlpha(IsFocused);
|
||||
else
|
||||
BgAlpha = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Tab? ActiveTab => _activeTab;
|
||||
|
||||
// Internal accessors for self-tests so the probes can reach the live
|
||||
@@ -99,6 +131,7 @@ internal sealed class MainWindow : Window
|
||||
{
|
||||
LastViewport = ImGui.GetWindowViewport().Handle;
|
||||
}
|
||||
_wasDocked = ImGui.IsWindowDocked();
|
||||
|
||||
// Primary pool-reset path; InputPreview has a defensive fallback for the MainWindow-closed edge case.
|
||||
_handlerLender.ResetCounter();
|
||||
|
||||
Reference in New Issue
Block a user