diff --git a/OpenNest.WinForms.Tests/PlateOverlapOverlayTests.cs b/OpenNest.WinForms.Tests/PlateOverlapOverlayTests.cs
index aa42adbd..26049c85 100644
--- a/OpenNest.WinForms.Tests/PlateOverlapOverlayTests.cs
+++ b/OpenNest.WinForms.Tests/PlateOverlapOverlayTests.cs
@@ -343,47 +343,41 @@ public class PlateOverlapOverlayTests
});
[Fact]
- public void ClearPlateDrawsAGreenCheckInsteadOfTheLabelButStatusKeepsTheWords() => RunSta(() =>
+ public void ClearPlateDrawsNoLabelButStatusKeepsTheWords() => RunSta(() =>
{
using var run = new OverlayRun();
run.View.Plate.Parts.RemoveAt(1);
run.Finish();
- Assert.True(run.View.OverlapOverlay.ShowsAllClear);
+ Assert.True(run.View.OverlapOverlay.ShowsNoLabel);
Assert.Equal("No material overlaps detected", run.View.Status);
- Assert.True(CheckIsDrawn(run));
+ Assert.True(CornerIsEmpty(run));
run.View.Plate.Parts.Add(Rectangle(1));
run.Finish();
- Assert.False(run.View.OverlapOverlay.ShowsAllClear);
- Assert.False(CheckIsDrawn(run));
+ Assert.False(run.View.OverlapOverlay.ShowsNoLabel);
+ Assert.False(CornerIsEmpty(run));
});
[Fact]
- public void ClearPlateKeepsAGrayCheckWhileRechecking() => RunSta(() =>
+ public void ClearPlateStaysEmptyWhileRechecking() => RunSta(() =>
{
using var run = new OverlayRun();
run.View.Plate.Parts.RemoveAt(1);
run.EnableAutoCheck();
var overlay = run.View.OverlapOverlay;
+ Assert.True(overlay.ShowsNoLabel); // Before the first result too.
var task = run.AutoTick();
- run.Next().Complete();
+ var work = run.Next();
+ Assert.True(overlay.ShowsNoLabel);
+ work.Complete();
run.Pump(task);
- Assert.True(overlay.ShowsAllClear);
+ Assert.True(overlay.ShowsNoLabel);
run.View.Plate.Parts[0].Offset(1, 0);
run.Paint();
Assert.True(overlay.IsAutoCheckScheduled);
- Assert.True(overlay.ShowsPendingCheck);
- Assert.False(overlay.ShowsAllClear);
- Assert.False(CheckIsDrawn(run)); // Gray, not green: this layout is unconfirmed.
-
- task = run.AutoTick();
- var work = run.Next();
- Assert.True(overlay.ShowsPendingCheck);
- work.Complete();
- run.Pump(task);
- Assert.False(overlay.ShowsPendingCheck);
- Assert.True(overlay.ShowsAllClear);
+ Assert.True(overlay.ShowsNoLabel);
+ Assert.True(CornerIsEmpty(run));
});
[Fact]
@@ -397,37 +391,60 @@ public class PlateOverlapOverlayTests
run.View.Plate.Parts[1].Offset(0.5, 0);
run.Paint();
- Assert.False(run.View.OverlapOverlay.ShowsPendingCheck);
- Assert.False(run.View.OverlapOverlay.ShowsAllClear);
+ Assert.False(run.View.OverlapOverlay.ShowsNoLabel);
});
- [Fact]
- public void StaleWithoutAutoCheckStillAsksForACheck() => RunSta(() =>
+ [Theory]
+ [InlineData("failed")]
+ [InlineData("canceled")]
+ public void FailedOrCanceledCheckIsNeverAnEmptyCorner(string outcome) => RunSta(() =>
{
using var run = new OverlayRun();
run.View.Plate.Parts.RemoveAt(1);
+ run.EnableAutoCheck();
+ var task = run.AutoTick();
+ var work = run.Next();
+ if (outcome == "failed")
+ work.Fail();
+ else
+ {
+ run.View.CancelOverlapCheck();
+ work.Complete();
+ }
+ run.Pump(task);
+ run.Paint();
+ Assert.False(run.View.OverlapOverlay.ShowsNoLabel);
+ });
+
+ [Fact]
+ public void WithoutAutoCheckPendingStatesKeepTheirText() => RunSta(() =>
+ {
+ using var run = new OverlayRun();
+ run.View.Plate.Parts.RemoveAt(1);
+ Assert.False(run.View.OverlapOverlay.ShowsNoLabel); // Not checked.
run.Finish();
run.View.Plate.Parts[0].Offset(1, 0);
run.Paint();
Assert.Equal(OverlapCheckStatus.Stale, run.View.OverlapStatus);
- Assert.False(run.View.OverlapOverlay.ShowsPendingCheck);
- Assert.False(run.View.OverlapOverlay.ShowsAllClear);
+ Assert.False(run.View.OverlapOverlay.ShowsNoLabel);
+ var task = run.Start();
+ var work = run.Next();
+ Assert.False(run.View.OverlapOverlay.ShowsNoLabel); // Checking.
+ work.Complete();
+ run.Pump(task);
});
- private static bool CheckIsDrawn(OverlayRun run)
+ private static bool CornerIsEmpty(OverlayRun run)
{
using var image = new Bitmap(64, 64);
using var graphics = Graphics.FromImage(image);
graphics.Clear(Color.White);
run.View.OverlapOverlay.Draw(graphics);
for (var x = 0; x < 64; x++)
- for (var y = 0; y < 64; y++)
- {
- var pixel = image.GetPixel(x, y);
- if (pixel.G > pixel.R + 60 && pixel.G > pixel.B + 40)
- return true;
- }
- return false;
+ for (var y = 0; y < 32; y++)
+ if (image.GetPixel(x, y).ToArgb() != Color.White.ToArgb())
+ return false;
+ return true;
}
[Fact]
diff --git a/OpenNest/Controls/OverlapOverlayController.cs b/OpenNest/Controls/OverlapOverlayController.cs
index c532f538..66d2c1de 100644
--- a/OpenNest/Controls/OverlapOverlayController.cs
+++ b/OpenNest/Controls/OverlapOverlayController.cs
@@ -80,13 +80,16 @@ internal sealed class OverlapOverlayController : IDisposable
? "Overlaps: check pending…"
: state.Message;
- /// The canvas shows a green check instead of the label: a pending recheck is not clear.
- internal bool ShowsAllClear => state.IsAllClear && !IsSettling;
+ ///
+ /// The corner stays empty unless something is wrong: on a clear result, and while an
+ /// automatic recheck settles after one or before the first. Views without automatic rechecks
+ /// keep their pending text, because nothing will arrive unless the user asks.
+ ///
+ internal bool ShowsNoLabel => IsSettling
+ ? state.SettledMessage == null || state.SettledClear
+ : state.IsAllClear;
- /// A gray check while a recheck settles: unconfirmed, and steady in the corner.
- internal bool ShowsPendingCheck => IsSettling && (state.SettledMessage == null || state.SettledClear);
-
- private bool IsSettling => autoCheck.IsWaiting || state.IsRunning;
+ private bool IsSettling => autoCheckUnits != null && (autoCheck.IsWaiting || state.IsRunning);
///
/// Recheck automatically after layout edits settle. Units are read when each request
@@ -687,41 +690,14 @@ internal sealed class OverlapOverlayController : IDisposable
}
}
- // Same corner as the label; Message keeps the words for the status bar.
- private void DrawCheck(Graphics graphics, Color color)
- {
- var scale = view.DeviceDpi / 96f;
- var box = 24 * scale;
- using var background = new SolidBrush(Color.FromArgb(235, Color.White));
- graphics.FillRectangle(background, 6, 6, box, box);
- using var pen = new Pen(color, 3 * scale)
- {
- StartCap = LineCap.Round,
- EndCap = LineCap.Round,
- LineJoin = LineJoin.Round,
- };
- var smoothing = graphics.SmoothingMode;
- graphics.SmoothingMode = SmoothingMode.AntiAlias;
- graphics.DrawLines(pen, new[]
- {
- new PointF(6 + 5 * scale, 6 + 13 * scale),
- new PointF(6 + 10 * scale, 6 + 18 * scale),
- new PointF(6 + 19 * scale, 6 + 7 * scale),
- });
- graphics.SmoothingMode = smoothing;
- }
-
private void DrawStateLabel(Graphics graphics)
{
var saved = graphics.Save();
try
{
graphics.ResetTransform();
- if (ShowsAllClear || ShowsPendingCheck)
- {
- DrawCheck(graphics, ShowsAllClear ? Color.FromArgb(0, 140, 60) : Color.FromArgb(150, 150, 150));
+ if (ShowsNoLabel)
return;
- }
// While settling, the last findings stay put, dimmed, instead of status text flickering.
var settling = IsSettling;
var text = (settling ? state.SettledMessage : Message)
diff --git a/docs/geometry/visual-overlap-check.md b/docs/geometry/visual-overlap-check.md
index 47d59614..de57678d 100644
--- a/docs/geometry/visual-overlap-check.md
+++ b/docs/geometry/visual-overlap-check.md
@@ -29,11 +29,12 @@ Small positive areas use significant-figure formatting rather than rounding to
zero. Selection and dragging remain ordinary plate operations, not overlay
interactions.
-A current, fully checked report with no finding of any kind draws a green check in
-the corner instead of words; the status bar still uses the wording below. While a
-recheck is pending or running the corner stays quiet: a gray check after a clear
-result or when there is no result yet, or the last findings dimmed in gray, neither
-of which says anything about the edited layout. Every
+A current, fully checked report with no finding of any kind leaves the corner empty;
+the status bar still uses the wording below. In a nest window the corner also stays
+empty while a recheck is pending or running after a clear result or before the first,
+and earlier findings stay dimmed in gray, which says nothing about the edited layout.
+Failed, canceled and incomplete checks always show text, and hosts without automatic
+rechecks keep their pending text, so an empty corner there is a finished clear check. Every
other state keeps a persistent label, which distinguishes unchecked, checking,
current with findings, incomplete, stale,
canceled, and failed checks. Only a completed, current, fully checked report can