Skip to content

Commit e997fcc

Browse files
committed
Get rid of System.Drawing.Color
1 parent a663438 commit e997fcc

10 files changed

Lines changed: 138 additions & 66 deletions

File tree

Arrays.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.Diagnostics;
66
using System.Linq;
77
using System.Numerics;
8-
using System.Drawing;
98
using System.Threading;
109
using System.ComponentModel;
1110

@@ -338,7 +337,7 @@ void ICollection.CopyTo(Array array, int index)
338337
}
339338

340339
public class ElementArray : Array<Element>
341-
{
340+
{
342341
public ElementArray() { }
343342

344343
public ElementArray(IEnumerable<Element> enumerable)
@@ -587,10 +586,10 @@ public ByteArray(int capacity)
587586
}
588587

589588
[CLSCompliant(false)]
590-
public class UInt64Array : Array<UInt64>
589+
public class UInt64Array : Array<ulong>
591590
{
592591
public UInt64Array() { }
593-
public UInt64Array(IEnumerable<UInt64> enumerable)
592+
public UInt64Array(IEnumerable<ulong> enumerable)
594593
: base(enumerable)
595594
{ }
596595
public UInt64Array(int capacity)

AttributeList.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public void DeferredLoad()
132132
}
133133
catch (Exception err)
134134
{
135-
throw new CodecException(String.Format("Deferred loading of attribute \"{0}\" on element {1} using codec {2} threw an exception.", Name, ((Element)Owner).ID, OwnerDatamodel.Codec), err);
135+
throw new CodecException($"Deferred loading of attribute \"{Name}\" on element {((Element)Owner).ID} using {OwnerDatamodel.Codec} codec threw an exception.", err);
136136
}
137137
Offset = 0;
138138

Codecs/Binary.cs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,21 @@ class Binary : IDeferredAttributeCodec, IDisposable
2727
static Binary()
2828
{
2929
SupportedAttributes[1] =
30-
SupportedAttributes[2] = new Type[] { typeof(Element), typeof(int), typeof(float), typeof(bool), typeof(string), typeof(byte[]), null /* ObjectID */, typeof(System.Drawing.Color), typeof(Vector2), typeof(Vector3), typeof(Vector4), typeof(Vector3) /* angle*/, typeof(Quaternion), typeof(Matrix4x4) };
30+
SupportedAttributes[2] = new Type[] {
31+
typeof(Element), typeof(int), typeof(float), typeof(bool), typeof(string), typeof(byte[]),
32+
null /* ObjectID */, typeof(Color), typeof(Vector2), typeof(Vector3), typeof(Vector4), typeof(Vector3) /* angle*/, typeof(Quaternion), typeof(Matrix4x4)
33+
};
3134
SupportedAttributes[3] =
3235
SupportedAttributes[4] =
33-
SupportedAttributes[5] = new Type[] { typeof(Element), typeof(int), typeof(float), typeof(bool), typeof(string), typeof(byte[]), typeof(TimeSpan), typeof(System.Drawing.Color), typeof(Vector2), typeof(Vector3), typeof(Vector4), typeof(Vector3) /* angle*/, typeof(Quaternion), typeof(Matrix4x4) };
34-
SupportedAttributes[9] = new Type[] { typeof(Element), typeof(int), typeof(float), typeof(bool), typeof(string), typeof(byte[]), typeof(TimeSpan), typeof(System.Drawing.Color), typeof(Vector2), typeof(Vector3), typeof(Vector4), typeof(Vector3) /* angle*/, typeof(Quaternion), typeof(Matrix4x4), typeof(UInt64), typeof(byte) };
36+
SupportedAttributes[5] = new Type[] {
37+
typeof(Element), typeof(int), typeof(float), typeof(bool), typeof(string), typeof(byte[]),
38+
typeof(TimeSpan), typeof(Color), typeof(Vector2), typeof(Vector3), typeof(Vector4), typeof(Vector3) /* angle*/, typeof(Quaternion), typeof(Matrix4x4)
39+
};
40+
SupportedAttributes[9] = new Type[] {
41+
typeof(Element), typeof(int), typeof(float), typeof(bool), typeof(string), typeof(byte[]),
42+
typeof(TimeSpan), typeof(Color), typeof(Vector2), typeof(Vector3), typeof(Vector4), typeof(Vector3) /* angle*/, typeof(Quaternion), typeof(Matrix4x4),
43+
typeof(ulong), typeof(byte)/*, typeof(QAngle) */
44+
};
3545
}
3646

3747
public void Dispose()
@@ -262,10 +272,10 @@ object ReadValue(Datamodel dm, Type type, bool raw_string)
262272
if (type == typeof(TimeSpan))
263273
return TimeSpan.FromTicks(Reader.ReadInt32() * (TimeSpan.TicksPerSecond / DatamodelTicksPerSecond));
264274

265-
if (type == typeof(System.Drawing.Color))
275+
if (type == typeof(Color))
266276
{
267277
var rgba = Reader.ReadBytes(4);
268-
return System.Drawing.Color.FromArgb(rgba[3], rgba[0], rgba[1], rgba[2]);
278+
return Color.FromBytes(rgba);
269279
}
270280

271281
if (type == typeof(Vector2))
@@ -423,7 +433,7 @@ void SkipAttribute()
423433

424434
if (type == typeof(TimeSpan))
425435
length = sizeof(int);
426-
else if (type == typeof(System.Drawing.Color))
436+
else if (type == typeof(Color))
427437
length = 4;
428438
else if (type == typeof(bool))
429439
length = 1;
@@ -626,9 +636,9 @@ void WriteAttribute(object value, bool in_array)
626636
return;
627637
}
628638

