fix: improve CadConverter sidebar layout and bend line visibility

Replace sidebar Panel+Splitter with SplitContainer for resizable file
list / filter panel. Sort file list alphabetically on insert. Widen bend
line dash spacing and draw ETCH layer entities on top of bend lines so
etch marks are visible.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 23:51:21 -04:00
parent 1ffe904892
commit f208569e72
3 changed files with 193 additions and 131 deletions

View File

@@ -48,12 +48,20 @@ namespace OpenNest.Controls
foreach (var entity in Entities)
{
if (IsEtchLayer(entity.Layer)) continue;
var pen = GetEntityPen(entity.Color);
DrawEntity(e.Graphics, entity, pen);
}
DrawBendLines(e.Graphics);
foreach (var entity in Entities)
{
if (!IsEtchLayer(entity.Layer)) continue;
var pen = GetEntityPen(entity.Color);
DrawEntity(e.Graphics, entity, pen);
}
#if DRAW_OFFSET
var offsetShape = new Shape();
@@ -138,6 +146,9 @@ namespace OpenNest.Controls
penCache.Clear();
}
private static bool IsEtchLayer(Layer layer) =>
string.Equals(layer?.Name, "ETCH", System.StringComparison.OrdinalIgnoreCase);
private void DrawBendLines(Graphics g)
{
if (Bends == null || Bends.Count == 0)
@@ -145,11 +156,11 @@ namespace OpenNest.Controls
using var bendPen = new Pen(Color.Yellow, 1.5f)
{
DashStyle = DashStyle.Dash
DashPattern = new float[] { 8, 6 }
};
using var selectedPen = new Pen(Color.Cyan, 2.5f)
{
DashStyle = DashStyle.Dash
DashPattern = new float[] { 8, 6 }
};
for (var i = 0; i < Bends.Count; i++)

View File

@@ -62,12 +62,20 @@ namespace OpenNest.Controls
public void AddItem(FileListItem item)
{
items.Add(item);
var index = items.BinarySearch(item, Comparer<FileListItem>.Create(
(a, b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase)));
if (index < 0) index = ~index;
items.Insert(index, item);
if (items.Count == 1)
{
selectedIndex = 0;
SelectedIndexChanged?.Invoke(this, selectedIndex);
}
else if (selectedIndex >= 0 && index <= selectedIndex)
{
selectedIndex++;
}
Invalidate();
}

View File

@@ -15,10 +15,9 @@ namespace OpenNest.Forms
private void InitializeComponent()
{
sidebarPanel = new System.Windows.Forms.Panel();
sidebarSplit = new System.Windows.Forms.SplitContainer();
fileList = new OpenNest.Controls.FileListControl();
filterPanel = new OpenNest.Controls.FilterPanel();
splitterSidebar = new System.Windows.Forms.Splitter();
entityView1 = new OpenNest.Controls.EntityView();
detailBar = new System.Windows.Forms.FlowLayoutPanel();
lblQty = new System.Windows.Forms.Label();
@@ -33,204 +32,248 @@ namespace OpenNest.Forms
bottomPanel1 = new OpenNest.Controls.BottomPanel();
cancelButton = new System.Windows.Forms.Button();
acceptButton = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)sidebarSplit).BeginInit();
sidebarSplit.Panel1.SuspendLayout();
sidebarSplit.Panel2.SuspendLayout();
sidebarSplit.SuspendLayout();
detailBar.SuspendLayout();
((System.ComponentModel.ISupportInitialize)numQuantity).BeginInit();
sidebarPanel.SuspendLayout();
bottomPanel1.SuspendLayout();
SuspendLayout();
//
// sidebarPanel (Left dock — contains file list + filter panel)
//
sidebarPanel.Dock = System.Windows.Forms.DockStyle.Left;
sidebarPanel.Name = "sidebarPanel";
sidebarPanel.Size = new System.Drawing.Size(260, 670);
sidebarPanel.Controls.Add(filterPanel);
sidebarPanel.Controls.Add(fileList);
//
// fileList (Top of sidebar)
//
fileList.Dock = System.Windows.Forms.DockStyle.Top;
//
// sidebarSplit
//
sidebarSplit.Dock = System.Windows.Forms.DockStyle.Left;
sidebarSplit.Location = new System.Drawing.Point(0, 0);
sidebarSplit.Name = "sidebarSplit";
sidebarSplit.Orientation = System.Windows.Forms.Orientation.Horizontal;
//
// sidebarSplit.Panel1
//
sidebarSplit.Panel1.Controls.Add(fileList);
//
// sidebarSplit.Panel2
//
sidebarSplit.Panel2.Controls.Add(filterPanel);
sidebarSplit.Size = new System.Drawing.Size(260, 670);
sidebarSplit.SplitterDistance = 300;
sidebarSplit.SplitterWidth = 5;
sidebarSplit.TabIndex = 2;
//
// fileList
//
fileList.AllowDrop = true;
fileList.BackColor = System.Drawing.Color.White;
fileList.Dock = System.Windows.Forms.DockStyle.Fill;
fileList.Font = new System.Drawing.Font("Segoe UI", 9F);
fileList.Location = new System.Drawing.Point(0, 0);
fileList.Name = "fileList";
fileList.Size = new System.Drawing.Size(260, 300);
//
// filterPanel (Fill remainder of sidebar)
//
fileList.TabIndex = 0;
//
// filterPanel
//
filterPanel.AutoScroll = true;
filterPanel.BackColor = System.Drawing.Color.White;
filterPanel.Dock = System.Windows.Forms.DockStyle.Fill;
filterPanel.Location = new System.Drawing.Point(0, 0);
filterPanel.Name = "filterPanel";
filterPanel.Size = new System.Drawing.Size(260, 370);
//
// splitterSidebar (between sidebar and preview)
//
splitterSidebar.Location = new System.Drawing.Point(260, 0);
splitterSidebar.Name = "splitterSidebar";
splitterSidebar.Size = new System.Drawing.Size(3, 670);
splitterSidebar.TabStop = false;
//
// entityView1 (Fill — main preview area)
//
filterPanel.Size = new System.Drawing.Size(260, 365);
filterPanel.TabIndex = 0;
//
// entityView1
//
entityView1.BackColor = System.Drawing.Color.FromArgb(33, 40, 48);
entityView1.Cursor = System.Windows.Forms.Cursors.Cross;
entityView1.Dock = System.Windows.Forms.DockStyle.Fill;
entityView1.Location = new System.Drawing.Point(260, 0);
entityView1.Name = "entityView1";
entityView1.Size = new System.Drawing.Size(761, 634);
//
// detailBar (Bottom of preview area)
//
detailBar.Dock = System.Windows.Forms.DockStyle.Bottom;
detailBar.Name = "detailBar";
detailBar.Size = new System.Drawing.Size(761, 36);
entityView1.Size = new System.Drawing.Size(764, 634);
entityView1.TabIndex = 0;
//
// detailBar
//
detailBar.BackColor = System.Drawing.Color.FromArgb(245, 245, 245);
detailBar.Controls.Add(lblQty);
detailBar.Controls.Add(numQuantity);
detailBar.Controls.Add(lblCust);
detailBar.Controls.Add(txtCustomer);
detailBar.Controls.Add(lblDimensions);
detailBar.Controls.Add(lblEntityCount);
detailBar.Controls.Add(btnSplit);
detailBar.Controls.Add(lblDetect);
detailBar.Controls.Add(cboBendDetector);
detailBar.Dock = System.Windows.Forms.DockStyle.Bottom;
detailBar.Location = new System.Drawing.Point(260, 634);
detailBar.Name = "detailBar";
detailBar.Padding = new System.Windows.Forms.Padding(4, 6, 4, 4);
detailBar.Size = new System.Drawing.Size(764, 36);
detailBar.TabIndex = 1;
detailBar.WrapContents = false;
//
//
// lblQty
//
lblQty.Text = "Qty:";
//
lblQty.AutoSize = true;
lblQty.Font = new System.Drawing.Font("Segoe UI", 9f);
lblQty.Font = new System.Drawing.Font("Segoe UI", 9F);
lblQty.Location = new System.Drawing.Point(6, 9);
lblQty.Margin = new System.Windows.Forms.Padding(2, 3, 0, 0);
//
lblQty.Name = "lblQty";
lblQty.Size = new System.Drawing.Size(29, 15);
lblQty.TabIndex = 0;
lblQty.Text = "Qty:";
//
// numQuantity
//
numQuantity.Size = new System.Drawing.Size(50, 24);
numQuantity.Minimum = 1;
numQuantity.Maximum = 9999;
numQuantity.Value = 1;
numQuantity.Font = new System.Drawing.Font("Segoe UI", 9f);
//
numQuantity.Font = new System.Drawing.Font("Segoe UI", 9F);
numQuantity.Location = new System.Drawing.Point(37, 6);
numQuantity.Margin = new System.Windows.Forms.Padding(2, 0, 8, 0);
//
numQuantity.Maximum = new decimal(new int[] { 9999, 0, 0, 0 });
numQuantity.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
numQuantity.Name = "numQuantity";
numQuantity.Size = new System.Drawing.Size(50, 23);
numQuantity.TabIndex = 1;
numQuantity.Value = new decimal(new int[] { 1, 0, 0, 0 });
//
// lblCust
//
lblCust.Text = "Customer:";
//
lblCust.AutoSize = true;
lblCust.Font = new System.Drawing.Font("Segoe UI", 9f);
lblCust.Font = new System.Drawing.Font("Segoe UI", 9F);
lblCust.Location = new System.Drawing.Point(97, 9);
lblCust.Margin = new System.Windows.Forms.Padding(2, 3, 0, 0);
//
lblCust.Name = "lblCust";
lblCust.Size = new System.Drawing.Size(62, 15);
lblCust.TabIndex = 2;
lblCust.Text = "Customer:";
//
// txtCustomer
//
txtCustomer.Size = new System.Drawing.Size(100, 24);
txtCustomer.Font = new System.Drawing.Font("Segoe UI", 9f);
//
txtCustomer.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
txtCustomer.Font = new System.Drawing.Font("Segoe UI", 9F);
txtCustomer.Location = new System.Drawing.Point(161, 6);
txtCustomer.Margin = new System.Windows.Forms.Padding(2, 0, 8, 0);
//
txtCustomer.Name = "txtCustomer";
txtCustomer.Size = new System.Drawing.Size(100, 23);
txtCustomer.TabIndex = 3;
//
// lblDimensions
//
//
lblDimensions.AutoSize = true;
lblDimensions.Font = new System.Drawing.Font("Segoe UI", 9f);
lblDimensions.Font = new System.Drawing.Font("Segoe UI", 9F);
lblDimensions.ForeColor = System.Drawing.Color.Gray;
lblDimensions.Location = new System.Drawing.Point(271, 9);
lblDimensions.Margin = new System.Windows.Forms.Padding(2, 3, 8, 0);
//
lblDimensions.Name = "lblDimensions";
lblDimensions.Size = new System.Drawing.Size(0, 15);
lblDimensions.TabIndex = 4;
//
// lblEntityCount
//
//
lblEntityCount.AutoSize = true;
lblEntityCount.Font = new System.Drawing.Font("Segoe UI", 9f);
lblEntityCount.Font = new System.Drawing.Font("Segoe UI", 9F);
lblEntityCount.ForeColor = System.Drawing.Color.Gray;
lblEntityCount.Location = new System.Drawing.Point(281, 9);
lblEntityCount.Margin = new System.Windows.Forms.Padding(2, 3, 8, 0);
//
lblEntityCount.Name = "lblEntityCount";
lblEntityCount.Size = new System.Drawing.Size(0, 15);
lblEntityCount.TabIndex = 5;
//
// btnSplit
//
btnSplit.Text = "Split...";
btnSplit.Size = new System.Drawing.Size(60, 24);
//
btnSplit.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
btnSplit.Font = new System.Drawing.Font("Segoe UI", 9f);
btnSplit.Font = new System.Drawing.Font("Segoe UI", 9F);
btnSplit.Location = new System.Drawing.Point(291, 6);
btnSplit.Margin = new System.Windows.Forms.Padding(2, 0, 8, 0);
//
btnSplit.Name = "btnSplit";
btnSplit.Size = new System.Drawing.Size(60, 24);
btnSplit.TabIndex = 6;
btnSplit.Text = "Split...";
//
// lblDetect
//
lblDetect.Text = "Bends:";
//
lblDetect.AutoSize = true;
lblDetect.Font = new System.Drawing.Font("Segoe UI", 9f);
lblDetect.Font = new System.Drawing.Font("Segoe UI", 9F);
lblDetect.Location = new System.Drawing.Point(361, 9);
lblDetect.Margin = new System.Windows.Forms.Padding(2, 3, 0, 0);
//
lblDetect.Name = "lblDetect";
lblDetect.Size = new System.Drawing.Size(42, 15);
lblDetect.TabIndex = 7;
lblDetect.Text = "Bends:";
//
// cboBendDetector
//
cboBendDetector.Size = new System.Drawing.Size(90, 24);
//
cboBendDetector.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
cboBendDetector.Font = new System.Drawing.Font("Segoe UI", 9f);
cboBendDetector.Font = new System.Drawing.Font("Segoe UI", 9F);
cboBendDetector.Location = new System.Drawing.Point(405, 6);
cboBendDetector.Margin = new System.Windows.Forms.Padding(2, 0, 0, 0);
detailBar.Controls.AddRange(new System.Windows.Forms.Control[] {
lblQty, numQuantity, lblCust, txtCustomer,
lblDimensions, lblEntityCount, btnSplit,
lblDetect, cboBendDetector
});
//
cboBendDetector.Name = "cboBendDetector";
cboBendDetector.Size = new System.Drawing.Size(90, 23);
cboBendDetector.TabIndex = 8;
//
// bottomPanel1
//
bottomPanel1.Dock = System.Windows.Forms.DockStyle.Bottom;
bottomPanel1.Name = "bottomPanel1";
bottomPanel1.Size = new System.Drawing.Size(1024, 50);
//
bottomPanel1.Controls.Add(cancelButton);
bottomPanel1.Controls.Add(acceptButton);
//
bottomPanel1.Dock = System.Windows.Forms.DockStyle.Bottom;
bottomPanel1.Location = new System.Drawing.Point(0, 670);
bottomPanel1.Name = "bottomPanel1";
bottomPanel1.Size = new System.Drawing.Size(1024, 50);
bottomPanel1.TabIndex = 3;
//
// cancelButton
//
//
cancelButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
cancelButton.Location = new System.Drawing.Point(922, 10);
cancelButton.Size = new System.Drawing.Size(90, 28);
cancelButton.Text = "Cancel";
cancelButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
cancelButton.Font = new System.Drawing.Font("Segoe UI", 9f);
//
cancelButton.Font = new System.Drawing.Font("Segoe UI", 9F);
cancelButton.Location = new System.Drawing.Point(922, 10);
cancelButton.Name = "cancelButton";
cancelButton.Size = new System.Drawing.Size(90, 28);
cancelButton.TabIndex = 0;
cancelButton.Text = "Cancel";
//
// acceptButton
//
//
acceptButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
acceptButton.DialogResult = System.Windows.Forms.DialogResult.OK;
acceptButton.Location = new System.Drawing.Point(826, 10);
acceptButton.Size = new System.Drawing.Size(90, 28);
acceptButton.Text = "Accept";
acceptButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
acceptButton.Font = new System.Drawing.Font("Segoe UI", 9f);
//
acceptButton.Font = new System.Drawing.Font("Segoe UI", 9F);
acceptButton.Location = new System.Drawing.Point(826, 10);
acceptButton.Name = "acceptButton";
acceptButton.Size = new System.Drawing.Size(90, 28);
acceptButton.TabIndex = 1;
acceptButton.Text = "Accept";
//
// CadConverterForm
// Add order: Fill last so it gets remaining space
//
//
AllowDrop = true;
AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
ClientSize = new System.Drawing.Size(1024, 720);
Controls.Add(entityView1);
Controls.Add(detailBar);
Controls.Add(splitterSidebar);
Controls.Add(sidebarPanel);
Controls.Add(sidebarSplit);
Controls.Add(bottomPanel1);
Font = new System.Drawing.Font("Segoe UI", 9f);
Font = new System.Drawing.Font("Segoe UI", 9F);
MinimizeBox = false;
Name = "CadConverterForm";
ShowIcon = false;
ShowInTaskbar = false;
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
Text = "CAD Converter";
AllowDrop = true;
WindowState = System.Windows.Forms.FormWindowState.Maximized;
sidebarSplit.Panel1.ResumeLayout(false);
sidebarSplit.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)sidebarSplit).EndInit();
sidebarSplit.ResumeLayout(false);
detailBar.ResumeLayout(false);
detailBar.PerformLayout();
((System.ComponentModel.ISupportInitialize)numQuantity).EndInit();
sidebarPanel.ResumeLayout(false);
bottomPanel1.ResumeLayout(false);
ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Panel sidebarPanel;
private System.Windows.Forms.Splitter splitterSidebar;
private System.Windows.Forms.SplitContainer sidebarSplit;
private Controls.FileListControl fileList;
private Controls.FilterPanel filterPanel;
private Controls.EntityView entityView1;