feat(drawings): explain an empty list that Hide Fully Nested Drawings emptied

With the filter on and every drawing nested, the Drawings tab was a blank
list with no hint why. It now shows a note that turns the filter off when
clicked. The filter is never turned off on its own: it is the user's
choice and would stay off when new drawings arrive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ajandClaude Opus 5.5 committed 2026-11-05 21:21:27 -05:00
1 parent 5eb7fd920b
commit 78a5ad88e2
3 files changed
+167

No files matched your search

@@ -0,0 +1,90 @@
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using OpenNest.CNC;
using OpenNest.Controls;
using OpenNest.Forms;
namespace OpenNest.WinForms.Tests.Controls;
[Collection("Fill operation lifetime")]
public class HideNestedDrawingsNoteTests
{
[Fact]
public void HidingEveryDrawingShowsANoteThatTurnsTheFilterOff() => RunSta(() =>
{
var nest = new Nest("hide");
var drawing = new Drawing("a", Square());
drawing.Quantity.Required = 1;
nest.Drawings.Add(drawing);
var plate = new Plate(100, 100) { Quantity = 1 };
nest.Plates.Add(plate);
plate.Parts.Add(new Part(drawing));
Assert.Equal(0, drawing.Quantity.Remaining);
using var form = new EditNestForm(nest) { Width = 1100, Height = 700 };
form.PlateView.SetOverlapAutoCheck(null);
form.Show();
Application.DoEvents();
var list = Field<DrawingListBox>(form, "drawingListBox1");
var hide = Field<ToolStripButton>(form, "hideNestedButton");
Assert.Null(list.EmptyText);
hide.Checked = true;
Assert.Empty(list.Items);
Assert.NotNull(list.EmptyText);
typeof(DrawingListBox)
.GetMethod("OnMouseUp", BindingFlags.Instance | BindingFlags.NonPublic)!
.Invoke(list, [new MouseEventArgs(MouseButtons.Left, 1, 20, 20, 0)]);
Assert.False(hide.Checked);
Assert.Single(list.Items);
Assert.Null(list.EmptyText);
});
[Fact]
public void ListWithRowsNeverRaisesTheNoteClick() => RunSta(() =>
{
using var list = new ClickableDrawingListBox { Size = new Size(260, 400), EmptyText = "note" };
list.Items.Add(new Drawing("a", Square()));
var clicks = 0;
list.EmptyTextClicked += (_, _) => clicks++;
list.Release(new MouseEventArgs(MouseButtons.Left, 1, 20, 300, 0));
Assert.Equal(0, clicks);
list.Items.Clear();
list.Release(new MouseEventArgs(MouseButtons.Right, 1, 20, 20, 0));
Assert.Equal(0, clicks);
list.Release(new MouseEventArgs(MouseButtons.Left, 1, 20, 20, 0));
Assert.Equal(1, clicks);
});
private static T Field<T>(EditNestForm form, string name) =>
(T)typeof(EditNestForm)
.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic)!
.GetValue(form)!;
private static Program Square()
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(0, 10);
program.LineTo(10, 10);
program.LineTo(10, 0);
program.LineTo(0, 0);
return program;
}
private static void RunSta(System.Action action) =>
StaTestThread.Run(action, TimeSpan.FromMinutes(3), "The STA test did not complete.");
private sealed class ClickableDrawingListBox : DrawingListBox
{
public void Release(MouseEventArgs e) => OnMouseUp(e);
}
}
+61
View File
@@ -8,6 +8,7 @@ namespace OpenNest.Controls
{
public class DrawingListBox : ListBox
{
private const int WM_PAINT = 0x000F;
private const int WM_ERASEBKGND = 0x0014;
private readonly Size imageSize;
@@ -115,6 +116,30 @@ namespace OpenNest.Controls
/// </summary>
public Plate Plate { get; set; }
private string emptyText;
/// <summary>
/// A note drawn in the middle of the list while it has no rows; null draws nothing.
/// Clicking the empty list while the note shows raises <see cref="EmptyTextClicked"/>.
/// </summary>
public string EmptyText
{
get => emptyText;
set
{
if (emptyText == value)
return;
emptyText = value;
Invalidate();
}
}
/// <summary>Raised when the empty list is clicked while <see cref="EmptyText"/> shows.</summary>
public event EventHandler EmptyTextClicked;
private bool IsShowingEmptyText => Items.Count == 0 && !string.IsNullOrEmpty(emptyText);
protected override void OnDrawItem(DrawItemEventArgs e)
{
if (e.Index >= Items.Count || e.Index <= -1)
@@ -227,6 +252,8 @@ namespace OpenNest.Controls
{
base.OnMouseMove(e);
Cursor = IsShowingEmptyText && EmptyTextClicked != null ? Cursors.Hand : Cursors.Default;
var drawing = pressedDrawing;
if (drawing == null || e.Button != MouseButtons.Left)
@@ -263,6 +290,36 @@ namespace OpenNest.Controls
{
pressedDrawing = null;
base.OnMouseUp(e);
if (e.Button == MouseButtons.Left && IsShowingEmptyText)
EmptyTextClicked?.Invoke(this, EventArgs.Empty);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
// The note wraps to the width, so a resize must repaint all of it.
if (IsShowingEmptyText)
Invalidate();
}
private void DrawEmptyText()
{
using var g = CreateGraphics();
var bounds = Rectangle.Inflate(ClientRectangle, -12, -12);
TextRenderer.DrawText(
g,
emptyText,
Font,
bounds,
SystemColors.GrayText,
TextFormatFlags.HorizontalCenter
| TextFormatFlags.Top
| TextFormatFlags.WordBreak
| TextFormatFlags.TextBoxControl
);
}
/// <summary>
@@ -310,6 +367,10 @@ namespace OpenNest.Controls
return;
}
base.WndProc(ref m);
// An owner-drawn list paints nothing when empty, so the note goes on top afterward.
if (m.Msg == WM_PAINT && IsShowingEmptyText)
DrawEmptyText();
}
}
+16
View File
@@ -479,6 +479,7 @@ namespace OpenNest.Forms
drawingListBox1.OpenInConverterRequested += drawingListBox1_OpenInConverterRequested;
drawingListBox1.DrawingPickedUp += drawingListBox1_DrawingPickedUp;
drawingListBox1.DrawingDropped += drawingListBox1_DrawingDropped;
drawingListBox1.EmptyTextClicked += (_, _) => hideNestedButton.Checked = false;
Activated += (_, _) => UpdateDrawingLibraryCommand();
UpdateDrawingLibraryCommand();
PlateView.BeginChangeHandler = BeginChange;
@@ -584,6 +585,20 @@ namespace OpenNest.Forms
drawingListBox1.TopIndex = topIndex;
drawingListBox1.EndUpdate();
UpdateDrawingListEmptyText();
}
/// <summary>
/// Explains an empty list that only Hide Fully Nested Drawings emptied, so the drawings
/// don't look lost; clicking the note turns the filter off. The filter stays the user's
/// choice and is never turned off on its own.
/// </summary>
private void UpdateDrawingListEmptyText()
{
drawingListBox1.EmptyText =
hideNestedButton.Checked && Nest.Drawings.Count > 0
? "All drawings are fully nested and hidden.\n\nClick here to show them."
: null;
}
public void Save()
@@ -1827,6 +1842,7 @@ namespace OpenNest.Forms
drawingListBox1.EndUpdate();
}
UpdateDrawingListEmptyText();
drawingListBox1.Invalidate();
// Parts were added or removed: rebuild the plate rows so the