mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-21 03:41:37 -04:00
feat(inspection): keep header zoom live while plate navigation is locked
Validation inspection disabled the whole plate header, so the zoom buttons and Ctrl+Plus/Ctrl+Minus stopped working even though wheel zoom and fit stay available. Group the plate navigation buttons into their own container so the inspection scope can lock them while leaving the viewport-only zoom controls and shortcuts live. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
311178c15a
commit
5180ce1506
6 files changed
+52
-9
No files matched your search
@@ -271,6 +271,35 @@ public class CuttingValidationPanelTests
|
||||
Assert.False(view.ValidationOverlay.IsAnimating);
|
||||
});
|
||||
|
||||
[Fact]
|
||||
public void HeaderZoomStaysLiveWhilePlateNavigationIsLocked() => RunSta(() =>
|
||||
{
|
||||
using var editor = RapidEditor();
|
||||
editor.Show();
|
||||
editor.PlateManager.LoadAt(0);
|
||||
editor.OpenValidationInspection();
|
||||
var panel = editor.CuttingInspection!;
|
||||
Pump(() => panel.ValidationReport != null && !panel.IsPlanning);
|
||||
var view = editor.PlateView;
|
||||
Button Zoom(string name) => Assert.IsType<Button>(editor.Controls.Find(name, true).Single());
|
||||
Zoom("btnZoomToFit").PerformClick(); // The docked panel narrowed the canvas.
|
||||
var fit = view.ViewScale;
|
||||
Zoom("btnZoomIn").PerformClick();
|
||||
Assert.True(view.ViewScale > fit);
|
||||
var zoomed = view.ViewScale;
|
||||
Zoom("btnZoomOut").PerformClick();
|
||||
Assert.True(view.ViewScale < zoomed);
|
||||
Zoom("btnZoomIn").PerformClick();
|
||||
Zoom("btnZoomToFit").PerformClick();
|
||||
Assert.Equal(fit, view.ViewScale, 3);
|
||||
var next = Field<Button>(editor, "btnNextPlate");
|
||||
next.PerformClick();
|
||||
Assert.Equal(0, editor.PlateManager.CurrentIndex);
|
||||
panel.RequestClose();
|
||||
next.PerformClick();
|
||||
Assert.Equal(1, editor.PlateManager.CurrentIndex);
|
||||
});
|
||||
|
||||
private static void InvokeView(Control target, string name, params object[] args) => target.GetType()
|
||||
.GetMethod(name, BindingFlags.NonPublic | BindingFlags.Instance)!.Invoke(target, args);
|
||||
|
||||
|
||||
@@ -586,6 +586,8 @@ namespace OpenNest.Controls
|
||||
InspectionCloseRequested();
|
||||
else if (keyData == Keys.F)
|
||||
ZoomToFit();
|
||||
else if (keyData is (Keys.Control | Keys.Oemplus) or (Keys.Control | Keys.OemMinus))
|
||||
return base.ProcessCmdKey(ref msg, keyData); // The host's zoom shortcuts stay live.
|
||||
return true;
|
||||
}
|
||||
// Audited: DrawControl/PlateView, Action key handlers, EditNestForm,
|
||||
|
||||
@@ -159,6 +159,12 @@ namespace OpenNest.Forms
|
||||
btnNextPlate.Location = new Point(btnSize.Width * 2, 0);
|
||||
btnLastPlate.Location = new Point(btnSize.Width * 3, 0);
|
||||
|
||||
// Inspection locks plate navigation as one container but leaves zoom live.
|
||||
var plateButtons = new Panel { Size = new System.Drawing.Size(btnSize.Width * 4, btnSize.Height) };
|
||||
plateButtons.Controls.AddRange(
|
||||
new Control[] { btnFirstPlate, btnPreviousPlate, btnNextPlate, btnLastPlate });
|
||||
ZoomControls = [zoomOutButton, zoomInButton, zoomToFitButton];
|
||||
|
||||
zoomOutButton.Location = new Point(btnSize.Width * 4 + 8, 0);
|
||||
zoomInButton.Location = new Point(btnSize.Width * 5 + 8, 0);
|
||||
zoomToFitButton.Location = new Point(btnSize.Width * 6 + 8, 0);
|
||||
@@ -174,8 +180,7 @@ namespace OpenNest.Forms
|
||||
navPanel.Controls.AddRange(
|
||||
new Control[]
|
||||
{
|
||||
btnFirstPlate, btnPreviousPlate, btnNextPlate, btnLastPlate,
|
||||
separator, zoomOutButton, zoomInButton, zoomToFitButton
|
||||
plateButtons, separator, zoomOutButton, zoomInButton, zoomToFitButton
|
||||
}
|
||||
);
|
||||
|
||||
@@ -263,6 +268,7 @@ namespace OpenNest.Forms
|
||||
public bool IsSidePanelVisible => !viewSplitContainer.Panel2Collapsed;
|
||||
|
||||
internal Control SidePanelHeader { get; private set; }
|
||||
internal Control[] ZoomControls { get; private set; }
|
||||
internal CuttingInspectionPanel CuttingInspection { get; private set; }
|
||||
private bool disposeAfterCuttingInspection;
|
||||
private bool closeAfterCuttingInspection;
|
||||
|
||||
@@ -78,6 +78,11 @@ namespace OpenNest.Forms
|
||||
return true;
|
||||
}
|
||||
// Standard inspection navigation reaches the canvas/panel; menu shortcuts cannot mutate.
|
||||
// The zoom shortcuts stay live with the header zoom buttons.
|
||||
if (keyData == mnuViewZoomIn.ShortcutKeys)
|
||||
ZoomIn_Click(this, EventArgs.Empty);
|
||||
else if (keyData == mnuViewZoomOut.ShortcutKeys)
|
||||
ZoomOut_Click(this, EventArgs.Empty);
|
||||
if ((keyData & (Keys.Control | Keys.Alt)) != 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -13,8 +13,7 @@ internal sealed class ValidationInspectionScope : IDisposable
|
||||
private readonly List<(Form Form, bool AllowDrop)> hosts = new();
|
||||
private bool disposed;
|
||||
private readonly PlateView view;
|
||||
private readonly Control inspector;
|
||||
private readonly Control header;
|
||||
private readonly Control[] live;
|
||||
private readonly Action close;
|
||||
private Form closingHost;
|
||||
private readonly bool previousInspection;
|
||||
@@ -22,8 +21,8 @@ internal sealed class ValidationInspectionScope : IDisposable
|
||||
public ValidationInspectionScope(EditNestForm editor, Control inspector, Control header, Action close)
|
||||
{
|
||||
view = editor.PlateView;
|
||||
this.inspector = inspector;
|
||||
this.header = header;
|
||||
// The header zoom buttons only change the viewport, like the canvas wheel.
|
||||
live = new[] { view, inspector, header }.Concat(editor.ZoomControls).Where(control => control != null).ToArray();
|
||||
this.close = close;
|
||||
previousInspection = view.InspectionOnly;
|
||||
view.InspectionOnly = true;
|
||||
@@ -43,9 +42,9 @@ internal sealed class ValidationInspectionScope : IDisposable
|
||||
{
|
||||
foreach (var child in parent.Controls.Cast<Control>())
|
||||
{
|
||||
if (ReferenceEquals(child, view) || ReferenceEquals(child, inspector) || ReferenceEquals(child, header))
|
||||
if (live.Contains(child))
|
||||
continue;
|
||||
if (child.Contains(view) || child.Contains(inspector) || header != null && child.Contains(header))
|
||||
if (live.Any(child.Contains))
|
||||
DisableExceptCanvas(child);
|
||||
else
|
||||
{
|
||||
|
||||
@@ -37,7 +37,9 @@ fresh verification and consent flow.
|
||||
Finish or cancel active nesting/fill operations before validating. The panel is
|
||||
exclusive with editing and other side-panel actions while it owns the nest. The
|
||||
main plate view remains available for wheel zoom, middle-button pan, and **F**
|
||||
or middle-button double-click to fit. Panel X, Cancel or Escape requests
|
||||
or middle-button double-click to fit. The plate header's zoom buttons and the
|
||||
**Ctrl+Plus**/**Ctrl+Minus** shortcuts also stay live; its plate navigation
|
||||
buttons stay locked. Panel X, Cancel or Escape requests
|
||||
cancellation and waits for the worker to stop before restoring editing controls.
|
||||
Switching to Plan mode also waits for any validation worker; it does not promote
|
||||
a live validation report into a plan check. Closing the editor or main window
|
||||
|
||||
Reference in new issue
Block a user