feat(window): wire move/resize flags and consolidate the duplicate toggle
This commit is contained in:
@@ -374,6 +374,7 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
|||||||
new SelfTests.HonorificHeaderRenderStep(this),
|
new SelfTests.HonorificHeaderRenderStep(this),
|
||||||
new SelfTests.PerformanceBaselineStep(this),
|
new SelfTests.PerformanceBaselineStep(this),
|
||||||
new SelfTests.MainWindowFocusOpacityStep(this),
|
new SelfTests.MainWindowFocusOpacityStep(this),
|
||||||
|
new SelfTests.MainWindowFlagsStep(this),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Re-surface the wizard for existing users when a major UX
|
// Re-surface the wizard for existing users when a major UX
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
|
using Dalamud.Plugin.SelfTest;
|
||||||
|
using HellionChat.Ui.Windows;
|
||||||
|
|
||||||
|
namespace HellionChat.SelfTests;
|
||||||
|
|
||||||
|
// B1-2 window flags. Drives the REAL MainWindow.PreDraw and asserts it wired
|
||||||
|
// Window.Flags to ResolveFlags(CanMove, CanResize), then pins the pure
|
||||||
|
// fresh-base contract: false/false adds NoMove|NoResize, true/true clears them
|
||||||
|
// (the masterplan's "flags must rebuild from a fresh base, else NoMove sticks
|
||||||
|
// after toggling back" risk). NoScrollbar|NoScrollWithMouse always present.
|
||||||
|
// Non-test caller of ResolveFlags: MainWindow.PreDraw.
|
||||||
|
internal sealed class MainWindowFlagsStep : ISelfTestStep
|
||||||
|
{
|
||||||
|
private readonly Plugin plugin;
|
||||||
|
|
||||||
|
public MainWindowFlagsStep(Plugin plugin)
|
||||||
|
{
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name => "Hellion Chat - MainWindow flags";
|
||||||
|
|
||||||
|
public SelfTestStepResult RunStep()
|
||||||
|
{
|
||||||
|
var window = this.plugin.MainWindow;
|
||||||
|
if (window is null)
|
||||||
|
{
|
||||||
|
ImGui.Text("Plugin.MainWindow is null");
|
||||||
|
return SelfTestStepResult.Fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wiring proof: drive the real PreDraw and confirm Flags == the helper's
|
||||||
|
// value for the live config. No state mutation needed.
|
||||||
|
var savedFlags = window.Flags;
|
||||||
|
window.PreDraw();
|
||||||
|
var expected = MainWindow.ResolveFlags(Plugin.Config.CanMove, Plugin.Config.CanResize);
|
||||||
|
if (window.Flags != expected)
|
||||||
|
{
|
||||||
|
ImGui.Text($"PreDraw set Flags {window.Flags}, expected ResolveFlags = {expected}");
|
||||||
|
window.Flags = savedFlags;
|
||||||
|
return SelfTestStepResult.Fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fresh-base contract: locked window carries NoMove|NoResize ...
|
||||||
|
var locked = MainWindow.ResolveFlags(false, false);
|
||||||
|
if (
|
||||||
|
!locked.HasFlag(ImGuiWindowFlags.NoMove)
|
||||||
|
|| !locked.HasFlag(ImGuiWindowFlags.NoResize)
|
||||||
|
|| !locked.HasFlag(ImGuiWindowFlags.NoScrollbar)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ImGui.Text(
|
||||||
|
$"ResolveFlags(false,false) = {locked}, missing NoMove/NoResize/NoScrollbar"
|
||||||
|
);
|
||||||
|
window.Flags = savedFlags;
|
||||||
|
return SelfTestStepResult.Fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... and re-enabling both CLEARS NoMove|NoResize (no accumulation).
|
||||||
|
var free = MainWindow.ResolveFlags(true, true);
|
||||||
|
if (free.HasFlag(ImGuiWindowFlags.NoMove) || free.HasFlag(ImGuiWindowFlags.NoResize))
|
||||||
|
{
|
||||||
|
ImGui.Text($"ResolveFlags(true,true) = {free}, NoMove/NoResize stuck after re-enable");
|
||||||
|
window.Flags = savedFlags;
|
||||||
|
return SelfTestStepResult.Fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.Flags = savedFlags;
|
||||||
|
return SelfTestStepResult.Pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CleanUp() { }
|
||||||
|
}
|
||||||
@@ -15,16 +15,6 @@ internal sealed class GeneralTab
|
|||||||
{
|
{
|
||||||
if (ImGui.CollapsingHeader("Behavior", ImGuiTreeNodeFlags.DefaultOpen))
|
if (ImGui.CollapsingHeader("Behavior", ImGuiTreeNodeFlags.DefaultOpen))
|
||||||
{
|
{
|
||||||
DrawToggle(
|
|
||||||
"Allow window movement",
|
|
||||||
() => Plugin.Config.CanMove,
|
|
||||||
v => Plugin.Config.CanMove = v
|
|
||||||
);
|
|
||||||
DrawToggle(
|
|
||||||
"Allow window resize",
|
|
||||||
() => Plugin.Config.CanResize,
|
|
||||||
v => Plugin.Config.CanResize = v
|
|
||||||
);
|
|
||||||
DrawToggle(
|
DrawToggle(
|
||||||
"Reduce motion (no theme crossfade)",
|
"Reduce motion (no theme crossfade)",
|
||||||
() => Plugin.Config.ReduceMotion,
|
() => Plugin.Config.ReduceMotion,
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ internal sealed class WindowTab
|
|||||||
|
|
||||||
if (ImGui.CollapsingHeader("Resize behavior", ImGuiTreeNodeFlags.DefaultOpen))
|
if (ImGui.CollapsingHeader("Resize behavior", ImGuiTreeNodeFlags.DefaultOpen))
|
||||||
{
|
{
|
||||||
|
DrawToggle(
|
||||||
|
"Allow movement",
|
||||||
|
() => Plugin.Config.CanMove,
|
||||||
|
v => Plugin.Config.CanMove = v
|
||||||
|
);
|
||||||
DrawToggle(
|
DrawToggle(
|
||||||
"Allow resize",
|
"Allow resize",
|
||||||
() => Plugin.Config.CanResize,
|
() => Plugin.Config.CanResize,
|
||||||
|
|||||||
@@ -66,9 +66,6 @@ internal sealed class MainWindow : Window
|
|||||||
MinimumSize = new Vector2(MinWidth, MinHeight),
|
MinimumSize = new Vector2(MinWidth, MinHeight),
|
||||||
MaximumSize = new Vector2(float.MaxValue, float.MaxValue),
|
MaximumSize = new Vector2(float.MaxValue, float.MaxValue),
|
||||||
};
|
};
|
||||||
// The message list owns its own scroll inside the body child;
|
|
||||||
// the outer window must not show a second scrollbar.
|
|
||||||
Flags = ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse;
|
|
||||||
IsOpen = Plugin.Config.MainWindowOpen;
|
IsOpen = Plugin.Config.MainWindowOpen;
|
||||||
RespectCloseHotkey = false;
|
RespectCloseHotkey = false;
|
||||||
}
|
}
|
||||||
@@ -80,6 +77,22 @@ internal sealed class MainWindow : Window
|
|||||||
internal float ResolveBgAlpha(bool isFocused) =>
|
internal float ResolveBgAlpha(bool isFocused) =>
|
||||||
isFocused ? Plugin.Config.WindowOpacity : Plugin.Config.WindowOpacityInactive;
|
isFocused ? Plugin.Config.WindowOpacity : Plugin.Config.WindowOpacityInactive;
|
||||||
|
|
||||||
|
// B1-2: rebuild flags from a fresh base every frame so toggling CanMove/
|
||||||
|
// CanResize back on actually CLEARS NoMove/NoResize (not accumulating).
|
||||||
|
// Move/resize toggle logic as 1.5.6 (ChatLogWindow.PreOpenCheck
|
||||||
|
// 1d3b429:703-707); base flags = today's MainWindow set (NoScrollbar|
|
||||||
|
// NoScrollWithMouse — the message list owns its own scroll; 1.5.6's
|
||||||
|
// NoFocusOnAppearing/NoTitleBar are deliberately not restored).
|
||||||
|
internal static ImGuiWindowFlags ResolveFlags(bool canMove, bool canResize)
|
||||||
|
{
|
||||||
|
var flags = ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse;
|
||||||
|
if (!canMove)
|
||||||
|
flags |= ImGuiWindowFlags.NoMove;
|
||||||
|
if (!canResize)
|
||||||
|
flags |= ImGuiWindowFlags.NoResize;
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
public override void PreDraw()
|
public override void PreDraw()
|
||||||
{
|
{
|
||||||
// Dalamud's WindowHost turns Window.BgAlpha into SetNextWindowBgAlpha
|
// Dalamud's WindowHost turns Window.BgAlpha into SetNextWindowBgAlpha
|
||||||
@@ -100,6 +113,8 @@ internal sealed class MainWindow : Window
|
|||||||
else
|
else
|
||||||
BgAlpha = null;
|
BgAlpha = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Flags = ResolveFlags(Plugin.Config.CanMove, Plugin.Config.CanResize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tab? ActiveTab => _activeTab;
|
public Tab? ActiveTab => _activeTab;
|
||||||
|
|||||||
Reference in New Issue
Block a user