diff --git a/OpenNest.WinForms.Tests/ClassicPaletteTests.cs b/OpenNest.WinForms.Tests/ClassicPaletteTests.cs index 4c007e36..e13125d6 100644 --- a/OpenNest.WinForms.Tests/ClassicPaletteTests.cs +++ b/OpenNest.WinForms.Tests/ClassicPaletteTests.cs @@ -38,23 +38,28 @@ public class ClassicPaletteTests return System.Math.Sqrt((l1 - l2) * (l1 - l2) + (a1 - a2) * (a1 - a2) + (b1 - b2) * (b1 - b2)); } - [Fact] - public void ClassicFillsAreClearlyDistinctFromEachOther() + public static TheoryData ListedPalettes => new() { "Blueprint", "Classic" }; + + [Theory] + [MemberData(nameof(ListedPalettes))] + public void FillsAreClearlyDistinctFromEachOther(string name) { - var colors = ColorSchemeRegistry.Get("Classic").PartColors; + var colors = ColorSchemeRegistry.Get(name).PartColors; Assert.Equal(12, colors.Length); for (var i = 0; i < colors.Length; i++) { for (var j = i + 1; j < colors.Length; j++) Assert.True(DeltaE(colors[i], colors[j]) >= 30, - $"Classic colors {i} and {j} are too similar ({DeltaE(colors[i], colors[j]):F1})."); + $"{name} colors {i} and {j} are too similar ({DeltaE(colors[i], colors[j]):F1})."); } } - [Fact] - public void ClassicFillsStayReadableAndClearOfEtchGreenAndTheSheet() + [Theory] + [MemberData(nameof(ListedPalettes))] + public void FillsStayReadableAndClearOfEtchGreenAndTheSheet(string name) { - var scheme = ColorSchemeRegistry.Get("Classic"); + var scheme = ColorSchemeRegistry.Get(name); + Assert.Equal(name, scheme.Name); Assert.All(scheme.PartColors, color => { Assert.True(Contrast(color, Color.Black) >= 4.5, $"{color} is too dark for black part IDs."); diff --git a/OpenNest.WinForms.Tests/FestiveColorSchemeTests.cs b/OpenNest.WinForms.Tests/FestiveColorSchemeTests.cs index ce54ff88..7130aa65 100644 --- a/OpenNest.WinForms.Tests/FestiveColorSchemeTests.cs +++ b/OpenNest.WinForms.Tests/FestiveColorSchemeTests.cs @@ -30,7 +30,7 @@ public class FestiveColorSchemeTests } [Fact] - public void FestiveSchemesRoundTripAndLeaveClassicAsDefault() + public void FestiveSchemesRoundTripAndLeaveBlueprintAsDefault() { foreach (var name in new[] { "Halloween", "Christmas", "4th of July" }) { @@ -41,7 +41,7 @@ public class FestiveColorSchemeTests Assert.Equal(scheme.PartColors.Select(c => c.ToArgb()), restored.PartColors.Select(c => c.ToArgb())); } - Assert.Equal("Classic", ColorSchemeRegistry.Get(null).Name); + Assert.Equal("Blueprint", ColorSchemeRegistry.Get(null).Name); } private static double Distance(Color a, Color b) diff --git a/OpenNest/ColorSchemeRegistry.cs b/OpenNest/ColorSchemeRegistry.cs index f431db4d..324aefb3 100644 --- a/OpenNest/ColorSchemeRegistry.cs +++ b/OpenNest/ColorSchemeRegistry.cs @@ -15,6 +15,7 @@ namespace OpenNest StringComparer.OrdinalIgnoreCase ) { + ["Blueprint"] = BuildBlueprint(), ["Classic"] = BuildClassic(), ["Pastel"] = BuildPastel(), ["Dark"] = BuildDark(), @@ -24,6 +25,8 @@ namespace OpenNest ["4th of July"] = BuildFourthOfJuly(), }; + public const string DefaultSchemeName = "Blueprint"; + private static List diskCache; public static IEnumerable AllSchemes @@ -40,12 +43,12 @@ namespace OpenNest public static ColorScheme Get(string name) { if (string.IsNullOrWhiteSpace(name)) - return builtIns["Classic"]; + return builtIns[DefaultSchemeName]; var hit = AllSchemes.FirstOrDefault(s => string.Equals(s.Name, name, StringComparison.OrdinalIgnoreCase) ); - return hit ?? builtIns["Classic"]; + return hit ?? builtIns[DefaultSchemeName]; } public static void ApplyActiveFromSettings() @@ -227,6 +230,39 @@ namespace OpenNest }, }; + // The default scheme. Its twelve fills were picked farthest-first in Lab (at least + // ~30 CIE76 apart), readable with black part IDs and clear of etch green, the sheet + // and the canvas. + private static ColorScheme BuildBlueprint() => + new ColorScheme + { + Name = "Blueprint", + BackgroundColor = Color.FromArgb(24, 52, 92), + LayoutOutlineColor = Color.FromArgb(120, 150, 190), + LayoutFillColor = Color.FromArgb(226, 236, 246), + BoundingBoxColor = Color.FromArgb(140, 200, 255), + RapidColor = Color.FromArgb(230, 90, 40), + OriginColor = Color.FromArgb(150, 175, 205), + EdgeSpacingColor = Color.FromArgb(160, 185, 215), + PreviewPartColor = Color.FromArgb(255, 200, 40), + PartOutlineColor = Color.FromArgb(20, 40, 70), + PartColors = new[] + { + Color.FromArgb(232, 136, 79), + Color.FromArgb(32, 168, 253), + Color.FromArgb(116, 242, 171), + Color.FromArgb(252, 138, 213), + Color.FromArgb(198, 198, 88), + Color.FromArgb(28, 231, 250), + Color.FromArgb(248, 186, 187), + Color.FromArgb(137, 169, 132), + Color.FromArgb(169, 152, 202), + Color.FromArgb(253, 116, 137), + Color.FromArgb(238, 216, 165), + Color.FromArgb(104, 169, 195), + }, + }; + private static ColorScheme BuildClassic() => new ColorScheme { diff --git a/OpenNest/Forms/OptionsForm.cs b/OpenNest/Forms/OptionsForm.cs index 777b1877..12450034 100644 --- a/OpenNest/Forms/OptionsForm.cs +++ b/OpenNest/Forms/OptionsForm.cs @@ -99,7 +99,7 @@ namespace OpenNest.Forms Settings.Default.CreateNewNestOnOpen = checkBox1.Checked; Settings.Default.AutoSizePlateFactor = (double)numericUpDown1.Value; Settings.Default.ActiveColorScheme = - colorSchemeCombo.SelectedItem as string ?? "Classic"; + colorSchemeCombo.SelectedItem as string ?? ColorSchemeRegistry.DefaultSchemeName; var disabledNames = new List(); foreach (DataGridViewRow row in strategyGrid.Rows) diff --git a/OpenNest/Properties/Settings.Designer.cs b/OpenNest/Properties/Settings.Designer.cs index 965f119a..7ed9ddb9 100644 --- a/OpenNest/Properties/Settings.Designer.cs +++ b/OpenNest/Properties/Settings.Designer.cs @@ -283,7 +283,7 @@ namespace OpenNest.Properties { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("Classic")] + [global::System.Configuration.DefaultSettingValueAttribute("Blueprint")] public string ActiveColorScheme { get { return ((string)(this["ActiveColorScheme"])); diff --git a/OpenNest/Properties/Settings.settings b/OpenNest/Properties/Settings.settings index 8f65e873..dab85c42 100644 --- a/OpenNest/Properties/Settings.settings +++ b/OpenNest/Properties/Settings.settings @@ -69,7 +69,7 @@ - Classic + Blueprint diff --git a/docs/nesting-view-colors.md b/docs/nesting-view-colors.md index 8a6a0866..e692c906 100644 --- a/docs/nesting-view-colors.md +++ b/docs/nesting-view-colors.md @@ -1,5 +1,16 @@ # Nesting-view colors +## Default scheme + +**Blueprint** is the default for new installs and the fallback for missing or +unknown scheme names: deep navy canvas, pale blue sheet, dark navy part +outlines, orange-red rapids and twelve part fills at least ~30 CIE76 apart that +stay readable with black part IDs and clear of the etch green, the sheet and the +canvas. A scheme already saved in **Tools > Options** is kept; choose Blueprint +there to switch an existing install. Classic remains available. + +## Workshop + Choose **Tools > Options > Color scheme > Workshop**, then **Save** for a high-contrast per-drawing view: