fix(plateview): keep nudged clones through dialogs

Windows reposts a mouse move when a dialog opens or closes, so Set
Offset Increment threw away arrow-key nudges by snapping the previews
back to the cursor. Only a real cursor move now moves them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ajandClaude Opus 5.5 committed 2026-11-01 12:42:33 -05:00
1 parent bbdd51fabc
commit 45f5ce6954
2 files changed
+58

No files matched your search

@@ -74,4 +74,44 @@ public class ActionCloneTests
view.SetAction(typeof(ActionSelect));
Assert.False(view.ActionHandlesF1);
}, TimeSpan.FromMinutes(1), "The STA test did not complete.");
[Fact]
public void ADialogsFakeMouseMoveLeavesNudgedPreviewsInPlace() => StaTestThread.Run(() =>
{
using var view = new PlateView { Plate = new Plate(48, 96), Size = new System.Drawing.Size(600, 600) };
view.ZoomToFit();
view.SetAction(typeof(ActionClone), Square("new"));
var preview = Assert.Single(view.SelectedParts);
MoveMouse(view, new System.Drawing.Point(300, 300));
var followed = preview.BasePart.BoundingBox.Location;
Nudge(view);
var nudged = preview.BasePart.BoundingBox.Location;
Assert.Equal(followed.X + view.OffsetIncrementDistance, nudged.X, 6);
// A repost of the last position, with no focus change.
MoveMouse(view, new System.Drawing.Point(300, 300));
Assert.Equal(nudged, preview.BasePart.BoundingBox.Location);
// Opening the dialog, then closing it: each post arrives where the cursor rests.
var rest = view.PointToClient(Cursor.Position);
Raise(view, "OnLostFocus", EventArgs.Empty);
MoveMouse(view, rest);
Assert.Equal(nudged, preview.BasePart.BoundingBox.Location);
Raise(view, "OnGotFocus", EventArgs.Empty);
MoveMouse(view, rest);
Assert.Equal(nudged, preview.BasePart.BoundingBox.Location);
// The next real move takes the previews back to the cursor.
MoveMouse(view, new System.Drawing.Point(rest.X + 20, rest.Y + 20));
Assert.NotEqual(nudged, preview.BasePart.BoundingBox.Location);
}, TimeSpan.FromMinutes(1), "The STA test did not complete.");
private static void MoveMouse(PlateView view, System.Drawing.Point point) =>
Raise(view, "OnMouseMove", new MouseEventArgs(MouseButtons.None, 0, point.X, point.Y, 0));
private static void Nudge(PlateView view) =>
typeof(PlateView).GetMethod("ProcessDialogKey", BindingFlags.Instance | BindingFlags.NonPublic)!
.Invoke(view, new object[] { Keys.Right });
}
+18
View File
@@ -16,6 +16,7 @@ namespace OpenNest.Actions
private readonly List<Part> sourceParts;
private double lastScale;
private System.Drawing.Point? restingCursor;
public ActionClone(PlateView plateView, Drawing drawing)
: this(plateView, new List<Part> { new Part(drawing) }) { }
@@ -27,6 +28,8 @@ namespace OpenNest.Actions
plateView.MouseMove += plateView_MouseMove;
plateView.MouseDown += plateView_MouseDown;
plateView.Paint += plateView_Paint;
plateView.GotFocus += plateView_FocusChanged;
plateView.LostFocus += plateView_FocusChanged;
sourceParts = partsToClone;
parts = new List<LayoutPart>();
@@ -101,13 +104,24 @@ namespace OpenNest.Actions
lastScale = plateView.ViewScale;
}
// Windows posts a mouse move when a dialog opens or closes, though the mouse stayed
// put. Following it would throw away arrow-key nudges, so only a real move counts.
private void plateView_MouseMove(object sender, MouseEventArgs e)
{
if (e.Location == restingCursor)
return;
restingCursor = e.Location;
var offset = plateView.CurrentPoint - parts.GetBoundingBox().Location;
parts.ForEach(p => p.Offset(offset));
plateView.Invalidate();
}
// The cursor may have been moved to the dialog's OK button, so measure the rest
// position afresh whenever focus leaves or returns.
private void plateView_FocusChanged(object sender, System.EventArgs e) =>
restingCursor = plateView.PointToClient(Cursor.Position);
public override bool SurvivesPlateChange => true;
// F1 sets the part in place, as it always has; help stays on the Help menu.
@@ -121,6 +135,8 @@ namespace OpenNest.Actions
plateView.MouseMove += plateView_MouseMove;
plateView.MouseDown += plateView_MouseDown;
plateView.Paint += plateView_Paint;
plateView.GotFocus += plateView_FocusChanged;
plateView.LostFocus += plateView_FocusChanged;
SelectPreviews();
}
@@ -131,6 +147,8 @@ namespace OpenNest.Actions
plateView.MouseMove -= plateView_MouseMove;
plateView.MouseDown -= plateView_MouseDown;
plateView.Paint -= plateView_Paint;
plateView.GotFocus -= plateView_FocusChanged;
plateView.LostFocus -= plateView_FocusChanged;
plateView.SelectedParts.Clear();
plateView.Invalidate();