feat(ui): add filtered pipe size dropdown to shape library

Renders PipeSize as a DropDownList ComboBox, filters entries to those fitting
the current hole geometry, disables the combo when Blind is checked, and
appends an invalid-pipe warning to the preview info when TryGetOD fails.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-10 17:50:01 -04:00
parent 9d66b78a11
commit b1d094104a

View File

@@ -192,6 +192,29 @@ namespace OpenNest.Forms
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
};
// 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
{
var tb = new TextBox
@@ -228,6 +251,8 @@ namespace OpenNest.Forms
{
if (suppressPreview || selectedEntry == null) return;
UpdatePipeSizeFilter();
try
{
var shape = CreateShapeFromInputs();
@@ -239,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
@@ -250,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);
@@ -264,6 +363,13 @@ namespace OpenNest.Forms
continue;
}
if (binding.Property.PropertyType == typeof(string))
{
var combo = (ComboBox)binding.Control;
binding.Property.SetValue(shape, combo.SelectedItem?.ToString());
continue;
}
var tb = (TextBox)binding.Control;
if (binding.Property.PropertyType == typeof(int))