fix(D.2b): windows not anchor-managed (regression: move/resize was reset each frame)

The anchor pass added in f911b5f runs on every element's children — including
UiRoot's children, which are the top-level WINDOWS. With the default Left|Top
anchor, ApplyAnchor reset each window's Left/Top/Width/Height back to its
captured design rect EVERY frame, so user move/resize was undone instantly ("I
can't resize or move it"). A window is user-positioned, so it must not be
anchor-managed by its parent: set UiNineSlicePanel.Anchors = None. Children
INSIDE the window still anchor to it (the bars keep stretching with width).

Regression tests: UiNineSlicePanel.Anchors == None; ApplyAnchor(None) is a no-op.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-14 19:06:58 +02:00
parent f911b5f0af
commit b303baf4a1
2 changed files with 25 additions and 0 deletions

View file

@ -29,6 +29,11 @@ public sealed class UiNineSlicePanel : UiPanel
BorderColor = Vector4.Zero; BorderColor = Vector4.Zero;
Draggable = true; // retail windows are movable Draggable = true; // retail windows are movable
Resizable = true; // retail windows are resizable Resizable = true; // retail windows are resizable
// A top-level window is USER-positioned: it must NOT be anchor-managed
// by its parent (UiRoot), or the per-frame anchor pass would reset its
// Left/Top/Width/Height every frame and undo move/resize. Children
// INSIDE the window still anchor to it (the bars stretch with width).
Anchors = AnchorEdges.None;
} }
/// <summary> /// <summary>

View file

@ -5,6 +5,26 @@ namespace AcDream.App.Tests.UI;
public class UiRootInputTests public class UiRootInputTests
{ {
[Fact]
public void UiNineSlicePanel_IsNotAnchorManaged_SoUserMoveResizeSticks()
{
// Regression: the per-frame anchor pass must NOT reset a window's rect,
// or move/resize get undone every frame. Windows are user-positioned.
var panel = new UiNineSlicePanel(_ => ((uint)1, 32, 32));
Assert.Equal(AnchorEdges.None, panel.Anchors);
}
[Fact]
public void ApplyAnchor_None_IsNoOp()
{
var e = new UiPanel { Left = 50, Top = 60, Width = 100, Height = 40, Anchors = AnchorEdges.None };
e.ApplyAnchor(800, 600);
Assert.Equal(50f, e.Left);
Assert.Equal(60f, e.Top);
Assert.Equal(100f, e.Width);
Assert.Equal(40f, e.Height);
}
[Fact] [Fact]
public void WantsMouse_TrueOverWidget_FalseOverEmptySpace() public void WantsMouse_TrueOverWidget_FalseOverEmptySpace()
{ {