diff --git a/OpenNest.Core/PlateDisplayNumbering.cs b/OpenNest.Core/PlateDisplayNumbering.cs
index e6b761b9..396ba3ca 100644
--- a/OpenNest.Core/PlateDisplayNumbering.cs
+++ b/OpenNest.Core/PlateDisplayNumbering.cs
@@ -48,17 +48,24 @@ namespace OpenNest
return plate != null && plate.Parts.Count == 0;
}
- /// Header text for the plate at .
- public static string FormatHeader(IList plates, int storageIndex, string plateSizeText)
+ ///
+ /// Header text for the plate at . A quantity above one is
+ /// appended as "×N"; a single sheet shows no quantity.
+ ///
+ public static string FormatHeader(IList plates, int storageIndex, string plateSizeText, int quantity = 1)
{
var displayed = DisplayedPlateNumber(plates, storageIndex);
if (displayed == null)
return IsTrailingSentinel(plates, storageIndex)
? "New plate (empty)"
: "No plates";
- return string.IsNullOrEmpty(plateSizeText)
- ? string.Format("Plate {0} of {1}", displayed.Value, DisplayedPlateCount(plates))
- : string.Format("Plate {0} of {1} | {2}", displayed.Value, DisplayedPlateCount(plates), plateSizeText);
+
+ var text = string.Format("Plate {0} of {1}", displayed.Value, DisplayedPlateCount(plates));
+ if (!string.IsNullOrEmpty(plateSizeText))
+ text += " | " + plateSizeText;
+ if (quantity > 1)
+ text += " | ×" + quantity;
+ return text;
}
}
}
diff --git a/OpenNest.Tests/PlateDisplayNumberingTests.cs b/OpenNest.Tests/PlateDisplayNumberingTests.cs
index 105735a6..31540823 100644
--- a/OpenNest.Tests/PlateDisplayNumberingTests.cs
+++ b/OpenNest.Tests/PlateDisplayNumberingTests.cs
@@ -44,6 +44,18 @@ public class PlateDisplayNumberingTests
Assert.Equal("New plate (empty)", PlateDisplayNumbering.FormatHeader(nest.Plates, sentinel, null));
}
+ [Fact]
+ public void Header_ShowsSizeAndQuantityAboveOne()
+ {
+ var nest = CreateNest();
+ nest.Plates.Add(WithPart());
+
+ Assert.Equal("Plate 1 of 1 | 60 x 120", PlateDisplayNumbering.FormatHeader(nest.Plates, 0, "60 x 120"));
+ Assert.Equal("Plate 1 of 1 | 60 x 120", PlateDisplayNumbering.FormatHeader(nest.Plates, 0, "60 x 120", 1));
+ Assert.Equal("Plate 1 of 1 | 60 x 120 | ×4", PlateDisplayNumbering.FormatHeader(nest.Plates, 0, "60 x 120", 4));
+ Assert.Equal("Plate 1 of 1 | ×2", PlateDisplayNumbering.FormatHeader(nest.Plates, 0, null, 2));
+ }
+
[Fact]
public void TwoRealPlatesThenSentinel_TotalIsTwo()
{
diff --git a/OpenNest.WinForms.Tests/Forms/MainStatusBarTests.cs b/OpenNest.WinForms.Tests/Forms/MainStatusBarTests.cs
new file mode 100644
index 00000000..035788b4
--- /dev/null
+++ b/OpenNest.WinForms.Tests/Forms/MainStatusBarTests.cs
@@ -0,0 +1,26 @@
+using System.Globalization;
+using OpenNest.Forms;
+
+namespace OpenNest.WinForms.Tests.Forms;
+
+public class MainStatusBarTests
+{
+ [Fact]
+ public void FormatMaterial_ShowsNameAndThicknessWithUnits()
+ {
+ var previous = CultureInfo.CurrentCulture;
+ CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
+ try
+ {
+ Assert.Equal("Material: A36 · 0.25 in", MainStatusBar.FormatMaterial("A36", 0.25, Units.Inches));
+ Assert.Equal("Material: 304 SS · 3 mm", MainStatusBar.FormatMaterial(" 304 SS ", 3, Units.Millimeters));
+ Assert.Equal("Material: A36", MainStatusBar.FormatMaterial("A36", 0, Units.Inches));
+ Assert.Equal("Material: 0.1875 in", MainStatusBar.FormatMaterial(null, 0.1875, Units.Inches));
+ Assert.Equal("Material: (none)", MainStatusBar.FormatMaterial("", 0, Units.Inches));
+ }
+ finally
+ {
+ CultureInfo.CurrentCulture = previous;
+ }
+ }
+}
diff --git a/OpenNest/Forms/EditNestForm.cs b/OpenNest/Forms/EditNestForm.cs
index c0e7e6f5..13de566b 100644
--- a/OpenNest/Forms/EditNestForm.cs
+++ b/OpenNest/Forms/EditNestForm.cs
@@ -995,7 +995,7 @@ namespace OpenNest.Forms
// Display-only numbering: the trailing empty new-plate sentinel is excluded from the
// total (and labeled as such); navigation and storage indexes are untouched.
plateInfoLabel.Text = PlateDisplayNumbering.FormatHeader(
- Nest.Plates, PlateManager.CurrentIndex, plate.Size.ToString());
+ Nest.Plates, PlateManager.CurrentIndex, plate.Size.ToString(), plate.Quantity);
btnFirstPlate.Enabled = !PlateManager.IsFirst;
btnPreviousPlate.Enabled = !PlateManager.IsFirst;
diff --git a/OpenNest/Forms/MainForm.Designer.cs b/OpenNest/Forms/MainForm.Designer.cs
index df0af5b8..b770d868 100644
--- a/OpenNest/Forms/MainForm.Designer.cs
+++ b/OpenNest/Forms/MainForm.Designer.cs
@@ -167,9 +167,7 @@ namespace OpenNest.Forms
statusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
locationStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
spacerLabel = new System.Windows.Forms.ToolStripStatusLabel();
- plateIndexStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
- plateSizeStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
- plateQtyStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
+ materialStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
plateUtilStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
selectionStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
toolStrip1 = new System.Windows.Forms.ToolStrip();
@@ -1094,7 +1092,7 @@ namespace OpenNest.Forms
//
// statusStrip1
//
- statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { statusLabel1, locationStatusLabel, selectionStatusLabel, spacerLabel, plateIndexStatusLabel, plateSizeStatusLabel, plateQtyStatusLabel, plateUtilStatusLabel });
+ statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { statusLabel1, locationStatusLabel, selectionStatusLabel, spacerLabel, materialStatusLabel, plateUtilStatusLabel });
statusStrip1.Location = new System.Drawing.Point(0, 630);
statusStrip1.Name = "statusStrip1";
statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 16, 0);
@@ -1130,30 +1128,16 @@ namespace OpenNest.Forms
spacerLabel.Padding = new System.Windows.Forms.Padding(5, 0, 5, 0);
spacerLabel.Size = new System.Drawing.Size(931, 19);
spacerLabel.Spring = true;
- //
- // plateIndexStatusLabel
- //
- plateIndexStatusLabel.BorderSides = System.Windows.Forms.ToolStripStatusLabelBorderSides.Left;
- plateIndexStatusLabel.Name = "plateIndexStatusLabel";
- plateIndexStatusLabel.Padding = new System.Windows.Forms.Padding(5, 0, 5, 0);
- plateIndexStatusLabel.Size = new System.Drawing.Size(85, 19);
- plateIndexStatusLabel.Text = "Plate : 0 of 0";
- //
- // plateSizeStatusLabel
- //
- plateSizeStatusLabel.BorderSides = System.Windows.Forms.ToolStripStatusLabelBorderSides.Left;
- plateSizeStatusLabel.Name = "plateSizeStatusLabel";
- plateSizeStatusLabel.Padding = new System.Windows.Forms.Padding(5, 0, 5, 0);
- plateSizeStatusLabel.Size = new System.Drawing.Size(67, 19);
- plateSizeStatusLabel.Text = "Size : 0x0";
- //
- // plateQtyStatusLabel
- //
- plateQtyStatusLabel.BorderSides = System.Windows.Forms.ToolStripStatusLabelBorderSides.Left;
- plateQtyStatusLabel.Name = "plateQtyStatusLabel";
- plateQtyStatusLabel.Padding = new System.Windows.Forms.Padding(5, 0, 5, 0);
- plateQtyStatusLabel.Size = new System.Drawing.Size(55, 19);
- plateQtyStatusLabel.Text = "Qty : 0";
+ //
+ // materialStatusLabel
+ //
+ materialStatusLabel.BorderSides = System.Windows.Forms.ToolStripStatusLabelBorderSides.Left;
+ materialStatusLabel.Name = "materialStatusLabel";
+ materialStatusLabel.Padding = new System.Windows.Forms.Padding(5, 0, 5, 0);
+ materialStatusLabel.Size = new System.Drawing.Size(85, 19);
+ materialStatusLabel.Text = "Material: (none)";
+ materialStatusLabel.ToolTipText = "Click to edit nest info";
+ materialStatusLabel.Click += MaterialStatusLabel_Click;
//
// plateUtilStatusLabel
//
@@ -1374,11 +1358,10 @@ namespace OpenNest.Forms
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
private System.Windows.Forms.ToolStripMenuItem mnuPlateRotate180;
private System.Windows.Forms.StatusStrip statusStrip1;
- private System.Windows.Forms.ToolStripStatusLabel plateSizeStatusLabel;
private System.Windows.Forms.ToolStripStatusLabel locationStatusLabel;
private System.Windows.Forms.ToolStrip toolStrip1;
private System.Windows.Forms.ToolStripButton btnOpen;
- private System.Windows.Forms.ToolStripStatusLabel plateIndexStatusLabel;
+ private System.Windows.Forms.ToolStripStatusLabel materialStatusLabel;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
private System.Windows.Forms.ToolStripMenuItem mnuWindow;
private System.Windows.Forms.ToolStripMenuItem mnuWindowCascade;
@@ -1386,7 +1369,6 @@ namespace OpenNest.Forms
private System.Windows.Forms.ToolStripMenuItem mnuWindowTileHorizontal;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem10;
private System.Windows.Forms.ToolStripMenuItem mnuCloseAll;
- private System.Windows.Forms.ToolStripStatusLabel plateQtyStatusLabel;
private System.Windows.Forms.ToolStripStatusLabel plateUtilStatusLabel;
private System.Windows.Forms.ToolStripMenuItem mnuFileExportAll;
private System.Windows.Forms.ToolStripMenuItem mnuFileExportNestReport;
diff --git a/OpenNest/Forms/MainForm.Nest.cs b/OpenNest/Forms/MainForm.Nest.cs
index fc7ff18d..c8ba479e 100644
--- a/OpenNest/Forms/MainForm.Nest.cs
+++ b/OpenNest/Forms/MainForm.Nest.cs
@@ -47,8 +47,10 @@ namespace OpenNest.Forms
private async void EditNest_Click(object sender, EventArgs e)
{
- if (activeForm != null)
- await activeForm.ShowNestInfoEditorAsync();
+ if (activeForm == null)
+ return;
+ await activeForm.ShowNestInfoEditorAsync();
+ statusBar.UpdatePlate(); // Material and thickness may have changed.
}
private void Clamps_Click(object sender, EventArgs e)
diff --git a/OpenNest/Forms/MainForm.Status.cs b/OpenNest/Forms/MainForm.Status.cs
index 3d5c704e..c781a220 100644
--- a/OpenNest/Forms/MainForm.Status.cs
+++ b/OpenNest/Forms/MainForm.Status.cs
@@ -65,6 +65,9 @@ namespace OpenNest.Forms
private void LocationStatusLabel_Click(object sender, EventArgs e) =>
statusBar.ToggleLocationMode();
+ private void MaterialStatusLabel_Click(object sender, EventArgs e) =>
+ EditNest_Click(sender, e);
+
#endregion Statusbar Events
}
}
diff --git a/OpenNest/Forms/MainForm.cs b/OpenNest/Forms/MainForm.cs
index 76c56364..3b1a40b1 100644
--- a/OpenNest/Forms/MainForm.cs
+++ b/OpenNest/Forms/MainForm.cs
@@ -106,7 +106,7 @@ namespace OpenNest.Forms
storage.StateChanged += Storage_StateChanged;
InitializeComponent();
statusBar = new MainStatusBar(statusLabel1, locationStatusLabel, selectionStatusLabel,
- plateIndexStatusLabel, plateSizeStatusLabel, plateQtyStatusLabel, plateUtilStatusLabel);
+ materialStatusLabel, plateUtilStatusLabel);
toolStrip1.Items.Add(CreateActionButton("btnCutPlanner", "Plan Cutting",
Resources.cut_planner, PlatePlanCutting_Click));
toolStrip1.Items.Add(CreateActionButton("btnSimulateCutting", "Simulate Cutting",
diff --git a/OpenNest/Forms/MainStatusBar.cs b/OpenNest/Forms/MainStatusBar.cs
index a0d95a87..cb56577a 100644
--- a/OpenNest/Forms/MainStatusBar.cs
+++ b/OpenNest/Forms/MainStatusBar.cs
@@ -1,5 +1,7 @@
using System;
+using System.Collections.Generic;
using System.Drawing;
+using System.Globalization;
using System.Linq;
using System.Windows.Forms;
using OpenNest.Collections;
@@ -10,7 +12,8 @@ namespace OpenNest.Forms
{
///
/// The main window's status labels for the active nest document: status text, cursor
- /// location, selection bounds and plate index/size/quantity/utilization. The location
+ /// location, selection bounds, nest material and plate utilization. Plate number, size and
+ /// quantity live in the plate view header instead. The location
/// follows the mouse (the default, throttled), or only left clicks while click mode is on;
/// the mode persists as a user setting.
///
@@ -22,9 +25,7 @@ namespace OpenNest.Forms
private readonly ToolStripStatusLabel status;
private readonly ToolStripStatusLabel location;
private readonly ToolStripStatusLabel selection;
- private readonly ToolStripStatusLabel plateIndex;
- private readonly ToolStripStatusLabel plateSize;
- private readonly ToolStripStatusLabel plateQty;
+ private readonly ToolStripStatusLabel material;
private readonly ToolStripStatusLabel plateUtil;
private readonly Timer locationTimer;
@@ -33,15 +34,12 @@ namespace OpenNest.Forms
private bool locationPending;
public MainStatusBar(ToolStripStatusLabel status, ToolStripStatusLabel location,
- ToolStripStatusLabel selection, ToolStripStatusLabel plateIndex, ToolStripStatusLabel plateSize,
- ToolStripStatusLabel plateQty, ToolStripStatusLabel plateUtil)
+ ToolStripStatusLabel selection, ToolStripStatusLabel material, ToolStripStatusLabel plateUtil)
{
this.status = status;
this.location = location;
this.selection = selection;
- this.plateIndex = plateIndex;
- this.plateSize = plateSize;
- this.plateQty = plateQty;
+ this.material = material;
this.plateUtil = plateUtil;
locationTimer = new Timer { Interval = LocationRefreshIntervalMs };
@@ -126,25 +124,13 @@ namespace OpenNest.Forms
{
if (form == null)
{
- plateIndex.Text = string.Empty;
- plateSize.Text = string.Empty;
- plateQty.Text = string.Empty;
+ material.Text = string.Empty;
plateUtil.Text = string.Empty;
return;
}
- plateIndex.Text = string.Format(
- "Plate: {0} of {1}",
- form.PlateManager.CurrentIndex + 1,
- form.PlateManager.Count
- );
-
- plateSize.Text = string.Format("Size: {0}", form.PlateView.Plate.Size);
-
- plateQty.Text = string.Format(
- "Qty: {0}",
- form.PlateView.Plate.Quantity
- );
+ var nest = form.Nest;
+ material.Text = FormatMaterial(nest.Material?.Name, nest.Thickness, nest.Units);
plateUtil.Text = string.Format(
"Util: {0:P1}",
@@ -152,6 +138,18 @@ namespace OpenNest.Forms
);
}
+ /// Status text for the nest's material and thickness, e.g. "Material: A36 · 0.25 in".
+ internal static string FormatMaterial(string name, double thickness, Units units)
+ {
+ var parts = new List();
+ if (!string.IsNullOrWhiteSpace(name))
+ parts.Add(name.Trim());
+ if (thickness > 0)
+ parts.Add(thickness.ToString("0.####", CultureInfo.CurrentCulture) + " " + UnitsHelper.GetShortString(units));
+
+ return "Material: " + (parts.Count == 0 ? "(none)" : string.Join(" · ", parts));
+ }
+
public void UpdateSelection()
{
if (form == null || form.PlateView.SelectedParts.Count == 0)