refactor: make ProgramEditorControl gcode editor read-only with contour comments

Remove the Apply button and OnApplyClicked handler since the gcode
editor is now read-only. Add contour label comments (e.g. "; Hole 1
(CCW)") to the formatted gcode output so users can see which feature
each group of codes belongs to.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-02 08:34:25 -04:00
parent a6e2845261
commit 3a24e76dbd
2 changed files with 35 additions and 82 deletions

View File

@@ -30,7 +30,6 @@ namespace OpenNest.Controls
editorPanel = new System.Windows.Forms.Panel(); editorPanel = new System.Windows.Forms.Panel();
gcodeEditor = new System.Windows.Forms.TextBox(); gcodeEditor = new System.Windows.Forms.TextBox();
editorToolbar = new System.Windows.Forms.Panel(); editorToolbar = new System.Windows.Forms.Panel();
applyButton = new System.Windows.Forms.Button();
lblGcode = new System.Windows.Forms.Label(); lblGcode = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)mainSplit).BeginInit(); ((System.ComponentModel.ISupportInitialize)mainSplit).BeginInit();
mainSplit.Panel1.SuspendLayout(); mainSplit.Panel1.SuspendLayout();
@@ -189,6 +188,7 @@ namespace OpenNest.Controls
gcodeEditor.Multiline = true; gcodeEditor.Multiline = true;
gcodeEditor.Name = "gcodeEditor"; gcodeEditor.Name = "gcodeEditor";
gcodeEditor.ScrollBars = System.Windows.Forms.ScrollBars.Both; gcodeEditor.ScrollBars = System.Windows.Forms.ScrollBars.Both;
gcodeEditor.ReadOnly = true;
gcodeEditor.Size = new System.Drawing.Size(260, 470); gcodeEditor.Size = new System.Drawing.Size(260, 470);
gcodeEditor.TabIndex = 1; gcodeEditor.TabIndex = 1;
gcodeEditor.WordWrap = false; gcodeEditor.WordWrap = false;
@@ -196,7 +196,6 @@ namespace OpenNest.Controls
// editorToolbar // editorToolbar
// //
editorToolbar.BackColor = System.Drawing.Color.FromArgb(245, 245, 245); editorToolbar.BackColor = System.Drawing.Color.FromArgb(245, 245, 245);
editorToolbar.Controls.Add(applyButton);
editorToolbar.Controls.Add(lblGcode); editorToolbar.Controls.Add(lblGcode);
editorToolbar.Dock = System.Windows.Forms.DockStyle.Top; editorToolbar.Dock = System.Windows.Forms.DockStyle.Top;
editorToolbar.Location = new System.Drawing.Point(0, 0); editorToolbar.Location = new System.Drawing.Point(0, 0);
@@ -204,18 +203,7 @@ namespace OpenNest.Controls
editorToolbar.Padding = new System.Windows.Forms.Padding(6, 4, 6, 4); editorToolbar.Padding = new System.Windows.Forms.Padding(6, 4, 6, 4);
editorToolbar.Size = new System.Drawing.Size(260, 30); editorToolbar.Size = new System.Drawing.Size(260, 30);
editorToolbar.TabIndex = 0; editorToolbar.TabIndex = 0;
// //
// applyButton
//
applyButton.Dock = System.Windows.Forms.DockStyle.Right;
applyButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
applyButton.Font = new System.Drawing.Font("Segoe UI", 9F);
applyButton.Location = new System.Drawing.Point(184, 4);
applyButton.Name = "applyButton";
applyButton.Size = new System.Drawing.Size(70, 22);
applyButton.TabIndex = 1;
applyButton.Text = "Apply";
//
// lblGcode // lblGcode
// //
lblGcode.AutoSize = true; lblGcode.AutoSize = true;
@@ -263,7 +251,6 @@ namespace OpenNest.Controls
private System.Windows.Forms.Panel editorPanel; private System.Windows.Forms.Panel editorPanel;
private System.Windows.Forms.Panel editorToolbar; private System.Windows.Forms.Panel editorToolbar;
private System.Windows.Forms.Label lblGcode; private System.Windows.Forms.Label lblGcode;
private System.Windows.Forms.Button applyButton;
private System.Windows.Forms.TextBox gcodeEditor; private System.Windows.Forms.TextBox gcodeEditor;
private System.Windows.Forms.ContextMenuStrip contourMenu; private System.Windows.Forms.ContextMenuStrip contourMenu;
private System.Windows.Forms.ToolStripMenuItem menuReverse; private System.Windows.Forms.ToolStripMenuItem menuReverse;

View File

