From 81c167320dfe4acc658aa8bdab31985040b45dc6 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Sun, 5 Apr 2026 01:16:09 -0400 Subject: [PATCH] feat: redesign AutoNest dialog with grouped layout and engine selector Rebuild the dialog from a flat layout into grouped sections: engine selector at top, Parts group with rotation columns and summary label, Options group, collapsible Plate Optimizer with single-field size parsing, and a clean button bar. Adds engine sync between dialog and toolbar. Co-Authored-By: Claude Opus 4.6 (1M context) --- OpenNest/Forms/AutoNestForm.Designer.cs | 318 ++++++++++++++---------- OpenNest/Forms/AutoNestForm.cs | 299 +++++++++++++++++----- OpenNest/Forms/MainForm.cs | 6 + 3 files changed, 424 insertions(+), 199 deletions(-) diff --git a/OpenNest/Forms/AutoNestForm.Designer.cs b/OpenNest/Forms/AutoNestForm.Designer.cs index a5941f5..25dc3da 100644 --- a/OpenNest/Forms/AutoNestForm.Designer.cs +++ b/OpenNest/Forms/AutoNestForm.Designer.cs @@ -1,16 +1,9 @@ -namespace OpenNest.Forms +namespace OpenNest.Forms { partial class AutoNestForm { - /// - /// Required designer variable. - /// private System.ComponentModel.IContainer components = null; - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) @@ -22,188 +15,253 @@ #region Windows Form Designer generated code - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// private void InitializeComponent() { - this.dataGridView1 = new System.Windows.Forms.DataGridView(); - this.bottomPanel1 = new OpenNest.Controls.BottomPanel(); - this.acceptButton = new System.Windows.Forms.Button(); + this.engineLabel = new System.Windows.Forms.Label(); + this.engineComboBox = new System.Windows.Forms.ComboBox(); + this.partsGroup = new System.Windows.Forms.GroupBox(); + this.partsGrid = new System.Windows.Forms.DataGridView(); + this.summaryLabel = new System.Windows.Forms.Label(); + this.optionsGroup = new System.Windows.Forms.GroupBox(); this.createNewPlatesAsNeededBox = new System.Windows.Forms.CheckBox(); - this.cancelButton = new System.Windows.Forms.Button(); + this.plateOptimizerGroup = new System.Windows.Forms.GroupBox(); this.optimizePlateSizeBox = new System.Windows.Forms.CheckBox(); - this.plateOptionsPanel = new System.Windows.Forms.Panel(); - this.plateOptionsGrid = new System.Windows.Forms.DataGridView(); + this.plateGrid = new System.Windows.Forms.DataGridView(); this.salvageRateLabel = new System.Windows.Forms.Label(); this.salvageRateBox = new System.Windows.Forms.TextBox(); this.salvageRatePercentLabel = new System.Windows.Forms.Label(); - ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.plateOptionsGrid)).BeginInit(); - this.bottomPanel1.SuspendLayout(); + this.buttonPanel = new System.Windows.Forms.Panel(); + this.acceptButton = new System.Windows.Forms.Button(); + this.cancelButton = new System.Windows.Forms.Button(); + ((System.ComponentModel.ISupportInitialize)(this.partsGrid)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.plateGrid)).BeginInit(); + this.partsGroup.SuspendLayout(); + this.optionsGroup.SuspendLayout(); + this.plateOptimizerGroup.SuspendLayout(); + this.buttonPanel.SuspendLayout(); this.SuspendLayout(); - // - // dataGridView1 - // - this.dataGridView1.AllowUserToDeleteRows = false; - this.dataGridView1.AllowUserToOrderColumns = true; - this.dataGridView1.AllowUserToResizeRows = false; - this.dataGridView1.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; - this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill; - this.dataGridView1.Location = new System.Drawing.Point(0, 0); - this.dataGridView1.Name = "dataGridView1"; - this.dataGridView1.RowHeadersVisible = false; - this.dataGridView1.Size = new System.Drawing.Size(545, 385); - this.dataGridView1.TabIndex = 0; - // - // bottomPanel1 - // - this.bottomPanel1.Controls.Add(this.optimizePlateSizeBox); - this.bottomPanel1.Controls.Add(this.acceptButton); - this.bottomPanel1.Controls.Add(this.createNewPlatesAsNeededBox); - this.bottomPanel1.Controls.Add(this.cancelButton); - this.bottomPanel1.Dock = System.Windows.Forms.DockStyle.Bottom; - this.bottomPanel1.Location = new System.Drawing.Point(0, 335); - this.bottomPanel1.Name = "bottomPanel1"; - this.bottomPanel1.Size = new System.Drawing.Size(545, 50); - this.bottomPanel1.TabIndex = 9; - // - // acceptButton - // - this.acceptButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.acceptButton.DialogResult = System.Windows.Forms.DialogResult.OK; - this.acceptButton.Location = new System.Drawing.Point(344, 9); - this.acceptButton.Margin = new System.Windows.Forms.Padding(4); - this.acceptButton.Name = "acceptButton"; - this.acceptButton.Size = new System.Drawing.Size(90, 28); - this.acceptButton.TabIndex = 6; - this.acceptButton.Text = "Accept"; - this.acceptButton.UseVisualStyleBackColor = true; - // + // + // engineLabel + // + this.engineLabel.AutoSize = true; + this.engineLabel.Location = new System.Drawing.Point(12, 15); + this.engineLabel.Name = "engineLabel"; + this.engineLabel.Size = new System.Drawing.Size(82, 16); + this.engineLabel.TabIndex = 0; + this.engineLabel.Text = "Nest Engine:"; + // + // engineComboBox + // + this.engineComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.engineComboBox.Location = new System.Drawing.Point(100, 12); + this.engineComboBox.Name = "engineComboBox"; + this.engineComboBox.Size = new System.Drawing.Size(200, 24); + this.engineComboBox.TabIndex = 1; + // + // partsGroup + // + this.partsGroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.partsGroup.Controls.Add(this.partsGrid); + this.partsGroup.Controls.Add(this.summaryLabel); + this.partsGroup.Location = new System.Drawing.Point(12, 42); + this.partsGroup.Name = "partsGroup"; + this.partsGroup.Size = new System.Drawing.Size(556, 210); + this.partsGroup.TabIndex = 2; + this.partsGroup.TabStop = false; + this.partsGroup.Text = "Parts"; + // + // partsGrid + // + this.partsGrid.AllowUserToAddRows = false; + this.partsGrid.AllowUserToDeleteRows = false; + this.partsGrid.AllowUserToResizeRows = false; + this.partsGrid.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.partsGrid.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.partsGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.partsGrid.Location = new System.Drawing.Point(10, 22); + this.partsGrid.Name = "partsGrid"; + this.partsGrid.RowHeadersVisible = false; + this.partsGrid.AutoGenerateColumns = false; + this.partsGrid.Size = new System.Drawing.Size(536, 160); + this.partsGrid.TabIndex = 0; + // + // summaryLabel + // + this.summaryLabel.AutoSize = true; + this.summaryLabel.ForeColor = System.Drawing.SystemColors.GrayText; + this.summaryLabel.Location = new System.Drawing.Point(10, 188); + this.summaryLabel.Name = "summaryLabel"; + this.summaryLabel.Size = new System.Drawing.Size(0, 16); + this.summaryLabel.TabIndex = 1; + // + // optionsGroup + // + this.optionsGroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.optionsGroup.Controls.Add(this.createNewPlatesAsNeededBox); + this.optionsGroup.Location = new System.Drawing.Point(12, 258); + this.optionsGroup.Name = "optionsGroup"; + this.optionsGroup.Size = new System.Drawing.Size(556, 48); + this.optionsGroup.TabIndex = 3; + this.optionsGroup.TabStop = false; + this.optionsGroup.Text = "Options"; + // // createNewPlatesAsNeededBox - // - this.createNewPlatesAsNeededBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + // this.createNewPlatesAsNeededBox.AutoSize = true; - this.createNewPlatesAsNeededBox.Location = new System.Drawing.Point(12, 15); + this.createNewPlatesAsNeededBox.Location = new System.Drawing.Point(10, 22); this.createNewPlatesAsNeededBox.Name = "createNewPlatesAsNeededBox"; this.createNewPlatesAsNeededBox.Size = new System.Drawing.Size(202, 20); - this.createNewPlatesAsNeededBox.TabIndex = 8; + this.createNewPlatesAsNeededBox.TabIndex = 0; this.createNewPlatesAsNeededBox.Text = "Create new plates as needed"; this.createNewPlatesAsNeededBox.UseVisualStyleBackColor = true; - // - // cancelButton - // - this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.cancelButton.Location = new System.Drawing.Point(442, 9); - this.cancelButton.Margin = new System.Windows.Forms.Padding(4); - this.cancelButton.Name = "cancelButton"; - this.cancelButton.Size = new System.Drawing.Size(90, 28); - this.cancelButton.TabIndex = 7; - this.cancelButton.Text = "Cancel"; - this.cancelButton.UseVisualStyleBackColor = true; + // + // plateOptimizerGroup + // + this.plateOptimizerGroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.plateOptimizerGroup.Controls.Add(this.optimizePlateSizeBox); + this.plateOptimizerGroup.Controls.Add(this.plateGrid); + this.plateOptimizerGroup.Controls.Add(this.salvageRateLabel); + this.plateOptimizerGroup.Controls.Add(this.salvageRateBox); + this.plateOptimizerGroup.Controls.Add(this.salvageRatePercentLabel); + this.plateOptimizerGroup.Location = new System.Drawing.Point(12, 312); + this.plateOptimizerGroup.Name = "plateOptimizerGroup"; + this.plateOptimizerGroup.Size = new System.Drawing.Size(556, 188); + this.plateOptimizerGroup.TabIndex = 4; + this.plateOptimizerGroup.TabStop = false; + this.plateOptimizerGroup.Text = " Plate Optimizer"; // // optimizePlateSizeBox // this.optimizePlateSizeBox.AutoSize = true; - this.optimizePlateSizeBox.Location = new System.Drawing.Point(220, 15); + this.optimizePlateSizeBox.Location = new System.Drawing.Point(10, 0); this.optimizePlateSizeBox.Name = "optimizePlateSizeBox"; - this.optimizePlateSizeBox.Size = new System.Drawing.Size(148, 20); - this.optimizePlateSizeBox.TabIndex = 10; - this.optimizePlateSizeBox.Text = "Optimize plate size"; + this.optimizePlateSizeBox.Size = new System.Drawing.Size(15, 14); + this.optimizePlateSizeBox.TabIndex = 0; this.optimizePlateSizeBox.UseVisualStyleBackColor = true; this.optimizePlateSizeBox.CheckedChanged += new System.EventHandler(this.optimizePlateSizeBox_CheckedChanged); // - // plateOptionsPanel + // plateGrid // - this.plateOptionsPanel.Controls.Add(this.plateOptionsGrid); - this.plateOptionsPanel.Controls.Add(this.salvageRateLabel); - this.plateOptionsPanel.Controls.Add(this.salvageRateBox); - this.plateOptionsPanel.Controls.Add(this.salvageRatePercentLabel); - this.plateOptionsPanel.Dock = System.Windows.Forms.DockStyle.Bottom; - this.plateOptionsPanel.Location = new System.Drawing.Point(0, 135); - this.plateOptionsPanel.Name = "plateOptionsPanel"; - this.plateOptionsPanel.Size = new System.Drawing.Size(545, 200); - this.plateOptionsPanel.TabIndex = 11; - this.plateOptionsPanel.Visible = false; - // - // plateOptionsGrid - // - this.plateOptionsGrid.AllowUserToOrderColumns = true; - this.plateOptionsGrid.AllowUserToResizeRows = false; - this.plateOptionsGrid.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.plateOptionsGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; - this.plateOptionsGrid.Dock = System.Windows.Forms.DockStyle.Fill; - this.plateOptionsGrid.Location = new System.Drawing.Point(0, 0); - this.plateOptionsGrid.Name = "plateOptionsGrid"; - this.plateOptionsGrid.RowHeadersVisible = false; - this.plateOptionsGrid.Size = new System.Drawing.Size(545, 170); - this.plateOptionsGrid.TabIndex = 0; + this.plateGrid.AllowUserToResizeRows = false; + this.plateGrid.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.plateGrid.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.plateGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.plateGrid.Location = new System.Drawing.Point(10, 22); + this.plateGrid.Name = "plateGrid"; + this.plateGrid.RowHeadersVisible = false; + this.plateGrid.AutoGenerateColumns = false; + this.plateGrid.Size = new System.Drawing.Size(536, 130); + this.plateGrid.TabIndex = 1; // // salvageRateLabel // - this.salvageRateLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.salvageRateLabel.AutoSize = true; - this.salvageRateLabel.Location = new System.Drawing.Point(8, 176); + this.salvageRateLabel.Location = new System.Drawing.Point(10, 162); this.salvageRateLabel.Name = "salvageRateLabel"; this.salvageRateLabel.Size = new System.Drawing.Size(96, 16); - this.salvageRateLabel.TabIndex = 1; + this.salvageRateLabel.TabIndex = 2; this.salvageRateLabel.Text = "Salvage Rate:"; // // salvageRateBox // - this.salvageRateBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.salvageRateBox.Location = new System.Drawing.Point(106, 173); + this.salvageRateBox.Location = new System.Drawing.Point(108, 159); this.salvageRateBox.Name = "salvageRateBox"; this.salvageRateBox.Size = new System.Drawing.Size(50, 22); - this.salvageRateBox.TabIndex = 2; + this.salvageRateBox.TabIndex = 3; this.salvageRateBox.Text = "50"; // // salvageRatePercentLabel // - this.salvageRatePercentLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.salvageRatePercentLabel.AutoSize = true; - this.salvageRatePercentLabel.Location = new System.Drawing.Point(158, 176); + this.salvageRatePercentLabel.Location = new System.Drawing.Point(160, 162); this.salvageRatePercentLabel.Name = "salvageRatePercentLabel"; this.salvageRatePercentLabel.Size = new System.Drawing.Size(21, 16); - this.salvageRatePercentLabel.TabIndex = 3; + this.salvageRatePercentLabel.TabIndex = 4; this.salvageRatePercentLabel.Text = "%"; // + // buttonPanel + // + this.buttonPanel.Controls.Add(this.acceptButton); + this.buttonPanel.Controls.Add(this.cancelButton); + this.buttonPanel.Dock = System.Windows.Forms.DockStyle.Bottom; + this.buttonPanel.Location = new System.Drawing.Point(0, 506); + this.buttonPanel.Name = "buttonPanel"; + this.buttonPanel.Size = new System.Drawing.Size(580, 50); + this.buttonPanel.TabIndex = 5; + // + // acceptButton + // + this.acceptButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.acceptButton.DialogResult = System.Windows.Forms.DialogResult.OK; + this.acceptButton.Location = new System.Drawing.Point(376, 12); + this.acceptButton.Name = "acceptButton"; + this.acceptButton.Size = new System.Drawing.Size(90, 28); + this.acceptButton.TabIndex = 0; + this.acceptButton.Text = "Accept"; + this.acceptButton.UseVisualStyleBackColor = true; + // + // cancelButton + // + this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(474, 12); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(90, 28); + this.cancelButton.TabIndex = 1; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + // // AutoNestForm - // + // + this.AcceptButton = this.acceptButton; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; - this.ClientSize = new System.Drawing.Size(545, 385); - this.Controls.Add(this.plateOptionsPanel); - this.Controls.Add(this.bottomPanel1); - this.Controls.Add(this.dataGridView1); + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(580, 556); + this.Controls.Add(this.engineLabel); + this.Controls.Add(this.engineComboBox); + this.Controls.Add(this.partsGroup); + this.Controls.Add(this.optionsGroup); + this.Controls.Add(this.plateOptimizerGroup); + this.Controls.Add(this.buttonPanel); this.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; this.Name = "AutoNestForm"; this.ShowIcon = false; this.ShowInTaskbar = false; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "AutoNest"; - ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.plateOptionsGrid)).EndInit(); - this.bottomPanel1.ResumeLayout(false); - this.bottomPanel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.partsGrid)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.plateGrid)).EndInit(); + this.partsGroup.ResumeLayout(false); + this.partsGroup.PerformLayout(); + this.optionsGroup.ResumeLayout(false); + this.optionsGroup.PerformLayout(); + this.plateOptimizerGroup.ResumeLayout(false); + this.plateOptimizerGroup.PerformLayout(); + this.buttonPanel.ResumeLayout(false); this.ResumeLayout(false); - + this.PerformLayout(); } #endregion - private System.Windows.Forms.DataGridView dataGridView1; - private System.Windows.Forms.Button acceptButton; - private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.Label engineLabel; + private System.Windows.Forms.ComboBox engineComboBox; + private System.Windows.Forms.GroupBox partsGroup; + private System.Windows.Forms.DataGridView partsGrid; + private System.Windows.Forms.Label summaryLabel; + private System.Windows.Forms.GroupBox optionsGroup; private System.Windows.Forms.CheckBox createNewPlatesAsNeededBox; - private Controls.BottomPanel bottomPanel1; + private System.Windows.Forms.GroupBox plateOptimizerGroup; private System.Windows.Forms.CheckBox optimizePlateSizeBox; - private System.Windows.Forms.Panel plateOptionsPanel; - private System.Windows.Forms.DataGridView plateOptionsGrid; + private System.Windows.Forms.DataGridView plateGrid; private System.Windows.Forms.Label salvageRateLabel; private System.Windows.Forms.TextBox salvageRateBox; private System.Windows.Forms.Label salvageRatePercentLabel; + private System.Windows.Forms.Panel buttonPanel; + private System.Windows.Forms.Button acceptButton; + private System.Windows.Forms.Button cancelButton; } -} \ No newline at end of file +} diff --git a/OpenNest/Forms/AutoNestForm.cs b/OpenNest/Forms/AutoNestForm.cs index 6a15581..bdf1391 100644 --- a/OpenNest/Forms/AutoNestForm.cs +++ b/OpenNest/Forms/AutoNestForm.cs @@ -1,20 +1,34 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Text.RegularExpressions; using System.Windows.Forms; +using OpenNest.Engine; namespace OpenNest.Forms { public partial class AutoNestForm : Form { + private static readonly Regex SizePattern = new(@"^(\d+\.?\d*)\s*[xX×]\s*(\d+\.?\d*)$"); + public AutoNestForm(Nest nest) { InitializeComponent(); + SetupPartsGrid(); + SetupPlateGrid(); + LoadEngines(); LoadDrawings(nest); - - dataGridView1.DataError += dataGridView1_DataError; LoadDefaultPlateOptions(); + SetPlateOptimizerVisible(false); + + partsGrid.DataError += PartsGrid_DataError; + } + + public string EngineName + { + get { return engineComboBox.SelectedItem as string; } + set { engineComboBox.SelectedItem = value; } } public bool AllowPlateCreation @@ -40,86 +54,102 @@ namespace OpenNest.Forms set { salvageRateBox.Text = (value * 100).ToString("F0"); } } - public List GetPlateOptions() + private void LoadEngines() { - var result = new List(); - var gridItems = plateOptionsGrid.DataSource as List; - if (gridItems == null) return result; - - foreach (var item in gridItems) - { - if (item.Width <= 0 || item.Length <= 0) continue; - result.Add(new PlateOption - { - Width = item.Width, - Length = item.Length, - Cost = item.Cost, - }); - } - - return result; + foreach (var engine in NestEngineRegistry.AvailableEngines) + engineComboBox.Items.Add(engine.Name); + engineComboBox.SelectedItem = NestEngineRegistry.ActiveEngineName; } - private void LoadDefaultPlateOptions() + private void SetupPartsGrid() { - var items = new List + partsGrid.Columns.Add(new DataGridViewTextBoxColumn { - new() { Width = 48, Length = 96, Cost = 0 }, - new() { Width = 48, Length = 120, Cost = 0 }, - new() { Width = 48, Length = 144, Cost = 0 }, - new() { Width = 60, Length = 96, Cost = 0 }, - new() { Width = 60, Length = 120, Cost = 0 }, - new() { Width = 60, Length = 144, Cost = 0 }, - new() { Width = 72, Length = 96, Cost = 0 }, - new() { Width = 72, Length = 120, Cost = 0 }, - new() { Width = 72, Length = 144, Cost = 0 }, + DataPropertyName = "DrawingName", + HeaderText = "Drawing Name", + Width = 160, + ReadOnly = true, + AutoSizeMode = DataGridViewAutoSizeColumnMode.None, + }); + partsGrid.Columns.Add(new DataGridViewTextBoxColumn + { + DataPropertyName = "Quantity", + HeaderText = "Qty", + Width = 50, + AutoSizeMode = DataGridViewAutoSizeColumnMode.None, + }); + partsGrid.Columns.Add(new DataGridViewTextBoxColumn + { + DataPropertyName = "Priority", + HeaderText = "Priority", + Width = 55, + AutoSizeMode = DataGridViewAutoSizeColumnMode.None, + }); + partsGrid.Columns.Add(new DataGridViewTextBoxColumn + { + DataPropertyName = "RotationStart", + HeaderText = "Rot Start", + Width = 65, + AutoSizeMode = DataGridViewAutoSizeColumnMode.None, + }); + partsGrid.Columns.Add(new DataGridViewTextBoxColumn + { + DataPropertyName = "RotationEnd", + HeaderText = "Rot End", + Width = 60, + AutoSizeMode = DataGridViewAutoSizeColumnMode.None, + }); + partsGrid.Columns.Add(new DataGridViewTextBoxColumn + { + DataPropertyName = "StepAngle", + HeaderText = "Step", + Width = 55, + AutoSizeMode = DataGridViewAutoSizeColumnMode.None, + }); + + partsGrid.CellValueChanged += PartsGrid_CellValueChanged; + partsGrid.CurrentCellDirtyStateChanged += (s, e) => + { + if (partsGrid.IsCurrentCellDirty) + partsGrid.CommitEdit(DataGridViewDataErrorContexts.Commit); }; - plateOptionsGrid.DataSource = items; } - public void LoadPlateOptions(List options, double salvageRate) + private void SetupPlateGrid() { - if (options != null && options.Count > 0) + plateGrid.Columns.Add(new DataGridViewTextBoxColumn { - var items = options.Select(o => new PlateOptionItem - { - Width = o.Width, - Length = o.Length, - Cost = o.Cost, - }).ToList(); - plateOptionsGrid.DataSource = items; - optimizePlateSizeBox.Checked = true; - } - SalvageRate = salvageRate; - } + DataPropertyName = "Size", + HeaderText = "Size", + Width = 120, + AutoSizeMode = DataGridViewAutoSizeColumnMode.None, + }); + plateGrid.Columns.Add(new DataGridViewTextBoxColumn + { + DataPropertyName = "Cost", + HeaderText = "Cost", + Width = 70, + AutoSizeMode = DataGridViewAutoSizeColumnMode.None, + }); - private void optimizePlateSizeBox_CheckedChanged(object sender, EventArgs e) - { - plateOptionsPanel.Visible = optimizePlateSizeBox.Checked; - } - - internal class PlateOptionItem - { - public double Width { get; set; } - public double Length { get; set; } - public double Cost { get; set; } + plateGrid.CellValidating += PlateGrid_CellValidating; } private void LoadDrawings(Nest nest) { var items = new List(); - dataGridView1.Rows.Clear(); foreach (var drawing in nest.Drawings) items.Add(GetDataGridViewItem(drawing)); - dataGridView1.DataSource = items; + partsGrid.DataSource = items; + UpdateSummary(); } public List GetNestItems() { var nestItems = new List(); - var gridItems = dataGridView1.DataSource as List; + var gridItems = partsGrid.DataSource as List; if (gridItems == null) return nestItems; @@ -143,6 +173,139 @@ namespace OpenNest.Forms return nestItems; } + public List GetPlateOptions() + { + var result = new List(); + var gridItems = plateGrid.DataSource as List; + if (gridItems == null) return result; + + foreach (var item in gridItems) + { + if (!TryParseSize(item.Size, out var width, out var length)) + continue; + if (width <= 0 || length <= 0) + continue; + + result.Add(new PlateOption + { + Width = width, + Length = length, + Cost = item.Cost, + }); + } + + return result; + } + + public void LoadPlateOptions(List options, double salvageRate) + { + if (options != null && options.Count > 0) + { + var items = options.Select(o => new PlateOptionItem + { + Size = FormatSize(o.Width, o.Length), + Cost = o.Cost, + }).ToList(); + plateGrid.DataSource = items; + optimizePlateSizeBox.Checked = true; + } + SalvageRate = salvageRate; + } + + private void LoadDefaultPlateOptions() + { + var items = new List + { + new() { Size = "48 x 96", Cost = 0 }, + new() { Size = "48 x 120", Cost = 0 }, + new() { Size = "48 x 144", Cost = 0 }, + new() { Size = "60 x 96", Cost = 0 }, + new() { Size = "60 x 120", Cost = 0 }, + new() { Size = "60 x 144", Cost = 0 }, + new() { Size = "72 x 96", Cost = 0 }, + new() { Size = "72 x 120", Cost = 0 }, + new() { Size = "72 x 144", Cost = 0 }, + }; + plateGrid.DataSource = items; + } + + private void optimizePlateSizeBox_CheckedChanged(object sender, EventArgs e) + { + SetPlateOptimizerVisible(optimizePlateSizeBox.Checked); + } + + private void SetPlateOptimizerVisible(bool visible) + { + plateGrid.Visible = visible; + salvageRateLabel.Visible = visible; + salvageRateBox.Visible = visible; + salvageRatePercentLabel.Visible = visible; + } + + private void UpdateSummary() + { + var gridItems = partsGrid.DataSource as List; + if (gridItems == null) + { + summaryLabel.Text = ""; + return; + } + + var totalQty = gridItems.Sum(i => System.Math.Max(0, i.Quantity)); + var drawingCount = gridItems.Count(i => i.Quantity > 0); + summaryLabel.Text = $"{totalQty} parts across {drawingCount} drawings"; + } + + private void PartsGrid_CellValueChanged(object sender, DataGridViewCellEventArgs e) + { + if (e.RowIndex < 0) return; + if (partsGrid.Columns[e.ColumnIndex].DataPropertyName == "Quantity") + UpdateSummary(); + } + + private void PlateGrid_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) + { + if (plateGrid.Columns[e.ColumnIndex].DataPropertyName != "Size") + return; + + var value = e.FormattedValue?.ToString(); + if (string.IsNullOrWhiteSpace(value)) + return; + + if (!TryParseSize(value, out _, out _)) + { + e.Cancel = true; + plateGrid.Rows[e.RowIndex].ErrorText = "Enter size as W x L (e.g. 48 x 96)"; + } + else + { + plateGrid.Rows[e.RowIndex].ErrorText = ""; + } + } + + private static bool TryParseSize(string value, out double width, out double length) + { + width = 0; + length = 0; + if (string.IsNullOrWhiteSpace(value)) return false; + var match = SizePattern.Match(value.Trim()); + if (!match.Success) return false; + width = double.Parse(match.Groups[1].Value, System.Globalization.CultureInfo.InvariantCulture); + length = double.Parse(match.Groups[2].Value, System.Globalization.CultureInfo.InvariantCulture); + return true; + } + + private static string FormatSize(double width, double length) + { + return $"{width:G} x {length:G}"; + } + + private void PartsGrid_DataError(object sender, DataGridViewDataErrorEventArgs e) + { + MessageBox.Show("Invalid input. Expected input type is " + + partsGrid[e.ColumnIndex, e.RowIndex].ValueType.Name); + } + private DataGridViewItem GetDataGridViewItem(Drawing dwg) { var item = new DataGridViewItem(); @@ -156,11 +319,6 @@ namespace OpenNest.Forms return item; } - private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e) - { - MessageBox.Show("Invalid input. Expected input type is " + dataGridView1[e.ColumnIndex, e.RowIndex].ValueType.Name); - } - private class DataGridViewItem { internal Drawing RefDrawing { get; set; } @@ -177,17 +335,20 @@ namespace OpenNest.Forms public int Priority { get; set; } - [Browsable(false)] // hide until implemented - [DisplayName("Rotation Start")] + [DisplayName("Rot Start")] public double RotationStart { get; set; } - [Browsable(false)] // hide until implemented - [DisplayName("Rotation End")] + [DisplayName("Rot End")] public double RotationEnd { get; set; } - [Browsable(false)] // hide until implemented - [DisplayName("Step Angle")] + [DisplayName("Step")] public double StepAngle { get; set; } } + + private class PlateOptionItem + { + public string Size { get; set; } + public double Cost { get; set; } + } } } diff --git a/OpenNest/Forms/MainForm.cs b/OpenNest/Forms/MainForm.cs index 9f1b71c..525bd3c 100644 --- a/OpenNest/Forms/MainForm.cs +++ b/OpenNest/Forms/MainForm.cs @@ -906,6 +906,12 @@ namespace OpenNest.Forms if (form.ShowDialog() != System.Windows.Forms.DialogResult.OK) return; + if (form.EngineName != null) + { + NestEngineRegistry.ActiveEngineName = form.EngineName; + engineComboBox.SelectedItem = form.EngineName; + } + var items = form.GetNestItems(); if (!items.Any(it => it.Quantity > 0))