From b324baa69a015d59cc37e3e1871fa32989c0f347 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Sat, 17 Oct 2026 01:59:34 -0400 Subject: [PATCH] fix(desktop): keep scrap cut-offs checkbox selectable during planning The cut planner disabled "Add scrap cut-offs" along with every other control while a plan ran, including the very first auto-started plan. It now stays enabled; toggling it mid-plan cancels the run in progress and restarts planning with the new setting. Co-Authored-By: Claude Sonnet 5 --- .../Forms/CuttingInspectionPanelTests.cs | 37 +++++++++++++++++++ OpenNest/Forms/CuttingInspectionPanel.cs | 37 ++++++++++++++++++- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/OpenNest.WinForms.Tests/Forms/CuttingInspectionPanelTests.cs b/OpenNest.WinForms.Tests/Forms/CuttingInspectionPanelTests.cs index 48ffbb03..65ef4681 100644 --- a/OpenNest.WinForms.Tests/Forms/CuttingInspectionPanelTests.cs +++ b/OpenNest.WinForms.Tests/Forms/CuttingInspectionPanelTests.cs @@ -538,6 +538,43 @@ public class CuttingInspectionPanelTests Assert.All(plate.Parts, part => Assert.False(part.HasManualLeadIns)); }); + [Fact] + public void TogglingScrapCutOffsWhilePlanningCancelsAndRestartsWithTheNewValue() => RunSta(() => + { + using var editor = Editor(); + editor.Show(); + editor.PlateManager.LoadAt(0); + var plate = editor.PlateView.Plate; + using var entered = new ManualResetEventSlim(); + using var release = new ManualResetEventSlim(); + editor.CuttingBeforePlan = _ => + { + entered.Set(); + release.Wait(TimeSpan.FromSeconds(30)); + }; + try + { + editor.OpenCuttingInspection(); + var panel = editor.CuttingInspection!; + PumpUntil(() => entered.IsSet); + Assert.True(panel.IsPlanning); + var checkBox = Field(panel, "autoCutOffsCheckBox"); + Assert.True(checkBox.Enabled); // stays selectable instead of being disabled like the other controls + + checkBox.Checked = true; // toggled mid-plan: cancels the run in progress and restarts + Assert.True(checkBox.Enabled); + release.Set(); + + PumpUntil(() => panel.Proposal != null && !panel.IsPlanning); + Assert.NotNull(panel.StagedCutOffs); + Assert.NotEmpty(plate.CutOffs); + } + finally + { + release.Set(); + } + }); + [Fact] public void ApplyKeepsTheStagedAutomaticCutOffsInThePlannedOrder() => RunSta(() => { diff --git a/OpenNest/Forms/CuttingInspectionPanel.cs b/OpenNest/Forms/CuttingInspectionPanel.cs index 3009b265..0c35b735 100644 --- a/OpenNest/Forms/CuttingInspectionPanel.cs +++ b/OpenNest/Forms/CuttingInspectionPanel.cs @@ -38,6 +38,7 @@ internal sealed class CuttingInspectionPanel : UserControl private bool closeRequested; private CuttingInspectionMode? pendingMode; private bool configuringMode; + private bool pendingReplan; internal CuttingInspectionMode Mode { get; private set; } internal PostVerificationReport ValidationReport { get; private set; } internal Func> Analyze { get; set; } @@ -195,7 +196,7 @@ internal sealed class CuttingInspectionPanel : UserControl cancelButton.Click += (_, _) => RequestClose(); settingsButton.Click += (_, _) => EditSettings(); keepOrderCheckBox.CheckedChanged += (_, _) => StartPlanning(); - autoCutOffsCheckBox.CheckedChanged += (_, _) => StartPlanning(); + autoCutOffsCheckBox.CheckedChanged += (_, _) => RestartPlanning(); cutOffSettingsButton.Click += (_, _) => EditCutOffSettings(); clearExistingButton.Click += (_, _) => ClearExistingWork(); acceptWarningsCheckBox.CheckedChanged += (_, _) => UpdateApply(); @@ -539,6 +540,29 @@ internal sealed class CuttingInspectionPanel : UserControl _ => "The ring marks the affected part; the exact spot is not known." }; + /// + /// Starts planning with the current settings. The scrap cut-offs checkbox stays enabled while + /// planning runs, so toggling it mid-plan cancels the run in progress and starts a fresh one + /// once that cancellation lands, instead of being ignored like other, disabled, controls. + /// + private void RestartPlanning() + { + if (Mode != CuttingInspectionMode.Plan || closed || closeRequested || pendingMode != null) + return; + if (!IsPlanning) + { + StartPlanning(); + return; + } + if (inspection.CloseRequested) + return; // Already finishing; the checkbox's latest value is picked up when that lands. + pendingReplan = true; + ClearResult(); + SetPlanning(true); + SetStatus(Tone.Neutral, "Restarting…"); + inspection.RequestClose(); + } + internal void StartPlanning() { if (Mode != CuttingInspectionMode.Plan || closed || IsPlanning || closeRequested || inspection.CloseRequested) @@ -591,9 +615,18 @@ internal sealed class CuttingInspectionPanel : UserControl inspection.CompletePlanning(work); if (closeRequested || pendingMode != null) { + pendingReplan = false; FinishTransition(); return; } + if (pendingReplan) + { + pendingReplan = false; + if (closed) return; + inspection = new CuttingProposalInspection(); + StartPlanning(); + return; + } if (closed || run != generation) return; SetPlanning(false); @@ -731,7 +764,7 @@ internal sealed class CuttingInspectionPanel : UserControl private void SetPlanning(bool running) { - settingsButton.Enabled = keepOrderCheckBox.Enabled = autoCutOffsCheckBox.Enabled = planButton.Enabled = !running; + settingsButton.Enabled = keepOrderCheckBox.Enabled = planButton.Enabled = !running; cutOffSettingsButton.Enabled = !running; clearExistingButton.Enabled = !running; previousButton.Enabled = !running && selectedPlate > 0;