From d80f76e386d5deeb741fcda4efa00b59c1ca71b8 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Wed, 15 Apr 2026 21:46:51 -0400 Subject: [PATCH] feat(ui): add ColorScheme.Name/PartColors instance props and JSON serializer Co-Authored-By: Claude Opus 4.6 (1M context) --- OpenNest/ColorScheme.cs | 5 +- OpenNest/ColorSchemeSerializer.cs | 82 +++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 OpenNest/ColorSchemeSerializer.cs diff --git a/OpenNest/ColorScheme.cs b/OpenNest/ColorScheme.cs index 6c34709..6f5e62d 100644 --- a/OpenNest/ColorScheme.cs +++ b/OpenNest/ColorScheme.cs @@ -13,10 +13,13 @@ namespace OpenNest private Color edgeSpacingColor; private Color previewPartColor; - public static Color[] PartColors => Drawing.PartColors; + public string Name { get; set; } = "Unnamed"; + + public Color[] PartColors { get; set; } = Drawing.PartColors; public static readonly ColorScheme Default = new ColorScheme { + Name = "Classic", BackgroundColor = Color.DarkGray, LayoutOutlineColor = Color.Gray, LayoutFillColor = Color.WhiteSmoke, diff --git a/OpenNest/ColorSchemeSerializer.cs b/OpenNest/ColorSchemeSerializer.cs new file mode 100644 index 0000000..146c2a5 --- /dev/null +++ b/OpenNest/ColorSchemeSerializer.cs @@ -0,0 +1,82 @@ +using System.Drawing; +using System.Globalization; +using System.Linq; +using System.Text.Json; + +namespace OpenNest +{ + public static class ColorSchemeSerializer + { + private static readonly JsonSerializerOptions JsonOptions = new() + { + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + + public static string Serialize(ColorScheme scheme) + { + var dto = new ColorSchemeDto + { + Name = scheme.Name, + BackgroundColor = ToHex(scheme.BackgroundColor), + LayoutOutlineColor = ToHex(scheme.LayoutOutlineColor), + LayoutFillColor = ToHex(scheme.LayoutFillColor), + BoundingBoxColor = ToHex(scheme.BoundingBoxColor), + RapidColor = ToHex(scheme.RapidColor), + OriginColor = ToHex(scheme.OriginColor), + EdgeSpacingColor = ToHex(scheme.EdgeSpacingColor), + PreviewPartColor = ToHex(scheme.PreviewPartColor), + PartColors = scheme.PartColors.Select(ToHex).ToArray() + }; + return JsonSerializer.Serialize(dto, JsonOptions); + } + + public static ColorScheme Deserialize(string json) + { + var dto = JsonSerializer.Deserialize(json, JsonOptions) + ?? throw new JsonException("ColorScheme JSON was null"); + + return new ColorScheme + { + Name = dto.Name ?? "Unnamed", + BackgroundColor = FromHex(dto.BackgroundColor), + LayoutOutlineColor = FromHex(dto.LayoutOutlineColor), + LayoutFillColor = FromHex(dto.LayoutFillColor), + BoundingBoxColor = FromHex(dto.BoundingBoxColor), + RapidColor = FromHex(dto.RapidColor), + OriginColor = FromHex(dto.OriginColor), + EdgeSpacingColor = FromHex(dto.EdgeSpacingColor), + PreviewPartColor = FromHex(dto.PreviewPartColor), + PartColors = (dto.PartColors ?? new string[0]).Select(FromHex).ToArray() + }; + } + + private static string ToHex(Color c) => + "#" + c.R.ToString("X2") + c.G.ToString("X2") + c.B.ToString("X2"); + + private static Color FromHex(string hex) + { + if (string.IsNullOrWhiteSpace(hex)) + return Color.Black; + var h = hex.TrimStart('#'); + var r = byte.Parse(h.Substring(0, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); + var g = byte.Parse(h.Substring(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); + var b = byte.Parse(h.Substring(4, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); + return Color.FromArgb(r, g, b); + } + + private class ColorSchemeDto + { + public string Name { get; set; } + public string BackgroundColor { get; set; } + public string LayoutOutlineColor { get; set; } + public string LayoutFillColor { get; set; } + public string BoundingBoxColor { get; set; } + public string RapidColor { get; set; } + public string OriginColor { get; set; } + public string EdgeSpacingColor { get; set; } + public string PreviewPartColor { get; set; } + public string[] PartColors { get; set; } + } + } +}