feat(ui): add NestProgressForm modeless dialog
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,184 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace OpenNest.Forms
|
||||||
|
{
|
||||||
|
public class NestProgressForm : Form
|
||||||
|
{
|
||||||
|
private readonly CancellationTokenSource cts;
|
||||||
|
|
||||||
|
private Label phaseValue;
|
||||||
|
private Label plateValue;
|
||||||
|
private Label partsValue;
|
||||||
|
private Label densityValue;
|
||||||
|
private Label remnantValue;
|
||||||
|
private Label plateLabel;
|
||||||
|
private Button stopButton;
|
||||||
|
private TableLayoutPanel table;
|
||||||
|
|
||||||
|
public NestProgressForm(CancellationTokenSource cts, bool showPlateRow = true)
|
||||||
|
{
|
||||||
|
this.cts = cts;
|
||||||
|
InitializeLayout(showPlateRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeLayout(bool showPlateRow)
|
||||||
|
{
|
||||||
|
Text = "Nesting Progress";
|
||||||
|
FormBorderStyle = FormBorderStyle.FixedToolWindow;
|
||||||
|
StartPosition = FormStartPosition.CenterParent;
|
||||||
|
ShowInTaskbar = false;
|
||||||
|
MinimizeBox = false;
|
||||||
|
MaximizeBox = false;
|
||||||
|
Size = new Size(280, showPlateRow ? 210 : 190);
|
||||||
|
|
||||||
|
table = new TableLayoutPanel
|
||||||
|
{
|
||||||
|
ColumnCount = 2,
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
AutoSize = true,
|
||||||
|
Padding = new Padding(8)
|
||||||
|
};
|
||||||
|
|
||||||
|
table.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 80));
|
||||||
|
table.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
|
||||||
|
|
||||||
|
phaseValue = AddRow(table, "Phase:");
|
||||||
|
plateValue = AddRow(table, "Plate:");
|
||||||
|
partsValue = AddRow(table, "Parts:");
|
||||||
|
densityValue = AddRow(table, "Density:");
|
||||||
|
remnantValue = AddRow(table, "Remnant:");
|
||||||
|
|
||||||
|
if (!showPlateRow)
|
||||||
|
{
|
||||||
|
plateLabel = FindLabel(table, "Plate:");
|
||||||
|
if (plateLabel != null)
|
||||||
|
SetRowVisible(plateLabel, plateValue, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
stopButton = new Button
|
||||||
|
{
|
||||||
|
Text = "Stop",
|
||||||
|
Width = 80,
|
||||||
|
Anchor = AnchorStyles.None,
|
||||||
|
Margin = new Padding(0, 8, 0, 8)
|
||||||
|
};
|
||||||
|
|
||||||
|
stopButton.Click += StopButton_Click;
|
||||||
|
|
||||||
|
var buttonPanel = new FlowLayoutPanel
|
||||||
|
{
|
||||||
|
FlowDirection = FlowDirection.RightToLeft,
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
AutoSize = true,
|
||||||
|
Padding = new Padding(8, 0, 8, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
buttonPanel.Controls.Add(stopButton);
|
||||||
|
|
||||||
|
Controls.Add(buttonPanel);
|
||||||
|
Controls.Add(table);
|
||||||
|
|
||||||
|
// Reverse order since Dock.Top stacks bottom-up
|
||||||
|
Controls.SetChildIndex(table, 0);
|
||||||
|
Controls.SetChildIndex(buttonPanel, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Label AddRow(TableLayoutPanel table, string labelText)
|
||||||
|
{
|
||||||
|
var row = table.RowCount;
|
||||||
|
table.RowCount = row + 1;
|
||||||
|
table.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||||
|
|
||||||
|
var label = new Label
|
||||||
|
{
|
||||||
|
Text = labelText,
|
||||||
|
Font = new Font(Font, FontStyle.Bold),
|
||||||
|
AutoSize = true,
|
||||||
|
Margin = new Padding(4)
|
||||||
|
};
|
||||||
|
|
||||||
|
var value = new Label
|
||||||
|
{
|
||||||
|
Text = "\u2014",
|
||||||
|
AutoSize = true,
|
||||||
|
Margin = new Padding(4)
|
||||||
|
};
|
||||||
|
|
||||||
|
table.Controls.Add(label, 0, row);
|
||||||
|
table.Controls.Add(value, 1, row);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Label FindLabel(TableLayoutPanel table, string text)
|
||||||
|
{
|
||||||
|
foreach (Control c in table.Controls)
|
||||||
|
{
|
||||||
|
if (c is Label l && l.Text == text)
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetRowVisible(Label label, Label value, bool visible)
|
||||||
|
{
|
||||||
|
label.Visible = visible;
|
||||||
|
value.Visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateProgress(NestProgress progress)
|
||||||
|
{
|
||||||
|
if (IsDisposed || !IsHandleCreated)
|
||||||
|
return;
|
||||||
|
|
||||||
|
phaseValue.Text = FormatPhase(progress.Phase);
|
||||||
|
plateValue.Text = progress.PlateNumber.ToString();
|
||||||
|
partsValue.Text = progress.BestPartCount.ToString();
|
||||||
|
densityValue.Text = progress.BestDensity.ToString("P1");
|
||||||
|
remnantValue.Text = $"{progress.UsableRemnantArea:F1} sq in";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowCompleted()
|
||||||
|
{
|
||||||
|
if (IsDisposed || !IsHandleCreated)
|
||||||
|
return;
|
||||||
|
|
||||||
|
phaseValue.Text = "Done";
|
||||||
|
stopButton.Text = "Close";
|
||||||
|
stopButton.Enabled = true;
|
||||||
|
stopButton.Click -= StopButton_Click;
|
||||||
|
stopButton.Click += (s, e) => Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopButton_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
cts.Cancel();
|
||||||
|
stopButton.Text = "Stopping...";
|
||||||
|
stopButton.Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||||
|
{
|
||||||
|
if (!cts.IsCancellationRequested)
|
||||||
|
cts.Cancel();
|
||||||
|
|
||||||
|
base.OnFormClosing(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatPhase(NestPhase phase)
|
||||||
|
{
|
||||||
|
switch (phase)
|
||||||
|
{
|
||||||
|
case NestPhase.Linear: return "Trying rotations...";
|
||||||
|
case NestPhase.RectBestFit: return "Trying best fit...";
|
||||||
|
case NestPhase.Pairs: return "Trying pairs...";
|
||||||
|
case NestPhase.Remainder: return "Filling remainder...";
|
||||||
|
default: return phase.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user