Merge remote-tracking branch 'origin/master'
This commit is contained in:
+366
-230
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,7 @@ namespace OpenNest.Controls
|
||||
public event EventHandler FilterChanged;
|
||||
public event EventHandler<int> BendLineSelected;
|
||||
public event EventHandler<int> BendLineRemoved;
|
||||
public event EventHandler<int> BendLineEdited;
|
||||
public event EventHandler AddBendLineClicked;
|
||||
|
||||
public FilterPanel()
|
||||
@@ -51,6 +52,18 @@ namespace OpenNest.Controls
|
||||
bendLinesList.SelectedIndexChanged += (s, e) =>
|
||||
BendLineSelected?.Invoke(this, bendLinesList.SelectedIndex);
|
||||
|
||||
var bendEditLink = new LinkLabel
|
||||
{
|
||||
Text = "Edit",
|
||||
AutoSize = true,
|
||||
Font = new Font("Segoe UI", 8f)
|
||||
};
|
||||
bendEditLink.LinkClicked += (s, e) =>
|
||||
{
|
||||
if (bendLinesList.SelectedIndex >= 0)
|
||||
BendLineEdited?.Invoke(this, bendLinesList.SelectedIndex);
|
||||
};
|
||||
|
||||
var bendDeleteLink = new LinkLabel
|
||||
{
|
||||
Text = "Remove",
|
||||
@@ -63,6 +76,12 @@ namespace OpenNest.Controls
|
||||
BendLineRemoved?.Invoke(this, bendLinesList.SelectedIndex);
|
||||
};
|
||||
|
||||
bendLinesList.DoubleClick += (s, e) =>
|
||||
{
|
||||
if (bendLinesList.SelectedIndex >= 0)
|
||||
BendLineEdited?.Invoke(this, bendLinesList.SelectedIndex);
|
||||
};
|
||||
|
||||
bendAddLink = new LinkLabel
|
||||
{
|
||||
Text = "Add Bend Line",
|
||||
@@ -80,6 +99,7 @@ namespace OpenNest.Controls
|
||||
WrapContents = false
|
||||
};
|
||||
bendLinksPanel.Controls.Add(bendAddLink);
|
||||
bendLinksPanel.Controls.Add(bendEditLink);
|
||||
bendLinksPanel.Controls.Add(bendDeleteLink);
|
||||
|
||||
bendLinesPanel.ContentPanel.Controls.Add(bendLinesList);
|
||||
|
||||
@@ -209,15 +209,8 @@ namespace OpenNest.Controls
|
||||
|
||||
private static Entity CloneEntity(Entity entity, Color color)
|
||||
{
|
||||
Entity clone = entity switch
|
||||
{
|
||||
Line line => new Line(line.StartPoint, line.EndPoint) { Layer = line.Layer, IsVisible = line.IsVisible },
|
||||
Arc arc => new Arc(arc.Center, arc.Radius, arc.StartAngle, arc.EndAngle, arc.IsReversed) { Layer = arc.Layer, IsVisible = arc.IsVisible },
|
||||
Circle circle => new Circle(circle.Center, circle.Radius) { Layer = circle.Layer, IsVisible = circle.IsVisible },
|
||||
_ => null,
|
||||
};
|
||||
if (clone != null)
|
||||
clone.Color = color;
|
||||
var clone = entity.Clone();
|
||||
clone.Color = color;
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,5 +99,17 @@ namespace OpenNest.Forms
|
||||
public double BendAngle => (double)numAngle.Value;
|
||||
|
||||
public double? BendRadius => chkRadius.Checked ? (double)numRadius.Value : null;
|
||||
|
||||
public void LoadBend(Bend bend)
|
||||
{
|
||||
cboDirection.SelectedIndex = bend.Direction == BendDirection.Up ? 1 : 0;
|
||||
if (bend.Angle.HasValue)
|
||||
numAngle.Value = (decimal)bend.Angle.Value;
|
||||
if (bend.Radius.HasValue)
|
||||
{
|
||||
chkRadius.Checked = true;
|
||||
numRadius.Value = (decimal)bend.Radius.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace OpenNest.Forms
|
||||
filterPanel.FilterChanged += OnFilterChanged;
|
||||
filterPanel.BendLineSelected += OnBendLineSelected;
|
||||
filterPanel.BendLineRemoved += OnBendLineRemoved;
|
||||
filterPanel.BendLineEdited += OnBendLineEdited;
|
||||
filterPanel.AddBendLineClicked += OnAddBendLineClicked;
|
||||
entityView1.LinePicked += OnLinePicked;
|
||||
entityView1.PickCancelled += OnPickCancelled;
|
||||
@@ -292,6 +293,29 @@ namespace OpenNest.Forms
|
||||
entityView1.Invalidate();
|
||||
}
|
||||
|
||||
private void OnBendLineEdited(object sender, int index)
|
||||
{
|
||||
var item = CurrentItem;
|
||||
if (item == null || index < 0 || index >= item.Bends.Count) return;
|
||||
|
||||
var bend = item.Bends[index];
|
||||
using var dialog = new BendLineDialog();
|
||||
dialog.LoadBend(bend);
|
||||
|
||||
if (dialog.ShowDialog(this) != DialogResult.OK) return;
|
||||
|
||||
bend.Direction = dialog.Direction;
|
||||
bend.Angle = dialog.BendAngle;
|
||||
bend.Radius = dialog.BendRadius;
|
||||
|
||||
Bend.UpdateEtchEntities(item.Entities, item.Bends);
|
||||
entityView1.Entities.Clear();
|
||||
entityView1.Entities.AddRange(item.Entities);
|
||||
entityView1.Bends = item.Bends;
|
||||
filterPanel.LoadItem(item.Entities, item.Bends);
|
||||
entityView1.Invalidate();
|
||||
}
|
||||
|
||||
private void OnQuantityChanged(object sender, EventArgs e)
|
||||
{
|
||||
var item = CurrentItem;
|
||||
|
||||
@@ -7,6 +7,7 @@ using OpenNest.Engine.Sequencing;
|
||||
using OpenNest.IO;
|
||||
using OpenNest.Math;
|
||||
using OpenNest.Properties;
|
||||
using OpenNest.Shapes;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
@@ -453,7 +454,11 @@ namespace OpenNest.Forms
|
||||
|
||||
public void ResizePlateToFitParts()
|
||||
{
|
||||
PlateView.Plate.AutoSize(Settings.Default.AutoSizePlateFactor);
|
||||
var options = new PlateSizeOptions
|
||||
{
|
||||
SnapIncrement = Settings.Default.AutoSizePlateFactor,
|
||||
};
|
||||
PlateView.Plate.SnapToStandardSize(options);
|
||||
PlateView.ZoomToPlate();
|
||||
PlateView.Refresh();
|
||||
UpdatePlateList();
|
||||
|
||||
@@ -180,27 +180,66 @@ namespace OpenNest.Forms
|
||||
|
||||
y += 18;
|
||||
|
||||
var tb = new TextBox
|
||||
Control editor;
|
||||
if (prop.PropertyType == typeof(bool))
|
||||
{
|
||||
Location = new Point(parametersPanel.Padding.Left, y),
|
||||
Width = panelWidth,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
|
||||
};
|
||||
var cb = new CheckBox
|
||||
{
|
||||
Location = new Point(parametersPanel.Padding.Left, y),
|
||||
AutoSize = true,
|
||||
Checked = sourceValues != null && (bool)prop.GetValue(sourceValues)
|
||||
};
|
||||
cb.CheckedChanged += (s, ev) => UpdatePreview();
|
||||
editor = cb;
|
||||
}
|
||||
else if (prop.PropertyType == typeof(string) && prop.Name == "PipeSize")
|
||||
{
|
||||
var combo = new ComboBox
|
||||
{
|
||||
Location = new Point(parametersPanel.Padding.Left, y),
|
||||
Width = panelWidth,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right,
|
||||
DropDownStyle = ComboBoxStyle.DropDownList
|
||||
};
|
||||
|
||||
if (sourceValues != null)
|
||||
// Initial population: every entry; the filter runs on first UpdatePreview.
|
||||
foreach (var entry in PipeSizes.All)
|
||||
combo.Items.Add(entry.Label);
|
||||
|
||||
var initial = sourceValues != null ? (string)prop.GetValue(sourceValues) : null;
|
||||
if (!string.IsNullOrEmpty(initial) && combo.Items.Contains(initial))
|
||||
combo.SelectedItem = initial;
|
||||
else if (combo.Items.Count > 0)
|
||||
combo.SelectedIndex = 0;
|
||||
|
||||
combo.SelectedIndexChanged += (s, ev) => UpdatePreview();
|
||||
editor = combo;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prop.PropertyType == typeof(int))
|
||||
tb.Text = ((int)prop.GetValue(sourceValues)).ToString();
|
||||
else
|
||||
tb.Text = ((double)prop.GetValue(sourceValues)).ToString("G");
|
||||
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();
|
||||
editor = tb;
|
||||
}
|
||||
|
||||
tb.TextChanged += (s, ev) => UpdatePreview();
|
||||
|
||||
parameterBindings.Add(new ParameterBinding { Property = prop, Control = tb });
|
||||
parameterBindings.Add(new ParameterBinding { Property = prop, Control = editor });
|
||||
|
||||
parametersPanel.Controls.Add(label);
|
||||
parametersPanel.Controls.Add(tb);
|
||||
parametersPanel.Controls.Add(editor);
|
||||
|
||||
y += 30;
|
||||
}
|
||||
@@ -212,6 +251,8 @@ namespace OpenNest.Forms
|
||||
{
|
||||
if (suppressPreview || selectedEntry == null) return;
|
||||
|
||||
UpdatePipeSizeFilter();
|
||||
|
||||
try
|
||||
{
|
||||
var shape = CreateShapeFromInputs();
|
||||
@@ -223,9 +264,17 @@ namespace OpenNest.Forms
|
||||
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));
|
||||
var info = string.Format("{0:F3} x {1:F3}", bb.Size.Length, bb.Size.Width);
|
||||
|
||||
if (shape is PipeFlangeShape flange
|
||||
&& !flange.Blind
|
||||
&& !string.IsNullOrEmpty(flange.PipeSize)
|
||||
&& !PipeSizes.TryGetOD(flange.PipeSize, out _))
|
||||
{
|
||||
info += " — Invalid pipe size, no bore cut";
|
||||
}
|
||||
|
||||
previewBox.SetInfo(nameTextBox.Text, info);
|
||||
}
|
||||
}
|
||||
catch
|
||||
@@ -234,6 +283,72 @@ namespace OpenNest.Forms
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePipeSizeFilter()
|
||||
{
|
||||
// Find the PipeSize combo and the numeric inputs it depends on.
|
||||
ComboBox pipeCombo = null;
|
||||
double holePattern = 0, holeDia = 0, clearance = 0;
|
||||
bool blind = false;
|
||||
|
||||
foreach (var binding in parameterBindings)
|
||||
{
|
||||
var name = binding.Property.Name;
|
||||
if (name == "PipeSize" && binding.Control is ComboBox cb)
|
||||
pipeCombo = cb;
|
||||
else if (name == "HolePatternDiameter" && binding.Control is TextBox tb1)
|
||||
double.TryParse(tb1.Text, out holePattern);
|
||||
else if (name == "HoleDiameter" && binding.Control is TextBox tb2)
|
||||
double.TryParse(tb2.Text, out holeDia);
|
||||
else if (name == "PipeClearance" && binding.Control is TextBox tb3)
|
||||
double.TryParse(tb3.Text, out clearance);
|
||||
else if (name == "Blind" && binding.Control is CheckBox chk)
|
||||
blind = chk.Checked;
|
||||
}
|
||||
|
||||
if (pipeCombo == null)
|
||||
return;
|
||||
|
||||
// Disable when blind, but keep visible with the selection preserved.
|
||||
pipeCombo.Enabled = !blind;
|
||||
|
||||
// Compute filter: pipeOD + clearance < HolePatternDiameter - HoleDiameter.
|
||||
var maxPipeOD = holePattern - holeDia - clearance;
|
||||
var fittingLabels = PipeSizes.GetFittingSizes(maxPipeOD).Select(e => e.Label).ToList();
|
||||
|
||||
// Sequence-equal on existing items — no-op if unchanged (avoids flicker).
|
||||
var currentLabels = pipeCombo.Items.Cast<string>().ToList();
|
||||
if (currentLabels.SequenceEqual(fittingLabels))
|
||||
return;
|
||||
|
||||
var previousSelection = pipeCombo.SelectedItem as string;
|
||||
|
||||
pipeCombo.BeginUpdate();
|
||||
try
|
||||
{
|
||||
pipeCombo.Items.Clear();
|
||||
foreach (var label in fittingLabels)
|
||||
pipeCombo.Items.Add(label);
|
||||
|
||||
if (fittingLabels.Count == 0)
|
||||
{
|
||||
// No pipe fits — leave unselected.
|
||||
}
|
||||
else if (previousSelection != null && fittingLabels.Contains(previousSelection))
|
||||
{
|
||||
pipeCombo.SelectedItem = previousSelection;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Select the largest (last, since PipeSizes.All is sorted ascending).
|
||||
pipeCombo.SelectedIndex = fittingLabels.Count - 1;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
pipeCombo.EndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private ShapeDefinition CreateShapeFromInputs()
|
||||
{
|
||||
var shape = (ShapeDefinition)Activator.CreateInstance(selectedEntry.ShapeType);
|
||||
@@ -241,6 +356,19 @@ namespace OpenNest.Forms
|
||||
|
||||
foreach (var binding in parameterBindings)
|
||||
{
|
||||
if (binding.Property.PropertyType == typeof(bool))
|
||||
{
|
||||
var cb = (CheckBox)binding.Control;
|
||||
binding.Property.SetValue(shape, cb.Checked);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (binding.Control is ComboBox combo)
|
||||
{
|
||||
binding.Property.SetValue(shape, combo.SelectedItem?.ToString());
|
||||
continue;
|
||||
}
|
||||
|
||||
var tb = (TextBox)binding.Control;
|
||||
|
||||
if (binding.Property.PropertyType == typeof(int))
|
||||
|
||||
Reference in New Issue
Block a user