mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-07 20:05:46 -05:00
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:
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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user