mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-29 10:11:21 -04:00
feat(simulator): lock the nest to viewing while the cut simulator is open
The simulator reuses Plan Cutting's inspection lock: the canvas pans and zooms and plates can be stepped through, but selection, part edits, menus, toolbars, lists and Undo/Redo are disabled until it closes. Escape or closing the nest closes the simulator first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
101d7b5a50
commit
a9396ba065
7 files changed
+45
-9
No files matched your search
@@ -10,6 +10,8 @@ namespace OpenNest.Forms
|
||||
/// <summary>
|
||||
/// Playback controls for a <see cref="CutSimulationOverlay"/> on a nest's plate view. Follows
|
||||
/// the current plate and rebuilds the timeline when parts are added, removed or resequenced.
|
||||
/// While it is open the nest is view-only, as in Plan Cutting: the canvas pans and zooms and
|
||||
/// plates can be stepped through, but nothing that edits is enabled.
|
||||
/// </summary>
|
||||
public sealed class CutSimulatorForm : Form
|
||||
{
|
||||
@@ -26,6 +28,7 @@ namespace OpenNest.Forms
|
||||
private readonly NumericUpDown feedBox, holeFeedBox, rapidBox, pierceBox;
|
||||
private readonly CheckBox skipEtchBox;
|
||||
private readonly CutTimeMachineBox machineBox;
|
||||
private readonly ValidationInspectionScope scope;
|
||||
private Plate plate;
|
||||
private bool updatingTrack;
|
||||
private bool rebuildQueued;
|
||||
@@ -184,6 +187,9 @@ namespace OpenNest.Forms
|
||||
nestForm.FormClosed += NestForm_FormClosed;
|
||||
AttachPlate(nestForm.PlateView.Plate);
|
||||
Rebuild();
|
||||
|
||||
scope = new ValidationInspectionScope(nestForm, Close, nestForm.PlateNavigation);
|
||||
nestForm.PlateView.InspectionCloseRequested = Close;
|
||||
}
|
||||
|
||||
private static NumericUpDown NewNumber(decimal value, decimal min, decimal max, int decimals, string suffix) =>
|
||||
@@ -447,9 +453,16 @@ namespace OpenNest.Forms
|
||||
nestForm.FormClosed -= NestForm_FormClosed;
|
||||
AttachPlate(null);
|
||||
if (!nestForm.PlateView.IsDisposed)
|
||||
{
|
||||
overlay.Clear();
|
||||
nestForm.PlateView.InspectionCloseRequested = null;
|
||||
}
|
||||
|
||||
base.OnFormClosed(e);
|
||||
|
||||
// Unlock after the editor has forgotten this form, then finish a close it held up.
|
||||
scope.Dispose();
|
||||
scope.ResumeHostClose();
|
||||
}
|
||||
|
||||
// Playback rewrites the status every frame; a plain label erases before it redraws, so it flashes.
|
||||
|
||||
@@ -401,7 +401,7 @@ internal sealed class CuttingInspectionPanel : UserControl
|
||||
|
||||
internal void Open()
|
||||
{
|
||||
scope = new ValidationInspectionScope(editor, this, editor.SidePanelHeader, RequestClose);
|
||||
scope = new ValidationInspectionScope(editor, RequestClose, this, editor.SidePanelHeader);
|
||||
view.InspectionCloseRequested = RequestClose;
|
||||
view.OverlapDisplay = OverlapDisplayMode.Off;
|
||||
view.ClearValidationFinding();
|
||||
|
||||
Generated
+3
@@ -16,6 +16,9 @@
|
||||
// A planning worker owns a captured inspection until its owner-thread join.
|
||||
if (disposing && DeferCuttingDisposal())
|
||||
return;
|
||||
// The simulator's lock disables the main window until it closes.
|
||||
if (disposing)
|
||||
cutSimulatorForm?.Close();
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace OpenNest.Forms
|
||||
|
||||
public bool CanRedo => History.CanRedo && CanRestore;
|
||||
|
||||
private bool CanRestore => !IsChangeInProgress && CuttingInspection == null;
|
||||
private bool CanRestore => !IsChangeInProgress && !IsInspecting;
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
|
||||
@@ -176,6 +176,7 @@ namespace OpenNest.Forms
|
||||
plateButtons.Controls.AddRange(
|
||||
new Control[] { btnFirstPlate, btnPreviousPlate, btnNextPlate, btnLastPlate });
|
||||
ZoomControls = [zoomOutButton, zoomInButton, zoomToFitButton];
|
||||
PlateNavigation = plateButtons;
|
||||
|
||||
zoomOutButton.Location = new Point(btnSize.Width * 4 + 8, 0);
|
||||
zoomInButton.Location = new Point(btnSize.Width * 5 + 8, 0);
|
||||
@@ -281,7 +282,20 @@ namespace OpenNest.Forms
|
||||
|
||||
internal Control SidePanelHeader { get; private set; }
|
||||
internal Control[] ZoomControls { get; private set; }
|
||||
internal Control PlateNavigation { get; private set; }
|
||||
internal CuttingInspectionPanel CuttingInspection { get; private set; }
|
||||
|
||||
/// <summary>True while Plan Cutting or the Cut Simulator holds the nest view-only.</summary>
|
||||
internal bool IsInspecting => CuttingInspection != null || cutSimulatorForm != null;
|
||||
|
||||
internal void EndInspection()
|
||||
{
|
||||
if (CuttingInspection != null)
|
||||
CuttingInspection.RequestClose();
|
||||
else
|
||||
cutSimulatorForm?.Close();
|
||||
}
|
||||
|
||||
private bool disposeAfterCuttingInspection;
|
||||
private bool closeAfterCuttingInspection;
|
||||
internal bool DeferCuttingDisposal()
|
||||
@@ -1118,7 +1132,10 @@ namespace OpenNest.Forms
|
||||
cutSimulatorForm.Activate();
|
||||
return;
|
||||
}
|
||||
if (CuttingInspection != null)
|
||||
return;
|
||||
|
||||
PlateView.EndAction();
|
||||
cutSimulatorForm = new CutSimulatorForm(this);
|
||||
cutSimulatorForm.FormClosed += (_, _) => cutSimulatorForm = null;
|
||||
var owner = MdiParent ?? (Form)this;
|
||||
|
||||
@@ -75,13 +75,12 @@ namespace OpenNest.Forms
|
||||
|
||||
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
||||
{
|
||||
var inspection = MdiChildren.OfType<EditNestForm>()
|
||||
.Select(form => form.CuttingInspection).FirstOrDefault(panel => panel != null);
|
||||
if (inspection != null)
|
||||
var inspected = MdiChildren.OfType<EditNestForm>().FirstOrDefault(form => form.IsInspecting);
|
||||
if (inspected != null)
|
||||
{
|
||||
if (keyData == Keys.Escape)
|
||||
{
|
||||
inspection.RequestClose();
|
||||
inspected.EndInspection();
|
||||
return true;
|
||||
}
|
||||
// Standard inspection navigation reaches the canvas/panel; menu shortcuts cannot mutate.
|
||||
|
||||
@@ -6,7 +6,11 @@ using OpenNest.Controls;
|
||||
|
||||
namespace OpenNest.Forms;
|
||||
|
||||
/// <summary>Keep live validation inputs stable while allowing navigation of the main canvas.</summary>
|
||||
/// <summary>
|
||||
/// Keep live validation inputs stable while allowing navigation of the main canvas. Locks the
|
||||
/// canvas to viewing and disables every other control of the main window except
|
||||
/// <c>keepLive</c> and the zoom buttons.
|
||||
/// </summary>
|
||||
internal sealed class ValidationInspectionScope : IDisposable
|
||||
{
|
||||
private readonly List<(Control Control, bool Enabled)> controls = new();
|
||||
@@ -18,11 +22,11 @@ internal sealed class ValidationInspectionScope : IDisposable
|
||||
private Form closingHost;
|
||||
private readonly bool previousInspection;
|
||||
|
||||
public ValidationInspectionScope(EditNestForm editor, Control inspector, Control header, Action close)
|
||||
public ValidationInspectionScope(EditNestForm editor, Action close, params Control[] keepLive)
|
||||
{
|
||||
view = editor.PlateView;
|
||||
// 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();
|
||||
live = keepLive.Prepend(view).Concat(editor.ZoomControls).Where(control => control != null).ToArray();
|
||||
this.close = close;
|
||||
previousInspection = view.InspectionOnly;
|
||||
view.InspectionOnly = true;
|
||||
|
||||
Reference in new issue
Block a user