@@ -1,7 +1,6 @@
using OpenNest.CNC; using OpenNest.CNC;
using OpenNest.Converters; using OpenNest.Converters;
using OpenNest.Geometry; using OpenNest.Geometry;
using OpenNest.IO;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
@@ -29,7 +28,6 @@ namespace OpenNest.Controls
menuMoveDown.Click += OnMoveDownClicked; menuMoveDown.Click += OnMoveDownClicked;
menuSequence.Click += OnSequenceClicked; menuSequence.Click += OnSequenceClicked;
contourMenu.Opening += OnContourMenuOpening; contourMenu.Opening += OnContourMenuOpening;
applyButton.Click += OnApplyClicked;
preview.PaintOverlay = OnPreviewPaintOverlay; preview.PaintOverlay = OnPreviewPaintOverlay;
} }
@@ -92,34 +90,47 @@ namespace OpenNest.Controls
private void UpdateGcodeText() private void UpdateGcodeText()
{ {
gcodeEditor.Text = Program != null ? FormatProgram(Program) : string.Empty; gcodeEditor.Text = Program != null ? FormatProgram(Program, contours) : string.Empty;
} }
private static string FormatProgram(Program pgm) private static string FormatProgram(Program pgm, List<ContourInfo> contours)
{ {
var sb = new System.Text.StringBuilder(); var sb = new System.Text.StringBuilder();
sb.AppendLine(pgm.Mode == Mode.Absolute ? "G90" : "G91"); sb.AppendLine(pgm.Mode == Mode.Absolute ? "G90" : "G91");
var lastWasRapid = false; var codeIndex = 0;
foreach (var code in pgm.Codes) var codes = pgm.Codes;
foreach (var contour in contours)
{ {
if (code is RapidMove rapid) var sub = ConvertGeometry.ToProgram(contour.Shape);
if (sub == null) continue;
sb.AppendLine();
sb.AppendLine($"; {contour.Label} ({contour.DirectionLabel})");
var lastWasRapid = false;
for (var i = 0; i < sub.Length && codeIndex < codes.Count; i++, codeIndex++)
{ {
if (!lastWasRapid && sb.Length > 0) var code = codes[codeIndex];
sb.AppendLine(); if (code is RapidMove rapid)
sb.AppendLine($"G00 X{FormatCoord(rapid.EndPoint.X)} Y{FormatCoord(rapid.EndPoint.Y)}"); {
lastWasRapid = true; if (!lastWasRapid)
} sb.AppendLine();
else if (code is ArcMove arc) sb.AppendLine($"G00 X{FormatCoord(rapid.EndPoint.X)} Y{FormatCoord(rapid.EndPoint.Y)}");
{ lastWasRapid = true;
var g = arc.Rotation == RotationType.CW ? "G02" : "G03"; }
sb.AppendLine($"{g} X{FormatCoord(arc.EndPoint.X)} Y{FormatCoord(arc.EndPoint.Y)} I{FormatCoord(arc.CenterPoint.X)} J{FormatCoord(arc.CenterPoint.Y)}"); else if (code is ArcMove arc)
lastWasRapid = false; {
} var g = arc.Rotation == RotationType.CW ? "G02" : "G03";
else if (code is LinearMove linear) sb.AppendLine($"{g} X{FormatCoord(arc.EndPoint.X)} Y{FormatCoord(arc.EndPoint.Y)} I{FormatCoord(arc.CenterPoint.X)} J{FormatCoord(arc.CenterPoint.Y)}");
{ lastWasRapid = false;
sb.AppendLine($"G01 X{FormatCoord(linear.EndPoint.X)} Y{FormatCoord(linear.EndPoint.Y)}"); }
lastWasRapid = false; else if (code is LinearMove linear)
{
sb.AppendLine($"G01 X{FormatCoord(linear.EndPoint.X)} Y{FormatCoord(linear.EndPoint.Y)}");
lastWasRapid = false;
}
} }
} }
@@ -418,50 +429,5 @@ namespace OpenNest.Controls
} }
} }
private void OnApplyClicked(object sender, EventArgs e)
{
var text = gcodeEditor.Text;
if (string.IsNullOrWhiteSpace(text))
{
MessageBox.Show("G-code is empty.", "Apply", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
using var stream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(text));
var reader = new ProgramReader(stream);
var parsed = reader.Read();
if (parsed == null || parsed.Length == 0)
{
MessageBox.Show("No valid G-code found.", "Apply", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
// Rebuild shapes from the parsed program
var entities = ConvertProgram.ToGeometry(parsed);
var shapes = ShapeBuilder.GetShapes(entities);
if (shapes.Count == 0)
{
MessageBox.Show("No contours found in parsed G-code.", "Apply", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
contours = ContourInfo.Classify(shapes);
Program = parsed;
isDirty = true;
PopulateContourList();
RefreshPreview();
ProgramChanged?.Invoke(this, EventArgs.Empty);
}
catch (Exception ex)
{
MessageBox.Show($"Error parsing G-code: {ex.Message}", "Apply",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
} }
} }