mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-03 10:01:38 -05:00
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:
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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user