Skip to content

Commit 1b99559

Browse files
committed
update submodules and align settings service with new IxMilia.Config code
1 parent 2679f66 commit 1b99559

15 files changed

+251
-67
lines changed

.devcontainer/devcontainer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"features": {
77
"ghcr.io/devcontainers/features/dotnet:2": {
88
"version": "9.0.100-preview.7.24407.12",
9-
"additionalVersions": "7.0"
9+
"additionalVersions": "8.0"
1010
},
1111
"ghcr.io/devcontainers/features/go:1": {
1212
"version": "1.19"
+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
using Xunit;
2+
3+
namespace IxMilia.BCad.Core.Test
4+
{
5+
public class SettingsTests : TestBase
6+
{
7+
[Fact]
8+
public void ParseSettingsFile()
9+
{
10+
var content = """
11+
AnglePrecision = 0
12+
Debug = False
13+
DrawingPrecision = 8
14+
DrawingUnits = Metric
15+
UnitFormat = Decimal
16+
17+
[Display]
18+
AngleSnap = True
19+
BackgroundColor = #FF2F2F2F
20+
CursorSize = 60
21+
EntitySelectionRadius = 3
22+
HotPointColor = #FF0000FF
23+
HotPointSize = 10
24+
Ortho = False
25+
PointDisplaySize = 48
26+
PointSnap = True
27+
RenderId = canvas
28+
SnapAngleDistance = 30
29+
SnapAngles = 0;90;180;270
30+
SnapPointColor = #FFFFFF00
31+
SnapPointDistance = 15
32+
SnapPointSize = 15
33+
TextCursorSize = 18
34+
""";
35+
var lines = content.Split('\n');
36+
Workspace.SettingsService.LoadFromLines(lines);
37+
38+
Assert.Equal(0, Workspace.SettingsService.GetValue<int>("AnglePrecision"));
39+
Assert.False(Workspace.SettingsService.GetValue<bool>("Debug"));
40+
Assert.Equal(8, Workspace.SettingsService.GetValue<int>("DrawingPrecision"));
41+
Assert.Equal(DrawingUnits.Metric, Workspace.SettingsService.GetValue<DrawingUnits>("DrawingUnits"));
42+
Assert.Equal(UnitFormat.Decimal, Workspace.SettingsService.GetValue<UnitFormat>("UnitFormat"));
43+
Assert.True(Workspace.SettingsService.GetValue<bool>("Display.AngleSnap"));
44+
Assert.Equal(CadColor.FromUInt32(0xFF2F2F2F), Workspace.SettingsService.GetValue<CadColor>("Display.BackgroundColor"));
45+
Assert.Equal(60, Workspace.SettingsService.GetValue<int>("Display.CursorSize"));
46+
Assert.Equal(3.0, Workspace.SettingsService.GetValue<double>("Display.EntitySelectionRadius"));
47+
Assert.Equal(CadColor.FromUInt32(0xFF0000FF), Workspace.SettingsService.GetValue<CadColor>("Display.HotPointColor"));
48+
Assert.Equal(10.0, Workspace.SettingsService.GetValue<double>("Display.HotPointSize"));
49+
Assert.False(Workspace.SettingsService.GetValue<bool>("Display.Ortho"));
50+
Assert.Equal(48.0, Workspace.SettingsService.GetValue<double>("Display.PointDisplaySize"));
51+
Assert.True(Workspace.SettingsService.GetValue<bool>("Display.PointSnap"));
52+
Assert.Equal("canvas", Workspace.SettingsService.GetValue<string>("Display.RenderId"));
53+
Assert.Equal(30.0, Workspace.SettingsService.GetValue<double>("Display.SnapAngleDistance"));
54+
Assert.Equal([0.0, 90.0, 180.0, 270.0], Workspace.SettingsService.GetValue<double[]>("Display.SnapAngles"));
55+
Assert.Equal(CadColor.FromUInt32(0xFFFFFF00), Workspace.SettingsService.GetValue<CadColor>("Display.SnapPointColor"));
56+
Assert.Equal(15.0, Workspace.SettingsService.GetValue<double>("Display.SnapPointDistance"));
57+
Assert.Equal(15.0, Workspace.SettingsService.GetValue<double>("Display.SnapPointSize"));
58+
Assert.Equal(18, Workspace.SettingsService.GetValue<int>("Display.TextCursorSize"));
59+
}
60+
61+
[Fact]
62+
public void SaveSettingsFile()
63+
{
64+
Workspace.SettingsService.SetValue("AnglePrecision", 0);
65+
Workspace.SettingsService.SetValue("Debug", false);
66+
Workspace.SettingsService.SetValue("DrawingPrecision", 8);
67+
Workspace.SettingsService.SetValue("DrawingUnits", DrawingUnits.Metric);
68+
Workspace.SettingsService.SetValue("UnitFormat", UnitFormat.Decimal);
69+
Workspace.SettingsService.SetValue("Display.AngleSnap", true);
70+
Workspace.SettingsService.SetValue("Display.BackgroundColor", CadColor.FromUInt32(0xFF2F2F2F));
71+
Workspace.SettingsService.SetValue("Display.CursorSize", 60);
72+
Workspace.SettingsService.SetValue("Display.EntitySelectionRadius", 3.0);
73+
Workspace.SettingsService.SetValue("Display.HotPointColor", CadColor.FromUInt32(0xFF0000FF));
74+
Workspace.SettingsService.SetValue("Display.HotPointSize", 10.0);
75+
Workspace.SettingsService.SetValue("Display.Ortho", false);
76+
Workspace.SettingsService.SetValue("Display.PointDisplaySize", 48.0);
77+
Workspace.SettingsService.SetValue("Display.PointSnap", true);
78+
Workspace.SettingsService.SetValue("Display.RenderId", "canvas");
79+
Workspace.SettingsService.SetValue("Display.SnapAngleDistance", 30.0);
80+
Workspace.SettingsService.SetValue("Display.SnapAngles", new double[] { 0.0, 90.0, 180.0, 270.0 });
81+
Workspace.SettingsService.SetValue("Display.SnapPointColor", CadColor.FromUInt32(0xFFFFFF00));
82+
Workspace.SettingsService.SetValue("Display.SnapPointDistance", 15.0);
83+
Workspace.SettingsService.SetValue("Display.SnapPointSize", 15.0);
84+
Workspace.SettingsService.SetValue("Display.TextCursorSize", 18);
85+
var actual = Workspace.SettingsService.WriteWithLines([]).Replace("\r", "");
86+
var expected = """
87+
AnglePrecision = 0
88+
Debug = False
89+
DrawingPrecision = 8
90+
DrawingUnits = Metric
91+
UnitFormat = Decimal
92+
93+
[Display]
94+
AngleSnap = True
95+
BackgroundColor = #FF2F2F2F
96+
CursorSize = 60
97+
EntitySelectionRadius = 3
98+
HotPointColor = #FF0000FF
99+
HotPointSize = 10
100+
Ortho = False
101+
PointDisplaySize = 48
102+
PointSnap = True
103+
RenderId = canvas
104+
SnapAngleDistance = 30
105+
SnapAngles = 0;90;180;270
106+
SnapPointColor = #FFFFFF00
107+
SnapPointDistance = 15
108+
SnapPointSize = 15
109+
TextCursorSize = 18
110+
""".Replace("\r", "");
111+
Assert.Equal(expected, actual);
112+
}
113+
114+
[Fact]
115+
public void SetValueFromString()
116+
{
117+
var initialCursorSize = Workspace.SettingsService.GetValue<int>("Display.CursorSize");
118+
Assert.NotEqual(4242, initialCursorSize);
119+
120+
Workspace.SettingsService.SetValueFromString("Display.CursorSize", "4242");
121+
122+
var finalCursorSize = Workspace.SettingsService.GetValue<int>("Display.CursorSize");
123+
Assert.Equal(4242, finalCursorSize);
124+
}
125+
}
126+
}

src/IxMilia.BCad.Core/IxMilia.BCad.Core.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>netstandard1.3</TargetFramework>
4+
<TargetFramework>netstandard2.0</TargetFramework>
55
<RootNamespace>IxMilia.BCad</RootNamespace>
66
<LangVersion>9.0</LangVersion>
77
</PropertyGroup>

src/IxMilia.BCad.Core/Services/ISettingsService.cs

+6
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,14 @@ public interface ISettingsService : IWorkspaceService
99
{
1010
event SettingChangedEventHandler SettingChanged;
1111
void RegisterSetting(string name, Type type, object value);
12+
13+
string ValueToString(Type type, object value);
14+
object StringToValue(Type type, string value);
15+
1216
T GetValue<T>(string settingName);
1317
void SetValue<T>(string settingName, T value);
18+
void SetValueFromString(string settinggName, string value);
19+
1420
void LoadFromLines(string[] lines);
1521
string WriteWithLines(string[] existingLines);
1622
}

src/IxMilia.BCad.Core/Services/SettingsService.cs

+104-28
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,37 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Globalization;
34
using System.Linq;
4-
using System.Reflection;
55
using IxMilia.BCad.Settings;
66
using IxMilia.Config;
77

88
namespace IxMilia.BCad.Services
99
{
1010
internal class SettingsService : ISettingsService
1111
{
12+
private delegate object ValueReader(string value);
13+
private delegate string ValueWriter(object value);
14+
1215
private IWorkspace _workspace;
13-
private Dictionary<string, Tuple<Type, object>> _settings = new Dictionary<string, Tuple<Type, object>>();
16+
private Dictionary<string, Tuple<Type, object>> _settings = new();
17+
private Dictionary<Type, Tuple<ValueReader, ValueWriter>> _typeConverters = new();
1418

1519
public event SettingChangedEventHandler SettingChanged;
1620

21+
private SettingsService()
22+
{
23+
_typeConverters.Add(typeof(bool), Tuple.Create<ValueReader, ValueWriter>(BoolReader, BoolWriter));
24+
_typeConverters.Add(typeof(CadColor), Tuple.Create<ValueReader, ValueWriter>(CadColorReader, CadColorWriter));
25+
_typeConverters.Add(typeof(double), Tuple.Create<ValueReader, ValueWriter>(DoubleReader, DoubleWriter));
26+
_typeConverters.Add(typeof(double[]), Tuple.Create(CreateArrayReader<double>(DoubleReader), CreateArrayWriter(DoubleWriter)));
27+
_typeConverters.Add(typeof(DrawingUnits), Tuple.Create<ValueReader, ValueWriter>(DrawingUnitsReader, DrawingUnitsWriter));
28+
_typeConverters.Add(typeof(int), Tuple.Create<ValueReader, ValueWriter>(IntReader, IntWriter));
29+
_typeConverters.Add(typeof(string), Tuple.Create<ValueReader, ValueWriter>(StringReader, StringWriter));
30+
_typeConverters.Add(typeof(UnitFormat), Tuple.Create<ValueReader, ValueWriter>(UnitFormatReader, UnitFormatWriter));
31+
}
32+
1733
public SettingsService(IWorkspace workspace)
34+
: this()
1835
{
1936
_workspace = workspace;
2037
}
@@ -28,8 +45,32 @@ public void RegisterSetting(string name, Type type, object value)
2845
else
2946
{
3047
_settings[name] = Tuple.Create(type, (object)null);
31-
SetValue(name, value, ignoreTypeCheck: true);
48+
SetValue(name, value);
49+
}
50+
}
51+
52+
public string ValueToString(Type type, object value)
53+
{
54+
if (!_typeConverters.TryGetValue(type, out var pair))
55+
{
56+
throw new InvalidOperationException($"No type converter for {type.Name}");
57+
}
58+
59+
var writer = pair.Item2;
60+
var s = writer(value);
61+
return s;
62+
}
63+
64+
public object StringToValue(Type type, string value)
65+
{
66+
if (!_typeConverters.TryGetValue(type, out var pair))
67+
{
68+
throw new InvalidOperationException($"No type converter for {type.Name}");
3269
}
70+
71+
var reader = pair.Item1;
72+
var o = reader(value);
73+
return o;
3374
}
3475

3576
public T GetValue<T>(string settingName)
@@ -49,46 +90,36 @@ public T GetValue<T>(string settingName)
4990
}
5091

5192
public void SetValue<T>(string settingName, T value)
52-
{
53-
SetValue(settingName, value, ignoreTypeCheck: false);
54-
}
55-
56-
private void SetValue<T>(string settingName, T value, bool ignoreTypeCheck = false)
5793
{
5894
if (!_settings.TryGetValue(settingName, out var pair))
5995
{
96+
// no such setting
6097
return;
6198
}
6299

63100
var type = pair.Item1;
64101
var oldValue = pair.Item2;
65102
object valueToSet = value;
66-
if (value is string && type != typeof(string))
67-
{
68-
// a terrible hack to get the appropriate parse method
69-
var tryParseFunction = typeof(ConfigExtensions).GetRuntimeMethods()
70-
.Single(m => m.Name == nameof(ConfigExtensions.TryParseValue) && m.GetParameters().Length == 2);
71-
tryParseFunction = tryParseFunction.MakeGenericMethod(type);
72-
var parameters = new object[] { value, null };
73-
if (!(bool)tryParseFunction.Invoke(null, parameters))
74-
{
75-
return;
76-
}
77-
78-
valueToSet = parameters[1];
79-
}
80-
else if (!ignoreTypeCheck && type != typeof(T))
103+
if (Equals(pair.Item2, valueToSet))
81104
{
105+
// no change
82106
return;
83107
}
84108

85-
if (Equals(pair.Item2, valueToSet))
109+
_settings[settingName] = Tuple.Create(type, valueToSet);
110+
SettingChanged?.Invoke(this, new SettingChangedEventArgs(settingName, type, oldValue, value));
111+
}
112+
113+
public void SetValueFromString(string settingName, string value)
114+
{
115+
if (!_settings.TryGetValue(settingName, out var pair))
86116
{
117+
// no such setting
87118
return;
88119
}
89120

90-
_settings[settingName] = Tuple.Create(type, valueToSet);
91-
SettingChanged?.Invoke(this, new SettingChangedEventArgs(settingName, type, oldValue, value));
121+
var nativeValue = StringToValue(pair.Item1, value);
122+
SetValue(settingName, nativeValue);
92123
}
93124

94125
public void LoadFromLines(string[] lines)
@@ -97,7 +128,14 @@ public void LoadFromLines(string[] lines)
97128
fileValues.ParseConfig(lines);
98129
foreach (var kvp in fileValues)
99130
{
100-
SetValue(kvp.Key, kvp.Value);
131+
if (!_settings.TryGetValue(kvp.Key, out var pair))
132+
{
133+
// no such setting
134+
continue;
135+
}
136+
137+
var v = StringToValue(pair.Item1, kvp.Value);
138+
SetValue(kvp.Key, v);
101139
}
102140
}
103141

@@ -106,7 +144,8 @@ public string WriteWithLines(string[] existingLines)
106144
var values = new Dictionary<string, string>();
107145
foreach (var kvp in _settings)
108146
{
109-
values[kvp.Key] = kvp.Value.Item2.ToConfigString();
147+
var s = ValueToString(kvp.Value.Item1, kvp.Value.Item2);
148+
values[kvp.Key] = s;
110149
}
111150

112151
var newContent = values.WriteConfig(existingLines);
@@ -126,5 +165,42 @@ public SettingData(string name, Type type, object value)
126165
Value = value;
127166
}
128167
}
168+
169+
private static object BoolReader(string value) => bool.Parse(value);
170+
private static string BoolWriter(object value) => ((bool)value).ToString(CultureInfo.InvariantCulture);
171+
172+
private static object CadColorReader(string value) => CadColor.Parse(value);
173+
private static string CadColorWriter(object value) => ((CadColor)value).ToString();
174+
175+
private static object DoubleReader(string value) => double.Parse(value, CultureInfo.InvariantCulture);
176+
private static string DoubleWriter(object value) => ((double)value).ToString(CultureInfo.InvariantCulture);
177+
178+
private static object DrawingUnitsReader(string value) => Enum.Parse(typeof(DrawingUnits), value);
179+
private static string DrawingUnitsWriter(object value) => ((DrawingUnits)value).ToString();
180+
181+
private static object IntReader(string value) => int.Parse(value, CultureInfo.InvariantCulture);
182+
private static string IntWriter(object value) => ((int)value).ToString(CultureInfo.InvariantCulture);
183+
184+
private static object StringReader(string value) => value;
185+
private static string StringWriter(object value) => value.ToString();
186+
187+
private static object UnitFormatReader(string value) => Enum.Parse(typeof(UnitFormat), value);
188+
private static string UnitFormatWriter(object value) => ((UnitFormat)value).ToString();
189+
190+
private static ValueReader CreateArrayReader<T>(Func<string, object> elementReader) => value => value.Split(';').Select(elementReader).Cast<T>().ToArray();
191+
private static ValueWriter CreateArrayWriter(Func<object, string> elementWriter)
192+
{
193+
return value =>
194+
{
195+
var array = (Array)value;
196+
var values = new List<object>();
197+
foreach (var x in array)
198+
{
199+
values.Add(elementWriter(x));
200+
}
201+
202+
return string.Join(";", values);
203+
};
204+
}
129205
}
130206
}

