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 double Diameter { get; set; }
|
||||||
|
|
||||||
|
public override void SetPreviewDefaults()
|
||||||
|
{
|
||||||
|
Diameter = 8;
|
||||||
|
}
|
||||||
|
|
||||||
public override Drawing GetDrawing()
|
public override Drawing GetDrawing()
|
||||||
{
|
{
|
||||||
var entities = new List<Entity>
|
var entities = new List<Entity>
|
||||||
|
|||||||
@@ -11,6 +11,15 @@ namespace OpenNest.Shapes
|
|||||||
public double HolePatternDiameter { get; set; }
|
public double HolePatternDiameter { get; set; }
|
||||||
public int HoleCount { 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()
|
public override Drawing GetDrawing()
|
||||||
{
|
{
|
||||||
var entities = new List<Entity>();
|
var entities = new List<Entity>();
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ namespace OpenNest.Shapes
|
|||||||
public double Base { get; set; }
|
public double Base { get; set; }
|
||||||
public double Height { get; set; }
|
public double Height { get; set; }
|
||||||
|
|
||||||
|
public override void SetPreviewDefaults()
|
||||||
|
{
|
||||||
|
Base = 8;
|
||||||
|
Height = 10;
|
||||||
|
}
|
||||||
|
|
||||||
public override Drawing GetDrawing()
|
public override Drawing GetDrawing()
|
||||||
{
|
{
|
||||||
var midX = Base / 2.0;
|
var midX = Base / 2.0;
|
||||||
|
|||||||
@@ -10,6 +10,14 @@ namespace OpenNest.Shapes
|
|||||||
public double LegWidth { get; set; }
|
public double LegWidth { get; set; }
|
||||||
public double LegHeight { get; set; }
|
public double LegHeight { get; set; }
|
||||||
|
|
||||||
|
public override void SetPreviewDefaults()
|
||||||
|
{
|
||||||
|
Width = 8;
|
||||||
|
Height = 10;
|
||||||
|
LegWidth = 3;
|
||||||
|
LegHeight = 3;
|
||||||
|
}
|
||||||
|
|
||||||
public override Drawing GetDrawing()
|
public override Drawing GetDrawing()
|
||||||
{
|
{
|
||||||
var lw = LegWidth > 0 ? LegWidth : Width / 2.0;
|
var lw = LegWidth > 0 ? LegWidth : Width / 2.0;
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ namespace OpenNest.Shapes
|
|||||||
{
|
{
|
||||||
public double Width { get; set; }
|
public double Width { get; set; }
|
||||||
|
|
||||||
|
public override void SetPreviewDefaults()
|
||||||
|
{
|
||||||
|
Width = 8;
|
||||||
|
}
|
||||||
|
|
||||||
public override Drawing GetDrawing()
|
public override Drawing GetDrawing()
|
||||||
{
|
{
|
||||||
var center = Width / 2.0;
|
var center = Width / 2.0;
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ namespace OpenNest.Shapes
|
|||||||
public double Length { get; set; }
|
public double Length { get; set; }
|
||||||
public double Width { get; set; }
|
public double Width { get; set; }
|
||||||
|
|
||||||
|
public override void SetPreviewDefaults()
|
||||||
|
{
|
||||||
|
Length = 12;
|
||||||
|
Width = 6;
|
||||||
|
}
|
||||||
|
|
||||||
public override Drawing GetDrawing()
|
public override Drawing GetDrawing()
|
||||||
{
|
{
|
||||||
var entities = new List<Entity>
|
var entities = new List<Entity>
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ namespace OpenNest.Shapes
|
|||||||
public double Width { get; set; }
|
public double Width { get; set; }
|
||||||
public double Height { get; set; }
|
public double Height { get; set; }
|
||||||
|
|
||||||
|
public override void SetPreviewDefaults()
|
||||||
|
{
|
||||||
|
Width = 8;
|
||||||
|
Height = 6;
|
||||||
|
}
|
||||||
|
|
||||||
public override Drawing GetDrawing()
|
public override Drawing GetDrawing()
|
||||||
{
|
{
|
||||||
var entities = new List<Entity>
|
var entities = new List<Entity>
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ namespace OpenNest.Shapes
|
|||||||
public double OuterDiameter { get; set; }
|
public double OuterDiameter { get; set; }
|
||||||
public double InnerDiameter { get; set; }
|
public double InnerDiameter { get; set; }
|
||||||
|
|
||||||
|
public override void SetPreviewDefaults()
|
||||||
|
{
|
||||||
|
OuterDiameter = 10;
|
||||||
|
InnerDiameter = 6;
|
||||||
|
}
|
||||||
|
|
||||||
public override Drawing GetDrawing()
|
public override Drawing GetDrawing()
|
||||||
{
|
{
|
||||||
var entities = new List<Entity>
|
var entities = new List<Entity>
|
||||||
|
|||||||
@@ -10,6 +10,13 @@ namespace OpenNest.Shapes
|
|||||||
public double Width { get; set; }
|
public double Width { get; set; }
|
||||||
public double Radius { get; set; }
|
public double Radius { get; set; }
|
||||||
|
|
||||||
|
public override void SetPreviewDefaults()
|
||||||
|
{
|
||||||
|
Length = 12;
|
||||||
|
Width = 6;
|
||||||
|
Radius = 1;
|
||||||
|
}
|
||||||
|
|
||||||
public override Drawing GetDrawing()
|
public override Drawing GetDrawing()
|
||||||
{
|
{
|
||||||
var r = Radius;
|
var r = Radius;
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ namespace OpenNest.Shapes
|
|||||||
|
|
||||||
public abstract Drawing GetDrawing();
|
public abstract Drawing GetDrawing();
|
||||||
|
|
||||||
|
public virtual void SetPreviewDefaults() { }
|
||||||
|
|
||||||
public static List<T> LoadFromJson<T>(string path) where T : ShapeDefinition
|
public static List<T> LoadFromJson<T>(string path) where T : ShapeDefinition
|
||||||
{
|
{
|
||||||
var json = File.ReadAllText(path);
|
var json = File.ReadAllText(path);
|
||||||
|
|||||||
@@ -10,6 +10,14 @@ namespace OpenNest.Shapes
|
|||||||
public double StemWidth { get; set; }
|
public double StemWidth { get; set; }
|
||||||
public double BarHeight { get; set; }
|
public double BarHeight { get; set; }
|
||||||
|
|
||||||
|
public override void SetPreviewDefaults()
|
||||||
|
{
|
||||||
|
Width = 10;
|
||||||
|
Height = 8;
|
||||||
|
StemWidth = 3;
|
||||||
|
BarHeight = 3;
|
||||||
|
}
|
||||||
|
|
||||||
public override Drawing GetDrawing()
|
public override Drawing GetDrawing()
|
||||||
{
|
{
|
||||||
var sw = StemWidth > 0 ? StemWidth : Width / 3.0;
|
var sw = StemWidth > 0 ? StemWidth : Width / 3.0;
|
||||||
|
|||||||
@@ -9,6 +9,13 @@ namespace OpenNest.Shapes
|
|||||||
public double BottomWidth { get; set; }
|
public double BottomWidth { get; set; }
|
||||||
public double Height { get; set; }
|
public double Height { get; set; }
|
||||||
|
|
||||||
|
public override void SetPreviewDefaults()
|
||||||
|
{
|
||||||
|
TopWidth = 6;
|
||||||
|
BottomWidth = 10;
|
||||||
|
Height = 6;
|
||||||
|
}
|
||||||
|
|
||||||
public override Drawing GetDrawing()
|
public override Drawing GetDrawing()
|
||||||
{
|
{
|
||||||
var offset = (BottomWidth - TopWidth) / 2.0;
|
var offset = (BottomWidth - TopWidth) / 2.0;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+10
-1
@@ -85,6 +85,7 @@
|
|||||||
mnuNest = new System.Windows.Forms.ToolStripMenuItem();
|
mnuNest = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
mnuNestEdit = new System.Windows.Forms.ToolStripMenuItem();
|
mnuNestEdit = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
mnuNestImportDrawing = new System.Windows.Forms.ToolStripMenuItem();
|
mnuNestImportDrawing = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
mnuNestShapeLibrary = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
toolStripMenuItem7 = new System.Windows.Forms.ToolStripSeparator();
|
toolStripMenuItem7 = new System.Windows.Forms.ToolStripSeparator();
|
||||||
mnuNestFirstPlate = new System.Windows.Forms.ToolStripMenuItem();
|
mnuNestFirstPlate = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
mnuNestLastPlate = new System.Windows.Forms.ToolStripMenuItem();
|
mnuNestLastPlate = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
@@ -559,7 +560,7 @@
|
|||||||
//
|
//
|
||||||
// mnuNest
|
// 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.Name = "mnuNest";
|
||||||
mnuNest.Size = new System.Drawing.Size(43, 20);
|
mnuNest.Size = new System.Drawing.Size(43, 20);
|
||||||
mnuNest.Text = "&Nest";
|
mnuNest.Text = "&Nest";
|
||||||
@@ -579,6 +580,13 @@
|
|||||||
mnuNestImportDrawing.Text = "Import Drawing";
|
mnuNestImportDrawing.Text = "Import Drawing";
|
||||||
mnuNestImportDrawing.Click += Import_Click;
|
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
|
||||||
//
|
//
|
||||||
toolStripMenuItem7.Name = "toolStripMenuItem7";
|
toolStripMenuItem7.Name = "toolStripMenuItem7";
|
||||||
@@ -1213,6 +1221,7 @@
|
|||||||
private System.Windows.Forms.ToolStripMenuItem mnuNest;
|
private System.Windows.Forms.ToolStripMenuItem mnuNest;
|
||||||
private System.Windows.Forms.ToolStripMenuItem mnuNestEdit;
|
private System.Windows.Forms.ToolStripMenuItem mnuNestEdit;
|
||||||
private System.Windows.Forms.ToolStripMenuItem mnuNestImportDrawing;
|
private System.Windows.Forms.ToolStripMenuItem mnuNestImportDrawing;
|
||||||
|
private System.Windows.Forms.ToolStripMenuItem mnuNestShapeLibrary;
|
||||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem7;
|
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem7;
|
||||||
private System.Windows.Forms.ToolStripMenuItem mnuNestFirstPlate;
|
private System.Windows.Forms.ToolStripMenuItem mnuNestFirstPlate;
|
||||||
private System.Windows.Forms.ToolStripMenuItem mnuNestLastPlate;
|
private System.Windows.Forms.ToolStripMenuItem mnuNestLastPlate;
|
||||||
|
|||||||
@@ -829,6 +829,20 @@ namespace OpenNest.Forms
|
|||||||
activeForm.Import();
|
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)
|
private void EditNest_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (activeForm == null) return;
|
if (activeForm == null) return;
|
||||||
|
|||||||
+338
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
<ItemGroup>
|
||||||
<Compile Remove="Controls\LayoutViewGL.cs" />
|
<Compile Remove="Controls\LayoutViewGL.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Configurations\**\*.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\OpenNest.Api\OpenNest.Api.csproj" />
|
<ProjectReference Include="..\OpenNest.Api\OpenNest.Api.csproj" />
|
||||||
<ProjectReference Include="..\OpenNest.Core\OpenNest.Core.csproj" />
|
<ProjectReference Include="..\OpenNest.Core\OpenNest.Core.csproj" />
|
||||||
|
|||||||
Reference in New Issue
Block a user