-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCursorOverlaySettings.cs
More file actions
169 lines (146 loc) · 5.85 KB
/
Copy pathCursorOverlaySettings.cs
File metadata and controls
169 lines (146 loc) · 5.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
using System.Text.Json;
using System.Text.Json.Nodes;
using SwitchifyPc.Core.Storage;
namespace SwitchifyPc.Core.Settings;
public sealed record CursorOverlayColorInfo(string Label, int[] Rgb, string Hex);
public sealed record CursorOverlaySettings(
bool Enabled,
string Size,
string Visibility,
bool Crosshairs,
string Color);
public static class CursorOverlaySettingsModel
{
public static readonly CursorOverlaySettings Default = new(
Enabled: true,
Size: "medium",
Visibility: "onInput",
Crosshairs: false,
Color: "red");
public static readonly IReadOnlyDictionary<string, int> SizePixels = new Dictionary<string, int>(StringComparer.Ordinal)
{
["small"] = 96,
["medium"] = 128,
["large"] = 176
};
public static readonly IReadOnlyDictionary<string, CursorOverlayColorInfo> Colors =
new Dictionary<string, CursorOverlayColorInfo>(StringComparer.Ordinal)
{
["red"] = new("Red", [211, 47, 47], "#d32f2f"),
["green"] = new("Green", [132, 255, 145], "#84ff91"),
["blue"] = new("Blue", [100, 166, 255], "#64a6ff"),
["yellow"] = new("Yellow", [255, 209, 102], "#ffd166"),
["white"] = new("White", [255, 255, 255], "#ffffff")
};
private static readonly HashSet<string> VisibilityValues = new(StringComparer.Ordinal)
{
"onInput",
"whileControlling"
};
public static CursorOverlaySettings Normalize(JsonNode? value)
{
if (value is not JsonObject candidate)
{
return Default;
}
return new CursorOverlaySettings(
Enabled: BooleanOrDefault(candidate, "enabled", Default.Enabled),
Size: StringSetOrDefault(candidate, "size", SizePixels.Keys, Default.Size),
Visibility: StringSetOrDefault(candidate, "visibility", VisibilityValues, Default.Visibility),
Crosshairs: BooleanOrDefault(candidate, "crosshairs", Default.Crosshairs),
Color: StringSetOrDefault(candidate, "color", Colors.Keys, Default.Color));
}
public static CursorOverlaySettings Normalize(object? value)
{
return Normalize(JsonSerializer.SerializeToNode(value));
}
public static CursorOverlaySettings Normalize(CursorOverlaySettings settings)
{
return new CursorOverlaySettings(
Enabled: settings.Enabled,
Size: SizePixels.ContainsKey(settings.Size) ? settings.Size : Default.Size,
Visibility: VisibilityValues.Contains(settings.Visibility) ? settings.Visibility : Default.Visibility,
Crosshairs: settings.Crosshairs,
Color: Colors.ContainsKey(settings.Color) ? settings.Color : Default.Color);
}
public static int ResolveSizePixels(string size)
{
return SizePixels.TryGetValue(size, out int pixels) ? pixels : SizePixels[Default.Size];
}
public static int[] ResolveColorRgb(string color)
{
return Colors.TryGetValue(color, out CursorOverlayColorInfo? value)
? value.Rgb.ToArray()
: Colors[Default.Color].Rgb.ToArray();
}
public static JsonObject ToJsonObject(CursorOverlaySettings settings)
{
CursorOverlaySettings normalized = Normalize(settings);
return new JsonObject
{
["enabled"] = normalized.Enabled,
["size"] = normalized.Size,
["visibility"] = normalized.Visibility,
["crosshairs"] = normalized.Crosshairs,
["color"] = normalized.Color
};
}
private static bool BooleanOrDefault(JsonObject value, string propertyName, bool fallback)
{
return value.TryGetPropertyValue(propertyName, out JsonNode? property) &&
property is not null &&
property.GetValueKind() is JsonValueKind.True or JsonValueKind.False
? property.GetValue<bool>()
: fallback;
}
private static string StringSetOrDefault(JsonObject value, string propertyName, IEnumerable<string> allowed, string fallback)
{
return value.TryGetPropertyValue(propertyName, out JsonNode? property) &&
property?.GetValueKind() == JsonValueKind.String &&
allowed.Contains(property.GetValue<string>(), StringComparer.Ordinal)
? property.GetValue<string>()
: fallback;
}
}
public interface ICursorOverlaySettingsStore
{
CursorOverlaySettings Load();
CursorOverlaySettings Save(CursorOverlaySettings settings);
}
public sealed class JsonCursorOverlaySettingsStore : ICursorOverlaySettingsStore
{
private readonly string filePath;
private readonly Action<string> warn;
public JsonCursorOverlaySettingsStore(string filePath, Action<string>? warn = null)
{
this.filePath = filePath;
this.warn = warn ?? Console.WriteLine;
}
public CursorOverlaySettings Load()
{
try
{
return CursorOverlaySettingsModel.Normalize(JsonNode.Parse(File.ReadAllText(filePath)));
}
catch (Exception error) when (error is FileNotFoundException or DirectoryNotFoundException)
{
return CursorOverlaySettingsModel.Default;
}
catch
{
warn("Switchify cursor overlay settings could not be loaded. Defaults will be used.");
return CursorOverlaySettingsModel.Default;
}
}
public CursorOverlaySettings Save(CursorOverlaySettings settings)
{
CursorOverlaySettings normalized = CursorOverlaySettingsModel.Normalize(settings);
string content = JsonSerializer.Serialize(CursorOverlaySettingsModel.ToJsonObject(normalized), JsonOptions) + "\n";
JsonFileStore.WriteJsonFileAtomicSync(filePath, content);
return normalized;
}
private static readonly JsonSerializerOptions JsonOptions = new()
{
WriteIndented = true
};
}