217 lines
8.1 KiB
C#
217 lines
8.1 KiB
C#
using System.Collections.Generic;
|
|
using AcDream.App.UI;
|
|
|
|
namespace AcDream.App.Tests.UI;
|
|
|
|
public sealed class RetailWindowManagerTests
|
|
{
|
|
[Fact]
|
|
public void Hide_ClearsRootOwnership_AndShowRestoresDefaultInput()
|
|
{
|
|
var root = new UiRoot { Width = 800, Height = 600 };
|
|
var frame = new UiPanel { Width = 300, Height = 150 };
|
|
var input = new UiField { Width = 200, Height = 20 };
|
|
frame.AddChild(input);
|
|
root.AddChild(frame);
|
|
root.DefaultTextInput = input;
|
|
root.Modal = frame;
|
|
root.SetKeyboardFocus(input);
|
|
root.SetCapture(input);
|
|
|
|
var controller = new RecordingController();
|
|
RetailWindowHandle handle = root.RegisterWindow("chat", frame, frame, controller);
|
|
var events = new List<string>();
|
|
handle.Hidden += _ => events.Add("hidden");
|
|
handle.Shown += _ => events.Add("shown");
|
|
|
|
frame.Visible = false;
|
|
|
|
Assert.False(frame.Visible);
|
|
Assert.Null(root.KeyboardFocus);
|
|
Assert.Null(root.Captured);
|
|
Assert.Null(root.Modal);
|
|
Assert.Null(root.DefaultTextInput);
|
|
Assert.Equal(1, controller.ShownCount);
|
|
Assert.Equal(1, controller.HiddenCount);
|
|
Assert.Equal(new[] { "hidden" }, events);
|
|
|
|
Assert.True(handle.Show());
|
|
|
|
Assert.True(frame.Visible);
|
|
Assert.Same(input, root.DefaultTextInput);
|
|
Assert.Equal(2, controller.ShownCount);
|
|
Assert.Equal(new[] { "hidden", "shown" }, events);
|
|
}
|
|
|
|
[Fact]
|
|
public void Handle_ReportsGeometryCloseAndLockLifecycle()
|
|
{
|
|
var root = new UiRoot { Width = 800, Height = 600 };
|
|
var frame = new UiPanel
|
|
{
|
|
Left = 10,
|
|
Top = 20,
|
|
Width = 100,
|
|
Height = 80,
|
|
MinWidth = 50,
|
|
MinHeight = 40,
|
|
};
|
|
root.AddChild(frame);
|
|
RetailWindowHandle handle = root.RegisterWindow("inventory", frame);
|
|
int moved = 0, resized = 0, hidden = 0, shown = 0, closed = 0;
|
|
var locks = new List<bool>();
|
|
handle.Moved += _ => moved++;
|
|
handle.Resized += _ => resized++;
|
|
handle.Hidden += _ => hidden++;
|
|
handle.Shown += _ => shown++;
|
|
handle.Closed += _ => closed++;
|
|
handle.LockChanged += (_, locked) => locks.Add(locked);
|
|
|
|
Assert.True(handle.MoveTo(30, 45));
|
|
Assert.Equal((30f, 45f), (frame.Left, frame.Top));
|
|
Assert.Equal(1, moved);
|
|
|
|
Assert.True(handle.ResizeTo(160, 120));
|
|
Assert.Equal((160f, 120f), (frame.Width, frame.Height));
|
|
Assert.Equal(1, resized);
|
|
|
|
root.WindowManager.SetLocked(true);
|
|
root.WindowManager.SetLocked(true);
|
|
root.WindowManager.SetLocked(false);
|
|
Assert.Equal(new[] { true, false }, locks);
|
|
|
|
Assert.True(handle.Close());
|
|
Assert.True(handle.Close());
|
|
Assert.False(handle.IsVisible);
|
|
Assert.Equal(1, hidden);
|
|
Assert.Equal(1, closed);
|
|
|
|
Assert.True(handle.Show());
|
|
Assert.True(handle.Close());
|
|
Assert.Equal(1, shown);
|
|
Assert.Equal(2, hidden);
|
|
Assert.Equal(2, closed);
|
|
}
|
|
|
|
[Fact]
|
|
public void PointerResize_ReportsCompletionThroughTypedHandle()
|
|
{
|
|
var root = new UiRoot { Width = 800, Height = 600 };
|
|
var frame = new UiPanel
|
|
{
|
|
Left = 10,
|
|
Top = 20,
|
|
Width = 100,
|
|
Height = 80,
|
|
Resizable = true,
|
|
};
|
|
root.AddChild(frame);
|
|
RetailWindowHandle handle = root.RegisterWindow("chat", frame);
|
|
int resized = 0;
|
|
handle.Resized += _ => resized++;
|
|
|
|
root.OnMouseDown(UiMouseButton.Left, 109, 60);
|
|
root.OnMouseMove(149, 60);
|
|
root.OnMouseUp(UiMouseButton.Left, 149, 60);
|
|
|
|
Assert.Equal(140f, frame.Width);
|
|
Assert.Equal(1, resized);
|
|
}
|
|
|
|
[Fact]
|
|
public void FocusAndCaptureTransitions_AreScopedToOwningHandle()
|
|
{
|
|
var root = new UiRoot { Width = 800, Height = 600 };
|
|
var first = new UiPanel { Width = 200, Height = 100 };
|
|
var second = new UiPanel { Left = 250, Width = 200, Height = 100 };
|
|
var firstField = new UiField { Width = 100, Height = 20 };
|
|
var secondField = new UiField { Width = 100, Height = 20 };
|
|
first.AddChild(firstField);
|
|
second.AddChild(secondField);
|
|
root.AddChild(first);
|
|
root.AddChild(second);
|
|
var firstController = new RecordingController();
|
|
var secondController = new RecordingController();
|
|
RetailWindowHandle firstHandle = root.RegisterWindow("first", first, first, firstController);
|
|
RetailWindowHandle secondHandle = root.RegisterWindow("second", second, second, secondController);
|
|
var firstCaptures = new List<UiElement?>();
|
|
var secondCaptures = new List<UiElement?>();
|
|
firstHandle.DescendantCaptureChanged += (_, element) => firstCaptures.Add(element);
|
|
secondHandle.DescendantCaptureChanged += (_, element) => secondCaptures.Add(element);
|
|
|
|
root.SetKeyboardFocus(firstField);
|
|
root.SetKeyboardFocus(secondField);
|
|
root.SetCapture(firstField);
|
|
root.SetCapture(secondField);
|
|
root.ReleaseCapture();
|
|
|
|
Assert.Equal(new UiElement?[] { firstField, null }, firstController.FocusChanges);
|
|
Assert.Equal(new UiElement?[] { secondField }, secondController.FocusChanges);
|
|
Assert.Equal(new UiElement?[] { firstField, null }, firstCaptures);
|
|
Assert.Equal(new UiElement?[] { secondField, null }, secondCaptures);
|
|
}
|
|
|
|
[Fact]
|
|
public void UnregisterAndTreeRemoval_DisposeControllersExactlyOnce()
|
|
{
|
|
var root = new UiRoot { Width = 800, Height = 600 };
|
|
var first = new UiPanel { Width = 100, Height = 100 };
|
|
var second = new UiPanel { Width = 100, Height = 100 };
|
|
root.AddChild(first);
|
|
root.AddChild(second);
|
|
var firstController = new RecordingController();
|
|
var secondController = new RecordingController();
|
|
RetailWindowHandle firstHandle = root.RegisterWindow("first", first, first, firstController);
|
|
RetailWindowHandle secondHandle = root.RegisterWindow("second", second, second, secondController);
|
|
|
|
Assert.True(root.UnregisterWindow("first"));
|
|
Assert.False(firstHandle.IsRegistered);
|
|
Assert.Equal(1, firstController.DisposeCount);
|
|
Assert.False(root.ShowWindow("first"));
|
|
|
|
Assert.True(root.RemoveChild(second));
|
|
Assert.False(secondHandle.IsRegistered);
|
|
Assert.Equal(1, secondController.DisposeCount);
|
|
Assert.False(root.ShowWindow("second"));
|
|
|
|
root.WindowManager.Dispose();
|
|
Assert.Equal(1, firstController.DisposeCount);
|
|
Assert.Equal(1, secondController.DisposeCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void AttachController_AfterRegistration_DeliversVisibilityAndOwnsDisposal()
|
|
{
|
|
var root = new UiRoot { Width = 800, Height = 600 };
|
|
var frame = new UiPanel { Width = 100, Height = 100 };
|
|
root.AddChild(frame);
|
|
RetailWindowHandle handle = root.RegisterWindow("inventory", frame);
|
|
var controller = new RecordingController();
|
|
|
|
root.WindowManager.AttachController("inventory", controller);
|
|
|
|
Assert.Same(controller, handle.Controller);
|
|
Assert.Equal(1, controller.ShownCount);
|
|
Assert.Throws<InvalidOperationException>(() =>
|
|
root.WindowManager.AttachController("inventory", new RecordingController()));
|
|
|
|
root.WindowManager.Dispose();
|
|
root.WindowManager.Dispose();
|
|
Assert.Equal(1, controller.HiddenCount);
|
|
Assert.Equal(1, controller.DisposeCount);
|
|
}
|
|
|
|
private sealed class RecordingController : IRetainedPanelController
|
|
{
|
|
public int ShownCount { get; private set; }
|
|
public int HiddenCount { get; private set; }
|
|
public int DisposeCount { get; private set; }
|
|
public List<UiElement?> FocusChanges { get; } = new();
|
|
|
|
public void OnShown() => ShownCount++;
|
|
public void OnHidden() => HiddenCount++;
|
|
public void OnDescendantFocusChanged(UiElement? focusedDescendant)
|
|
=> FocusChanges.Add(focusedDescendant);
|
|
public void Dispose() => DisposeCount++;
|
|
}
|
|
}
|