acdream/tests/AcDream.App.Tests/UI/UiRootInputTests.cs
Erik f911b5f0af feat(D.2b): anchor layout — vital bars stretch with window; drop Vitals heading
Add AnchorEdges [Flags] enum and Anchors property (default Left|Top, so
all existing elements are unchanged) to UiElement. ApplyAnchor() captures
the design-time margins on first call then recomputes Left/Top/Width/Height
each frame; DrawSelfAndChildren drives it for every child before painting.
ComputeAnchoredRect is public + static so it can be unit-tested without a
running frame loop.

MarkupDocument.Build gains a private Anchor() CSV parser and threads it
into the <meter> initializer via the anchor= attribute.

vitals.xml: remove title="Vitals" (retail vitals has no heading) and add
anchor="left,top,right" to all three meter bars so they stretch when the
panel is dragged wider.

Two new xUnit tests in UiRootInputTests: Left+Right stretches width;
Left+Top only keeps fixed size. All 19 App.Tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 18:58:58 +02:00

136 lines
5.1 KiB
C#

using System.Numerics;
using AcDream.App.UI;
namespace AcDream.App.Tests.UI;
public class UiRootInputTests
{
[Fact]
public void WantsMouse_TrueOverWidget_FalseOverEmptySpace()
{
var root = new UiRoot { Width = 800, Height = 600 };
var panel = new UiPanel { Left = 10, Top = 10, Width = 100, Height = 50 };
root.AddChild(panel);
root.OnMouseMove(50, 30); // inside the panel
Assert.True(root.WantsMouse);
root.OnMouseMove(500, 400); // empty space
Assert.False(root.WantsMouse);
}
[Fact]
public void WindowDrag_RepositionsDraggablePanel_StopsOnRelease()
{
var root = new UiRoot { Width = 800, Height = 600 };
var panel = new UiPanel { Left = 10, Top = 10, Width = 100, Height = 50, Draggable = true };
root.AddChild(panel);
root.OnMouseDown(UiMouseButton.Left, 20, 20); // grab at (10,10) into the panel
root.OnMouseMove(120, 90); // drag
Assert.Equal(110f, panel.Left); // 120 - 10
Assert.Equal(80f, panel.Top); // 90 - 10
root.OnMouseUp(UiMouseButton.Left, 120, 90);
root.OnMouseMove(300, 300); // released — must not move
Assert.Equal(110f, panel.Left);
Assert.Equal(80f, panel.Top);
}
[Fact]
public void NonDraggablePanel_DoesNotMoveOnDrag()
{
var root = new UiRoot { Width = 800, Height = 600 };
var panel = new UiPanel { Left = 10, Top = 10, Width = 100, Height = 50 }; // Draggable defaults false
root.AddChild(panel);
root.OnMouseDown(UiMouseButton.Left, 20, 20);
root.OnMouseMove(120, 90);
Assert.Equal(10f, panel.Left);
Assert.Equal(10f, panel.Top);
}
[Fact]
public void ResizeRect_RightBottom_GrowsSizeOnly()
{
var (x, y, w, h) = UiRoot.ResizeRect(10, 20, 100, 50,
ResizeEdges.Right | ResizeEdges.Bottom, dx: 30, dy: 15, minW: 40, minH: 40);
Assert.Equal(10f, x); Assert.Equal(20f, y);
Assert.Equal(130f, w); Assert.Equal(65f, h);
}
[Fact]
public void ResizeRect_LeftTop_MovesOriginAndClampsToMin()
{
// Drag left edge right by 80 on a 100-wide / min-40 window: width clamps to 40,
// origin shifts so the RIGHT edge (110) stays put → x = 70.
var (x, _, w, _) = UiRoot.ResizeRect(10, 20, 100, 50,
ResizeEdges.Left, dx: 80, dy: 0, minW: 40, minH: 40);
Assert.Equal(40f, w);
Assert.Equal(70f, x);
}
[Fact]
public void HitEdges_DetectsCornerAndInteriorNone()
{
var panel = new UiPanel { Left = 100, Top = 100, Width = 200, Height = 100 };
// bottom-right corner (300,200)
Assert.Equal(ResizeEdges.Right | ResizeEdges.Bottom, UiRoot.HitEdges(panel, 300, 200, 5));
// deep interior → no edges
Assert.Equal(ResizeEdges.None, UiRoot.HitEdges(panel, 200, 150, 5));
}
[Fact]
public void EdgeDrag_ResizesPanel_InteriorDragMoves()
{
var root = new UiRoot { Width = 800, Height = 600 };
var panel = new UiPanel { Left = 100, Top = 100, Width = 200, Height = 100,
Draggable = true, Resizable = true, MinWidth = 40, MinHeight = 40 };
root.AddChild(panel);
// grab just inside the right edge (x=298, within ResizeGrip=5 of x=300) and drag right → wider, same origin
root.OnMouseDown(UiMouseButton.Left, 298, 150);
root.OnMouseMove(338, 150);
Assert.Equal(240f, panel.Width);
Assert.Equal(100f, panel.Left);
root.OnMouseUp(UiMouseButton.Left, 338, 150);
// grab the interior and drag → moves
root.OnMouseDown(UiMouseButton.Left, 200, 150);
root.OnMouseMove(220, 170);
Assert.Equal(120f, panel.Left);
Assert.Equal(120f, panel.Top);
root.OnMouseUp(UiMouseButton.Left, 220, 170);
}
[Fact]
public void HitEdges_RespectsResizeAxisLock()
{
var panel = new UiPanel { Left = 100, Top = 100, Width = 200, Height = 100, ResizeY = false };
// right edge still detected (X allowed)
Assert.True((UiRoot.HitEdges(panel, 300, 150, 5) & ResizeEdges.Right) != 0);
// bottom edge masked out (Y locked)
Assert.True((UiRoot.HitEdges(panel, 200, 200, 5) & ResizeEdges.Bottom) == 0);
}
[Fact]
public void ComputeAnchoredRect_LeftRight_StretchesWidth()
{
// bar at x=8,w=200 in a 220-wide parent (right margin 12). Parent grows to 300.
var (x, _, w, _) = UiElement.ComputeAnchoredRect(
AnchorEdges.Left | AnchorEdges.Right | AnchorEdges.Top,
mL: 8, mT: 24, mR: 12, mB: 58, w0: 200, h0: 14, parentW: 300, parentH: 96);
Assert.Equal(8f, x);
Assert.Equal(280f, w); // 300 - 12 - 8
}
[Fact]
public void ComputeAnchoredRect_LeftTopOnly_KeepsFixedSizeAndOrigin()
{
var (x, y, w, h) = UiElement.ComputeAnchoredRect(
AnchorEdges.Left | AnchorEdges.Top,
mL: 8, mT: 24, mR: 12, mB: 58, w0: 200, h0: 14, parentW: 300, parentH: 96);
Assert.Equal(8f, x); Assert.Equal(24f, y);
Assert.Equal(200f, w); Assert.Equal(14f, h);
}
}