feat: add Parts/Groups tabs with editable material, thickness, and per-group plate sizes
- Parts tab: shows all BOM items, editable Material/Thickness for matched rows, grayed-out rows for items without DXF files - Groups tab: auto-computed from parts with editable Plate Width/Length per material+thickness group - Editing Material/Thickness on Parts tab immediately re-groups - Per-group plate sizes preserved across re-groups Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Generated
+296
-150
@@ -16,149 +16,270 @@ namespace OpenNest.Forms
|
|||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
grpInput = new System.Windows.Forms.GroupBox();
|
grpInput = new System.Windows.Forms.GroupBox();
|
||||||
|
tbl = new System.Windows.Forms.TableLayoutPanel();
|
||||||
|
lblJobName = new System.Windows.Forms.Label();
|
||||||
txtJobName = new System.Windows.Forms.TextBox();
|
txtJobName = new System.Windows.Forms.TextBox();
|
||||||
|
lblBomFile = new System.Windows.Forms.Label();
|
||||||
txtBomFile = new System.Windows.Forms.TextBox();
|
txtBomFile = new System.Windows.Forms.TextBox();
|
||||||
btnBrowseBom = new System.Windows.Forms.Button();
|
btnBrowseBom = new System.Windows.Forms.Button();
|
||||||
|
lblDxfFolder = new System.Windows.Forms.Label();
|
||||||
txtDxfFolder = new System.Windows.Forms.TextBox();
|
txtDxfFolder = new System.Windows.Forms.TextBox();
|
||||||
btnBrowseDxf = new System.Windows.Forms.Button();
|
btnBrowseDxf = new System.Windows.Forms.Button();
|
||||||
|
lblPlateSize = new System.Windows.Forms.Label();
|
||||||
|
platePanel = new System.Windows.Forms.FlowLayoutPanel();
|
||||||
txtPlateWidth = new System.Windows.Forms.TextBox();
|
txtPlateWidth = new System.Windows.Forms.TextBox();
|
||||||
|
lblPlateX = new System.Windows.Forms.Label();
|
||||||
txtPlateLength = new System.Windows.Forms.TextBox();
|
txtPlateLength = new System.Windows.Forms.TextBox();
|
||||||
btnAnalyze = new System.Windows.Forms.Button();
|
btnAnalyze = new System.Windows.Forms.Button();
|
||||||
grpGroups = new System.Windows.Forms.GroupBox();
|
tabControl = new System.Windows.Forms.TabControl();
|
||||||
|
tabParts = new System.Windows.Forms.TabPage();
|
||||||
|
dgvParts = new System.Windows.Forms.DataGridView();
|
||||||
|
tabGroups = new System.Windows.Forms.TabPage();
|
||||||
dgvGroups = new System.Windows.Forms.DataGridView();
|
dgvGroups = new System.Windows.Forms.DataGridView();
|
||||||
pnlBottom = new System.Windows.Forms.Panel();
|
pnlBottom = new System.Windows.Forms.Panel();
|
||||||
lblSummary = new System.Windows.Forms.Label();
|
lblSummary = new System.Windows.Forms.Label();
|
||||||
btnClose = new System.Windows.Forms.Button();
|
|
||||||
btnCreateNests = new System.Windows.Forms.Button();
|
btnCreateNests = new System.Windows.Forms.Button();
|
||||||
|
btnClose = new System.Windows.Forms.Button();
|
||||||
var tbl = new System.Windows.Forms.TableLayoutPanel();
|
|
||||||
var lblJobName = new System.Windows.Forms.Label();
|
|
||||||
var lblBomFile = new System.Windows.Forms.Label();
|
|
||||||
var lblDxfFolder = new System.Windows.Forms.Label();
|
|
||||||
var lblPlateSize = new System.Windows.Forms.Label();
|
|
||||||
var lblPlateX = new System.Windows.Forms.Label();
|
|
||||||
var platePanel = new System.Windows.Forms.FlowLayoutPanel();
|
|
||||||
|
|
||||||
grpInput.SuspendLayout();
|
grpInput.SuspendLayout();
|
||||||
grpGroups.SuspendLayout();
|
tbl.SuspendLayout();
|
||||||
|
platePanel.SuspendLayout();
|
||||||
|
tabControl.SuspendLayout();
|
||||||
|
tabParts.SuspendLayout();
|
||||||
|
((System.ComponentModel.ISupportInitialize)dgvParts).BeginInit();
|
||||||
|
tabGroups.SuspendLayout();
|
||||||
((System.ComponentModel.ISupportInitialize)dgvGroups).BeginInit();
|
((System.ComponentModel.ISupportInitialize)dgvGroups).BeginInit();
|
||||||
pnlBottom.SuspendLayout();
|
pnlBottom.SuspendLayout();
|
||||||
SuspendLayout();
|
SuspendLayout();
|
||||||
|
//
|
||||||
// ---- TableLayoutPanel for input fields ----
|
// grpInput
|
||||||
tbl.ColumnCount = 3;
|
//
|
||||||
tbl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.AutoSize));
|
|
||||||
tbl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
|
||||||
tbl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.AutoSize));
|
|
||||||
tbl.RowCount = 5;
|
|
||||||
tbl.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.AutoSize));
|
|
||||||
tbl.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.AutoSize));
|
|
||||||
tbl.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.AutoSize));
|
|
||||||
tbl.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.AutoSize));
|
|
||||||
tbl.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.AutoSize));
|
|
||||||
tbl.Dock = System.Windows.Forms.DockStyle.Fill;
|
|
||||||
tbl.Padding = new System.Windows.Forms.Padding(3);
|
|
||||||
|
|
||||||
// Row 0 — Job Name
|
|
||||||
lblJobName.Text = "Job Name:";
|
|
||||||
lblJobName.AutoSize = true;
|
|
||||||
lblJobName.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
|
||||||
lblJobName.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
|
||||||
tbl.Controls.Add(lblJobName, 0, 0);
|
|
||||||
|
|
||||||
txtJobName.Dock = System.Windows.Forms.DockStyle.Fill;
|
|
||||||
txtJobName.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
|
||||||
tbl.Controls.Add(txtJobName, 1, 0);
|
|
||||||
tbl.SetColumnSpan(txtJobName, 2);
|
|
||||||
|
|
||||||
// Row 1 — BOM File
|
|
||||||
lblBomFile.Text = "BOM File:";
|
|
||||||
lblBomFile.AutoSize = true;
|
|
||||||
lblBomFile.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
|
||||||
lblBomFile.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
|
||||||
tbl.Controls.Add(lblBomFile, 0, 1);
|
|
||||||
|
|
||||||
txtBomFile.Dock = System.Windows.Forms.DockStyle.Fill;
|
|
||||||
txtBomFile.ReadOnly = true;
|
|
||||||
txtBomFile.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
|
||||||
tbl.Controls.Add(txtBomFile, 1, 1);
|
|
||||||
|
|
||||||
btnBrowseBom.Text = "...";
|
|
||||||
btnBrowseBom.Size = new System.Drawing.Size(35, 25);
|
|
||||||
btnBrowseBom.Margin = new System.Windows.Forms.Padding(0, 5, 3, 3);
|
|
||||||
btnBrowseBom.Click += new System.EventHandler(BrowseBom_Click);
|
|
||||||
tbl.Controls.Add(btnBrowseBom, 2, 1);
|
|
||||||
|
|
||||||
// Row 2 — DXF Folder
|
|
||||||
lblDxfFolder.Text = "DXF Folder:";
|
|
||||||
lblDxfFolder.AutoSize = true;
|
|
||||||
lblDxfFolder.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
|
||||||
lblDxfFolder.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
|
||||||
tbl.Controls.Add(lblDxfFolder, 0, 2);
|
|
||||||
|
|
||||||
txtDxfFolder.Dock = System.Windows.Forms.DockStyle.Fill;
|
|
||||||
txtDxfFolder.ReadOnly = true;
|
|
||||||
txtDxfFolder.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
|
||||||
tbl.Controls.Add(txtDxfFolder, 1, 2);
|
|
||||||
|
|
||||||
btnBrowseDxf.Text = "...";
|
|
||||||
btnBrowseDxf.Size = new System.Drawing.Size(35, 25);
|
|
||||||
btnBrowseDxf.Margin = new System.Windows.Forms.Padding(0, 5, 3, 3);
|
|
||||||
btnBrowseDxf.Click += new System.EventHandler(BrowseDxf_Click);
|
|
||||||
tbl.Controls.Add(btnBrowseDxf, 2, 2);
|
|
||||||
|
|
||||||
// Row 3 — Plate Size
|
|
||||||
lblPlateSize.Text = "Plate Size:";
|
|
||||||
lblPlateSize.AutoSize = true;
|
|
||||||
lblPlateSize.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
|
||||||
lblPlateSize.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
|
||||||
tbl.Controls.Add(lblPlateSize, 0, 3);
|
|
||||||
|
|
||||||
platePanel.AutoSize = true;
|
|
||||||
platePanel.WrapContents = false;
|
|
||||||
platePanel.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
|
|
||||||
txtPlateWidth.Size = new System.Drawing.Size(60, 23);
|
|
||||||
txtPlateWidth.Text = "60";
|
|
||||||
lblPlateX.Text = " x ";
|
|
||||||
lblPlateX.AutoSize = true;
|
|
||||||
lblPlateX.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
|
||||||
txtPlateLength.Size = new System.Drawing.Size(60, 23);
|
|
||||||
txtPlateLength.Text = "120";
|
|
||||||
platePanel.Controls.Add(txtPlateWidth);
|
|
||||||
platePanel.Controls.Add(lblPlateX);
|
|
||||||
platePanel.Controls.Add(txtPlateLength);
|
|
||||||
tbl.Controls.Add(platePanel, 1, 3);
|
|
||||||
|
|
||||||
// Row 4 — Analyze button
|
|
||||||
btnAnalyze.Text = "Analyze";
|
|
||||||
btnAnalyze.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
|
|
||||||
btnAnalyze.Size = new System.Drawing.Size(110, 30);
|
|
||||||
btnAnalyze.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
|
||||||
btnAnalyze.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
|
||||||
btnAnalyze.Click += new System.EventHandler(Analyze_Click);
|
|
||||||
tbl.Controls.Add(btnAnalyze, 1, 4);
|
|
||||||
tbl.SetColumnSpan(btnAnalyze, 2);
|
|
||||||
|
|
||||||
// ---- grpInput ----
|
|
||||||
grpInput.Controls.Add(tbl);
|
grpInput.Controls.Add(tbl);
|
||||||
grpInput.Dock = System.Windows.Forms.DockStyle.Top;
|
grpInput.Dock = System.Windows.Forms.DockStyle.Top;
|
||||||
|
grpInput.Location = new System.Drawing.Point(0, 0);
|
||||||
grpInput.Name = "grpInput";
|
grpInput.Name = "grpInput";
|
||||||
grpInput.Height = 200;
|
|
||||||
grpInput.Padding = new System.Windows.Forms.Padding(6);
|
grpInput.Padding = new System.Windows.Forms.Padding(6);
|
||||||
|
grpInput.Size = new System.Drawing.Size(804, 200);
|
||||||
grpInput.TabIndex = 0;
|
grpInput.TabIndex = 0;
|
||||||
grpInput.TabStop = false;
|
grpInput.TabStop = false;
|
||||||
grpInput.Text = "Input";
|
grpInput.Text = "Input";
|
||||||
|
//
|
||||||
// ---- grpGroups ----
|
// tbl
|
||||||
grpGroups.Controls.Add(dgvGroups);
|
//
|
||||||
grpGroups.Dock = System.Windows.Forms.DockStyle.Fill;
|
tbl.ColumnCount = 3;
|
||||||
grpGroups.Name = "grpGroups";
|
tbl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||||
grpGroups.Padding = new System.Windows.Forms.Padding(10, 6, 10, 6);
|
tbl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||||
grpGroups.TabIndex = 1;
|
tbl.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||||
grpGroups.TabStop = false;
|
tbl.Controls.Add(lblJobName, 0, 0);
|
||||||
grpGroups.Text = "Material Groups";
|
tbl.Controls.Add(txtJobName, 1, 0);
|
||||||
|
tbl.Controls.Add(lblBomFile, 0, 1);
|
||||||
// ---- dgvGroups ----
|
tbl.Controls.Add(txtBomFile, 1, 1);
|
||||||
|
tbl.Controls.Add(btnBrowseBom, 2, 1);
|
||||||
|
tbl.Controls.Add(lblDxfFolder, 0, 2);
|
||||||
|
tbl.Controls.Add(txtDxfFolder, 1, 2);
|
||||||
|
tbl.Controls.Add(btnBrowseDxf, 2, 2);
|
||||||
|
tbl.Controls.Add(lblPlateSize, 0, 3);
|
||||||
|
tbl.Controls.Add(platePanel, 1, 3);
|
||||||
|
tbl.Controls.Add(btnAnalyze, 1, 4);
|
||||||
|
tbl.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
tbl.Location = new System.Drawing.Point(6, 22);
|
||||||
|
tbl.Name = "tbl";
|
||||||
|
tbl.Padding = new System.Windows.Forms.Padding(3);
|
||||||
|
tbl.RowCount = 5;
|
||||||
|
tbl.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||||
|
tbl.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||||
|
tbl.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||||
|
tbl.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||||
|
tbl.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||||
|
tbl.Size = new System.Drawing.Size(792, 172);
|
||||||
|
tbl.TabIndex = 0;
|
||||||
|
//
|
||||||
|
// lblJobName
|
||||||
|
//
|
||||||
|
lblJobName.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||||
|
lblJobName.AutoSize = true;
|
||||||
|
lblJobName.Location = new System.Drawing.Point(6, 13);
|
||||||
|
lblJobName.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
||||||
|
lblJobName.Name = "lblJobName";
|
||||||
|
lblJobName.Size = new System.Drawing.Size(63, 15);
|
||||||
|
lblJobName.TabIndex = 0;
|
||||||
|
lblJobName.Text = "Job Name:";
|
||||||
|
//
|
||||||
|
// txtJobName
|
||||||
|
//
|
||||||
|
tbl.SetColumnSpan(txtJobName, 2);
|
||||||
|
txtJobName.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
txtJobName.Location = new System.Drawing.Point(79, 9);
|
||||||
|
txtJobName.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
||||||
|
txtJobName.Name = "txtJobName";
|
||||||
|
txtJobName.Size = new System.Drawing.Size(707, 23);
|
||||||
|
txtJobName.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// lblBomFile
|
||||||
|
//
|
||||||
|
lblBomFile.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||||
|
lblBomFile.AutoSize = true;
|
||||||
|
lblBomFile.Location = new System.Drawing.Point(6, 45);
|
||||||
|
lblBomFile.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
||||||
|
lblBomFile.Name = "lblBomFile";
|
||||||
|
lblBomFile.Size = new System.Drawing.Size(58, 15);
|
||||||
|
lblBomFile.TabIndex = 2;
|
||||||
|
lblBomFile.Text = "BOM File:";
|
||||||
|
//
|
||||||
|
// txtBomFile
|
||||||
|
//
|
||||||
|
txtBomFile.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
txtBomFile.Location = new System.Drawing.Point(79, 41);
|
||||||
|
txtBomFile.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
||||||
|
txtBomFile.Name = "txtBomFile";
|
||||||
|
txtBomFile.ReadOnly = true;
|
||||||
|
txtBomFile.Size = new System.Drawing.Size(669, 23);
|
||||||
|
txtBomFile.TabIndex = 3;
|
||||||
|
//
|
||||||
|
// btnBrowseBom
|
||||||
|
//
|
||||||
|
btnBrowseBom.Location = new System.Drawing.Point(751, 40);
|
||||||
|
btnBrowseBom.Margin = new System.Windows.Forms.Padding(0, 5, 3, 3);
|
||||||
|
btnBrowseBom.Name = "btnBrowseBom";
|
||||||
|
btnBrowseBom.Size = new System.Drawing.Size(35, 25);
|
||||||
|
btnBrowseBom.TabIndex = 4;
|
||||||
|
btnBrowseBom.Text = "...";
|
||||||
|
btnBrowseBom.Click += BrowseBom_Click;
|
||||||
|
//
|
||||||
|
// lblDxfFolder
|
||||||
|
//
|
||||||
|
lblDxfFolder.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||||
|
lblDxfFolder.AutoSize = true;
|
||||||
|
lblDxfFolder.Location = new System.Drawing.Point(6, 78);
|
||||||
|
lblDxfFolder.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
||||||
|
lblDxfFolder.Name = "lblDxfFolder";
|
||||||
|
lblDxfFolder.Size = new System.Drawing.Size(67, 15);
|
||||||
|
lblDxfFolder.TabIndex = 5;
|
||||||
|
lblDxfFolder.Text = "DXF Folder:";
|
||||||
|
//
|
||||||
|
// txtDxfFolder
|
||||||
|
//
|
||||||
|
txtDxfFolder.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
txtDxfFolder.Location = new System.Drawing.Point(79, 74);
|
||||||
|
txtDxfFolder.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
||||||
|
txtDxfFolder.Name = "txtDxfFolder";
|
||||||
|
txtDxfFolder.ReadOnly = true;
|
||||||
|
txtDxfFolder.Size = new System.Drawing.Size(669, 23);
|
||||||
|
txtDxfFolder.TabIndex = 6;
|
||||||
|
//
|
||||||
|
// btnBrowseDxf
|
||||||
|
//
|
||||||
|
btnBrowseDxf.Location = new System.Drawing.Point(751, 73);
|
||||||
|
btnBrowseDxf.Margin = new System.Windows.Forms.Padding(0, 5, 3, 3);
|
||||||
|
btnBrowseDxf.Name = "btnBrowseDxf";
|
||||||
|
btnBrowseDxf.Size = new System.Drawing.Size(35, 25);
|
||||||
|
btnBrowseDxf.TabIndex = 7;
|
||||||
|
btnBrowseDxf.Text = "...";
|
||||||
|
btnBrowseDxf.Click += BrowseDxf_Click;
|
||||||
|
//
|
||||||
|
// lblPlateSize
|
||||||
|
//
|
||||||
|
lblPlateSize.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||||
|
lblPlateSize.AutoSize = true;
|
||||||
|
lblPlateSize.Location = new System.Drawing.Point(6, 112);
|
||||||
|
lblPlateSize.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
||||||
|
lblPlateSize.Name = "lblPlateSize";
|
||||||
|
lblPlateSize.Size = new System.Drawing.Size(59, 15);
|
||||||
|
lblPlateSize.TabIndex = 8;
|
||||||
|
lblPlateSize.Text = "Plate Size:";
|
||||||
|
//
|
||||||
|
// platePanel
|
||||||
|
//
|
||||||
|
platePanel.AutoSize = true;
|
||||||
|
platePanel.Controls.Add(txtPlateWidth);
|
||||||
|
platePanel.Controls.Add(lblPlateX);
|
||||||
|
platePanel.Controls.Add(txtPlateLength);
|
||||||
|
platePanel.Location = new System.Drawing.Point(76, 104);
|
||||||
|
platePanel.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
|
||||||
|
platePanel.Name = "platePanel";
|
||||||
|
platePanel.Size = new System.Drawing.Size(156, 29);
|
||||||
|
platePanel.TabIndex = 9;
|
||||||
|
platePanel.WrapContents = false;
|
||||||
|
//
|
||||||
|
// txtPlateWidth
|
||||||
|
//
|
||||||
|
txtPlateWidth.Location = new System.Drawing.Point(3, 3);
|
||||||
|
txtPlateWidth.Name = "txtPlateWidth";
|
||||||
|
txtPlateWidth.Size = new System.Drawing.Size(60, 23);
|
||||||
|
txtPlateWidth.TabIndex = 0;
|
||||||
|
txtPlateWidth.Text = "60";
|
||||||
|
//
|
||||||
|
// lblPlateX
|
||||||
|
//
|
||||||
|
lblPlateX.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||||
|
lblPlateX.AutoSize = true;
|
||||||
|
lblPlateX.Location = new System.Drawing.Point(69, 7);
|
||||||
|
lblPlateX.Name = "lblPlateX";
|
||||||
|
lblPlateX.Size = new System.Drawing.Size(18, 15);
|
||||||
|
lblPlateX.TabIndex = 1;
|
||||||
|
lblPlateX.Text = " x ";
|
||||||
|
//
|
||||||
|
// txtPlateLength
|
||||||
|
//
|
||||||
|
txtPlateLength.Location = new System.Drawing.Point(93, 3);
|
||||||
|
txtPlateLength.Name = "txtPlateLength";
|
||||||
|
txtPlateLength.Size = new System.Drawing.Size(60, 23);
|
||||||
|
txtPlateLength.TabIndex = 2;
|
||||||
|
txtPlateLength.Text = "120";
|
||||||
|
//
|
||||||
|
// btnAnalyze
|
||||||
|
//
|
||||||
|
btnAnalyze.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
||||||
|
tbl.SetColumnSpan(btnAnalyze, 2);
|
||||||
|
btnAnalyze.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
|
||||||
|
btnAnalyze.Location = new System.Drawing.Point(676, 142);
|
||||||
|
btnAnalyze.Margin = new System.Windows.Forms.Padding(3, 6, 3, 3);
|
||||||
|
btnAnalyze.Name = "btnAnalyze";
|
||||||
|
btnAnalyze.Size = new System.Drawing.Size(110, 30);
|
||||||
|
btnAnalyze.TabIndex = 10;
|
||||||
|
btnAnalyze.Text = "Analyze";
|
||||||
|
btnAnalyze.Click += Analyze_Click;
|
||||||
|
//
|
||||||
|
// tabControl
|
||||||
|
//
|
||||||
|
tabControl.Controls.Add(tabParts);
|
||||||
|
tabControl.Controls.Add(tabGroups);
|
||||||
|
tabControl.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
tabControl.Location = new System.Drawing.Point(0, 200);
|
||||||
|
tabControl.Name = "tabControl";
|
||||||
|
tabControl.SelectedIndex = 0;
|
||||||
|
tabControl.Size = new System.Drawing.Size(804, 365);
|
||||||
|
tabControl.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// tabParts
|
||||||
|
//
|
||||||
|
tabParts.Controls.Add(dgvParts);
|
||||||
|
tabParts.Name = "tabParts";
|
||||||
|
tabParts.Padding = new System.Windows.Forms.Padding(3);
|
||||||
|
tabParts.Text = "Parts";
|
||||||
|
//
|
||||||
|
// dgvParts
|
||||||
|
//
|
||||||
|
dgvParts.AllowUserToAddRows = false;
|
||||||
|
dgvParts.AllowUserToDeleteRows = false;
|
||||||
|
dgvParts.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
|
||||||
|
dgvParts.BackgroundColor = System.Drawing.SystemColors.Window;
|
||||||
|
dgvParts.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||||
|
dgvParts.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||||
|
dgvParts.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
dgvParts.Name = "dgvParts";
|
||||||
|
dgvParts.RowHeadersVisible = false;
|
||||||
|
dgvParts.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
||||||
|
dgvParts.TabIndex = 0;
|
||||||
|
//
|
||||||
|
// tabGroups
|
||||||
|
//
|
||||||
|
tabGroups.Controls.Add(dgvGroups);
|
||||||
|
tabGroups.Name = "tabGroups";
|
||||||
|
tabGroups.Padding = new System.Windows.Forms.Padding(3);
|
||||||
|
tabGroups.Text = "Groups";
|
||||||
|
//
|
||||||
|
// dgvGroups
|
||||||
|
//
|
||||||
dgvGroups.AllowUserToAddRows = false;
|
dgvGroups.AllowUserToAddRows = false;
|
||||||
dgvGroups.AllowUserToDeleteRows = false;
|
dgvGroups.AllowUserToDeleteRows = false;
|
||||||
dgvGroups.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
|
dgvGroups.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
|
||||||
@@ -167,67 +288,82 @@ namespace OpenNest.Forms
|
|||||||
dgvGroups.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
dgvGroups.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||||
dgvGroups.Dock = System.Windows.Forms.DockStyle.Fill;
|
dgvGroups.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
dgvGroups.Name = "dgvGroups";
|
dgvGroups.Name = "dgvGroups";
|
||||||
dgvGroups.ReadOnly = true;
|
|
||||||
dgvGroups.RowHeadersVisible = false;
|
dgvGroups.RowHeadersVisible = false;
|
||||||
dgvGroups.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
dgvGroups.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
||||||
dgvGroups.TabIndex = 0;
|
dgvGroups.TabIndex = 0;
|
||||||
|
//
|
||||||
// ---- pnlBottom ----
|
// pnlBottom
|
||||||
|
//
|
||||||
pnlBottom.Controls.Add(lblSummary);
|
pnlBottom.Controls.Add(lblSummary);
|
||||||
pnlBottom.Controls.Add(btnCreateNests);
|
pnlBottom.Controls.Add(btnCreateNests);
|
||||||
pnlBottom.Controls.Add(btnClose);
|
pnlBottom.Controls.Add(btnClose);
|
||||||
pnlBottom.Dock = System.Windows.Forms.DockStyle.Bottom;
|
pnlBottom.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||||
pnlBottom.Height = 50;
|
pnlBottom.Location = new System.Drawing.Point(0, 565);
|
||||||
pnlBottom.Name = "pnlBottom";
|
pnlBottom.Name = "pnlBottom";
|
||||||
pnlBottom.Padding = new System.Windows.Forms.Padding(10, 10, 10, 10);
|
pnlBottom.Padding = new System.Windows.Forms.Padding(10);
|
||||||
|
pnlBottom.Size = new System.Drawing.Size(804, 50);
|
||||||
pnlBottom.TabIndex = 2;
|
pnlBottom.TabIndex = 2;
|
||||||
|
//
|
||||||
// ---- lblSummary ----
|
// lblSummary
|
||||||
|
//
|
||||||
lblSummary.AutoSize = true;
|
lblSummary.AutoSize = true;
|
||||||
lblSummary.ForeColor = System.Drawing.Color.Gray;
|
|
||||||
lblSummary.Dock = System.Windows.Forms.DockStyle.Left;
|
lblSummary.Dock = System.Windows.Forms.DockStyle.Left;
|
||||||
|
lblSummary.ForeColor = System.Drawing.Color.Gray;
|
||||||
|
lblSummary.Location = new System.Drawing.Point(10, 10);
|
||||||
lblSummary.Name = "lblSummary";
|
lblSummary.Name = "lblSummary";
|
||||||
|
lblSummary.Size = new System.Drawing.Size(0, 15);
|
||||||
lblSummary.TabIndex = 0;
|
lblSummary.TabIndex = 0;
|
||||||
lblSummary.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
lblSummary.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||||
|
//
|
||||||
// ---- btnClose ----
|
// btnCreateNests
|
||||||
btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
//
|
||||||
btnClose.Dock = System.Windows.Forms.DockStyle.Right;
|
btnCreateNests.Dock = System.Windows.Forms.DockStyle.Right;
|
||||||
btnClose.Name = "btnClose";
|
|
||||||
btnClose.Size = new System.Drawing.Size(80, 30);
|
|
||||||
btnClose.TabIndex = 2;
|
|
||||||
btnClose.Text = "Close";
|
|
||||||
btnClose.Click += new System.EventHandler(BtnClose_Click);
|
|
||||||
|
|
||||||
// ---- btnCreateNests ----
|
|
||||||
btnCreateNests.Enabled = false;
|
btnCreateNests.Enabled = false;
|
||||||
btnCreateNests.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
|
btnCreateNests.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
|
||||||
btnCreateNests.Dock = System.Windows.Forms.DockStyle.Right;
|
btnCreateNests.Location = new System.Drawing.Point(604, 10);
|
||||||
|
btnCreateNests.Margin = new System.Windows.Forms.Padding(0, 0, 6, 0);
|
||||||
btnCreateNests.Name = "btnCreateNests";
|
btnCreateNests.Name = "btnCreateNests";
|
||||||
btnCreateNests.Size = new System.Drawing.Size(110, 30);
|
btnCreateNests.Size = new System.Drawing.Size(110, 30);
|
||||||
btnCreateNests.TabIndex = 1;
|
btnCreateNests.TabIndex = 1;
|
||||||
btnCreateNests.Text = "Create Nests";
|
btnCreateNests.Text = "Create Nests";
|
||||||
btnCreateNests.Margin = new System.Windows.Forms.Padding(0, 0, 6, 0);
|
btnCreateNests.Click += CreateNests_Click;
|
||||||
btnCreateNests.Click += new System.EventHandler(CreateNests_Click);
|
//
|
||||||
|
// btnClose
|
||||||
// ---- BomImportForm ----
|
//
|
||||||
|
btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||||
|
btnClose.Dock = System.Windows.Forms.DockStyle.Right;
|
||||||
|
btnClose.Location = new System.Drawing.Point(714, 10);
|
||||||
|
btnClose.Name = "btnClose";
|
||||||
|
btnClose.Size = new System.Drawing.Size(80, 30);
|
||||||
|
btnClose.TabIndex = 2;
|
||||||
|
btnClose.Text = "Close";
|
||||||
|
btnClose.Click += BtnClose_Click;
|
||||||
|
//
|
||||||
|
// BomImportForm
|
||||||
|
//
|
||||||
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
CancelButton = btnClose;
|
CancelButton = btnClose;
|
||||||
ClientSize = new System.Drawing.Size(520, 500);
|
ClientSize = new System.Drawing.Size(804, 615);
|
||||||
Controls.Add(grpGroups);
|
Controls.Add(tabControl);
|
||||||
Controls.Add(pnlBottom);
|
Controls.Add(pnlBottom);
|
||||||
Controls.Add(grpInput);
|
Controls.Add(grpInput);
|
||||||
Font = new System.Drawing.Font("Segoe UI", 9F);
|
Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||||
MinimumSize = new System.Drawing.Size(400, 350);
|
|
||||||
MaximizeBox = false;
|
MaximizeBox = false;
|
||||||
|
MinimumSize = new System.Drawing.Size(400, 350);
|
||||||
Name = "BomImportForm";
|
Name = "BomImportForm";
|
||||||
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
Text = "Import BOM";
|
Text = "Import BOM";
|
||||||
grpInput.ResumeLayout(false);
|
grpInput.ResumeLayout(false);
|
||||||
grpInput.PerformLayout();
|
tbl.ResumeLayout(false);
|
||||||
grpGroups.ResumeLayout(false);
|
tbl.PerformLayout();
|
||||||
|
platePanel.ResumeLayout(false);
|
||||||
|
platePanel.PerformLayout();
|
||||||
|
tabParts.ResumeLayout(false);
|
||||||
|
((System.ComponentModel.ISupportInitialize)dgvParts).EndInit();
|
||||||
|
tabGroups.ResumeLayout(false);
|
||||||
((System.ComponentModel.ISupportInitialize)dgvGroups).EndInit();
|
((System.ComponentModel.ISupportInitialize)dgvGroups).EndInit();
|
||||||
|
tabControl.ResumeLayout(false);
|
||||||
pnlBottom.ResumeLayout(false);
|
pnlBottom.ResumeLayout(false);
|
||||||
pnlBottom.PerformLayout();
|
pnlBottom.PerformLayout();
|
||||||
ResumeLayout(false);
|
ResumeLayout(false);
|
||||||
@@ -244,11 +380,21 @@ namespace OpenNest.Forms
|
|||||||
private System.Windows.Forms.TextBox txtPlateWidth;
|
private System.Windows.Forms.TextBox txtPlateWidth;
|
||||||
private System.Windows.Forms.TextBox txtPlateLength;
|
private System.Windows.Forms.TextBox txtPlateLength;
|
||||||
private System.Windows.Forms.Button btnAnalyze;
|
private System.Windows.Forms.Button btnAnalyze;
|
||||||
private System.Windows.Forms.GroupBox grpGroups;
|
private System.Windows.Forms.TabControl tabControl;
|
||||||
|
private System.Windows.Forms.TabPage tabParts;
|
||||||
|
private System.Windows.Forms.DataGridView dgvParts;
|
||||||
|
private System.Windows.Forms.TabPage tabGroups;
|
||||||
private System.Windows.Forms.DataGridView dgvGroups;
|
private System.Windows.Forms.DataGridView dgvGroups;
|
||||||
private System.Windows.Forms.Panel pnlBottom;
|
private System.Windows.Forms.Panel pnlBottom;
|
||||||
private System.Windows.Forms.Label lblSummary;
|
private System.Windows.Forms.Label lblSummary;
|
||||||
private System.Windows.Forms.Button btnCreateNests;
|
private System.Windows.Forms.Button btnCreateNests;
|
||||||
private System.Windows.Forms.Button btnClose;
|
private System.Windows.Forms.Button btnClose;
|
||||||
|
private System.Windows.Forms.TableLayoutPanel tbl;
|
||||||
|
private System.Windows.Forms.Label lblJobName;
|
||||||
|
private System.Windows.Forms.Label lblBomFile;
|
||||||
|
private System.Windows.Forms.Label lblDxfFolder;
|
||||||
|
private System.Windows.Forms.Label lblPlateSize;
|
||||||
|
private System.Windows.Forms.FlowLayoutPanel platePanel;
|
||||||
|
private System.Windows.Forms.Label lblPlateX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+310
-50
@@ -6,6 +6,7 @@ using OpenNest.IO.Bom;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
@@ -14,15 +15,21 @@ namespace OpenNest.Forms
|
|||||||
{
|
{
|
||||||
public partial class BomImportForm : Form
|
public partial class BomImportForm : Form
|
||||||
{
|
{
|
||||||
private BomAnalysis _analysis;
|
private List<BomPartRow> _parts;
|
||||||
|
private Dictionary<string, (double Width, double Length)> _plateSizes;
|
||||||
|
private bool _suppressRegroup;
|
||||||
|
|
||||||
public Form MdiParentForm { get; set; }
|
public Form MdiParentForm { get; set; }
|
||||||
|
|
||||||
public BomImportForm()
|
public BomImportForm()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
_parts = new List<BomPartRow>();
|
||||||
|
_plateSizes = new Dictionary<string, (double, double)>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region File Browsing
|
||||||
|
|
||||||
private void BrowseBom_Click(object sender, EventArgs e)
|
private void BrowseBom_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
using var dlg = new OpenFileDialog
|
using var dlg = new OpenFileDialog
|
||||||
@@ -37,11 +44,9 @@ namespace OpenNest.Forms
|
|||||||
|
|
||||||
txtBomFile.Text = dlg.FileName;
|
txtBomFile.Text = dlg.FileName;
|
||||||
|
|
||||||
// Default DXF folder to the same directory as the BOM file
|
|
||||||
if (string.IsNullOrWhiteSpace(txtDxfFolder.Text))
|
if (string.IsNullOrWhiteSpace(txtDxfFolder.Text))
|
||||||
txtDxfFolder.Text = Path.GetDirectoryName(dlg.FileName);
|
txtDxfFolder.Text = Path.GetDirectoryName(dlg.FileName);
|
||||||
|
|
||||||
// Derive job name by stripping " BOM" suffix and extension
|
|
||||||
if (string.IsNullOrWhiteSpace(txtJobName.Text))
|
if (string.IsNullOrWhiteSpace(txtJobName.Text))
|
||||||
{
|
{
|
||||||
var name = Path.GetFileNameWithoutExtension(dlg.FileName);
|
var name = Path.GetFileNameWithoutExtension(dlg.FileName);
|
||||||
@@ -65,6 +70,10 @@ namespace OpenNest.Forms
|
|||||||
txtDxfFolder.Text = dlg.SelectedPath;
|
txtDxfFolder.Text = dlg.SelectedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Analyze
|
||||||
|
|
||||||
private void Analyze_Click(object sender, EventArgs e)
|
private void Analyze_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (!File.Exists(txtBomFile.Text))
|
if (!File.Exists(txtBomFile.Text))
|
||||||
@@ -80,11 +89,13 @@ namespace OpenNest.Forms
|
|||||||
using (var reader = new BomReader(txtBomFile.Text))
|
using (var reader = new BomReader(txtBomFile.Text))
|
||||||
items = reader.GetItems();
|
items = reader.GetItems();
|
||||||
|
|
||||||
_analysis = BomAnalyzer.Analyze(items, txtDxfFolder.Text);
|
var analysis = BomAnalyzer.Analyze(items, txtDxfFolder.Text);
|
||||||
|
BuildPartRows(items, analysis);
|
||||||
PopulateGrid(_analysis);
|
PopulatePartsGrid();
|
||||||
UpdateSummary(_analysis);
|
RebuildGroups();
|
||||||
btnCreateNests.Enabled = _analysis.Groups.Count > 0;
|
UpdateSummary();
|
||||||
|
btnCreateNests.Enabled = true;
|
||||||
|
tabControl.SelectedTab = tabParts;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -93,53 +104,280 @@ namespace OpenNest.Forms
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulateGrid(BomAnalysis analysis)
|
private void BuildPartRows(List<BomItem> items, BomAnalysis analysis)
|
||||||
{
|
{
|
||||||
var table = new DataTable();
|
var matchedPaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
table.Columns.Add("Material", typeof(string));
|
|
||||||
table.Columns.Add("Thickness", typeof(string));
|
|
||||||
table.Columns.Add("Parts", typeof(int));
|
|
||||||
table.Columns.Add("Total Qty", typeof(int));
|
|
||||||
|
|
||||||
foreach (var group in analysis.Groups)
|
foreach (var group in analysis.Groups)
|
||||||
|
foreach (var part in group.Parts)
|
||||||
|
if (part.DxfPath != null)
|
||||||
|
matchedPaths[part.Item.FileName ?? ""] = part.DxfPath;
|
||||||
|
|
||||||
|
_parts = new List<BomPartRow>();
|
||||||
|
|
||||||
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
var partCount = group.Parts.Count;
|
var row = new BomPartRow
|
||||||
var totalQty = group.Parts.Sum(p => p.Item.Qty ?? 0);
|
{
|
||||||
table.Rows.Add(group.Material, group.Thickness.ToString("0.###"), partCount, totalQty);
|
ItemNum = item.ItemNum,
|
||||||
|
FileName = item.FileName,
|
||||||
|
Qty = item.Qty,
|
||||||
|
Description = item.Description,
|
||||||
|
Material = item.Material,
|
||||||
|
Thickness = item.Thickness,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(item.FileName))
|
||||||
|
{
|
||||||
|
row.Status = "Skipped";
|
||||||
|
row.IsEditable = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var lookupName = item.FileName;
|
||||||
|
if (lookupName.EndsWith(".dxf", StringComparison.OrdinalIgnoreCase))
|
||||||
|
lookupName = Path.GetFileNameWithoutExtension(lookupName);
|
||||||
|
|
||||||
|
if (matchedPaths.TryGetValue(lookupName, out var dxfPath))
|
||||||
|
{
|
||||||
|
row.DxfPath = dxfPath;
|
||||||
|
row.Status = "Matched";
|
||||||
|
row.IsEditable = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
row.Status = "No DXF";
|
||||||
|
row.IsEditable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_parts.Add(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
_plateSizes.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Parts Tab
|
||||||
|
|
||||||
|
private void PopulatePartsGrid()
|
||||||
|
{
|
||||||
|
_suppressRegroup = true;
|
||||||
|
|
||||||
|
var table = new DataTable();
|
||||||
|
table.Columns.Add("Item #", typeof(string));
|
||||||
|
table.Columns.Add("File Name", typeof(string));
|
||||||
|
table.Columns.Add("Qty", typeof(string));
|
||||||
|
table.Columns.Add("Description", typeof(string));
|
||||||
|
table.Columns.Add("Material", typeof(string));
|
||||||
|
table.Columns.Add("Thickness", typeof(string));
|
||||||
|
table.Columns.Add("Status", typeof(string));
|
||||||
|
|
||||||
|
foreach (var part in _parts)
|
||||||
|
{
|
||||||
|
table.Rows.Add(
|
||||||
|
part.ItemNum?.ToString() ?? "",
|
||||||
|
part.FileName ?? "",
|
||||||
|
part.Qty?.ToString() ?? "",
|
||||||
|
part.Description ?? "",
|
||||||
|
part.Material ?? "",
|
||||||
|
part.Thickness?.ToString("0.####") ?? "",
|
||||||
|
part.Status
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
dgvParts.DataSource = table;
|
||||||
|
|
||||||
|
// Make non-editable columns read-only
|
||||||
|
foreach (DataGridViewColumn col in dgvParts.Columns)
|
||||||
|
{
|
||||||
|
if (col.Name != "Material" && col.Name != "Thickness")
|
||||||
|
col.ReadOnly = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Style rows by status
|
||||||
|
for (var i = 0; i < _parts.Count; i++)
|
||||||
|
{
|
||||||
|
if (!_parts[i].IsEditable)
|
||||||
|
{
|
||||||
|
dgvParts.Rows[i].ReadOnly = true;
|
||||||
|
dgvParts.Rows[i].DefaultCellStyle.ForeColor = Color.Gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dgvParts.CellValueChanged -= DgvParts_CellValueChanged;
|
||||||
|
dgvParts.CellValueChanged += DgvParts_CellValueChanged;
|
||||||
|
|
||||||
|
_suppressRegroup = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DgvParts_CellValueChanged(object sender, DataGridViewCellEventArgs e)
|
||||||
|
{
|
||||||
|
if (_suppressRegroup || e.RowIndex < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var colName = dgvParts.Columns[e.ColumnIndex].Name;
|
||||||
|
if (colName != "Material" && colName != "Thickness")
|
||||||
|
return;
|
||||||
|
|
||||||
|
var part = _parts[e.RowIndex];
|
||||||
|
if (!part.IsEditable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (colName == "Material")
|
||||||
|
part.Material = dgvParts.Rows[e.RowIndex].Cells[e.ColumnIndex].Value?.ToString();
|
||||||
|
|
||||||
|
if (colName == "Thickness")
|
||||||
|
{
|
||||||
|
var text = dgvParts.Rows[e.RowIndex].Cells[e.ColumnIndex].Value?.ToString();
|
||||||
|
part.Thickness = double.TryParse(text, out var t) ? t : (double?)null;
|
||||||
|
}
|
||||||
|
|
||||||
|
RebuildGroups();
|
||||||
|
UpdateSummary();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Groups Tab
|
||||||
|
|
||||||
|
private void RebuildGroups()
|
||||||
|
{
|
||||||
|
// Save existing plate sizes before rebuilding
|
||||||
|
SavePlateSizes();
|
||||||
|
|
||||||
|
var defaultWidth = double.TryParse(txtPlateWidth.Text, out var w) ? w : 60;
|
||||||
|
var defaultLength = double.TryParse(txtPlateLength.Text, out var l) ? l : 120;
|
||||||
|
|
||||||
|
var groups = _parts
|
||||||
|
.Where(p => p.IsEditable
|
||||||
|
&& !string.IsNullOrWhiteSpace(p.Material)
|
||||||
|
&& p.Thickness.HasValue)
|
||||||
|
.GroupBy(p => new
|
||||||
|
{
|
||||||
|
Material = p.Material.ToUpperInvariant(),
|
||||||
|
Thickness = p.Thickness.Value
|
||||||
|
})
|
||||||
|
.OrderBy(g => g.First().Material)
|
||||||
|
.ThenBy(g => g.Key.Thickness)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var table = new DataTable();
|
||||||
|
table.Columns.Add("Material", typeof(string));
|
||||||
|
table.Columns.Add("Thickness", typeof(double));
|
||||||
|
table.Columns.Add("Parts", typeof(int));
|
||||||
|
table.Columns.Add("Total Qty", typeof(int));
|
||||||
|
table.Columns.Add("Plate Width", typeof(double));
|
||||||
|
table.Columns.Add("Plate Length", typeof(double));
|
||||||
|
|
||||||
|
foreach (var group in groups)
|
||||||
|
{
|
||||||
|
var material = group.First().Material;
|
||||||
|
var thickness = group.Key.Thickness;
|
||||||
|
var key = GroupKey(material, thickness);
|
||||||
|
|
||||||
|
var plateWidth = _plateSizes.TryGetValue(key, out var size) ? size.Width : defaultWidth;
|
||||||
|
var plateLength = _plateSizes.TryGetValue(key, out _) ? size.Length : defaultLength;
|
||||||
|
|
||||||
|
table.Rows.Add(
|
||||||
|
material,
|
||||||
|
thickness,
|
||||||
|
group.Count(),
|
||||||
|
group.Sum(p => p.Qty ?? 0),
|
||||||
|
plateWidth,
|
||||||
|
plateLength
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
dgvGroups.DataSource = table;
|
dgvGroups.DataSource = table;
|
||||||
|
|
||||||
|
// Material, Thickness, Parts, Total Qty are read-only
|
||||||
|
if (dgvGroups.Columns.Count >= 6)
|
||||||
|
{
|
||||||
|
dgvGroups.Columns["Material"].ReadOnly = true;
|
||||||
|
dgvGroups.Columns["Thickness"].ReadOnly = true;
|
||||||
|
dgvGroups.Columns["Parts"].ReadOnly = true;
|
||||||
|
dgvGroups.Columns["Total Qty"].ReadOnly = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
btnCreateNests.Enabled = table.Rows.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateSummary(BomAnalysis analysis)
|
private void SavePlateSizes()
|
||||||
{
|
{
|
||||||
var parts = new List<string>();
|
if (dgvGroups.DataSource is not DataTable table)
|
||||||
if (analysis.Skipped.Count > 0)
|
return;
|
||||||
parts.Add($"{analysis.Skipped.Count} skipped (no DXF file or thickness given)");
|
|
||||||
if (analysis.Unmatched.Count > 0)
|
|
||||||
parts.Add($"{analysis.Unmatched.Count} unmatched (DXF file not found)");
|
|
||||||
|
|
||||||
lblSummary.Text = parts.Count > 0
|
_plateSizes.Clear();
|
||||||
? string.Join(", ", parts)
|
foreach (DataRow row in table.Rows)
|
||||||
: string.Empty;
|
{
|
||||||
|
var material = row["Material"]?.ToString() ?? "";
|
||||||
|
var thickness = row["Thickness"] is double t ? t : 0;
|
||||||
|
var key = GroupKey(material, thickness);
|
||||||
|
|
||||||
|
var width = row["Plate Width"] is double pw ? pw : 60;
|
||||||
|
var length = row["Plate Length"] is double pl ? pl : 120;
|
||||||
|
|
||||||
|
_plateSizes[key] = (width, length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GroupKey(string material, double thickness)
|
||||||
|
=> $"{material?.ToUpperInvariant()}|{thickness}";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Summary
|
||||||
|
|
||||||
|
private void UpdateSummary()
|
||||||
|
{
|
||||||
|
var skipped = _parts.Count(p => p.Status == "Skipped");
|
||||||
|
var noDxf = _parts.Count(p => p.Status == "No DXF");
|
||||||
|
var matched = _parts.Count(p => p.Status == "Matched");
|
||||||
|
|
||||||
|
var summaryParts = new List<string>();
|
||||||
|
if (skipped > 0)
|
||||||
|
summaryParts.Add($"{skipped} skipped (no file name)");
|
||||||
|
if (noDxf > 0)
|
||||||
|
summaryParts.Add($"{noDxf} no DXF found");
|
||||||
|
|
||||||
|
lblSummary.Text = summaryParts.Count > 0
|
||||||
|
? string.Join(", ", summaryParts)
|
||||||
|
: $"{matched} parts matched";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Create Nests
|
||||||
|
|
||||||
private void CreateNests_Click(object sender, EventArgs e)
|
private void CreateNests_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (_analysis == null || _analysis.Groups.Count == 0)
|
if (_parts == null || _parts.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!double.TryParse(txtPlateWidth.Text, out var plateWidth) || plateWidth <= 0)
|
// Save latest plate size edits
|
||||||
{
|
SavePlateSizes();
|
||||||
MessageBox.Show("Plate width must be a positive number.", "Validation Error",
|
|
||||||
MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!double.TryParse(txtPlateLength.Text, out var plateLength) || plateLength <= 0)
|
var defaultWidth = double.TryParse(txtPlateWidth.Text, out var dw) ? dw : 60;
|
||||||
|
var defaultLength = double.TryParse(txtPlateLength.Text, out var dl) ? dl : 120;
|
||||||
|
|
||||||
|
var groups = _parts
|
||||||
|
.Where(p => p.IsEditable
|
||||||
|
&& !string.IsNullOrWhiteSpace(p.Material)
|
||||||
|
&& p.Thickness.HasValue
|
||||||
|
&& !string.IsNullOrWhiteSpace(p.DxfPath))
|
||||||
|
.GroupBy(p => new
|
||||||
|
{
|
||||||
|
Material = p.Material.ToUpperInvariant(),
|
||||||
|
Thickness = p.Thickness.Value
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (groups.Count == 0)
|
||||||
{
|
{
|
||||||
MessageBox.Show("Plate length must be a positive number.", "Validation Error",
|
MessageBox.Show("No groups with matched DXF files to create nests from.", "Nothing to Create",
|
||||||
MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,36 +386,43 @@ namespace OpenNest.Forms
|
|||||||
var nestsCreated = 0;
|
var nestsCreated = 0;
|
||||||
var importErrors = new List<string>();
|
var importErrors = new List<string>();
|
||||||
|
|
||||||
foreach (var group in _analysis.Groups)
|
foreach (var group in groups)
|
||||||
{
|
{
|
||||||
var nestName = $"{jobName} - {group.Thickness:0.###} {group.Material}";
|
var material = group.First().Material;
|
||||||
|
var thickness = group.Key.Thickness;
|
||||||
|
var key = GroupKey(material, thickness);
|
||||||
|
|
||||||
|
var plateWidth = _plateSizes.TryGetValue(key, out var size) ? size.Width : defaultWidth;
|
||||||
|
var plateLength = _plateSizes.TryGetValue(key, out _) ? size.Length : defaultLength;
|
||||||
|
|
||||||
|
var nestName = $"{jobName} - {thickness:0.###} {material}";
|
||||||
var nest = new Nest(nestName);
|
var nest = new Nest(nestName);
|
||||||
nest.DateCreated = DateTime.Now;
|
nest.DateCreated = DateTime.Now;
|
||||||
nest.DateLastModified = DateTime.Now;
|
nest.DateLastModified = DateTime.Now;
|
||||||
nest.PlateDefaults.Size = new Size(plateWidth, plateLength);
|
nest.PlateDefaults.Size = new Geometry.Size(plateWidth, plateLength);
|
||||||
nest.PlateDefaults.Thickness = group.Thickness;
|
nest.PlateDefaults.Thickness = thickness;
|
||||||
nest.PlateDefaults.Material = new Material(group.Material);
|
nest.PlateDefaults.Material = new Material(material);
|
||||||
nest.PlateDefaults.Quadrant = 1;
|
nest.PlateDefaults.Quadrant = 1;
|
||||||
nest.PlateDefaults.PartSpacing = 1;
|
nest.PlateDefaults.PartSpacing = 1;
|
||||||
nest.PlateDefaults.EdgeSpacing = new Spacing(1, 1, 1, 1);
|
nest.PlateDefaults.EdgeSpacing = new Spacing(1, 1, 1, 1);
|
||||||
|
|
||||||
foreach (var matched in group.Parts)
|
foreach (var part in group)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(matched.DxfPath) || !File.Exists(matched.DxfPath))
|
if (!File.Exists(part.DxfPath))
|
||||||
{
|
{
|
||||||
importErrors.Add($"{matched.Item.FileName}: DXF file not found");
|
importErrors.Add($"{part.FileName}: DXF file not found");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = importer.Import(matched.DxfPath);
|
var result = importer.Import(part.DxfPath);
|
||||||
|
|
||||||
var drawingName = Path.GetFileNameWithoutExtension(matched.DxfPath);
|
var drawingName = Path.GetFileNameWithoutExtension(part.DxfPath);
|
||||||
var drawing = new Drawing(drawingName);
|
var drawing = new Drawing(drawingName);
|
||||||
drawing.Source.Path = matched.DxfPath;
|
drawing.Source.Path = part.DxfPath;
|
||||||
drawing.Quantity.Required = matched.Item.Qty ?? 1;
|
drawing.Quantity.Required = part.Qty ?? 1;
|
||||||
drawing.Material = new Material(group.Material);
|
drawing.Material = new Material(material);
|
||||||
|
|
||||||
var pgm = ConvertGeometry.ToProgram(result.Entities);
|
var pgm = ConvertGeometry.ToProgram(result.Entities);
|
||||||
|
|
||||||
@@ -194,7 +439,7 @@ namespace OpenNest.Forms
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
importErrors.Add($"{matched.Item.FileName}: {ex.Message}");
|
importErrors.Add($"{part.FileName}: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,9 +466,24 @@ namespace OpenNest.Forms
|
|||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
private void BtnClose_Click(object sender, EventArgs e)
|
private void BtnClose_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class BomPartRow
|
||||||
|
{
|
||||||
|
public int? ItemNum { get; set; }
|
||||||
|
public string FileName { get; set; }
|
||||||
|
public int? Qty { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public string Material { get; set; }
|
||||||
|
public double? Thickness { get; set; }
|
||||||
|
public string DxfPath { get; set; }
|
||||||
|
public string Status { get; set; }
|
||||||
|
public bool IsEditable { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user