feat(ui): make Blueprint the default color scheme

- Add the Blueprint scheme: navy canvas, pale blue sheet, dark navy part
  outlines, orange-red rapids and twelve distinct, readable part fills.
- Use it as the settings default and the fallback for unknown scheme names,
  and list it first in Options. Saved scheme choices are kept.
- Run the palette spacing and readability tests over Blueprint and Classic.
- Document the default in nesting-view-colors.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ajandClaude Opus 5.5 committed 2026-10-18 20:04:41 -04:00
1 parent 66afea5a51
commit c875edcdd1
7 files changed
+66 -14

No files matched your search

+12 -7
View File
@@ -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<string> 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.");
@@ -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)
+38 -2
View File
@@ -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<ColorScheme> diskCache;
public static IEnumerable<ColorScheme> 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
{
+1 -1
View File
@@ -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<string>();
foreach (DataGridViewRow row in strategyGrid.Rows)
+1 -1
View File
@@ -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"]));
+1 -1
View File
@@ -69,7 +69,7 @@
<Value Profile="(Default)" />
</Setting>
<Setting Name="ActiveColorScheme" Type="System.String" Scope="User">
<Value Profile="(Default)">Classic</Value>
<Value Profile="(Default)">Blueprint</Value>
</Setting>
<Setting Name="UpdateFeedUrl" Type="System.String" Scope="User">
<Value Profile="(Default)" />
+11
View File
@@ -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: