fix(ui): PatternTileForm layout, orientation, and dropdown display

Move PlateViews and labels to designer file so they show in VS.
Fix nest orientation by swapping Box(Width,Length) to Box(Length,Width)
matching plate convention (Length=X, Width=Y). Add ComboBox Format
handler to show Drawing.Name. Zoom to fit after moving parts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-18 22:48:19 -04:00
parent 0472c12113
commit 62ec6484c8
3 changed files with 507 additions and 199 deletions

View File

@@ -13,140 +13,368 @@ namespace OpenNest.Forms
private void InitializeComponent()
{
this.topPanel = new System.Windows.Forms.FlowLayoutPanel();
this.lblDrawingA = new System.Windows.Forms.Label();
this.cboDrawingA = new System.Windows.Forms.ComboBox();
this.lblDrawingB = new System.Windows.Forms.Label();
this.cboDrawingB = new System.Windows.Forms.ComboBox();
this.lblPlateSize = new System.Windows.Forms.Label();
this.txtPlateSize = new System.Windows.Forms.TextBox();
this.lblPartSpacing = new System.Windows.Forms.Label();
this.nudPartSpacing = new System.Windows.Forms.NumericUpDown();
this.btnAutoArrange = new System.Windows.Forms.Button();
this.btnApply = new System.Windows.Forms.Button();
this.splitContainer = new System.Windows.Forms.SplitContainer();
this.topPanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.nudPartSpacing)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
this.splitContainer.SuspendLayout();
this.SuspendLayout();
//
ColorScheme colorScheme1 = new ColorScheme();
Plate plate1 = new Plate();
Material material1 = new Material();
Collections.ObservableList<Part> observableList_11 = new Collections.ObservableList<Part>();
Plate plate2 = new Plate();
Material material2 = new Material();
Collections.ObservableList<Part> observableList_12 = new Collections.ObservableList<Part>();
Plate plate3 = new Plate();
Material material3 = new Material();
Collections.ObservableList<Part> observableList_13 = new Collections.ObservableList<Part>();
topPanel = new System.Windows.Forms.FlowLayoutPanel();
lblDrawingA = new System.Windows.Forms.Label();
cboDrawingA = new System.Windows.Forms.ComboBox();
lblDrawingB = new System.Windows.Forms.Label();
cboDrawingB = new System.Windows.Forms.ComboBox();
lblPlateSize = new System.Windows.Forms.Label();
txtPlateSize = new System.Windows.Forms.TextBox();
lblPartSpacing = new System.Windows.Forms.Label();
nudPartSpacing = new System.Windows.Forms.NumericUpDown();
btnAutoArrange = new System.Windows.Forms.Button();
btnApply = new System.Windows.Forms.Button();
splitContainer = new System.Windows.Forms.SplitContainer();
cellView = new OpenNest.Controls.PlateView();
splitContainer1 = new System.Windows.Forms.SplitContainer();
hPreview = new OpenNest.Controls.PlateView();
hLabel = new System.Windows.Forms.Label();
vPreview = new OpenNest.Controls.PlateView();
vLabel = new System.Windows.Forms.Label();
topPanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)nudPartSpacing).BeginInit();
((System.ComponentModel.ISupportInitialize)splitContainer).BeginInit();
splitContainer.Panel1.SuspendLayout();
splitContainer.Panel2.SuspendLayout();
splitContainer.SuspendLayout();
((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit();
splitContainer1.Panel1.SuspendLayout();
splitContainer1.Panel2.SuspendLayout();
splitContainer1.SuspendLayout();
SuspendLayout();
//
// topPanel
//
this.topPanel.Controls.Add(this.lblDrawingA);
this.topPanel.Controls.Add(this.cboDrawingA);
this.topPanel.Controls.Add(this.lblDrawingB);
this.topPanel.Controls.Add(this.cboDrawingB);
this.topPanel.Controls.Add(this.lblPlateSize);
this.topPanel.Controls.Add(this.txtPlateSize);
this.topPanel.Controls.Add(this.lblPartSpacing);
this.topPanel.Controls.Add(this.nudPartSpacing);
this.topPanel.Controls.Add(this.btnAutoArrange);
this.topPanel.Controls.Add(this.btnApply);
this.topPanel.Dock = System.Windows.Forms.DockStyle.Top;
this.topPanel.Height = 36;
this.topPanel.Name = "topPanel";
this.topPanel.WrapContents = false;
this.topPanel.Padding = new System.Windows.Forms.Padding(4, 2, 4, 2);
//
//
topPanel.Controls.Add(lblDrawingA);
topPanel.Controls.Add(cboDrawingA);
topPanel.Controls.Add(lblDrawingB);
topPanel.Controls.Add(cboDrawingB);
topPanel.Controls.Add(lblPlateSize);
topPanel.Controls.Add(txtPlateSize);
topPanel.Controls.Add(lblPartSpacing);
topPanel.Controls.Add(nudPartSpacing);
topPanel.Controls.Add(btnAutoArrange);
topPanel.Controls.Add(btnApply);
topPanel.Dock = System.Windows.Forms.DockStyle.Top;
topPanel.Location = new System.Drawing.Point(0, 0);
topPanel.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
topPanel.Name = "topPanel";
topPanel.Padding = new System.Windows.Forms.Padding(5, 2, 5, 2);
topPanel.Size = new System.Drawing.Size(1220, 42);
topPanel.TabIndex = 2;
topPanel.WrapContents = false;
//
// lblDrawingA
//
this.lblDrawingA.AutoSize = true;
this.lblDrawingA.Margin = new System.Windows.Forms.Padding(3, 5, 0, 0);
this.lblDrawingA.Name = "lblDrawingA";
this.lblDrawingA.Text = "Drawing A:";
//
//
lblDrawingA.AutoSize = true;
lblDrawingA.Location = new System.Drawing.Point(9, 8);
lblDrawingA.Margin = new System.Windows.Forms.Padding(4, 6, 0, 0);
lblDrawingA.Name = "lblDrawingA";
lblDrawingA.Size = new System.Drawing.Size(65, 15);
lblDrawingA.TabIndex = 0;
lblDrawingA.Text = "Drawing A:";
//
// cboDrawingA
//
this.cboDrawingA.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboDrawingA.Margin = new System.Windows.Forms.Padding(3, 3, 0, 0);
this.cboDrawingA.Name = "cboDrawingA";
this.cboDrawingA.Width = 130;
//
//
cboDrawingA.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
cboDrawingA.Location = new System.Drawing.Point(78, 5);
cboDrawingA.Margin = new System.Windows.Forms.Padding(4, 3, 0, 0);
cboDrawingA.Name = "cboDrawingA";
cboDrawingA.Size = new System.Drawing.Size(151, 23);
cboDrawingA.TabIndex = 1;
//
// lblDrawingB
//
this.lblDrawingB.AutoSize = true;
this.lblDrawingB.Margin = new System.Windows.Forms.Padding(10, 5, 0, 0);
this.lblDrawingB.Name = "lblDrawingB";
this.lblDrawingB.Text = "Drawing B:";
//
//
lblDrawingB.AutoSize = true;
lblDrawingB.Location = new System.Drawing.Point(241, 8);
lblDrawingB.Margin = new System.Windows.Forms.Padding(12, 6, 0, 0);
lblDrawingB.Name = "lblDrawingB";
lblDrawingB.Size = new System.Drawing.Size(64, 15);
lblDrawingB.TabIndex = 2;
lblDrawingB.Text = "Drawing B:";
//
// cboDrawingB
//
this.cboDrawingB.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboDrawingB.Margin = new System.Windows.Forms.Padding(3, 3, 0, 0);
this.cboDrawingB.Name = "cboDrawingB";
this.cboDrawingB.Width = 130;
//
//
cboDrawingB.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
cboDrawingB.Location = new System.Drawing.Point(309, 5);
cboDrawingB.Margin = new System.Windows.Forms.Padding(4, 3, 0, 0);
cboDrawingB.Name = "cboDrawingB";
cboDrawingB.Size = new System.Drawing.Size(151, 23);
cboDrawingB.TabIndex = 3;
//
// lblPlateSize
//
this.lblPlateSize.AutoSize = true;
this.lblPlateSize.Margin = new System.Windows.Forms.Padding(10, 5, 0, 0);
this.lblPlateSize.Name = "lblPlateSize";
this.lblPlateSize.Text = "Plate:";
//
//
lblPlateSize.AutoSize = true;
lblPlateSize.Location = new System.Drawing.Point(472, 8);
lblPlateSize.Margin = new System.Windows.Forms.Padding(12, 6, 0, 0);
lblPlateSize.Name = "lblPlateSize";
lblPlateSize.Size = new System.Drawing.Size(36, 15);
lblPlateSize.TabIndex = 4;
lblPlateSize.Text = "Plate:";
//
// txtPlateSize
//
this.txtPlateSize.Margin = new System.Windows.Forms.Padding(3, 3, 0, 0);
this.txtPlateSize.Name = "txtPlateSize";
this.txtPlateSize.Width = 90;
//
//
txtPlateSize.Location = new System.Drawing.Point(512, 5);
txtPlateSize.Margin = new System.Windows.Forms.Padding(4, 3, 0, 0);
txtPlateSize.Name = "txtPlateSize";
txtPlateSize.Size = new System.Drawing.Size(104, 23);
txtPlateSize.TabIndex = 5;
//
// lblPartSpacing
//
this.lblPartSpacing.AutoSize = true;
this.lblPartSpacing.Margin = new System.Windows.Forms.Padding(10, 5, 0, 0);
this.lblPartSpacing.Name = "lblPartSpacing";
this.lblPartSpacing.Text = "Spacing:";
//
//
lblPartSpacing.AutoSize = true;
lblPartSpacing.Location = new System.Drawing.Point(628, 8);
lblPartSpacing.Margin = new System.Windows.Forms.Padding(12, 6, 0, 0);
lblPartSpacing.Name = "lblPartSpacing";
lblPartSpacing.Size = new System.Drawing.Size(52, 15);
lblPartSpacing.TabIndex = 6;
lblPartSpacing.Text = "Spacing:";
//
// nudPartSpacing
//
this.nudPartSpacing.DecimalPlaces = 2;
this.nudPartSpacing.Increment = new decimal(new int[] { 25, 0, 0, 131072 });
this.nudPartSpacing.Maximum = new decimal(new int[] { 100, 0, 0, 0 });
this.nudPartSpacing.Minimum = new decimal(new int[] { 0, 0, 0, 0 });
this.nudPartSpacing.Margin = new System.Windows.Forms.Padding(3, 3, 0, 0);
this.nudPartSpacing.Name = "nudPartSpacing";
this.nudPartSpacing.Width = 70;
//
//
nudPartSpacing.DecimalPlaces = 2;
nudPartSpacing.Increment = new decimal(new int[] { 25, 0, 0, 131072 });
nudPartSpacing.Location = new System.Drawing.Point(684, 5);
nudPartSpacing.Margin = new System.Windows.Forms.Padding(4, 3, 0, 0);
nudPartSpacing.Name = "nudPartSpacing";
nudPartSpacing.Size = new System.Drawing.Size(82, 23);
nudPartSpacing.TabIndex = 7;
//
// btnAutoArrange
//
this.btnAutoArrange.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnAutoArrange.Margin = new System.Windows.Forms.Padding(10, 3, 0, 0);
this.btnAutoArrange.Name = "btnAutoArrange";
this.btnAutoArrange.Size = new System.Drawing.Size(100, 26);
this.btnAutoArrange.Text = "Auto Arrange";
//
//
btnAutoArrange.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
btnAutoArrange.Location = new System.Drawing.Point(778, 5);
btnAutoArrange.Margin = new System.Windows.Forms.Padding(12, 3, 0, 0);
btnAutoArrange.Name = "btnAutoArrange";
btnAutoArrange.Size = new System.Drawing.Size(117, 30);
btnAutoArrange.TabIndex = 8;
btnAutoArrange.Text = "Auto Arrange";
//
// btnApply
//
this.btnApply.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnApply.Margin = new System.Windows.Forms.Padding(6, 3, 0, 0);
this.btnApply.Name = "btnApply";
this.btnApply.Size = new System.Drawing.Size(80, 26);
this.btnApply.Text = "Apply";
//
//
btnApply.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
btnApply.Location = new System.Drawing.Point(902, 5);
btnApply.Margin = new System.Windows.Forms.Padding(7, 3, 0, 0);
btnApply.Name = "btnApply";
btnApply.Size = new System.Drawing.Size(93, 30);
btnApply.TabIndex = 9;
btnApply.Text = "Apply";
//
// splitContainer
//
this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer.Name = "splitContainer";
this.splitContainer.SplitterDistance = 350;
this.splitContainer.TabIndex = 1;
//
//
splitContainer.Dock = System.Windows.Forms.DockStyle.Fill;
splitContainer.Location = new System.Drawing.Point(0, 42);
splitContainer.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
splitContainer.Name = "splitContainer";
//
// splitContainer.Panel1
//
splitContainer.Panel1.Controls.Add(cellView);
//
// splitContainer.Panel2
//
splitContainer.Panel2.Controls.Add(splitContainer1);
splitContainer.Size = new System.Drawing.Size(1220, 677);
splitContainer.SplitterDistance = 610;
splitContainer.SplitterWidth = 5;
splitContainer.TabIndex = 1;
//
// cellView
//
cellView.ActiveWorkArea = null;
cellView.AllowDrop = true;
cellView.AllowPan = true;
cellView.AllowSelect = true;
cellView.AllowZoom = true;
cellView.BackColor = System.Drawing.Color.DarkGray;
colorScheme1.BackgroundColor = System.Drawing.Color.DarkGray;
colorScheme1.BoundingBoxColor = System.Drawing.Color.FromArgb(128, 128, 255);
colorScheme1.EdgeSpacingColor = System.Drawing.Color.FromArgb(180, 180, 180);
colorScheme1.LayoutFillColor = System.Drawing.Color.WhiteSmoke;
colorScheme1.LayoutOutlineColor = System.Drawing.Color.Gray;
colorScheme1.OriginColor = System.Drawing.Color.Gray;
colorScheme1.PreviewPartColor = System.Drawing.Color.FromArgb(255, 140, 0);
colorScheme1.RapidColor = System.Drawing.Color.DodgerBlue;
cellView.ColorScheme = colorScheme1;
cellView.DebugRemnantPriorities = null;
cellView.DebugRemnants = null;
cellView.Dock = System.Windows.Forms.DockStyle.Fill;
cellView.DrawBounds = false;
cellView.DrawOffset = false;
cellView.DrawOrigin = false;
cellView.DrawRapid = false;
cellView.FillParts = true;
cellView.Location = new System.Drawing.Point(0, 0);
cellView.Name = "cellView";
cellView.OffsetIncrementDistance = 10D;
cellView.OffsetTolerance = 0.001D;
material1.Density = 0D;
material1.Grade = null;
material1.Name = null;
plate1.Material = material1;
plate1.Parts = observableList_11;
plate1.PartSpacing = 0D;
plate1.Quadrant = 1;
plate1.Quantity = 0;
plate1.Thickness = 0D;
cellView.Plate = plate1;
cellView.RotateIncrementAngle = 10D;
cellView.Size = new System.Drawing.Size(610, 677);
cellView.Status = "Select";
cellView.TabIndex = 0;
//
// splitContainer1
//
splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
splitContainer1.IsSplitterFixed = true;
splitContainer1.Location = new System.Drawing.Point(0, 0);
splitContainer1.Name = "splitContainer1";
splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
//
// splitContainer1.Panel1
//
splitContainer1.Panel1.Controls.Add(hPreview);
splitContainer1.Panel1.Controls.Add(hLabel);
//
// splitContainer1.Panel2
//
splitContainer1.Panel2.Controls.Add(vPreview);
splitContainer1.Panel2.Controls.Add(vLabel);
splitContainer1.Size = new System.Drawing.Size(605, 677);
splitContainer1.SplitterDistance = 333;
splitContainer1.TabIndex = 0;
//
// hPreview
//
hPreview.ActiveWorkArea = null;
hPreview.AllowPan = true;
hPreview.AllowSelect = false;
hPreview.AllowZoom = true;
hPreview.BackColor = System.Drawing.Color.DarkGray;
hPreview.ColorScheme = colorScheme1;
hPreview.DebugRemnantPriorities = null;
hPreview.DebugRemnants = null;
hPreview.Dock = System.Windows.Forms.DockStyle.Fill;
hPreview.DrawBounds = false;
hPreview.DrawOffset = false;
hPreview.DrawOrigin = true;
hPreview.DrawRapid = false;
hPreview.FillParts = true;
hPreview.Location = new System.Drawing.Point(0, 20);
hPreview.Name = "hPreview";
hPreview.OffsetIncrementDistance = 10D;
hPreview.OffsetTolerance = 0.001D;
material2.Density = 0D;
material2.Grade = null;
material2.Name = null;
plate2.Material = material2;
plate2.Parts = observableList_12;
plate2.PartSpacing = 0D;
plate2.Quadrant = 1;
plate2.Quantity = 0;
plate2.Thickness = 0D;
hPreview.Plate = plate2;
hPreview.RotateIncrementAngle = 10D;
hPreview.Size = new System.Drawing.Size(605, 313);
hPreview.Status = "Select";
hPreview.TabIndex = 0;
//
// hLabel
//
hLabel.Dock = System.Windows.Forms.DockStyle.Top;
hLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
hLabel.ForeColor = System.Drawing.Color.FromArgb(80, 80, 80);
hLabel.Location = new System.Drawing.Point(0, 0);
hLabel.Name = "hLabel";
hLabel.Padding = new System.Windows.Forms.Padding(4, 0, 0, 0);
hLabel.Size = new System.Drawing.Size(605, 20);
hLabel.TabIndex = 1;
hLabel.Text = "Horizontal — 0 parts";
hLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// vPreview
//
vPreview.ActiveWorkArea = null;
vPreview.AllowPan = true;
vPreview.AllowSelect = false;
vPreview.AllowZoom = true;
vPreview.BackColor = System.Drawing.Color.DarkGray;
vPreview.ColorScheme = colorScheme1;
vPreview.DebugRemnantPriorities = null;
vPreview.DebugRemnants = null;
vPreview.Dock = System.Windows.Forms.DockStyle.Fill;
vPreview.DrawBounds = false;
vPreview.DrawOffset = false;
vPreview.DrawOrigin = true;
vPreview.DrawRapid = false;
vPreview.FillParts = true;
vPreview.Location = new System.Drawing.Point(0, 20);
vPreview.Name = "vPreview";
vPreview.OffsetIncrementDistance = 10D;
vPreview.OffsetTolerance = 0.001D;
material3.Density = 0D;
material3.Grade = null;
material3.Name = null;
plate3.Material = material3;
plate3.Parts = observableList_13;
plate3.PartSpacing = 0D;
plate3.Quadrant = 1;
plate3.Quantity = 0;
plate3.Thickness = 0D;
vPreview.Plate = plate3;
vPreview.RotateIncrementAngle = 10D;
vPreview.Size = new System.Drawing.Size(605, 320);
vPreview.Status = "Select";
vPreview.TabIndex = 0;
//
// vLabel
//
vLabel.Dock = System.Windows.Forms.DockStyle.Top;
vLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
vLabel.ForeColor = System.Drawing.Color.FromArgb(80, 80, 80);
vLabel.Location = new System.Drawing.Point(0, 0);
vLabel.Name = "vLabel";
vLabel.Padding = new System.Windows.Forms.Padding(4, 0, 0, 0);
vLabel.Size = new System.Drawing.Size(605, 20);
vLabel.TabIndex = 1;
vLabel.Text = "Vertical — 0 parts";
vLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// PatternTileForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(900, 550);
this.Controls.Add(this.splitContainer);
this.Controls.Add(this.topPanel);
this.MinimumSize = new System.Drawing.Size(700, 400);
this.Name = "PatternTileForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Pattern Tile";
this.topPanel.ResumeLayout(false);
this.topPanel.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.nudPartSpacing)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit();
this.splitContainer.ResumeLayout(false);
this.ResumeLayout(false);
//
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
ClientSize = new System.Drawing.Size(1220, 719);
Controls.Add(splitContainer);
Controls.Add(topPanel);
Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
MinimumSize = new System.Drawing.Size(814, 456);
Name = "PatternTileForm";
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
Text = "Pattern Tile";
WindowState = System.Windows.Forms.FormWindowState.Maximized;
topPanel.ResumeLayout(false);
topPanel.PerformLayout();
((System.ComponentModel.ISupportInitialize)nudPartSpacing).EndInit();
splitContainer.Panel1.ResumeLayout(false);
splitContainer.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)splitContainer).EndInit();
splitContainer.ResumeLayout(false);
splitContainer1.Panel1.ResumeLayout(false);
splitContainer1.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit();
splitContainer1.ResumeLayout(false);
ResumeLayout(false);
}
private System.Windows.Forms.FlowLayoutPanel topPanel;
@@ -161,5 +389,11 @@ namespace OpenNest.Forms
private System.Windows.Forms.Button btnAutoArrange;
private System.Windows.Forms.Button btnApply;
private System.Windows.Forms.SplitContainer splitContainer;
private OpenNest.Controls.PlateView cellView;
private System.Windows.Forms.SplitContainer splitContainer1;
private OpenNest.Controls.PlateView hPreview;
private System.Windows.Forms.Label hLabel;
private OpenNest.Controls.PlateView vPreview;
private System.Windows.Forms.Label vLabel;
}
}

