From c2cfd182737499464cd2e9a2e20b9a575c363d66 Mon Sep 17 00:00:00 2001 From: Misaki Date: Sat, 28 Mar 2026 14:30:28 +0900 Subject: [PATCH] fix(dock): address reviewer feedback on drag state and boundary tests --- .../Controls/Internal/Docking/DockMath.cs | 10 ++++- .../Ghost.Editor/View/Controls/DockLayout.cs | 12 +++-- src/Test/Ghost.UnitTest/DockLayoutTest.cs | 44 +++++++++++++++++++ 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/Editor/Ghost.Editor.Core/Controls/Internal/Docking/DockMath.cs b/src/Editor/Ghost.Editor.Core/Controls/Internal/Docking/DockMath.cs index 6d87c55..ad49763 100644 --- a/src/Editor/Ghost.Editor.Core/Controls/Internal/Docking/DockMath.cs +++ b/src/Editor/Ghost.Editor.Core/Controls/Internal/Docking/DockMath.cs @@ -3,7 +3,7 @@ namespace Ghost.Editor.Core.Controls.Internal.Docking; /// /// Defines the possible dock positions for a drop operation. /// -public enum DockPosition +internal enum DockPosition { Center, Top, @@ -16,7 +16,7 @@ public enum DockPosition /// /// Helper class for docking-related calculations. /// -public static class DockMath +internal static class DockMath { /// /// Calculates the dock position based on the relative position within a target element. @@ -24,6 +24,12 @@ public static class DockMath /// public static DockPosition CalculateDockPosition(double width, double height, double x, double y, double threshold) { + // Guard against invalid inputs + if (width <= 0 || height <= 0) return DockPosition.None; + + // Clamp threshold to valid range [0, 0.5] + threshold = Math.Max(0, Math.Min(0.5, threshold)); + if (x < width * threshold) return DockPosition.Left; if (x > width * (1 - threshold)) return DockPosition.Right; if (y < height * threshold) return DockPosition.Top; diff --git a/src/Editor/Ghost.Editor/View/Controls/DockLayout.cs b/src/Editor/Ghost.Editor/View/Controls/DockLayout.cs index 94572db..99934da 100644 --- a/src/Editor/Ghost.Editor/View/Controls/DockLayout.cs +++ b/src/Editor/Ghost.Editor/View/Controls/DockLayout.cs @@ -324,16 +324,21 @@ public sealed partial class DockLayout : Control private void TabView_DragLeave(object sender, DragEventArgs e) { - ClearDragState(); + ClearOverlayState(); } - private void ClearDragState() + private void ClearOverlayState() { if (_dropTargetOverlay != null) { _dropTargetOverlay.Visibility = Visibility.Collapsed; } _currentDropPosition = DockPosition.None; + } + + private void ClearDragOperationState() + { + ClearOverlayState(); _draggedItem = null; _sourceNode = null; } @@ -374,10 +379,9 @@ public sealed partial class DockLayout : Control } } - // Add a dummy TabView_Drop method so it compiles, we will implement it in Task 6 private void TabView_Drop(object sender, DragEventArgs e) { - ClearDragState(); + ClearDragOperationState(); } protected override void OnApplyTemplate() diff --git a/src/Test/Ghost.UnitTest/DockLayoutTest.cs b/src/Test/Ghost.UnitTest/DockLayoutTest.cs index ab39bc3..f8f249c 100644 --- a/src/Test/Ghost.UnitTest/DockLayoutTest.cs +++ b/src/Test/Ghost.UnitTest/DockLayoutTest.cs @@ -59,4 +59,48 @@ public class DockLayoutTest var pos = DockMath.CalculateDockPosition(100, 100, 90, 90, THRESHOLD); Assert.AreEqual(DockPosition.Right, pos); } + + [TestMethod] + public void TestCalculateDockPosition_Boundary_Left() + { + // x = 25 is exactly on the threshold. Current logic: x < 25 is Left, so 25 is Center. + var pos = DockMath.CalculateDockPosition(100, 100, 25, 50, THRESHOLD); + Assert.AreEqual(DockPosition.Center, pos); + + pos = DockMath.CalculateDockPosition(100, 100, 24.9, 50, THRESHOLD); + Assert.AreEqual(DockPosition.Left, pos); + } + + [TestMethod] + public void TestCalculateDockPosition_Boundary_Right() + { + // x = 75 is exactly on the threshold (100 * (1 - 0.25)). Current logic: x > 75 is Right, so 75 is Center. + var pos = DockMath.CalculateDockPosition(100, 100, 75, 50, THRESHOLD); + Assert.AreEqual(DockPosition.Center, pos); + + pos = DockMath.CalculateDockPosition(100, 100, 75.1, 50, THRESHOLD); + Assert.AreEqual(DockPosition.Right, pos); + } + + [TestMethod] + public void TestCalculateDockPosition_InvalidSize() + { + var pos = DockMath.CalculateDockPosition(0, 100, 50, 50, THRESHOLD); + Assert.AreEqual(DockPosition.None, pos); + + pos = DockMath.CalculateDockPosition(100, -10, 50, 50, THRESHOLD); + Assert.AreEqual(DockPosition.None, pos); + } + + [TestMethod] + public void TestCalculateDockPosition_ThresholdClamping() + { + // Threshold > 0.5 should be clamped to 0.5 + var pos = DockMath.CalculateDockPosition(100, 100, 40, 50, 0.8); + Assert.AreEqual(DockPosition.Left, pos); + + // Threshold < 0 should be clamped to 0 + pos = DockMath.CalculateDockPosition(100, 100, 0.1, 50, -0.1); + Assert.AreEqual(DockPosition.Center, pos); + } }