diff --git a/src/AcDream.App/UI/MarkupDocument.cs b/src/AcDream.App/UI/MarkupDocument.cs index d4b0cb42..e27cd294 100644 --- a/src/AcDream.App/UI/MarkupDocument.cs +++ b/src/AcDream.App/UI/MarkupDocument.cs @@ -34,6 +34,14 @@ public static class MarkupDocument Height = F(root, "h"), }; + // Optional per-window resize-axis lock: resize="x" | "y" | "both" | "none". + string? resize = (string?)root.Attribute("resize"); + if (resize is not null) + { + panel.ResizeX = resize is "x" or "both"; + panel.ResizeY = resize is "y" or "both"; + } + string? title = (string?)root.Attribute("title"); if (!string.IsNullOrEmpty(title)) { diff --git a/src/AcDream.App/UI/UiElement.cs b/src/AcDream.App/UI/UiElement.cs index 30c4b260..48e1955b 100644 --- a/src/AcDream.App/UI/UiElement.cs +++ b/src/AcDream.App/UI/UiElement.cs @@ -101,6 +101,11 @@ public abstract class UiElement public float MinWidth { get; set; } = 40f; public float MinHeight { get; set; } = 40f; + /// Allow horizontal (width) resize. Ignored unless . + public bool ResizeX { get; set; } = true; + /// Allow vertical (height) resize. Ignored unless . + public bool ResizeY { get; set; } = true; + // ── Tree structure ────────────────────────────────────────────────── public UiElement? Parent { get; private set; } diff --git a/src/AcDream.App/UI/UiRoot.cs b/src/AcDream.App/UI/UiRoot.cs index 1b72ec9f..6f836253 100644 --- a/src/AcDream.App/UI/UiRoot.cs +++ b/src/AcDream.App/UI/UiRoot.cs @@ -542,6 +542,8 @@ public sealed class UiRoot : UiElement if (System.Math.Abs(x - r) <= grip) e |= ResizeEdges.Right; if (System.Math.Abs(y - t) <= grip) e |= ResizeEdges.Top; if (System.Math.Abs(y - b) <= grip) e |= ResizeEdges.Bottom; + if (!w.ResizeX) e &= ~(ResizeEdges.Left | ResizeEdges.Right); + if (!w.ResizeY) e &= ~(ResizeEdges.Top | ResizeEdges.Bottom); return e; } diff --git a/src/AcDream.App/UI/assets/vitals.xml b/src/AcDream.App/UI/assets/vitals.xml index 868926d4..83d59c3b 100644 --- a/src/AcDream.App/UI/assets/vitals.xml +++ b/src/AcDream.App/UI/assets/vitals.xml @@ -1,4 +1,4 @@ - + diff --git a/tests/AcDream.App.Tests/UI/MarkupDocumentTests.cs b/tests/AcDream.App.Tests/UI/MarkupDocumentTests.cs index 8ba52d27..5e76ab95 100644 --- a/tests/AcDream.App.Tests/UI/MarkupDocumentTests.cs +++ b/tests/AcDream.App.Tests/UI/MarkupDocumentTests.cs @@ -47,4 +47,13 @@ public class MarkupDocumentTests Assert.Null(meter.Fill()); Assert.Null(meter.Label()); } + + [Fact] + public void Build_ResizeAttrX_SetsHorizontalOnly() + { + const string xml = ""; + var panel = MarkupDocument.Build(xml, new object(), _ => ((uint)1, 32, 32)); + Assert.True(panel.ResizeX); + Assert.False(panel.ResizeY); + } } diff --git a/tests/AcDream.App.Tests/UI/UiRootInputTests.cs b/tests/AcDream.App.Tests/UI/UiRootInputTests.cs index 6ea9e317..9ba7dae5 100644 --- a/tests/AcDream.App.Tests/UI/UiRootInputTests.cs +++ b/tests/AcDream.App.Tests/UI/UiRootInputTests.cs @@ -102,4 +102,14 @@ public class UiRootInputTests 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); + } }