fix: improve program editor formatting, file switching, and entity colors

- Replace Program.ToString() with Cincinnati-style formatter (spaced
  coordinates, blank lines between contours, trailing zero suppression)
- Fix empty Program tab when switching files while on the tab by
  loading immediately instead of only marking stale
- Set contour-type colors on entities at load time and restore base
  colors before selection highlight to prevent color bleed to CAD view

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-31 21:56:53 -04:00
parent 5d824a1aff
commit 0cae9e88e7
2 changed files with 91 additions and 18 deletions
+62 -9
View File
@@ -44,6 +44,15 @@ namespace OpenNest.Controls
} }
contours = ContourInfo.Classify(shapes); contours = ContourInfo.Classify(shapes);
// Assign contour-type colors once so the CAD view also picks them up
foreach (var contour in contours)
{
var color = GetContourColor(contour.Type, false);
foreach (var entity in contour.Shape.Entities)
entity.Color = color;
}
Program = BuildProgram(contours); Program = BuildProgram(contours);
isDirty = false; isDirty = false;
isLoaded = true; isLoaded = true;
@@ -86,7 +95,43 @@ namespace OpenNest.Controls
private void UpdateGcodeText() private void UpdateGcodeText()
{ {
gcodeEditor.Text = Program?.ToString() ?? string.Empty; gcodeEditor.Text = Program != null ? FormatProgram(Program) : string.Empty;
}
private static string FormatProgram(Program pgm)
{
var sb = new System.Text.StringBuilder();
sb.AppendLine(pgm.Mode == Mode.Absolute ? "G90" : "G91");
var lastWasRapid = false;
foreach (var code in pgm.Codes)
{
if (code is RapidMove rapid)
{
if (!lastWasRapid && sb.Length > 0)
sb.AppendLine();
sb.AppendLine($"G00 X{FormatCoord(rapid.EndPoint.X)} Y{FormatCoord(rapid.EndPoint.Y)}");
lastWasRapid = true;
}
else if (code is ArcMove arc)
{
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)}");
lastWasRapid = false;
}
else if (code is LinearMove linear)
{
sb.AppendLine($"G01 X{FormatCoord(linear.EndPoint.X)} Y{FormatCoord(linear.EndPoint.Y)}");
lastWasRapid = false;
}
}
return sb.ToString();
}
private static string FormatCoord(double value)
{
return System.Math.Round(value, 4).ToString("0.####", System.Globalization.CultureInfo.InvariantCulture);
} }
private void RefreshPreview() private void RefreshPreview()
@@ -94,20 +139,28 @@ namespace OpenNest.Controls
preview.ClearPenCache(); preview.ClearPenCache();
preview.Entities.Clear(); preview.Entities.Clear();
// Restore base colors first (undo any selection highlight)
foreach (var contour in contours)
{
var baseColor = GetContourColor(contour.Type, false);
foreach (var entity in contour.Shape.Entities)
entity.Color = baseColor;
}
for (var i = 0; i < contours.Count; i++) for (var i = 0; i < contours.Count; i++)
{ {
var contour = contours[i]; var contour = contours[i];
var selected = contourList.SelectedIndices.Contains(i); var selected = contourList.SelectedIndices.Contains(i);
var color = GetContourColor(contour.Type, selected);
foreach (var entity in contour.Shape.Entities)
{
entity.Color = color;
preview.Entities.Add(entity);
}
if (selected) if (selected)
AddDirectionArrows(contour.Shape, color); {
var selColor = GetContourColor(contour.Type, true);
foreach (var entity in contour.Shape.Entities)
entity.Color = selColor;
AddDirectionArrows(contour.Shape, selColor);
}
preview.Entities.AddRange(contour.Shape.Entities);
} }
preview.ZoomToFit(); preview.ZoomToFit();
+29 -9
View File
@@ -137,7 +137,10 @@ namespace OpenNest.Forms
LoadItem(item); LoadItem(item);
staleProgram = true; staleProgram = true;
programEditor.Clear(); if (viewTabs.SelectedTab == tabProgram)
LoadProgramTab();
else
programEditor.Clear();
} }
private void LoadItem(FileListItem item) private void LoadItem(FileListItem item)
@@ -240,17 +243,34 @@ namespace OpenNest.Forms
private void OnViewTabChanged(object sender, EventArgs e) private void OnViewTabChanged(object sender, EventArgs e)
{ {
if (viewTabs.SelectedTab == tabProgram && staleProgram) if (viewTabs.SelectedTab == tabProgram && staleProgram)
LoadProgramTab();
}
private void LoadProgramTab()
{
var item = CurrentItem;
if (item == null)
{ {
var item = CurrentItem; programEditor.Clear();
if (item == null) return;
var entities = item.Entities.Where(en => en.Layer.IsVisible && en.IsVisible).ToList();
if (entities.Count == 0) return;
var normalized = ShapeProfile.NormalizeEntities(entities);
programEditor.LoadEntities(normalized);
staleProgram = false; staleProgram = false;
return;
} }
var entities = item.Entities.Where(en => en.Layer.IsVisible && en.IsVisible).ToList();
if (entities.Count == 0)
{
programEditor.Clear();
staleProgram = false;
return;
}
var normalized = ShapeProfile.NormalizeEntities(entities);
programEditor.LoadEntities(normalized);
staleProgram = false;
// Refresh CAD view to show contour-type colors
entityView1.ClearPenCache();
entityView1.Invalidate();
} }
private void OnBendLineSelected(object sender, int index) private void OnBendLineSelected(object sender, int index)