From b303baf4a16a20981fd5a936c80dc58b975d9da2 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 14 Jun 2026 19:06:58 +0200 Subject: [PATCH] fix(D.2b): windows not anchor-managed (regression: move/resize was reset each frame) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- src/AcDream.App/UI/UiNineSlicePanel.cs | 5 +++++ .../AcDream.App.Tests/UI/UiRootInputTests.cs | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/AcDream.App/UI/UiNineSlicePanel.cs b/src/AcDream.App/UI/UiNineSlicePanel.cs index 576da3e1..2e4465a1 100644 --- a/src/AcDream.App/UI/UiNineSlicePanel.cs +++ b/src/AcDream.App/UI/UiNineSlicePanel.cs @@ -29,6 +29,11 @@ public sealed class UiNineSlicePanel : UiPanel BorderColor = Vector4.Zero; Draggable = true; // retail windows are movable 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; } /// diff --git a/tests/AcDream.App.Tests/UI/UiRootInputTests.cs b/tests/AcDream.App.Tests/UI/UiRootInputTests.cs index d3b3cc0b..1adbffcd 100644 --- a/tests/AcDream.App.Tests/UI/UiRootInputTests.cs +++ b/tests/AcDream.App.Tests/UI/UiRootInputTests.cs @@ -5,6 +5,26 @@ namespace AcDream.App.Tests.UI; 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] public void WantsMouse_TrueOverWidget_FalseOverEmptySpace() {