629-
if (value is System.Drawing.Color colour_value)
639+
if (value is Color colour_value)
630640
{
631-
Writer.Write(new byte[] { colour_value.R, colour_value.G, colour_value.B, colour_value.A });
641+
Writer.Write(colour_value.ToBytes());
632642
return;
633643
}
634644

Codecs/KeyValues2.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ static KeyValues2()
2828
TypeNames[typeof(string)] = "string";
2929
TypeNames[typeof(byte[])] = "binary";
3030
TypeNames[typeof(TimeSpan)] = "time";
31-
TypeNames[typeof(System.Drawing.Color)] = "color";
31+
TypeNames[typeof(Color)] = "color";
3232
TypeNames[typeof(Vector2)] = "vector2";
3333
TypeNames[typeof(Vector3)] = "vector3";
3434
TypeNames[typeof(Vector4)] = "vector4";
@@ -240,9 +240,9 @@ void WriteAttribute(string name, Type type, object value, bool in_array)
240240
value = BitConverter.ToString((byte[])value).Replace("-", String.Empty);
241241
else if (type == typeof(TimeSpan))
242242
value = ((TimeSpan)value).TotalSeconds;
243-
else if (type == typeof(System.Drawing.Color))
243+
else if (type == typeof(Color))
244244
{
245-
var c = (System.Drawing.Color)value;
245+
var c = (Color)value;
246246
value = String.Join(" ", new int[] { c.R, c.G, c.B, c.A });
247247
}
248248
else if (value is ulong ulong_value)
@@ -516,7 +516,7 @@ object Decode_ParseValue(Type type, string value)
516516
if (type == typeof(Element))
517517
return Decode_ParseElement(value);
518518
if (type == typeof(int))
519-
return Int32.Parse(value);
519+
return int.Parse(value);
520520
else if (type == typeof(float))
521521
return float.Parse(value);
522522
else if (type == typeof(bool))
@@ -535,13 +535,13 @@ object Decode_ParseValue(Type type, string value)
535535

536536
var num_list = value.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
537537

538-
if (type == typeof(System.Drawing.Color))
538+
if (type == typeof(Color))
539539
{
540540
var rgba = num_list.Select(i => byte.Parse(i)).ToArray();
541-
return System.Drawing.Color.FromArgb(rgba[3], rgba[0], rgba[1], rgba[2]);
541+
return Color.FromBytes(rgba);
542542
}
543543

