Skip to content

Commit 39d8926

Browse files
vchelaruclaude
andauthored
Default Standards palette on when setting is absent (#3408) (#3536)
Make GeneralSettingsFile.UseStandardsPalette nullable (bool?): null means the user has never chosen and resolves to on via the new EffectiveUseStandardsPalette; an explicit true/false (written by the View-menu toggle) is honored, so a user who opted out stays out. The tree-view read sites and the menu checkbox now read EffectiveUseStandardsPalette. The menu toggle still writes a concrete true/false, so the palette can still be turned off from View > Standards palette. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 037b936 commit 39d8926

4 files changed

Lines changed: 70 additions & 11 deletions

File tree

Gum/Plugins/InternalPlugins/MenuStripPlugin/MenuStripManager.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ void AddSeparator(MenuItem parent)
280280
{
281281
Header = "Standards palette (experimental)",
282282
IsCheckable = true,
283-
IsChecked = _projectManager.GeneralSettingsFile?.UseStandardsPalette ?? false
283+
IsChecked = _projectManager.GeneralSettingsFile?.EffectiveUseStandardsPalette ?? false
284284
};
285285
// WPF toggles IsChecked before Click fires for a checkable item.
286286
_standardsPaletteMenuItem.Click += (_, _) =>
@@ -292,7 +292,7 @@ void AddSeparator(MenuItem parent)
292292
}
293293
settings.UseStandardsPalette = _standardsPaletteMenuItem.IsChecked;
294294
settings.Save();
295-
_messenger.Send(new StandardsPaletteSettingChangedMessage(settings.UseStandardsPalette));
295+
_messenger.Send(new StandardsPaletteSettingChangedMessage(settings.EffectiveUseStandardsPalette));
296296
};
297297
_viewMenuItem.Items.Add(_standardsPaletteMenuItem);
298298

@@ -349,7 +349,7 @@ public void RefreshUI()
349349
// The settings file loads after PopulateMenu, so keep the checkmark in sync here.
350350
if (_standardsPaletteMenuItem != null && _projectManager.GeneralSettingsFile is { } generalSettings)
351351
{
352-
_standardsPaletteMenuItem.IsChecked = generalSettings.UseStandardsPalette;
352+
_standardsPaletteMenuItem.IsChecked = generalSettings.EffectiveUseStandardsPalette;
353353
}
354354

355355
if (_selectedState.SelectedStateSave != null && _selectedState.SelectedStateSave.Name != "Default")

