mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-03 10:01:38 -05:00
feat(ui): keep the overlap corner quiet during rechecks
A pending or running recheck no longer swaps the green check for status text. A clear result stays as a gray check, and earlier findings stay as dimmed text, neither of which claims anything about the edited layout. Views without automatic rechecks still ask for a manual check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c0cd7c6aff
commit
fd37cbffef
5 files changed
+111
-8
No files matched your search
@@ -31,6 +31,13 @@ public sealed class OverlapReportState
|
||||
public bool IsAllClear => Status == OverlapCheckStatus.Current && Report.Pairs.Count == 0
|
||||
&& Report.ClampFindings.Count == 0 && Report.CutOffClampFindings.Count == 0
|
||||
&& Report.SpacingPairs.Count == 0;
|
||||
/// <summary>
|
||||
/// The last published result's message, kept through layout edits and rechecks so the canvas
|
||||
/// stays quiet until the next result; never a claim about the current layout. Null when none.
|
||||
/// </summary>
|
||||
public string SettledMessage { get; private set; }
|
||||
/// <summary>Whether that last published result was all clear.</summary>
|
||||
public bool SettledClear { get; private set; }
|
||||
|
||||
public string Message => Status switch
|
||||
{
|
||||
@@ -91,6 +98,8 @@ public sealed class OverlapReportState
|
||||
observedDisplayStamp = stamp;
|
||||
uncheckedPartCount = CountUncheckedParts(report.Issues.Concat(report.SpacingIssues));
|
||||
Status = report.IsComplete ? OverlapCheckStatus.Current : OverlapCheckStatus.Incomplete;
|
||||
SettledMessage = Message;
|
||||
SettledClear = IsAllClear;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -175,7 +184,11 @@ public sealed class OverlapReportState
|
||||
private void Clear(OverlapCheckStatus status, bool preserveDisplay = false)
|
||||
{
|
||||
if (!preserveDisplay)
|
||||
{
|
||||
ClearDisplayPairs();
|
||||
SettledMessage = null;
|
||||
SettledClear = false;
|
||||
}
|
||||
Generation++;
|
||||
Report = null;
|
||||
uncheckedPartCount = 0;
|
||||
|
||||
@@ -200,6 +200,29 @@ public class OverlapSpacingLabelTests
|
||||
Assert.False(state.IsAllClear);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SettledResult_SurvivesEditsAndRechecksButNotFailureOrCancel()
|
||||
{
|
||||
var plate = PlateWith(Spacing, Square(0), Square(4.1));
|
||||
var state = new OverlapReportState();
|
||||
Assert.Null(state.SettledMessage);
|
||||
Assert.True(state.TryPublish(state.Begin(plate), plate, Analyze(plate)));
|
||||
const string message = "No material overlaps; part spacing: 1 pairs too close";
|
||||
|
||||
plate.Parts[1].Offset(1, 0);
|
||||
state.EnsureFresh(plate);
|
||||
Assert.Equal((message, false), (state.SettledMessage, state.SettledClear));
|
||||
var request = state.Begin(plate);
|
||||
Assert.Equal(message, state.SettledMessage);
|
||||
|
||||
Assert.True(state.TryPublish(request, plate, Analyze(plate)));
|
||||
Assert.True(state.SettledClear);
|
||||
|
||||
Assert.True(state.TryFail(state.Begin(plate), plate));
|
||||
Assert.Null(state.SettledMessage);
|
||||
Assert.False(state.SettledClear);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Presentation_ShowsPositionsNamesAndGap()
|
||||
{
|
||||
|
||||
@@ -358,6 +358,62 @@ public class PlateOverlapOverlayTests
|
||||
Assert.False(CheckIsDrawn(run));
|
||||
});
|
||||
|
||||
[Fact]
|
||||
public void ClearPlateKeepsAGrayCheckWhileRechecking() => RunSta(() =>
|
||||
{
|
||||
using var run = new OverlayRun();
|
||||
run.View.Plate.Parts.RemoveAt(1);
|
||||
run.EnableAutoCheck();
|
||||
var overlay = run.View.OverlapOverlay;
|
||||
var task = run.AutoTick();
|
||||
run.Next().Complete();
|
||||
run.Pump(task);
|
||||
Assert.True(overlay.ShowsAllClear);
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
[Fact]
|
||||
public void FindingsStayInTheLabelWhileRechecking() => RunSta(() =>
|
||||
{
|
||||
using var run = new OverlayRun();
|
||||
run.EnableAutoCheck();
|
||||
var task = run.AutoTick();
|
||||
run.Next().Complete();
|
||||
run.Pump(task);
|
||||
|
||||
run.View.Plate.Parts[1].Offset(0.5, 0);
|
||||
run.Paint();
|
||||
Assert.False(run.View.OverlapOverlay.ShowsPendingCheck);
|
||||
Assert.False(run.View.OverlapOverlay.ShowsAllClear);
|
||||
});
|
||||
|
||||
[Fact]
|
||||
public void StaleWithoutAutoCheckStillAsksForACheck() => RunSta(() =>
|
||||
{
|
||||
using var run = new OverlayRun();
|
||||
run.View.Plate.Parts.RemoveAt(1);
|
||||
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);
|
||||
});
|
||||
|
||||
private static bool CheckIsDrawn(OverlayRun run)
|
||||
{
|
||||
using var image = new Bitmap(64, 64);
|
||||
|
||||
@@ -81,7 +81,12 @@ internal sealed class OverlapOverlayController : IDisposable
|
||||
: 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 && !autoCheck.IsWaiting;
|
||||
internal bool ShowsAllClear => state.IsAllClear && !IsSettling;
|
||||
|
||||
/// <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;
|
||||
|
||||
/// <summary>
|
||||
/// Recheck automatically after layout edits settle. Units are read when each request
|
||||
@@ -683,13 +688,13 @@ internal sealed class OverlapOverlayController : IDisposable
|
||||
}
|
||||
|
||||
// Same corner as the label; Message keeps the words for the status bar.
|
||||
private void DrawAllClear(Graphics graphics)
|
||||
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.FromArgb(0, 140, 60), 3 * scale)
|
||||
using var pen = new Pen(color, 3 * scale)
|
||||
{
|
||||
StartCap = LineCap.Round,
|
||||
EndCap = LineCap.Round,
|
||||
@@ -712,16 +717,19 @@ internal sealed class OverlapOverlayController : IDisposable
|
||||
try
|
||||
{
|
||||
graphics.ResetTransform();
|
||||
if (ShowsAllClear)
|
||||
if (ShowsAllClear || ShowsPendingCheck)
|
||||
{
|
||||
DrawAllClear(graphics);
|
||||
DrawCheck(graphics, ShowsAllClear ? Color.FromArgb(0, 140, 60) : Color.FromArgb(150, 150, 150));
|
||||
return;
|
||||
}
|
||||
var text = Message + (state.DisplayMode == OverlapDisplayMode.Off ? " (display off)" : "");
|
||||
// While settling, the last findings stay put, dimmed, instead of status text flickering.
|
||||
var settling = IsSettling;
|
||||
var text = (settling ? state.SettledMessage : Message)
|
||||
+ (state.DisplayMode == OverlapDisplayMode.Off ? " (display off)" : "");
|
||||
var size = graphics.MeasureString(text, view.Font);
|
||||
using var background = new SolidBrush(Color.FromArgb(235, Color.White));
|
||||
graphics.FillRectangle(background, 6, 6, size.Width + 8, size.Height + 6);
|
||||
graphics.DrawString(text, view.Font, Brushes.DarkRed, 10, 9);
|
||||
graphics.DrawString(text, view.Font, settling ? Brushes.Gray : Brushes.DarkRed, 10, 9);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -30,7 +30,10 @@ 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. Every
|
||||
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
|
||||
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