feat: add Shape Library UI with configurable shapes and flange presets
Add a Shape Library dialog (Nest > Shape Library) for creating drawings
from built-in parametric shapes. Supports configuration presets loaded
from JSON files — ships with 136 standard pipe flanges. Parameters use
TextBox inputs with architectural unit parsing (feet/inches, fractions).
- ShapeLibraryForm with split layout: shape list, preview, parameters
- ShapePreviewControl for auto-zoom rendering with info overlay
- ArchUnits utility for parsing architectural measurements
- SetPreviewDefaults() on all ShapeDefinition subclasses
- Convention-based config discovery (Configurations/{ShapeName}.json)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,11 @@ namespace OpenNest.Shapes
|
||||
{
|
||||
public double Diameter { get; set; }
|
||||
|
||||
public override void SetPreviewDefaults()
|
||||
{
|
||||
Diameter = 8;
|
||||
}
|
||||
|
||||
public override Drawing GetDrawing()
|
||||
{
|
||||
var entities = new List<Entity>
|
||||
|
||||
@@ -11,6 +11,15 @@ namespace OpenNest.Shapes
|
||||
public double HolePatternDiameter { get; set; }
|
||||
public int HoleCount { get; set; }
|
||||
|
||||
public override void SetPreviewDefaults()
|
||||
{
|
||||
NominalPipeSize = 2;
|
||||
OD = 7.5;
|
||||
HoleDiameter = 0.875;
|
||||
HolePatternDiameter = 5.5;
|
||||
HoleCount = 8;
|
||||
}
|
||||
|
||||
public override Drawing GetDrawing()
|
||||
{
|
||||
var entities = new List<Entity>();
|
||||
|
||||
@@ -8,6 +8,12 @@ namespace OpenNest.Shapes
|
||||
public double Base { get; set; }
|
||||
public double Height { get; set; }
|
||||
|
||||
public override void SetPreviewDefaults()
|
||||
{
|
||||
Base = 8;
|
||||
Height = 10;
|
||||
}
|
||||
|
||||
public override Drawing GetDrawing()
|
||||
{
|
||||
var midX = Base / 2.0;
|
||||
|
||||
@@ -10,6 +10,14 @@ namespace OpenNest.Shapes
|
||||
public double LegWidth { get; set; }
|
||||
public double LegHeight { get; set; }
|
||||
|
||||
public override void SetPreviewDefaults()
|
||||
{
|
||||
Width = 8;
|
||||
Height = 10;
|
||||
LegWidth = 3;
|
||||
LegHeight = 3;
|
||||
}
|
||||
|
||||
public override Drawing GetDrawing()
|
||||
{
|
||||
var lw = LegWidth > 0 ? LegWidth : Width / 2.0;
|
||||
|
||||
@@ -7,6 +7,11 @@ namespace OpenNest.Shapes
|
||||
{
|
||||
public double Width { get; set; }
|
||||
|
||||
public override void SetPreviewDefaults()
|
||||
{
|
||||
Width = 8;
|
||||
}
|
||||
|
||||
public override Drawing GetDrawing()
|
||||
{
|
||||
var center = Width / 2.0;
|
||||
|
||||
@@ -8,6 +8,12 @@ namespace OpenNest.Shapes
|
||||
public double Length { get; set; }
|
||||
public double Width { get; set; }
|
||||
|
||||
public override void SetPreviewDefaults()
|
||||
{
|
||||
Length = 12;
|
||||
Width = 6;
|
||||
}
|
||||
|
||||
public override Drawing GetDrawing()
|
||||
{
|
||||
var entities = new List<Entity>
|
||||
|
||||
@@ -8,6 +8,12 @@ namespace OpenNest.Shapes
|
||||
public double Width { get; set; }
|
||||
public double Height { get; set; }
|
||||
|
||||
public override void SetPreviewDefaults()
|
||||
{
|
||||
Width = 8;
|
||||
Height = 6;
|
||||
}
|
||||
|
||||
public override Drawing GetDrawing()
|
||||
{
|
||||
var entities = new List<Entity>
|
||||
|
||||
@@ -8,6 +8,12 @@ namespace OpenNest.Shapes
|
||||
public double OuterDiameter { get; set; }
|
||||
public double InnerDiameter { get; set; }
|
||||
|
||||
public override void SetPreviewDefaults()
|
||||
{
|
||||
OuterDiameter = 10;
|
||||
InnerDiameter = 6;
|
||||
}
|
||||
|
||||
public override Drawing GetDrawing()
|
||||
{
|
||||
var entities = new List<Entity>
|
||||
|
||||
@@ -10,6 +10,13 @@ namespace OpenNest.Shapes
|
||||
public double Width { get; set; }
|
||||
public double Radius { get; set; }
|
||||
|
||||
public override void SetPreviewDefaults()
|
||||
{
|
||||
Length = 12;
|
||||
Width = 6;
|
||||
Radius = 1;
|
||||
}
|
||||
|
||||
public override Drawing GetDrawing()
|
||||
{
|
||||
var r = Radius;
|
||||
|
||||
@@ -26,6 +26,8 @@ namespace OpenNest.Shapes
|
||||
|
||||
public abstract Drawing GetDrawing();
|
||||
|
||||
public virtual void SetPreviewDefaults() { }
|
||||
|
||||
public static List<T> LoadFromJson<T>(string path) where T : ShapeDefinition
|
||||
{
|
||||
var json = File.ReadAllText(path);
|
||||
|
||||
@@ -10,6 +10,14 @@ namespace OpenNest.Shapes
|
||||
public double StemWidth { get; set; }
|
||||
public double BarHeight { get; set; }
|
||||
|
||||
public override void SetPreviewDefaults()
|
||||
{
|
||||
Width = 10;
|
||||
Height = 8;
|
||||
StemWidth = 3;
|
||||
BarHeight = 3;
|
||||
}
|
||||
|
||||
public override Drawing GetDrawing()
|
||||
{
|
||||
var sw = StemWidth > 0 ? StemWidth : Width / 3.0;
|
||||
|
||||
@@ -9,6 +9,13 @@ namespace OpenNest.Shapes
|
||||
public double BottomWidth { get; set; }
|
||||
public double Height { get; set; }
|
||||
|
||||
public override void SetPreviewDefaults()
|
||||
{
|
||||
TopWidth = 6;
|
||||
BottomWidth = 10;
|
||||
Height = 6;
|
||||
}
|
||||
|
||||
public override Drawing GetDrawing()
|
||||
{
|
||||
var offset = (BottomWidth - TopWidth) / 2.0;
|
||||
|
||||
84
OpenNest/ArchUnits.cs
Normal file
84
OpenNest/ArchUnits.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using OpenNest.IO.Bom;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OpenNest
|
||||
{
|
||||
public static class ArchUnits
|
||||
{
|
||||
private static readonly Regex UnitRegex =
|
||||
new Regex("^(?<Feet>\\d+\\.?\\d*\\s*')?\\s*(?<Inches>\\d+\\.?\\d*\\s*\")?$");
|
||||
|
||||
public static double ParseToInches(string input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
return 0;
|
||||
|
||||
var sb = new StringBuilder(input.Trim().ToLower());
|
||||
|
||||
sb.Replace("ft", "'");
|
||||
sb.Replace("feet", "'");
|
||||
sb.Replace("foot", "'");
|
||||
sb.Replace("inches", "\"");
|
||||
sb.Replace("inch", "\"");
|
||||
sb.Replace("in", "\"");
|
||||
|
||||
input = Fraction.ReplaceFractionsWithDecimals(sb.ToString());
|
||||
|
||||
var match = UnitRegex.Match(input);
|
||||
|
||||
if (!match.Success)
|
||||
{
|
||||
if (!input.Contains("'") && !input.Contains("\""))
|
||||
{
|
||||
if (double.TryParse(input.Trim(), out var plainInches))
|
||||
return System.Math.Round(plainInches, 8);
|
||||
}
|
||||
|
||||
throw new FormatException("Input is not in a valid format.");
|
||||
}
|
||||
|
||||
var feet = match.Groups["Feet"];
|
||||
var inches = match.Groups["Inches"];
|
||||
var totalInches = 0.0;
|
||||
|
||||
if (feet.Success)
|
||||
{
|
||||
var x = double.Parse(feet.Value.Remove(feet.Length - 1));
|
||||
totalInches += x * 12;
|
||||
}
|
||||
|
||||
if (inches.Success)
|
||||
{
|
||||
var x = double.Parse(inches.Value.Remove(inches.Length - 1));
|
||||
totalInches += x;
|
||||
}
|
||||
|
||||
return System.Math.Round(totalInches, 8);
|
||||
}
|
||||
|
||||
public static double GetLengthInches(TextBox tb)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (double.TryParse(tb.Text, out var d))
|
||||
{
|
||||
tb.ForeColor = SystemColors.WindowText;
|
||||
return d;
|
||||
}
|
||||
|
||||
var x = ParseToInches(tb.Text);
|
||||
tb.ForeColor = SystemColors.WindowText;
|
||||
return x;
|
||||
}
|
||||
catch
|
||||
{
|
||||
tb.ForeColor = Color.Red;
|
||||
return double.NaN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1090
OpenNest/Configurations/FlangeShape.json
Normal file
1090
OpenNest/Configurations/FlangeShape.json
Normal file
File diff suppressed because it is too large
Load Diff
79
OpenNest/Controls/ShapePreviewControl.cs
Normal file
79
OpenNest/Controls/ShapePreviewControl.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OpenNest.Controls
|
||||
{
|
||||
public class ShapePreviewControl : PlateView
|
||||
{
|
||||
private string[] infoLines;
|
||||
|
||||
public ShapePreviewControl()
|
||||
{
|
||||
DrawOrigin = false;
|
||||
DrawBounds = false;
|
||||
AllowPan = false;
|
||||
AllowSelect = false;
|
||||
AllowZoom = false;
|
||||
AllowDrop = false;
|
||||
BackColor = Color.White;
|
||||
}
|
||||
|
||||
public void SetInfo(params string[] lines)
|
||||
{
|
||||
infoLines = lines;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
public void ShowDrawing(Drawing drawing)
|
||||
{
|
||||
Plate.Parts.Clear();
|
||||
Plate.Size = new Geometry.Size(0, 0);
|
||||
|
||||
if (drawing?.Program != null)
|
||||
{
|
||||
AddPartFromDrawing(drawing, Geometry.Vector.Zero);
|
||||
ZoomToFit();
|
||||
}
|
||||
else
|
||||
{
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnResize(System.EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
|
||||
if (Plate.Parts.Count > 0)
|
||||
ZoomToFit(false);
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
|
||||
e.Graphics.TranslateTransform(origin.X, origin.Y);
|
||||
Renderer.DrawPlate(e.Graphics);
|
||||
Renderer.DrawParts(e.Graphics);
|
||||
e.Graphics.ResetTransform();
|
||||
|
||||
PaintInfo(e.Graphics);
|
||||
}
|
||||
|
||||
private void PaintInfo(Graphics g)
|
||||
{
|
||||
if (infoLines == null) return;
|
||||
|
||||
var lineHeight = Font.GetHeight(g) + 1;
|
||||
var y = 4f;
|
||||
|
||||
foreach (var line in infoLines)
|
||||
{
|
||||
if (string.IsNullOrEmpty(line)) continue;
|
||||
g.DrawString(line, Font, Brushes.Black, 4, y);
|
||||
y += lineHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
OpenNest/Forms/MainForm.Designer.cs
generated
13
OpenNest/Forms/MainForm.Designer.cs
generated
@@ -85,6 +85,7 @@
|
||||
mnuNest = new System.Windows.Forms.ToolStripMenuItem();
|
||||
mnuNestEdit = new System.Windows.Forms.ToolStripMenuItem();
|
||||
mnuNestImportDrawing = new System.Windows.Forms.ToolStripMenuItem();
|
||||
mnuNestShapeLibrary = new System.Windows.Forms.ToolStripMenuItem();
|
||||
toolStripMenuItem7 = new System.Windows.Forms.ToolStripSeparator();
|
||||
mnuNestFirstPlate = new System.Windows.Forms.ToolStripMenuItem();
|
||||
mnuNestLastPlate = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -559,7 +560,7 @@
|
||||
//
|
||||
// mnuNest
|
||||
//
|
||||
mnuNest.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { mnuNestEdit, mnuNestImportDrawing, toolStripMenuItem7, mnuNestFirstPlate, mnuNestLastPlate, toolStripMenuItem6, mnuNestNextPlate, mnuNestPreviousPlate, toolStripMenuItem12, runAutoNestToolStripMenuItem, autoSequenceAllPlatesToolStripMenuItem, mnuNestRemoveEmptyPlates, mnuNestPost, toolStripMenuItem19, calculateCutTimeToolStripMenuItem, toolStripMenuItem22, mnuNestAssignLeadIns, mnuNestRemoveLeadIns });
|
||||
mnuNest.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { mnuNestEdit, mnuNestImportDrawing, mnuNestShapeLibrary, toolStripMenuItem7, mnuNestFirstPlate, mnuNestLastPlate, toolStripMenuItem6, mnuNestNextPlate, mnuNestPreviousPlate, toolStripMenuItem12, runAutoNestToolStripMenuItem, autoSequenceAllPlatesToolStripMenuItem, mnuNestRemoveEmptyPlates, mnuNestPost, toolStripMenuItem19, calculateCutTimeToolStripMenuItem, toolStripMenuItem22, mnuNestAssignLeadIns, mnuNestRemoveLeadIns });
|
||||
mnuNest.Name = "mnuNest";
|
||||
mnuNest.Size = new System.Drawing.Size(43, 20);
|
||||
mnuNest.Text = "&Nest";
|
||||
@@ -578,7 +579,14 @@
|
||||
mnuNestImportDrawing.Size = new System.Drawing.Size(205, 22);
|
||||
mnuNestImportDrawing.Text = "Import Drawing";
|
||||
mnuNestImportDrawing.Click += Import_Click;
|
||||
//
|
||||
//
|
||||
// mnuNestShapeLibrary
|
||||
//
|
||||
mnuNestShapeLibrary.Name = "mnuNestShapeLibrary";
|
||||
mnuNestShapeLibrary.Size = new System.Drawing.Size(205, 22);
|
||||
mnuNestShapeLibrary.Text = "Shape Library";
|
||||
mnuNestShapeLibrary.Click += ShapeLibrary_Click;
|
||||
//
|
||||
// toolStripMenuItem7
|
||||
//
|
||||
toolStripMenuItem7.Name = "toolStripMenuItem7";
|
||||
@@ -1213,6 +1221,7 @@
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuNest;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuNestEdit;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuNestImportDrawing;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuNestShapeLibrary;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem7;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuNestFirstPlate;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuNestLastPlate;
|
||||
|
||||
@@ -829,6 +829,20 @@ namespace OpenNest.Forms
|
||||
activeForm.Import();
|
||||
}
|
||||
|
||||
private void ShapeLibrary_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (activeForm == null) return;
|
||||
|
||||
var form = new ShapeLibraryForm();
|
||||
form.ShowDialog();
|
||||
|
||||
var drawings = form.GetDrawings();
|
||||
if (drawings.Count == 0) return;
|
||||
|
||||
drawings.ForEach(d => activeForm.Nest.Drawings.Add(d));
|
||||
activeForm.UpdateDrawingList();
|
||||
}
|
||||
|
||||
private void EditNest_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (activeForm == null) return;
|
||||
|
||||
338
OpenNest/Forms/ShapeLibraryForm.Designer.cs
generated
Normal file
338
OpenNest/Forms/ShapeLibraryForm.Designer.cs
generated
Normal file
@@ -0,0 +1,338 @@
|
||||
namespace OpenNest.Forms
|
||||
{
|
||||
partial class ShapeLibraryForm
|
||||
{
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
ColorScheme colorScheme1 = new ColorScheme();
|
||||
CutOffSettings cutOffSettings1 = new CutOffSettings();
|
||||
Plate plate1 = new Plate();
|
||||
Collections.ObservableList<CutOff> observableList_11 = new Collections.ObservableList<CutOff>();
|
||||
Collections.ObservableList<Part> observableList_12 = new Collections.ObservableList<Part>();
|
||||
splitContainer = new System.Windows.Forms.SplitContainer();
|
||||
shapeListBox = new System.Windows.Forms.ListBox();
|
||||
layoutTable = new System.Windows.Forms.TableLayoutPanel();
|
||||
fieldsTable = new System.Windows.Forms.TableLayoutPanel();
|
||||
nameLabel = new System.Windows.Forms.Label();
|
||||
nameTextBox = new System.Windows.Forms.TextBox();
|
||||
qtyLabel = new System.Windows.Forms.Label();
|
||||
quantityUpDown = new OpenNest.Controls.NumericUpDown();
|
||||
configLabel = new System.Windows.Forms.Label();
|
||||
configComboBox = new System.Windows.Forms.ComboBox();
|
||||
contentPanel = new System.Windows.Forms.Panel();
|
||||
previewBox = new OpenNest.Controls.ShapePreviewControl();
|
||||
parametersPanel = new System.Windows.Forms.Panel();
|
||||
buttonPanel = new System.Windows.Forms.Panel();
|
||||
addButton = new System.Windows.Forms.Button();
|
||||
closeButton = new System.Windows.Forms.Button();
|
||||
((System.ComponentModel.ISupportInitialize)splitContainer).BeginInit();
|
||||
splitContainer.Panel1.SuspendLayout();
|
||||
splitContainer.Panel2.SuspendLayout();
|
||||
splitContainer.SuspendLayout();
|
||||
layoutTable.SuspendLayout();
|
||||
fieldsTable.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)quantityUpDown).BeginInit();
|
||||
contentPanel.SuspendLayout();
|
||||
buttonPanel.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// splitContainer
|
||||
//
|
||||
splitContainer.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
splitContainer.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
|
||||
splitContainer.Location = new System.Drawing.Point(0, 0);
|
||||
splitContainer.Name = "splitContainer";
|
||||
//
|
||||
// splitContainer.Panel1
|
||||
//
|
||||
splitContainer.Panel1.Controls.Add(shapeListBox);
|
||||
//
|
||||
// splitContainer.Panel2
|
||||
//
|
||||
splitContainer.Panel2.Controls.Add(layoutTable);
|
||||
splitContainer.Size = new System.Drawing.Size(750, 520);
|
||||
splitContainer.SplitterDistance = 150;
|
||||
splitContainer.TabIndex = 0;
|
||||
//
|
||||
// shapeListBox
|
||||
//
|
||||
shapeListBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
shapeListBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
shapeListBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
|
||||
shapeListBox.Font = new System.Drawing.Font("Segoe UI", 10F);
|
||||
shapeListBox.IntegralHeight = false;
|
||||
shapeListBox.ItemHeight = 32;
|
||||
shapeListBox.Location = new System.Drawing.Point(0, 0);
|
||||
shapeListBox.Name = "shapeListBox";
|
||||
shapeListBox.Size = new System.Drawing.Size(150, 520);
|
||||
shapeListBox.TabIndex = 0;
|
||||
//
|
||||
// layoutTable
|
||||
//
|
||||
layoutTable.ColumnCount = 1;
|
||||
layoutTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
layoutTable.Controls.Add(fieldsTable, 0, 0);
|
||||
layoutTable.Controls.Add(contentPanel, 0, 1);
|
||||
layoutTable.Controls.Add(buttonPanel, 0, 2);
|
||||
layoutTable.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
layoutTable.Location = new System.Drawing.Point(0, 0);
|
||||
layoutTable.Name = "layoutTable";
|
||||
layoutTable.Padding = new System.Windows.Forms.Padding(6, 4, 6, 0);
|
||||
layoutTable.RowCount = 3;
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
layoutTable.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 44F));
|
||||
layoutTable.Size = new System.Drawing.Size(596, 520);
|
||||
layoutTable.TabIndex = 0;
|
||||
//
|
||||
// fieldsTable
|
||||
//
|
||||
fieldsTable.AutoSize = true;
|
||||
fieldsTable.ColumnCount = 2;
|
||||
fieldsTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
fieldsTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
fieldsTable.Controls.Add(nameLabel, 0, 0);
|
||||
fieldsTable.Controls.Add(nameTextBox, 1, 0);
|
||||
fieldsTable.Controls.Add(qtyLabel, 0, 1);
|
||||
fieldsTable.Controls.Add(quantityUpDown, 1, 1);
|
||||
fieldsTable.Controls.Add(configLabel, 0, 2);
|
||||
fieldsTable.Controls.Add(configComboBox, 1, 2);
|
||||
fieldsTable.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
fieldsTable.Location = new System.Drawing.Point(6, 4);
|
||||
fieldsTable.Margin = new System.Windows.Forms.Padding(0, 0, 0, 4);
|
||||
fieldsTable.Name = "fieldsTable";
|
||||
fieldsTable.RowCount = 3;
|
||||
fieldsTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
fieldsTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
fieldsTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
fieldsTable.Size = new System.Drawing.Size(584, 97);
|
||||
fieldsTable.TabIndex = 0;
|
||||
//
|
||||
// nameLabel
|
||||
//
|
||||
nameLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
nameLabel.AutoSize = true;
|
||||
nameLabel.Location = new System.Drawing.Point(4, 8);
|
||||
nameLabel.Margin = new System.Windows.Forms.Padding(4, 4, 8, 4);
|
||||
nameLabel.Name = "nameLabel";
|
||||
nameLabel.Size = new System.Drawing.Size(46, 17);
|
||||
nameLabel.TabIndex = 0;
|
||||
nameLabel.Text = "Name:";
|
||||
//
|
||||
// nameTextBox
|
||||
//
|
||||
nameTextBox.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
nameTextBox.Location = new System.Drawing.Point(102, 4);
|
||||
nameTextBox.Margin = new System.Windows.Forms.Padding(0, 4, 4, 4);
|
||||
nameTextBox.Name = "nameTextBox";
|
||||
nameTextBox.Size = new System.Drawing.Size(478, 25);
|
||||
nameTextBox.TabIndex = 1;
|
||||
//
|
||||
// qtyLabel
|
||||
//
|
||||
qtyLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
qtyLabel.AutoSize = true;
|
||||
qtyLabel.Location = new System.Drawing.Point(4, 41);
|
||||
qtyLabel.Margin = new System.Windows.Forms.Padding(4, 4, 8, 4);
|
||||
qtyLabel.Name = "qtyLabel";
|
||||
qtyLabel.Size = new System.Drawing.Size(59, 17);
|
||||
qtyLabel.TabIndex = 2;
|
||||
qtyLabel.Text = "Quantity:";
|
||||
//
|
||||
// quantityUpDown
|
||||
//
|
||||
quantityUpDown.Location = new System.Drawing.Point(102, 37);
|
||||
quantityUpDown.Margin = new System.Windows.Forms.Padding(0, 4, 4, 4);
|
||||
quantityUpDown.Maximum = new decimal(new int[] { 999999, 0, 0, 0 });
|
||||
quantityUpDown.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
|
||||
quantityUpDown.Name = "quantityUpDown";
|
||||
quantityUpDown.Size = new System.Drawing.Size(100, 25);
|
||||
quantityUpDown.Suffix = "";
|
||||
quantityUpDown.TabIndex = 2;
|
||||
quantityUpDown.Value = new decimal(new int[] { 1, 0, 0, 0 });
|
||||
//
|
||||
// configLabel
|
||||
//
|
||||
configLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
configLabel.AutoSize = true;
|
||||
configLabel.Location = new System.Drawing.Point(4, 73);
|
||||
configLabel.Margin = new System.Windows.Forms.Padding(4, 4, 8, 4);
|
||||
configLabel.Name = "configLabel";
|
||||
configLabel.Size = new System.Drawing.Size(90, 17);
|
||||
configLabel.TabIndex = 3;
|
||||
configLabel.Text = "Configuration:";
|
||||
configLabel.Visible = false;
|
||||
//
|
||||
// configComboBox
|
||||
//
|
||||
configComboBox.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
configComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
configComboBox.Location = new System.Drawing.Point(102, 70);
|
||||
configComboBox.Margin = new System.Windows.Forms.Padding(0, 4, 4, 4);
|
||||
configComboBox.Name = "configComboBox";
|
||||
configComboBox.Size = new System.Drawing.Size(478, 25);
|
||||
configComboBox.TabIndex = 3;
|
||||
configComboBox.Visible = false;
|
||||
//
|
||||
// contentPanel
|
||||
//
|
||||
contentPanel.Controls.Add(previewBox);
|
||||
contentPanel.Controls.Add(parametersPanel);
|
||||
contentPanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
contentPanel.Location = new System.Drawing.Point(9, 108);
|
||||
contentPanel.Name = "contentPanel";
|
||||
contentPanel.Size = new System.Drawing.Size(578, 365);
|
||||
contentPanel.TabIndex = 1;
|
||||
//
|
||||
// previewBox
|
||||
//
|
||||
previewBox.ActiveWorkArea = null;
|
||||
previewBox.AllowPan = false;
|
||||
previewBox.AllowSelect = false;
|
||||
previewBox.AllowZoom = false;
|
||||
previewBox.BackColor = System.Drawing.Color.White;
|
||||
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;
|
||||
previewBox.ColorScheme = colorScheme1;
|
||||
cutOffSettings1.CutDirection = CutDirection.AwayFromOrigin;
|
||||
cutOffSettings1.MinSegmentLength = 0.05D;
|
||||
cutOffSettings1.Overtravel = 0D;
|
||||
cutOffSettings1.PartClearance = 0.02D;
|
||||
previewBox.CutOffSettings = cutOffSettings1;
|
||||
previewBox.DebugRemnantPriorities = null;
|
||||
previewBox.DebugRemnants = null;
|
||||
previewBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
previewBox.DrawBounds = false;
|
||||
previewBox.DrawCutDirection = false;
|
||||
previewBox.DrawOffset = false;
|
||||
previewBox.DrawOrigin = false;
|
||||
previewBox.DrawPiercePoints = false;
|
||||
previewBox.DrawRapid = false;
|
||||
previewBox.FillParts = true;
|
||||
previewBox.Location = new System.Drawing.Point(0, 0);
|
||||
previewBox.Name = "previewBox";
|
||||
previewBox.OffsetIncrementDistance = 10D;
|
||||
previewBox.OffsetTolerance = 0.001D;
|
||||
plate1.CutOffs = observableList_11;
|
||||
plate1.CuttingParameters = null;
|
||||
plate1.GrainAngle = 0D;
|
||||
plate1.Parts = observableList_12;
|
||||
plate1.PartSpacing = 0D;
|
||||
plate1.Quadrant = 1;
|
||||
plate1.Quantity = 0;
|
||||
previewBox.Plate = plate1;
|
||||
previewBox.RotateIncrementAngle = 10D;
|
||||
previewBox.ShowBendLines = false;
|
||||
previewBox.Size = new System.Drawing.Size(318, 365);
|
||||
previewBox.Status = "Select";
|
||||
previewBox.TabIndex = 4;
|
||||
previewBox.TabStop = false;
|
||||
//
|
||||
// parametersPanel
|
||||
//
|
||||
parametersPanel.AutoScroll = true;
|
||||
parametersPanel.Dock = System.Windows.Forms.DockStyle.Right;
|
||||
parametersPanel.Location = new System.Drawing.Point(318, 0);
|
||||
parametersPanel.Name = "parametersPanel";
|
||||
parametersPanel.Padding = new System.Windows.Forms.Padding(8, 0, 0, 0);
|
||||
parametersPanel.Size = new System.Drawing.Size(260, 365);
|
||||
parametersPanel.TabIndex = 5;
|
||||
//
|
||||
// buttonPanel
|
||||
//
|
||||
buttonPanel.Controls.Add(addButton);
|
||||
buttonPanel.Controls.Add(closeButton);
|
||||
buttonPanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
buttonPanel.Location = new System.Drawing.Point(9, 479);
|
||||
buttonPanel.Name = "buttonPanel";
|
||||
buttonPanel.Size = new System.Drawing.Size(578, 38);
|
||||
buttonPanel.TabIndex = 2;
|
||||
//
|
||||
// addButton
|
||||
//
|
||||
addButton.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
|
||||
addButton.Location = new System.Drawing.Point(379, 5);
|
||||
addButton.Name = "addButton";
|
||||
addButton.Size = new System.Drawing.Size(100, 30);
|
||||
addButton.TabIndex = 0;
|
||||
addButton.Text = "Add to Nest";
|
||||
addButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// closeButton
|
||||
//
|
||||
closeButton.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
|
||||
closeButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
closeButton.Location = new System.Drawing.Point(485, 5);
|
||||
closeButton.Name = "closeButton";
|
||||
closeButton.Size = new System.Drawing.Size(90, 30);
|
||||
closeButton.TabIndex = 1;
|
||||
closeButton.Text = "Close";
|
||||
closeButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ShapeLibraryForm
|
||||
//
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
|
||||
CancelButton = closeButton;
|
||||
ClientSize = new System.Drawing.Size(750, 520);
|
||||
Controls.Add(splitContainer);
|
||||
Font = new System.Drawing.Font("Segoe UI", 9.75F);
|
||||
MinimizeBox = false;
|
||||
MinimumSize = new System.Drawing.Size(600, 400);
|
||||
Name = "ShapeLibraryForm";
|
||||
ShowIcon = false;
|
||||
ShowInTaskbar = false;
|
||||
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
Text = "Shape Library";
|
||||
splitContainer.Panel1.ResumeLayout(false);
|
||||
splitContainer.Panel2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)splitContainer).EndInit();
|
||||
splitContainer.ResumeLayout(false);
|
||||
layoutTable.ResumeLayout(false);
|
||||
layoutTable.PerformLayout();
|
||||
fieldsTable.ResumeLayout(false);
|
||||
fieldsTable.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)quantityUpDown).EndInit();
|
||||
contentPanel.ResumeLayout(false);
|
||||
buttonPanel.ResumeLayout(false);
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.SplitContainer splitContainer;
|
||||
private System.Windows.Forms.ListBox shapeListBox;
|
||||
private System.Windows.Forms.TableLayoutPanel layoutTable;
|
||||
private System.Windows.Forms.TableLayoutPanel fieldsTable;
|
||||
private System.Windows.Forms.Label nameLabel;
|
||||
private System.Windows.Forms.TextBox nameTextBox;
|
||||
private System.Windows.Forms.Label qtyLabel;
|
||||
private Controls.NumericUpDown quantityUpDown;
|
||||
private System.Windows.Forms.Label configLabel;
|
||||
private System.Windows.Forms.ComboBox configComboBox;
|
||||
private System.Windows.Forms.Panel contentPanel;
|
||||
private Controls.ShapePreviewControl previewBox;
|
||||
private System.Windows.Forms.Panel parametersPanel;
|
||||
private System.Windows.Forms.Panel buttonPanel;
|
||||
private System.Windows.Forms.Button addButton;
|
||||
private System.Windows.Forms.Button closeButton;
|
||||
}
|
||||
}
|
||||
322
OpenNest/Forms/ShapeLibraryForm.cs
Normal file
322
OpenNest/Forms/ShapeLibraryForm.cs
Normal file
@@ -0,0 +1,322 @@
|
||||
using OpenNest.Shapes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OpenNest.Forms
|
||||
{
|
||||
public partial class ShapeLibraryForm : Form
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
private readonly List<Drawing> addedDrawings = new List<Drawing>();
|
||||
private readonly List<ShapeEntry> shapeEntries = new List<ShapeEntry>();
|
||||
private readonly List<ParameterBinding> parameterBindings = new List<ParameterBinding>();
|
||||
|
||||
private ShapeEntry selectedEntry;
|
||||
private bool suppressPreview;
|
||||
|
||||
public ShapeLibraryForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
DiscoverShapes();
|
||||
PopulateShapeList();
|
||||
|
||||
shapeListBox.DrawItem += ShapeListBox_DrawItem;
|
||||
shapeListBox.SelectedIndexChanged += ShapeListBox_SelectedIndexChanged;
|
||||
configComboBox.SelectedIndexChanged += ConfigComboBox_SelectedIndexChanged;
|
||||
addButton.Click += AddButton_Click;
|
||||
closeButton.Click += (s, e) => Close();
|
||||
|
||||
if (shapeListBox.Items.Count > 0)
|
||||
shapeListBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
public List<Drawing> GetDrawings() => addedDrawings;
|
||||
|
||||
private void DiscoverShapes()
|
||||
{
|
||||
var baseType = typeof(ShapeDefinition);
|
||||
var shapeTypes = baseType.Assembly.GetTypes()
|
||||
.Where(t => t.IsClass && !t.IsAbstract && baseType.IsAssignableFrom(t))
|
||||
.OrderBy(t => t.Name)
|
||||
.ToList();
|
||||
|
||||
var configDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Configurations");
|
||||
|
||||
foreach (var type in shapeTypes)
|
||||
{
|
||||
var entry = new ShapeEntry { ShapeType = type };
|
||||
entry.DisplayName = FriendlyName(type.Name);
|
||||
|
||||
var configPath = Path.Combine(configDir, type.Name + ".json");
|
||||
if (File.Exists(configPath))
|
||||
entry.Configurations = LoadConfigurations(type, configPath);
|
||||
|
||||
shapeEntries.Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
private List<ShapeDefinition> LoadConfigurations(Type shapeType, string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(path);
|
||||
var listType = typeof(List<>).MakeGenericType(shapeType);
|
||||
var list = JsonSerializer.Deserialize(json, listType, JsonOptions);
|
||||
return ((System.Collections.IEnumerable)list).Cast<ShapeDefinition>().ToList();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateShapeList()
|
||||
{
|
||||
foreach (var entry in shapeEntries)
|
||||
shapeListBox.Items.Add(entry);
|
||||
}
|
||||
|
||||
private void ShapeListBox_DrawItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
if (e.Index < 0) return;
|
||||
|
||||
e.DrawBackground();
|
||||
|
||||
var entry = (ShapeEntry)shapeListBox.Items[e.Index];
|
||||
var textColor = (e.State & DrawItemState.Selected) != 0
|
||||
? SystemColors.HighlightText
|
||||
: SystemColors.ControlText;
|
||||
|
||||
var text = entry.DisplayName;
|
||||
if (entry.HasConfigurations)
|
||||
text += $" ({entry.Configurations.Count})";
|
||||
|
||||
using (var brush = new SolidBrush(textColor))
|
||||
{
|
||||
var format = new StringFormat { LineAlignment = StringAlignment.Center };
|
||||
var rect = new RectangleF(8, e.Bounds.Y, e.Bounds.Width - 8, e.Bounds.Height);
|
||||
e.Graphics.DrawString(text, e.Font, brush, rect, format);
|
||||
}
|
||||
|
||||
e.DrawFocusRectangle();
|
||||
}
|
||||
|
||||
private void ShapeListBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (shapeListBox.SelectedIndex < 0) return;
|
||||
|
||||
selectedEntry = (ShapeEntry)shapeListBox.SelectedItem;
|
||||
suppressPreview = true;
|
||||
|
||||
var hasConfigs = selectedEntry.HasConfigurations;
|
||||
configLabel.Visible = hasConfigs;
|
||||
configComboBox.Visible = hasConfigs;
|
||||
|
||||
if (hasConfigs)
|
||||
{
|
||||
configComboBox.Items.Clear();
|
||||
foreach (var cfg in selectedEntry.Configurations)
|
||||
configComboBox.Items.Add(cfg.Name);
|
||||
|
||||
configComboBox.SelectedIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
nameTextBox.Text = selectedEntry.DisplayName;
|
||||
var defaults = (ShapeDefinition)Activator.CreateInstance(selectedEntry.ShapeType);
|
||||
defaults.SetPreviewDefaults();
|
||||
BuildParameterControls(selectedEntry.ShapeType, defaults);
|
||||
}
|
||||
|
||||
suppressPreview = false;
|
||||
UpdatePreview();
|
||||
}
|
||||
|
||||
private void ConfigComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (configComboBox.SelectedIndex < 0 || selectedEntry == null) return;
|
||||
|
||||
var config = selectedEntry.Configurations[configComboBox.SelectedIndex];
|
||||
nameTextBox.Text = config.Name;
|
||||
|
||||
suppressPreview = true;
|
||||
BuildParameterControls(selectedEntry.ShapeType, config);
|
||||
suppressPreview = false;
|
||||
UpdatePreview();
|
||||
}
|
||||
|
||||
private void BuildParameterControls(Type shapeType, ShapeDefinition sourceValues)
|
||||
{
|
||||
parametersPanel.SuspendLayout();
|
||||
parametersPanel.Controls.Clear();
|
||||
parameterBindings.Clear();
|
||||
|
||||
var props = shapeType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
|
||||
.Where(p => p.CanRead && p.CanWrite && p.Name != "Name")
|
||||
.ToArray();
|
||||
|
||||
var panelWidth = parametersPanel.ClientSize.Width - parametersPanel.Padding.Horizontal;
|
||||
var y = 4;
|
||||
|
||||
foreach (var prop in props)
|
||||
{
|
||||
var label = new Label
|
||||
{
|
||||
Text = FriendlyName(prop.Name),
|
||||
Location = new Point(parametersPanel.Padding.Left, y),
|
||||
AutoSize = true
|
||||
};
|
||||
|
||||
y += 18;
|
||||
|
||||
var tb = new TextBox
|
||||
{
|
||||
Location = new Point(parametersPanel.Padding.Left, y),
|
||||
Width = panelWidth,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
|
||||
};
|
||||
|
||||
if (sourceValues != null)
|
||||
{
|
||||
if (prop.PropertyType == typeof(int))
|
||||
tb.Text = ((int)prop.GetValue(sourceValues)).ToString();
|
||||
else
|
||||
tb.Text = ((double)prop.GetValue(sourceValues)).ToString("G");
|
||||
}
|
||||
|
||||
tb.TextChanged += (s, ev) => UpdatePreview();
|
||||
|
||||
parameterBindings.Add(new ParameterBinding { Property = prop, Control = tb });
|
||||
|
||||
parametersPanel.Controls.Add(label);
|
||||
parametersPanel.Controls.Add(tb);
|
||||
|
||||
y += 30;
|
||||
}
|
||||
|
||||
parametersPanel.ResumeLayout(true);
|
||||
}
|
||||
|
||||
private void UpdatePreview()
|
||||
{
|
||||
if (suppressPreview || selectedEntry == null) return;
|
||||
|
||||
try
|
||||
{
|
||||
var shape = CreateShapeFromInputs();
|
||||
if (shape == null) return;
|
||||
|
||||
var drawing = shape.GetDrawing();
|
||||
previewBox.ShowDrawing(drawing);
|
||||
|
||||
if (drawing?.Program != null)
|
||||
{
|
||||
var bb = drawing.Program.BoundingBox();
|
||||
previewBox.SetInfo(
|
||||
nameTextBox.Text,
|
||||
string.Format("{0:F3} x {1:F3}", bb.Size.Length, bb.Size.Width));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
previewBox.ShowDrawing(null);
|
||||
}
|
||||
}
|
||||
|
||||
private ShapeDefinition CreateShapeFromInputs()
|
||||
{
|
||||
var shape = (ShapeDefinition)Activator.CreateInstance(selectedEntry.ShapeType);
|
||||
shape.Name = nameTextBox.Text;
|
||||
|
||||
foreach (var binding in parameterBindings)
|
||||
{
|
||||
var tb = (TextBox)binding.Control;
|
||||
|
||||
if (binding.Property.PropertyType == typeof(int))
|
||||
{
|
||||
if (int.TryParse(tb.Text, out var intVal))
|
||||
{
|
||||
binding.Property.SetValue(shape, intVal);
|
||||
tb.ForeColor = SystemColors.WindowText;
|
||||
}
|
||||
else
|
||||
{
|
||||
tb.ForeColor = Color.Red;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var val = ArchUnits.GetLengthInches(tb);
|
||||
if (double.IsNaN(val))
|
||||
return null;
|
||||
|
||||
binding.Property.SetValue(shape, val);
|
||||
}
|
||||
}
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
private void AddButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var shape = CreateShapeFromInputs();
|
||||
if (shape == null) return;
|
||||
|
||||
var drawing = shape.GetDrawing();
|
||||
drawing.Color = Drawing.GetNextColor();
|
||||
drawing.Quantity.Required = (int)quantityUpDown.Value;
|
||||
|
||||
addedDrawings.Add(drawing);
|
||||
DialogResult = DialogResult.OK;
|
||||
|
||||
addButton.Text = $"Added ({addedDrawings.Count})";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(
|
||||
$"Failed to create shape: {ex.Message}",
|
||||
"Error",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
private static string FriendlyName(string name)
|
||||
{
|
||||
if (name.EndsWith("Shape"))
|
||||
name = name.Substring(0, name.Length - 5);
|
||||
|
||||
return Regex.Replace(name, @"(?<=[a-z0-9])([A-Z])", " $1");
|
||||
}
|
||||
|
||||
private class ShapeEntry
|
||||
{
|
||||
public Type ShapeType { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public List<ShapeDefinition> Configurations { get; set; }
|
||||
public bool HasConfigurations => Configurations != null && Configurations.Count > 0;
|
||||
|
||||
public override string ToString() => DisplayName;
|
||||
}
|
||||
|
||||
private class ParameterBinding
|
||||
{
|
||||
public PropertyInfo Property { get; set; }
|
||||
public Control Control { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
120
OpenNest/Forms/ShapeLibraryForm.resx
Normal file
120
OpenNest/Forms/ShapeLibraryForm.resx
Normal 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>
|
||||
@@ -10,6 +10,11 @@
|
||||
<ItemGroup>
|
||||
<Compile Remove="Controls\LayoutViewGL.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Configurations\**\*.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenNest.Api\OpenNest.Api.csproj" />
|
||||
<ProjectReference Include="..\OpenNest.Core\OpenNest.Core.csproj" />
|
||||
|
||||
Reference in New Issue
Block a user