Gum/Plugins/InternalPlugins/TreeView/ElementTreeViewManager.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,7 @@ _selectedState.SelectedElement is { } element && element is not StandardElementS
839839
/// </summary>
840840
public void ApplyStandardsPaletteMode()
841841
{
842-
bool usePalette = _projectState.GeneralSettings?.UseStandardsPalette == true;
842+
bool usePalette = _projectState.GeneralSettings?.EffectiveUseStandardsPalette == true;
843843

844844
if (mStandardElementsTreeNode != null)
845845
{
@@ -1460,7 +1460,7 @@ private void CreateRootTreeNodesIfNecessary()
14601460
// When the experimental Standards palette is on, the Standard folder is replaced by the
14611461
// chip palette, so it is not shown in the tree. The node object is still kept (and still
14621462
// populated) so toggling the setting at runtime can restore it without a full rebuild.
1463-
if (_projectState.GeneralSettings?.UseStandardsPalette != true)
1463+
if (_projectState.GeneralSettings?.EffectiveUseStandardsPalette != true)
14641464
{
14651465
ObjectTreeView.Nodes.Add(mStandardElementsTreeNode);
14661466
}
@@ -1807,7 +1807,7 @@ public void RefreshUi()
18071807
// signal that standard elements may have changed (e.g. "Add Skia Standard Elements", which
18081808
// only calls RefreshElementTreeView and raises no ElementAdd event). RefreshChips is
18091809
// idempotent, so this is a no-op when the standard set is unchanged.
1810-
if (_projectState.GeneralSettings?.UseStandardsPalette == true)
1810+
if (_projectState.GeneralSettings?.EffectiveUseStandardsPalette == true)
18111811
{
18121812
RefreshStandardsPaletteChips();
18131813
}

Gum/Settings/GeneralSettingsFile.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,27 @@ public bool AutoSave
5454
}
5555

5656
/// <summary>
57-
/// When true, the experimental "Standards palette" UI is used: the Standard folder is
58-
/// removed from the element tree and the standard types are shown as a draggable chip
59-
/// palette at the bottom of the Project panel instead. Opt-in while experimental.
57+
/// The user's explicit choice for the "Standards palette" UI, or null when they have never
58+
/// chosen. When on, the Standard folder is removed from the element tree and the standard
59+
/// types are shown as a draggable chip palette at the bottom of the Project panel instead.
60+
/// Null (absent from GeneralSettings.xml) resolves to on via <see cref="EffectiveUseStandardsPalette"/>;
61+
/// an explicit false written by the View-menu toggle keeps a user opted out. Read
62+
/// <see cref="EffectiveUseStandardsPalette"/> for the resolved value rather than this raw setting.
6063
/// </summary>
61-
public bool UseStandardsPalette
64+
public bool? UseStandardsPalette
6265
{
6366
get;
6467
set;
6568
}
6669

70+
/// <summary>
71+
/// The resolved Standards-palette mode. Defaults to on when the user has never made an
72+
/// explicit choice (<see cref="UseStandardsPalette"/> is null); otherwise honors their choice.
73+
/// </summary>
74+
[XmlIgnore]
75+
[JsonIgnore]
76+
public bool EffectiveUseStandardsPalette => UseStandardsPalette ?? true;
77+
6778
public int FrameRate
6879
{
6980
get;
@@ -142,7 +153,8 @@ public GeneralSettingsFile()
142153
{
143154
ShowTextOutlines = false;
144155
AutoSave = true;
145-
UseStandardsPalette = false;
156+
// UseStandardsPalette is intentionally left null (unset) so a user who has never chosen
157+
// resolves to on via EffectiveUseStandardsPalette. See #3408.
146158
FrameRate = 30;
147159
LeftAndEverythingSplitterDistance = 196;
148160
PreviewSplitterDistance = 558;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System.IO;
2+
using System.Xml.Serialization;
3+
using Gum.Settings;
4+
using Shouldly;
5+
6+
namespace GumToolUnitTests.Settings;
7+
8+
public class GeneralSettingsFileTests
9+
{
10+
[Theory]
11+
[InlineData(null, true)] // Never chosen -> the Standards palette defaults on.
12+
[InlineData(false, false)] // Explicit opt-out is honored.
13+
[InlineData(true, true)] // Explicit opt-in is honored.
14+
public void EffectiveUseStandardsPalette_ResolvesUnsetToOn(bool? stored, bool expected)
15+
{
16+
GeneralSettingsFile settings = new GeneralSettingsFile
17+
{
18+
UseStandardsPalette = stored
19+
};
20+
21+
settings.EffectiveUseStandardsPalette.ShouldBe(expected);
22+
}
23+
24+
[Fact]
25+
public void UseStandardsPalette_DefaultsToNull_SoNewUsersGetPaletteOn()
26+
{
27+
GeneralSettingsFile settings = new GeneralSettingsFile();
28+
29+
settings.UseStandardsPalette.HasValue.ShouldBeFalse();
30+
settings.EffectiveUseStandardsPalette.ShouldBeTrue();
31+
}
32+
33+
[Theory]
34+
// Setting absent from the file (fresh installs / users who never toggled it) resolves to on.
35+
[InlineData("<GeneralSettingsFile></GeneralSettingsFile>", true)]
36+
// A value explicitly written to the file is honored, so an opt-out survives the flip.
37+
[InlineData("<GeneralSettingsFile><UseStandardsPalette>false</UseStandardsPalette></GeneralSettingsFile>", false)]
38+
[InlineData("<GeneralSettingsFile><UseStandardsPalette>true</UseStandardsPalette></GeneralSettingsFile>", true)]
39+
public void EffectiveUseStandardsPalette_ResolvesFromDeserializedXml(string xml, bool expected)
40+
{
41+
XmlSerializer serializer = new XmlSerializer(typeof(GeneralSettingsFile));
42+
using StringReader reader = new StringReader(xml);
43+
GeneralSettingsFile settings = (GeneralSettingsFile)serializer.Deserialize(reader)!;
44+
45+
settings.EffectiveUseStandardsPalette.ShouldBe(expected);
46+
}
47+
}

0 commit comments

Comments
 (0)