544-
if (type == typeof(UInt64)) return UInt64.Parse(value.Remove(0, 2), System.Globalization.NumberStyles.HexNumber);
544+
if (type == typeof(ulong)) return ulong.Parse(value.Remove(0, 2), System.Globalization.NumberStyles.HexNumber);
545545
if (type == typeof(byte)) return byte.Parse(value);
546546

547547
var f_list = num_list.Select(i => float.Parse(i)).ToArray();
@@ -554,8 +554,9 @@ object Decode_ParseValue(Type type, string value)
554554
f_list[4], f_list[5], f_list[6], f_list[7],
555555
f_list[8], f_list[9], f_list[10], f_list[11],
556556
f_list[12], f_list[13], f_list[14], f_list[15]);
557+
else if (type == typeof(QAngle)) return new QAngle(f_list[0], f_list[1], f_list[2]);
557558

558-
else throw new ArgumentException("Internal error: ParseValue passed unsupported Type.");
559+
else throw new ArgumentException($"Internal error: ParseValue passed unsupported type: {type}.");
559560
}
560561

561562
public Datamodel Decode(int encoding_version, string format, int format_version, Stream stream, DeferredMode defer_mode)
@@ -578,7 +579,7 @@ public Datamodel Decode(int encoding_version, string format, int format_version,
578579
try
579580
{ Decode_ParseElement(next); }
580581
catch (Exception err)
581-
{ throw new CodecException(String.Format("KeyValues2 decode failed on line {0}:\n\n{1}", Line, err.Message), err); }
582+
{ throw new CodecException($"KeyValues2 decode failed on line {Line}:\n\n{err.Message}", err); }
582583
}
583584

584585
return DM;

Datamodel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public DebugView(Datamodel dm)
4545
typeof(string),
4646
typeof(byte[]),
4747
typeof(TimeSpan),
48-
typeof(System.Drawing.Color),
48+
typeof(Color),
4949
typeof(Vector2),
5050
typeof(Vector3),
5151
typeof(Vector4),

ICodec.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public static System.Collections.IList MakeList(Type t, int count)
100100
return new BinaryArray(count);
101101
if (t == typeof(TimeSpan))
102102
return new TimeSpanArray(count);
103-
if (t == typeof(System.Drawing.Color))
103+
if (t == typeof(Color))
104104
return new ColorArray(count);
105105
if (t == typeof(Vector2))
106106
return new Vector2Array(count);
@@ -114,10 +114,10 @@ public static System.Collections.IList MakeList(Type t, int count)
114114
return new MatrixArray(count);
115115
if (t == typeof(byte))
116116
return new ByteArray(count);
117-
if (t == typeof(UInt64))
117+
if (t == typeof(ulong))
118118
return new UInt64Array(count);
119119

120-
throw new ArgumentException("Unrecognised Type.");
120+
throw new ArgumentException($"Unhandled or invalid type: {t}");
121121
}
122122

