feat: add MachineConfigForm editor with tree navigation and MainForm menu integration
Wires the OpenNest.Data layer into the UI: adds project reference, creates MachineConfigForm (tree-based editor for machines/materials/thicknesses with import/export), and adds Tools > Machine Configuration... menu item. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
419
OpenNest/Forms/MachineConfigForm.cs
Normal file
419
OpenNest/Forms/MachineConfigForm.cs
Normal file
@@ -0,0 +1,419 @@
|
||||
using OpenNest.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OpenNest.Forms
|
||||
{
|
||||
public class MachineConfigForm : Form
|
||||
{
|
||||
private readonly IDataProvider _provider;
|
||||
private readonly TreeView _tree;
|
||||
private readonly Panel _detailPanel;
|
||||
|
||||
private MachineConfig _currentMachine;
|
||||
|
||||
public MachineConfigForm(IDataProvider provider)
|
||||
{
|
||||
_provider = provider;
|
||||
|
||||
Text = "Machine Configuration";
|
||||
Size = new Size(900, 600);
|
||||
StartPosition = FormStartPosition.CenterParent;
|
||||
MinimumSize = new Size(700, 400);
|
||||
|
||||
var splitContainer = new SplitContainer
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
SplitterDistance = 250,
|
||||
FixedPanel = FixedPanel.Panel1
|
||||
};
|
||||
|
||||
_tree = new TreeView
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
HideSelection = false
|
||||
};
|
||||
_tree.AfterSelect += Tree_AfterSelect;
|
||||
|
||||
var treeButtonPanel = new FlowLayoutPanel
|
||||
{
|
||||
Dock = DockStyle.Bottom,
|
||||
AutoSize = true,
|
||||
FlowDirection = FlowDirection.LeftToRight,
|
||||
WrapContents = true,
|
||||
Padding = new Padding(2)
|
||||
};
|
||||
|
||||
var addMachineButton = new Button { Text = "+ Machine", AutoSize = true };
|
||||
addMachineButton.Click += AddMachine_Click;
|
||||
var removeMachineButton = new Button { Text = "- Machine", AutoSize = true };
|
||||
removeMachineButton.Click += RemoveMachine_Click;
|
||||
var addMaterialButton = new Button { Text = "+ Material", AutoSize = true };
|
||||
addMaterialButton.Click += AddMaterial_Click;
|
||||
var removeMaterialButton = new Button { Text = "- Material", AutoSize = true };
|
||||
removeMaterialButton.Click += RemoveMaterial_Click;
|
||||
var addThicknessButton = new Button { Text = "+ Thickness", AutoSize = true };
|
||||
addThicknessButton.Click += AddThickness_Click;
|
||||
var removeThicknessButton = new Button { Text = "- Thickness", AutoSize = true };
|
||||
removeThicknessButton.Click += RemoveThickness_Click;
|
||||
|
||||
treeButtonPanel.Controls.AddRange(new Control[]
|
||||
{
|
||||
addMachineButton, removeMachineButton,
|
||||
addMaterialButton, removeMaterialButton,
|
||||
addThicknessButton, removeThicknessButton
|
||||
});
|
||||
|
||||
splitContainer.Panel1.Controls.Add(_tree);
|
||||
splitContainer.Panel1.Controls.Add(treeButtonPanel);
|
||||
|
||||
_detailPanel = new Panel { Dock = DockStyle.Fill, AutoScroll = true };
|
||||
splitContainer.Panel2.Controls.Add(_detailPanel);
|
||||
|
||||
var bottomPanel = new FlowLayoutPanel
|
||||
{
|
||||
Dock = DockStyle.Bottom,
|
||||
AutoSize = true,
|
||||
FlowDirection = FlowDirection.RightToLeft,
|
||||
Padding = new Padding(4)
|
||||
};
|
||||
|
||||
var saveButton = new Button { Text = "Save", AutoSize = true };
|
||||
saveButton.Click += Save_Click;
|
||||
var importButton = new Button { Text = "Import...", AutoSize = true };
|
||||
importButton.Click += Import_Click;
|
||||
var exportButton = new Button { Text = "Export...", AutoSize = true };
|
||||
exportButton.Click += Export_Click;
|
||||
|
||||
bottomPanel.Controls.AddRange(new Control[] { saveButton, exportButton, importButton });
|
||||
|
||||
Controls.Add(splitContainer);
|
||||
Controls.Add(bottomPanel);
|
||||
|
||||
LoadTree();
|
||||
}
|
||||
|
||||
private void LoadTree()
|
||||
{
|
||||
_tree.Nodes.Clear();
|
||||
foreach (var summary in _provider.GetMachines())
|
||||
{
|
||||
var machine = _provider.GetMachine(summary.Id);
|
||||
if (machine is null) continue;
|
||||
|
||||
var machineNode = new TreeNode(machine.Name) { Tag = machine };
|
||||
foreach (var material in machine.Materials)
|
||||
{
|
||||
var matNode = new TreeNode(material.Name) { Tag = material };
|
||||
foreach (var thickness in material.Thicknesses)
|
||||
{
|
||||
var thickNode = new TreeNode(thickness.Value.ToString("0.####")) { Tag = thickness };
|
||||
matNode.Nodes.Add(thickNode);
|
||||
}
|
||||
machineNode.Nodes.Add(matNode);
|
||||
}
|
||||
_tree.Nodes.Add(machineNode);
|
||||
}
|
||||
|
||||
if (_tree.Nodes.Count > 0)
|
||||
_tree.SelectedNode = _tree.Nodes[0];
|
||||
}
|
||||
|
||||
private void Tree_AfterSelect(object sender, TreeViewEventArgs e)
|
||||
{
|
||||
_detailPanel.Controls.Clear();
|
||||
if (e.Node?.Tag is null) return;
|
||||
|
||||
switch (e.Node.Tag)
|
||||
{
|
||||
case MachineConfig machine:
|
||||
_currentMachine = machine;
|
||||
ShowMachineDetails(machine);
|
||||
break;
|
||||
case MaterialConfig material:
|
||||
_currentMachine = e.Node.Parent?.Tag as MachineConfig;
|
||||
ShowMaterialDetails(material);
|
||||
break;
|
||||
case ThicknessConfig thickness:
|
||||
_currentMachine = e.Node.Parent?.Parent?.Tag as MachineConfig;
|
||||
ShowThicknessDetails(thickness);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowMachineDetails(MachineConfig machine)
|
||||
{
|
||||
var layout = CreateDetailLayout();
|
||||
var row = 0;
|
||||
|
||||
AddField(layout, ref row, "Name:", CreateTextBox(machine.Name, v => machine.Name = v));
|
||||
AddField(layout, ref row, "Type:", CreateEnumCombo(machine.Type, v => machine.Type = v));
|
||||
AddField(layout, ref row, "Units:", CreateEnumCombo(machine.Units, v => machine.Units = v));
|
||||
|
||||
_detailPanel.Controls.Add(layout);
|
||||
}
|
||||
|
||||
private void ShowMaterialDetails(MaterialConfig material)
|
||||
{
|
||||
var layout = CreateDetailLayout();
|
||||
var row = 0;
|
||||
|
||||
AddField(layout, ref row, "Name:", CreateTextBox(material.Name, v => material.Name = v));
|
||||
AddField(layout, ref row, "Grade:", CreateTextBox(material.Grade, v => material.Grade = v));
|
||||
AddField(layout, ref row, "Density:", CreateNumericBox(material.Density, v => material.Density = v, 4));
|
||||
|
||||
_detailPanel.Controls.Add(layout);
|
||||
}
|
||||
|
||||
private void ShowThicknessDetails(ThicknessConfig thickness)
|
||||
{
|
||||
var layout = CreateDetailLayout();
|
||||
var row = 0;
|
||||
|
||||
AddField(layout, ref row, "Thickness:", CreateNumericBox(thickness.Value, v => thickness.Value = v, 4));
|
||||
AddField(layout, ref row, "Kerf:", CreateNumericBox(thickness.Kerf, v => thickness.Kerf = v, 4));
|
||||
AddField(layout, ref row, "Assist Gas:", CreateTextBox(thickness.AssistGas, v => thickness.AssistGas = v));
|
||||
|
||||
AddSectionHeader(layout, ref row, "Lead In");
|
||||
AddField(layout, ref row, "Type:", CreateTextBox(thickness.LeadIn.Type, v => thickness.LeadIn.Type = v));
|
||||
AddField(layout, ref row, "Length:", CreateNumericBox(thickness.LeadIn.Length, v => thickness.LeadIn.Length = v, 4));
|
||||
AddField(layout, ref row, "Angle:", CreateNumericBox(thickness.LeadIn.Angle, v => thickness.LeadIn.Angle = v, 1));
|
||||
AddField(layout, ref row, "Radius:", CreateNumericBox(thickness.LeadIn.Radius, v => thickness.LeadIn.Radius = v, 4));
|
||||
|
||||
AddSectionHeader(layout, ref row, "Lead Out");
|
||||
AddField(layout, ref row, "Type:", CreateTextBox(thickness.LeadOut.Type, v => thickness.LeadOut.Type = v));
|
||||
AddField(layout, ref row, "Length:", CreateNumericBox(thickness.LeadOut.Length, v => thickness.LeadOut.Length = v, 4));
|
||||
AddField(layout, ref row, "Angle:", CreateNumericBox(thickness.LeadOut.Angle, v => thickness.LeadOut.Angle = v, 1));
|
||||
AddField(layout, ref row, "Radius:", CreateNumericBox(thickness.LeadOut.Radius, v => thickness.LeadOut.Radius = v, 4));
|
||||
|
||||
AddSectionHeader(layout, ref row, "Cut Off");
|
||||
AddField(layout, ref row, "Part Clearance:", CreateNumericBox(thickness.CutOff.PartClearance, v => thickness.CutOff.PartClearance = v, 4));
|
||||
AddField(layout, ref row, "Overtravel:", CreateNumericBox(thickness.CutOff.Overtravel, v => thickness.CutOff.Overtravel = v, 4));
|
||||
AddField(layout, ref row, "Min Segment:", CreateNumericBox(thickness.CutOff.MinSegmentLength, v => thickness.CutOff.MinSegmentLength = v, 4));
|
||||
AddField(layout, ref row, "Direction:", CreateTextBox(thickness.CutOff.Direction, v => thickness.CutOff.Direction = v));
|
||||
|
||||
AddSectionHeader(layout, ref row, "Plate Sizes");
|
||||
var sizesText = string.Join(", ", thickness.PlateSizes);
|
||||
AddField(layout, ref row, "Sizes:", CreateTextBox(sizesText, v =>
|
||||
{
|
||||
thickness.PlateSizes = v.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList();
|
||||
}));
|
||||
|
||||
_detailPanel.Controls.Add(layout);
|
||||
}
|
||||
|
||||
private static TableLayoutPanel CreateDetailLayout()
|
||||
{
|
||||
var layout = new TableLayoutPanel
|
||||
{
|
||||
Dock = DockStyle.Top,
|
||||
AutoSize = true,
|
||||
ColumnCount = 2,
|
||||
Padding = new Padding(8)
|
||||
};
|
||||
layout.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
|
||||
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
|
||||
return layout;
|
||||
}
|
||||
|
||||
private static void AddField(TableLayoutPanel layout, ref int row, string label, Control control)
|
||||
{
|
||||
layout.RowCount = row + 1;
|
||||
layout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||
layout.Controls.Add(new Label { Text = label, AutoSize = true, Anchor = AnchorStyles.Left, Margin = new Padding(0, 6, 8, 0) }, 0, row);
|
||||
control.Dock = DockStyle.Fill;
|
||||
layout.Controls.Add(control, 1, row);
|
||||
row++;
|
||||
}
|
||||
|
||||
private static void AddSectionHeader(TableLayoutPanel layout, ref int row, string text)
|
||||
{
|
||||
layout.RowCount = row + 1;
|
||||
layout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||
var label = new Label
|
||||
{
|
||||
Text = text,
|
||||
AutoSize = true,
|
||||
Font = new Font(Control.DefaultFont, FontStyle.Bold),
|
||||
Margin = new Padding(0, 12, 0, 4)
|
||||
};
|
||||
layout.SetColumnSpan(label, 2);
|
||||
layout.Controls.Add(label, 0, row);
|
||||
row++;
|
||||
}
|
||||
|
||||
private static TextBox CreateTextBox(string value, Action<string> setter)
|
||||
{
|
||||
var textBox = new TextBox { Text = value };
|
||||
textBox.TextChanged += (s, e) => setter(textBox.Text);
|
||||
return textBox;
|
||||
}
|
||||
|
||||
private static NumericUpDown CreateNumericBox(double value, Action<double> setter, int decimals)
|
||||
{
|
||||
var numeric = new NumericUpDown
|
||||
{
|
||||
DecimalPlaces = decimals,
|
||||
Minimum = 0,
|
||||
Maximum = 10000,
|
||||
Increment = (decimal)System.Math.Pow(10, -decimals),
|
||||
Value = (decimal)value
|
||||
};
|
||||
numeric.ValueChanged += (s, e) => setter((double)numeric.Value);
|
||||
return numeric;
|
||||
}
|
||||
|
||||
private static ComboBox CreateEnumCombo<T>(T currentValue, Action<T> setter) where T : struct, Enum
|
||||
{
|
||||
var combo = new ComboBox
|
||||
{
|
||||
DropDownStyle = ComboBoxStyle.DropDownList
|
||||
};
|
||||
combo.Items.AddRange(Enum.GetNames<T>().Cast<object>().ToArray());
|
||||
combo.SelectedItem = currentValue.ToString();
|
||||
combo.SelectedIndexChanged += (s, e) =>
|
||||
{
|
||||
if (Enum.TryParse<T>(combo.SelectedItem?.ToString(), out var val))
|
||||
setter(val);
|
||||
};
|
||||
return combo;
|
||||
}
|
||||
|
||||
private void Save_Click(object sender, EventArgs e)
|
||||
{
|
||||
foreach (TreeNode machineNode in _tree.Nodes)
|
||||
{
|
||||
if (machineNode.Tag is MachineConfig machine)
|
||||
_provider.SaveMachine(machine);
|
||||
}
|
||||
MessageBox.Show("Machine configurations saved.", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
|
||||
private void AddMachine_Click(object sender, EventArgs e)
|
||||
{
|
||||
var machine = new MachineConfig { Name = "New Machine" };
|
||||
_provider.SaveMachine(machine);
|
||||
LoadTree();
|
||||
}
|
||||
|
||||
private void RemoveMachine_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_tree.SelectedNode?.Tag is not MachineConfig machine) return;
|
||||
if (MessageBox.Show($"Delete machine '{machine.Name}'?", "Confirm", MessageBoxButtons.YesNo) != DialogResult.Yes) return;
|
||||
|
||||
_provider.DeleteMachine(machine.Id);
|
||||
LoadTree();
|
||||
}
|
||||
|
||||
private void AddMaterial_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_currentMachine is null) return;
|
||||
|
||||
_currentMachine.Materials.Add(new MaterialConfig { Name = "New Material" });
|
||||
_provider.SaveMachine(_currentMachine);
|
||||
LoadTree();
|
||||
}
|
||||
|
||||
private void RemoveMaterial_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_tree.SelectedNode?.Tag is not MaterialConfig material) return;
|
||||
if (_currentMachine is null) return;
|
||||
|
||||
_currentMachine.Materials.Remove(material);
|
||||
_provider.SaveMachine(_currentMachine);
|
||||
LoadTree();
|
||||
}
|
||||
|
||||
private void AddThickness_Click(object sender, EventArgs e)
|
||||
{
|
||||
var material = _tree.SelectedNode?.Tag as MaterialConfig;
|
||||
if (material is null && _tree.SelectedNode?.Tag is ThicknessConfig)
|
||||
material = _tree.SelectedNode.Parent?.Tag as MaterialConfig;
|
||||
if (material is null || _currentMachine is null) return;
|
||||
|
||||
material.Thicknesses.Add(new ThicknessConfig { Value = 0.250 });
|
||||
_provider.SaveMachine(_currentMachine);
|
||||
LoadTree();
|
||||
}
|
||||
|
||||
private void RemoveThickness_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_tree.SelectedNode?.Tag is not ThicknessConfig thickness) return;
|
||||
var material = _tree.SelectedNode.Parent?.Tag as MaterialConfig;
|
||||
if (material is null || _currentMachine is null) return;
|
||||
|
||||
material.Thicknesses.Remove(thickness);
|
||||
_provider.SaveMachine(_currentMachine);
|
||||
LoadTree();
|
||||
}
|
||||
|
||||
private void Import_Click(object sender, EventArgs e)
|
||||
{
|
||||
using (var dialog = new OpenFileDialog
|
||||
{
|
||||
Filter = "JSON files (*.json)|*.json",
|
||||
Title = "Import Machine Configuration"
|
||||
})
|
||||
{
|
||||
if (dialog.ShowDialog() != DialogResult.OK) return;
|
||||
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(dialog.FileName);
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }
|
||||
};
|
||||
var machine = JsonSerializer.Deserialize<MachineConfig>(json, options);
|
||||
if (machine is null) return;
|
||||
|
||||
machine.Id = Guid.NewGuid();
|
||||
_provider.SaveMachine(machine);
|
||||
LoadTree();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Failed to import: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Export_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_currentMachine is null) return;
|
||||
|
||||
using (var dialog = new SaveFileDialog
|
||||
{
|
||||
Filter = "JSON files (*.json)|*.json",
|
||||
FileName = $"{_currentMachine.Name}.json",
|
||||
Title = "Export Machine Configuration"
|
||||
})
|
||||
{
|
||||
if (dialog.ShowDialog() != DialogResult.OK) return;
|
||||
|
||||
try
|
||||
{
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }
|
||||
};
|
||||
var json = JsonSerializer.Serialize(_currentMachine, options);
|
||||
File.WriteAllText(dialog.FileName, json);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Failed to export: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
OpenNest/Forms/MainForm.Designer.cs
generated
13
OpenNest/Forms/MainForm.Designer.cs
generated
@@ -79,6 +79,7 @@
|
||||
mnuSetOffsetIncrement = new System.Windows.Forms.ToolStripMenuItem();
|
||||
mnuSetRotationIncrement = new System.Windows.Forms.ToolStripMenuItem();
|
||||
toolStripMenuItem15 = new System.Windows.Forms.ToolStripSeparator();
|
||||
mnuToolsMachineConfig = new System.Windows.Forms.ToolStripMenuItem();
|
||||
mnuToolsOptions = new System.Windows.Forms.ToolStripMenuItem();
|
||||
mnuNest = new System.Windows.Forms.ToolStripMenuItem();
|
||||
mnuNestEdit = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -403,7 +404,7 @@
|
||||
//
|
||||
// mnuTools
|
||||
//
|
||||
mnuTools.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { mnuToolsMeasureArea, mnuToolsBestFitViewer, mnuToolsPatternTile, mnuToolsAlign, toolStripMenuItem14, mnuSetOffsetIncrement, mnuSetRotationIncrement, toolStripMenuItem15, mnuToolsOptions });
|
||||
mnuTools.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { mnuToolsMeasureArea, mnuToolsBestFitViewer, mnuToolsPatternTile, mnuToolsAlign, toolStripMenuItem14, mnuSetOffsetIncrement, mnuSetRotationIncrement, toolStripMenuItem15, mnuToolsMachineConfig, mnuToolsOptions });
|
||||
mnuTools.Name = "mnuTools";
|
||||
mnuTools.Size = new System.Drawing.Size(47, 20);
|
||||
mnuTools.Text = "&Tools";
|
||||
@@ -528,8 +529,15 @@
|
||||
toolStripMenuItem15.Name = "toolStripMenuItem15";
|
||||
toolStripMenuItem15.Size = new System.Drawing.Size(211, 6);
|
||||
//
|
||||
// mnuToolsMachineConfig
|
||||
//
|
||||
mnuToolsMachineConfig.Name = "mnuToolsMachineConfig";
|
||||
mnuToolsMachineConfig.Size = new System.Drawing.Size(214, 22);
|
||||
mnuToolsMachineConfig.Text = "Machine Configuration...";
|
||||
mnuToolsMachineConfig.Click += MachineConfig_Click;
|
||||
//
|
||||
// mnuToolsOptions
|
||||
//
|
||||
//
|
||||
mnuToolsOptions.Name = "mnuToolsOptions";
|
||||
mnuToolsOptions.Size = new System.Drawing.Size(214, 22);
|
||||
mnuToolsOptions.Text = "Options";
|
||||
@@ -1154,6 +1162,7 @@
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuViewDrawOffset;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem5;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuTools;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuToolsMachineConfig;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuToolsOptions;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuNest;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuNestEdit;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using OpenNest.Actions;
|
||||
using OpenNest.Collections;
|
||||
using OpenNest.Data;
|
||||
using OpenNest.Engine.BestFit;
|
||||
using OpenNest.Engine.Fill;
|
||||
using OpenNest.Geometry;
|
||||
@@ -739,6 +740,17 @@ namespace OpenNest.Forms
|
||||
form.ShowDialog();
|
||||
}
|
||||
|
||||
private void MachineConfig_Click(object sender, EventArgs e)
|
||||
{
|
||||
var appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "OpenNest", "Machines");
|
||||
var provider = new LocalJsonProvider(appDataPath);
|
||||
provider.EnsureDefaults();
|
||||
using (var form = new MachineConfigForm(provider))
|
||||
{
|
||||
form.ShowDialog(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void AlignLeft_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (activeForm == null) return;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenNest.Api\OpenNest.Api.csproj" />
|
||||
<ProjectReference Include="..\OpenNest.Core\OpenNest.Core.csproj" />
|
||||
<ProjectReference Include="..\OpenNest.Data\OpenNest.Data.csproj" />
|
||||
<ProjectReference Include="..\OpenNest.Engine\OpenNest.Engine.csproj" />
|
||||
<ProjectReference Include="..\OpenNest.Gpu\OpenNest.Gpu.csproj" />
|
||||
<ProjectReference Include="..\OpenNest.IO\OpenNest.IO.csproj" />
|
||||
|
||||
Reference in New Issue
Block a user