src/IxMilia.BCad.Core/WorkspaceBase.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -106,17 +106,17 @@ private void RegisterDefaultSettings()
106106
SettingsService.RegisterSetting(DefaultSettingsNames.DrawingUnits, typeof(DrawingUnits), DrawingUnits.English);
107107
SettingsService.RegisterSetting(DefaultSettingsNames.UnitFormat, typeof(UnitFormat), UnitFormat.Architectural);
108108
SettingsService.RegisterSetting(DisplaySettingsNames.AngleSnap, typeof(bool), true);
109-
SettingsService.RegisterSetting(DisplaySettingsNames.BackgroundColor, typeof(CadColor), "#FF2F2F2F");
109+
SettingsService.RegisterSetting(DisplaySettingsNames.BackgroundColor, typeof(CadColor), CadColor.Parse("#FF2F2F2F"));
110110
SettingsService.RegisterSetting(DisplaySettingsNames.CursorSize, typeof(int), 60);
111111
SettingsService.RegisterSetting(DisplaySettingsNames.EntitySelectionRadius, typeof(double), 3.0);
112-
SettingsService.RegisterSetting(DisplaySettingsNames.HotPointColor, typeof(CadColor), "#FF0000FF");
112+
SettingsService.RegisterSetting(DisplaySettingsNames.HotPointColor, typeof(CadColor), CadColor.Parse("#FF0000FF"));
113113
SettingsService.RegisterSetting(DisplaySettingsNames.HotPointSize, typeof(double), 10.0);
114114
SettingsService.RegisterSetting(DisplaySettingsNames.Ortho, typeof(bool), false);
115115
SettingsService.RegisterSetting(DisplaySettingsNames.PointSnap, typeof(bool), true);
116116
SettingsService.RegisterSetting(DisplaySettingsNames.RenderId, typeof(string), "webgl");
117117
SettingsService.RegisterSetting(DisplaySettingsNames.SnapAngleDistance, typeof(double), 30.0);
118118
SettingsService.RegisterSetting(DisplaySettingsNames.SnapAngles, typeof(double[]), new[] { 0.0, 90.0, 180.0, 270.0 });
119-
SettingsService.RegisterSetting(DisplaySettingsNames.SnapPointColor, typeof(CadColor), "#FFFFFF00");
119+
SettingsService.RegisterSetting(DisplaySettingsNames.SnapPointColor, typeof(CadColor), CadColor.Parse("#FFFFFF00"));
120120
SettingsService.RegisterSetting(DisplaySettingsNames.SnapPointDistance, typeof(double), 15.0);
121121
SettingsService.RegisterSetting(DisplaySettingsNames.SnapPointSize, typeof(double), 15.0);
122122
SettingsService.RegisterSetting(DisplaySettingsNames.TextCursorSize, typeof(int), 18);

src/IxMilia.BCad.Rpc/ServerAgent.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ public async Task<JObject> ShowDialog(string id, object parameter)
542542

543543
public void SetSetting(string name, string value)
544544
{
545-
Workspace.SettingsService.SetValue(name, value);
545+
Workspace.SettingsService.SetValueFromString(name, value);
546546
}
547547

548548
public string GetVersionInformation()

0 commit comments

Comments
 (0)