123123
/// <summary>
@@ -139,8 +139,8 @@ public static System.Collections.IList MakeList(Type t, System.Collections.IEnum
139139
return new BinaryArray(source.Cast<byte[]>());
140140
if (t == typeof(TimeSpan))
141141
return new TimeSpanArray(source.Cast<TimeSpan>());
142-
if (t == typeof(System.Drawing.Color))
143-
return new ColorArray(source.Cast<System.Drawing.Color>());
142+
if (t == typeof(Color))
143+
return new ColorArray(source.Cast<Color>());
144144
if (t == typeof(Vector2))
145145
return new Vector2Array(source.Cast<Vector2>());
146146
if (t == typeof(Vector3))
@@ -153,7 +153,7 @@ public static System.Collections.IList MakeList(Type t, System.Collections.IEnum
153153
return new MatrixArray(source.Cast<Matrix4x4>());
154154
if (t == typeof(byte))
155155
return new ByteArray(source.Cast<byte>());
156-
if (t == typeof(UInt64))
156+
if (t == typeof(ulong))
157157
return new UInt64Array(source.Cast<UInt64>());
158158

159159
throw new ArgumentException("Unrecognised Type.");

README.md

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,12 @@ The following CLR types are supported as Datamodel attributes:
1414
* `byte[]`
1515
* `ulong`
1616
* `System.TimeSpan`
17-
* `System.Drawing.Color`
1817

1918
Additionally, the following Datamodel.NET types are supported:
2019

2120
* `Element` (a named collection of attributes)
2221
* `Vector2`
23-
* `Vector3` / `Angle`
22+
* `Vector3` / `QAngle`
2423
* `Vector4` / `Quaternion`
2524
* `Matrix` (4x4)
2625

@@ -32,22 +31,10 @@ Additionally, the following Datamodel.NET types are supported:
3231
* Support for all known versions of Valve's `binary` and `keyvalues2` DMX encodings
3332
* Convenient `IEnumerable`, `INotifyPropertyChanged` and `INotifyCollectionChanged` implementations
3433
* Supports partial trust
35-
* Supports XAML
3634
* Inline documentation
3735
* Binary codec supports just-in-time attribute loading
3836
* Write your own codecs with the `ICodec` interface
39-
40-
### Data Binding
41-
42-
You can bind to an attribute as if it were a property of the host element, e.g. `{Binding MyElement.Hello}`. If an attribute's name collides with a statically-defined property of `Element` then use indexer syntax instead, e.g. `{Binding MyElement[Owner]}`.
43-
44-
### ObservableAttribute
45-
46-
In order to correctly implement `IDictionary`, attributes are exposed as `KeyValuePair` objects. Since these aren't great for data binding the utility type `ObservableAttribute` is provided.
47-
48-
`ObservableAttribute` will automatically wrap its descendants. For further binding convenience it will also wrap array items, generating an index-based label in place of an attribute key for each.
49-
50-
An `IValueConverter` class is provided in a comment block at the start of `ObservableAttribute`'s class definition.
37+
* Support for property based attributes
5138

5239
## Quick example
5340

@@ -62,12 +49,9 @@ var MyString = HelloWorld.Root.Get<string>("Hello");
6249
HelloWorld.Save("hello world.dmx", "keyvalues2", 1); // must provide an encoding name and version
6350
```
6451

65-
```xml
66-
<Datamodel Format="helloworld" FormatVersion="1">
67-
<Datamodel.Root>
68-
<Element Name="my_root">
69-
<sys:String x:Key="Hello">World</sys:String>
70-
</Element>
71-
</Datamodel.Root>
72-
</Datamodel>
52+
```vdf
53+
<--! dmx encoding keyvalues2 1 format helloworld 1>
54+
{
55+
"Hello" "string" "World"
56+
}
7357
```

Tests/Tests.cs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using Datamodel;
99
using System.Numerics;
1010
using DM = Datamodel.Datamodel;
11-
using System.Text;
1211

1312
namespace Datamodel_Tests
1413
{
@@ -29,13 +28,29 @@ static DatamodelTests()
2928
Random.Shared.NextBytes(binary);
3029
var quat = Quaternion.Normalize(new Quaternion(1, 2, 3, 4)); // dmxconvert will normalise this if I don't!
3130

32-
TestValues_V1 = new List<object>(new object[] { "hello_world", 1, 1.5f, true, binary, null, System.Drawing.Color.Blue,
33-
new Vector2(1,2), new Vector3(1,2,3), new Vector4(1,2,3,4), quat, new Matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) });
31+
TestValues_V1 = new List<object> {
32+
"hello_world",
33+
1,
34+
1.5f,
35+
true,
36+
binary,
37+
null,
38+
new Color(1, 255, 2, 244),
39+
new Vector2(1,2),
40+
new Vector3(1,2,3),
41+
new Vector4(1,2,3,4),
42+
quat,
43+
new Matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)
44+
};
3445

3546
TestValues_V2 = TestValues_V1.ToList();
36-
TestValues_V2[5] = TimeSpan.FromMinutes(5) + TimeSpan.FromTicks(TimeSpan.TicksPerMillisecond / 2);
47+
TestValues_V2.Add(TimeSpan.FromMinutes(5) + TimeSpan.FromTicks(TimeSpan.TicksPerMillisecond / 2));
3748

38-
TestValues_V3 = TestValues_V1.Concat(new object[] { (byte)0xFF, (UInt64)0xFFFFFFFF }).ToList();
49+
TestValues_V3 = TestValues_V1.Concat(new object[] {
50+
(byte)0xFF,
51+
(ulong)0xFFFFFFFF,
52+
//new QAngle(0, 90, 180)
53+
}).ToList();
3954
}
4055