View File

@@ -1,4 +1,3 @@
using OpenNest.Controls;
using OpenNest.Engine.Fill;
using OpenNest.Geometry;
using System;
@@ -9,27 +8,9 @@ using GeoSize = OpenNest.Geometry.Size;
namespace OpenNest.Forms
{
public enum PatternTileTarget
{
CurrentPlate,
NewPlate
}
public class PatternTileResult
{
public List<Part> Parts { get; set; }
public PatternTileTarget Target { get; set; }
public GeoSize PlateSize { get; set; }
}
public partial class PatternTileForm : Form
{
private readonly Nest nest;
private readonly PlateView cellView;
private readonly PlateView hPreview;
private readonly PlateView vPreview;
private readonly Label hLabel;
private readonly Label vLabel;
public PatternTileResult Result { get; private set; }
@@ -38,53 +19,11 @@ namespace OpenNest.Forms
this.nest = nest;
InitializeComponent();
// Unit cell editor — plate outline hidden via zero-size plate
cellView = new PlateView();
// Hide plate outline via zero-size plate
cellView.Plate.Size = new GeoSize(0, 0);
cellView.Plate.Quantity = 0; // prevent Drawing.Quantity.Nested side-effects
cellView.DrawOrigin = false;
cellView.DrawBounds = false; // hide selection bounding box overlay
cellView.Dock = DockStyle.Fill;
splitContainer.Panel1.Controls.Add(cellView);
// Right side: vertical split with horizontal and vertical preview
var previewSplit = new SplitContainer
{
Dock = DockStyle.Fill,
Orientation = Orientation.Horizontal,
SplitterDistance = 250
};
splitContainer.Panel2.Controls.Add(previewSplit);
hLabel = new Label
{
Dock = DockStyle.Top,
Height = 20,
Text = "Horizontal — 0 parts",
TextAlign = System.Drawing.ContentAlignment.MiddleLeft,
Font = new System.Drawing.Font("Segoe UI", 9f, System.Drawing.FontStyle.Bold),
ForeColor = System.Drawing.Color.FromArgb(80, 80, 80),
Padding = new Padding(4, 0, 0, 0)
};
hPreview = CreatePreviewView();
previewSplit.Panel1.Controls.Add(hPreview);
previewSplit.Panel1.Controls.Add(hLabel);
vLabel = new Label
{
Dock = DockStyle.Top,
Height = 20,
Text = "Vertical — 0 parts",
TextAlign = System.Drawing.ContentAlignment.MiddleLeft,
Font = new System.Drawing.Font("Segoe UI", 9f, System.Drawing.FontStyle.Bold),
ForeColor = System.Drawing.Color.FromArgb(80, 80, 80),
Padding = new Padding(4, 0, 0, 0)
};
vPreview = CreatePreviewView();
previewSplit.Panel2.Controls.Add(vPreview);
previewSplit.Panel2.Controls.Add(vLabel);
cellView.Plate.Quantity = 0;
hPreview.Plate.Quantity = 0;
vPreview.Plate.Quantity = 0;
// Populate drawing dropdowns
var drawings = nest.Drawings.OrderBy(d => d.Name).ToList();
@@ -103,6 +42,12 @@ namespace OpenNest.Forms
txtPlateSize.Text = defaults.Size.ToString();
nudPartSpacing.Value = (decimal)defaults.PartSpacing;
// Format drawing names in dropdowns
cboDrawingA.FormattingEnabled = true;
cboDrawingA.Format += ComboDrawing_Format;
cboDrawingB.FormattingEnabled = true;
cboDrawingB.Format += ComboDrawing_Format;
// Wire events
cboDrawingA.SelectedIndexChanged += OnDrawingChanged;
cboDrawingB.SelectedIndexChanged += OnDrawingChanged;
@@ -113,6 +58,12 @@ namespace OpenNest.Forms
cellView.MouseUp += OnCellMouseUp;
}
private void ComboDrawing_Format(object sender, ListControlConvertEventArgs e)
{
if (e.Value is Drawing d)
e.Value = d.Name;
}
private Drawing SelectedDrawingA =>
cboDrawingA.SelectedItem as Drawing;
@@ -145,6 +96,7 @@ namespace OpenNest.Forms
if (e.Button == MouseButtons.Left && cellView.Plate.Parts.Count >= 2)
{
CompactCellParts();
cellView.ZoomToFit();
}
RebuildPreview();
@@ -228,17 +180,6 @@ namespace OpenNest.Forms
}
}
private static PlateView CreatePreviewView()
{
var view = new PlateView();
view.Plate.Quantity = 0;
view.AllowSelect = false;
view.AllowDrop = false;
view.DrawBounds = false;
view.Dock = DockStyle.Fill;
return view;
}
private void UpdatePreviewPlateSize()
{
if (!TryGetPlateSize(out var size))
@@ -278,7 +219,7 @@ namespace OpenNest.Forms
if (pattern == null)
return;
var workArea = new Box(0, 0, plateSize.Width, plateSize.Length);
var workArea = new Box(0, 0, plateSize.Length, plateSize.Width);
var filler = new FillLinear(workArea, PartSpacing);
var hParts = filler.Fill(pattern, NestDirection.Horizontal);
@@ -387,7 +328,7 @@ namespace OpenNest.Forms
if (pattern == null)
return;
var filler = new FillLinear(new Box(0, 0, plateSize.Width, plateSize.Length), PartSpacing);
var filler = new FillLinear(new Box(0, 0, plateSize.Length, plateSize.Width), PartSpacing);
var tiledParts = filler.Fill(pattern, applyDirection);
Result = new PatternTileResult
@@ -403,4 +344,17 @@ namespace OpenNest.Forms
Close();
}
}
public enum PatternTileTarget
{
CurrentPlate,
NewPlate
}
public class PatternTileResult
{
public List<Part> Parts { get; set; }
public PatternTileTarget Target { get; set; }
public GeoSize PlateSize { get; set; }
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>