feat(ui): leave the overlap corner empty unless something is wrong

Drop the check mark: a clear result, and an automatic recheck after one,
now draw nothing. Findings and failed, canceled or incomplete checks keep
their text, and views without automatic rechecks keep their pending text.
The status bar still reports a manual check's result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ajandClaude Opus 5.5 committed 2026-11-01 23:42:25 -05:00
1 parent fd37cbffef
commit ac7ee41801
3 files changed
+66 -72

No files matched your search

@@ -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]
+10 -34
View File
@@ -80,13 +80,16 @@ internal sealed class OverlapOverlayController : IDisposable
? "Overlaps: check pending…"
: state.Message;
/// <summary>The canvas shows a green check instead of the label: a pending recheck is not clear.</summary>
internal bool ShowsAllClear => state.IsAllClear && !IsSettling;
/// <summary>
/// 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.
/// </summary>
internal bool ShowsNoLabel => IsSettling
? state.SettledMessage == null || state.SettledClear
: state.IsAllClear;
/// <summary>A gray check while a recheck settles: unconfirmed, and steady in the corner.</summary>
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);
/// <summary>
/// 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)
+6 -5
View File
@@ -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