4156

@@ -173,7 +188,7 @@ private void CompareVector(DM dm, string name, float[] actual)
173188
Assert.AreEqual(t.Item1, t.Item2, 1e-6, name);
174189
}
175190

176-
protected void ValidatePopulated(string encoding_name, int encoding_version)
191+
protected static void ValidatePopulated(string encoding_name, int encoding_version)
177192
{
178193
var dm = DM.Load(DmxConvertPath);
179194
Assert.AreEqual(RootGuid, dm.Root.ID);
@@ -182,13 +197,12 @@ protected void ValidatePopulated(string encoding_name, int encoding_version)
182197
if (value == null) continue;
183198
var name = value.GetType().Name;
184199

185-
if (value is ICollection)
186-
CollectionAssert.AreEqual((ICollection)value, (ICollection)dm.Root[name]);
187-
else if (value is System.Drawing.Color)
188-
Assert.AreEqual(((System.Drawing.Color)value).ToArgb(), dm.Root.Get<System.Drawing.Color>(name).ToArgb());
189-
else if (value is Quaternion)
200+
if (value is ICollection collection)
201+
CollectionAssert.AreEqual(collection, (ICollection)dm.Root[name]);
202+
else if (value is Color color)
203+
Assert.AreEqual(color, dm.Root.Get<Color>(name));
204+
else if (value is Quaternion quat)
190205
{
191-
var quat = (Quaternion)value;
192206
var expected = dm.Root.Get<Quaternion>(name);
193207
Assert.AreEqual(quat.W, expected.W, 1e-6, name + " W");
194208
Assert.AreEqual(quat.X, expected.X, 1e-6, name + " X");
@@ -202,7 +216,7 @@ protected void ValidatePopulated(string encoding_name, int encoding_version)
202216
dm.Dispose();
203217
}
204218

205-
protected DM Create(string encoding, int version, bool memory_save = false)
219+
protected static DM Create(string encoding, int version, bool memory_save = false)
206220
{
207221
var dm = MakeDatamodel();
208222
Populate(dm, encoding, version);

Types/Color.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
3+
namespace Datamodel;
4+
5+
public struct Color : IEquatable<Color>
6+
{
7+
public byte R;
8+
public byte G;
9+
public byte B;
10+
public byte A;
11+
12+
public Color(byte r, byte g, byte b, byte a)
13+
{
14+
R = r;
15+
G = g;
16+
B = b;
17+
A = a;
18+
}
19+
20+
public static bool operator ==(Color first, Color second)
21+
=> first.R == second.R && first.G == second.G && first.B == second.B && first.A == second.A;
22+
23+
public static bool operator !=(Color a, Color b)
24+
=> !(a == b);
25+
26+
public static Color FromBytes(byte[] bytes)
27+
=> new(bytes[0], bytes[1], bytes[2], bytes[3]);
28+
29+
public byte[] ToBytes()
30+
=> new byte[] { R, G, B, A };
31+
32+
public override int GetHashCode()
33+
=> HashCode.Combine(R, G, B, A);
34+
35+
public bool Equals(Color other)
36+
=> this == other;
37+
38+
public override bool Equals(object obj)
39+
{
40+
if (obj is Color color)
41+
return this == color;
42+
return false;
43+
}
44+
}

0 commit comments

Comments
 (0)