Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Made custom data in layouts typed #356

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion RGB.NET.Devices.Debug/DebugRGBDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public sealed class DebugRGBDevice : AbstractRGBDevice<DebugRGBDeviceInfo>, IUnk
/// Internal constructor of <see cref="DebugRGBDeviceInfo"/>.
/// </summary>
internal DebugRGBDevice(IDeviceLayout layout, Action<IEnumerable<Led>>? updateLedsAction = null)
: base(new DebugRGBDeviceInfo(layout.Type, layout.Vendor ?? "RGB.NET", layout.Model ?? "Debug", layout.CustomData), new DebugDeviceUpdateQueue())
: base(new DebugRGBDeviceInfo(layout.Type, layout.Vendor ?? "RGB.NET", layout.Model ?? "Debug", layout.UntypedCustomData), new DebugDeviceUpdateQueue())
{
this.Layout = layout;
this._updateLedsAction = updateLedsAction;
Expand Down
77 changes: 32 additions & 45 deletions RGB.NET.Layout/DeviceLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,23 @@ namespace RGB.NET.Layout;
/// </summary>
[Serializable]
[XmlRoot("Device")]
public class DeviceLayout : IDeviceLayout
public class DeviceLayout : DeviceLayout<object, object>
Copy link
Collaborator Author

@RobertBeekman RobertBeekman Oct 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a 100% sure on this, it's a nice shortcut to deal with layouts if you're not interested in custom data but it creates this scenario, which confused me a bit at first:

DeviceLayout layoutA = new DeviceLayout();
DeviceLayout<object, object> layoutB = new DeviceLayout<object, object>();

layoutA = layoutB; // not possible as DeviceLayout<object, object> is technically a subtype of DeviceLayout
layoutB = layoutA; // possible because DeviceLayout is a derived type of DeviceLayout<object, object>

{ }

/// <summary>
/// Represents the serializable layout of a <see cref="IRGBDevice"/>.
/// </summary>
[Serializable]
[XmlRoot("Device")]
public class DeviceLayout<TCustomData> : DeviceLayout<TCustomData, object>
{ }

/// <summary>
/// Represents the serializable layout of a <see cref="IRGBDevice"/>.
/// </summary>
[Serializable]
[XmlRoot("Device")]
public class DeviceLayout<TCustomData, TCustomLedData> : IDeviceLayout
{
#region Properties & Fields

Expand Down Expand Up @@ -92,7 +108,7 @@ public class DeviceLayout : IDeviceLayout
/// Normally you should use <see cref="Leds"/> to access this data.
/// </summary>
[XmlArray("Leds")]
public List<LedLayout> InternalLeds { get; set; } = new();
public List<LedLayout<TCustomLedData>> InternalLeds { get; set; } = new();

/// <summary>
/// Gets or sets a list of <see cref="LedLayout"/> representing all the <see cref="Led"/> of the <see cref="DeviceLayout"/>.
Expand All @@ -101,15 +117,15 @@ public class DeviceLayout : IDeviceLayout
public IEnumerable<ILedLayout> Leds => InternalLeds;

/// <summary>
/// Gets or sets the internal custom data of this layout.
/// Normally you should use <see cref="CustomData"/> to access or set this data.
/// Gets or sets the custom data of this layout.
/// </summary>
[XmlElement("CustomData")]
public object? InternalCustomData { get; set; }
public TCustomData? CustomData { get; set; }

/// <inheritdoc />
[XmlIgnore]
public object? CustomData { get; set; }
/// <summary>
/// Gets the untyped custom data of this layout.
/// </summary>
public object? UntypedCustomData => CustomData;

#endregion

Expand All @@ -119,27 +135,21 @@ public class DeviceLayout : IDeviceLayout
/// Creates a new <see cref="DeviceLayout"/> from the specified xml.
/// </summary>
/// <param name="stream">The stream that contains the layout to be loaded.</param>
/// <param name="customDeviceDataType">The type of the custom data.</param>
/// <param name="customLedDataType">The type of the custom data of the leds.</param>
/// <returns>The deserialized <see cref="DeviceLayout"/>.</returns>
public static DeviceLayout? Load(Stream stream, Type? customDeviceDataType = null, Type? customLedDataType = null)
/// <returns>The deserialized <see cref="DeviceLayout{TCustomData, TCustomLedData}"/>.</returns>
public static DeviceLayout<TCustomData, TCustomLedData>? Load(Stream stream)
{
try
{
XmlSerializer serializer = new(typeof(DeviceLayout));
DeviceLayout? layout = serializer.Deserialize(stream) as DeviceLayout;
if (layout != null)
layout.CustomData = layout.GetCustomData(layout.InternalCustomData, customDeviceDataType);
XmlSerializer serializer = new(typeof(DeviceLayout<TCustomData, TCustomLedData>));
DeviceLayout<TCustomData, TCustomLedData>? layout = serializer.Deserialize(stream) as DeviceLayout<TCustomData, TCustomLedData>;

if (layout?.InternalLeds != null)
{
LedLayout? lastLed = null;
foreach (LedLayout led in layout.InternalLeds)
LedLayout<TCustomLedData>? lastLed = null;
foreach (LedLayout<TCustomLedData> led in layout.InternalLeds)
{
led.CalculateValues(layout, lastLed);
lastLed = led;

led.CustomData = layout.GetCustomData(led.InternalCustomData, customLedDataType);
}
}

Expand All @@ -155,36 +165,13 @@ public class DeviceLayout : IDeviceLayout
/// Creates a new <see cref="DeviceLayout"/> from the specified xml.
/// </summary>
/// <param name="path">The path to the xml file.</param>
/// <param name="customDeviceDataType">The type of the custom data.</param>
/// <param name="customLedDataType">The type of the custom data of the leds.</param>
/// <returns>The deserialized <see cref="DeviceLayout"/>.</returns>
public static DeviceLayout? Load(string path, Type? customDeviceDataType = null, Type? customLedDataType = null)
public static DeviceLayout<TCustomData, TCustomLedData>? Load(string path)
{
if (!File.Exists(path)) return null;

using Stream stream = File.OpenRead(path);
return Load(stream, customDeviceDataType, customLedDataType);
}

/// <summary>
/// Gets the deserialized custom data.
/// </summary>
/// <param name="customData">The internal custom data node.</param>
/// <param name="type">The type of the custom data.</param>
/// <returns>The deserialized custom data object.</returns>
protected virtual object? GetCustomData(object? customData, Type? type)
{
XmlNode? node = (customData as XmlNode) ?? (customData as IEnumerable<XmlNode>)?.FirstOrDefault()?.ParentNode; //HACK DarthAffe 16.01.2021: This gives us the CustomData-Node
if ((node == null) || (type == null)) return null;

using MemoryStream ms = new();
using StreamWriter writer = new(ms);

writer.Write(node.OuterXml);
writer.Flush();
ms.Seek(0, SeekOrigin.Begin);

return new XmlSerializer(type).Deserialize(ms);
return Load(stream);
}

#endregion
Expand Down
16 changes: 13 additions & 3 deletions RGB.NET.Layout/IDeviceLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,24 @@ public interface IDeviceLayout
/// Gets or sets the height of the <see cref="IDeviceLayout"/>.
/// </summary>
float Height { get; }

/// <summary>
/// Gets or sets the width of one 'unit' used for the calculation of led positions and sizes.
/// </summary>
float LedUnitWidth { get; set; }

/// <summary>
/// Gets or sets the height of one 'unit' used for the calculation of led positions and sizes.
/// </summary>
float LedUnitHeight { get; set; }

/// <summary>
/// Gets or sets a list of <see cref="ILedLayout"/> representing all the <see cref="Led"/> of the <see cref="IDeviceLayout"/>.
/// </summary>
IEnumerable<ILedLayout> Leds { get; }

/// <summary>
/// Gets the the custom data associated with the device.
/// Gets the untyped custom data of this layout.
/// </summary>
object? CustomData { get; }
object? UntypedCustomData { get; }
}
4 changes: 2 additions & 2 deletions RGB.NET.Layout/ILedLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public interface ILedLayout
float Height { get; }

/// <summary>
/// Gets the the custom data associated with the LED.
/// Gets the untyped custom data of this layout.
/// </summary>
object? CustomData { get; }
object? UntypedCustomData { get; }
}
4 changes: 2 additions & 2 deletions RGB.NET.Layout/LayoutExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static class LayoutExtension
public static void ApplyTo(this IDeviceLayout layout, IRGBDevice device, bool createMissingLeds = false, bool removeExcessiveLeds = false)
{
device.Size = new Size(layout.Width, layout.Height);
device.DeviceInfo.LayoutMetadata = layout.CustomData;
device.DeviceInfo.LayoutMetadata = layout.UntypedCustomData;

HashSet<LedId> ledIds = new();
foreach (ILedLayout layoutLed in layout.Leds)
Expand All @@ -39,7 +39,7 @@ public static void ApplyTo(this IDeviceLayout layout, IRGBDevice device, bool cr
led.Size = new Size(layoutLed.Width, layoutLed.Height);
led.Shape = layoutLed.Shape;
led.ShapeData = layoutLed.ShapeData;
led.LayoutMetadata = layoutLed.CustomData;
led.LayoutMetadata = layoutLed.UntypedCustomData;
}
}
}
Expand Down
37 changes: 23 additions & 14 deletions RGB.NET.Layout/LedLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,15 @@ namespace RGB.NET.Layout;
/// </summary>
[Serializable]
[XmlType("Led")]
public class LedLayout : ILedLayout
public class LedLayout : LedLayout<object>
{ }

/// <summary>
/// Represents the serializable layout of a <see cref="Led"/>.
/// </summary>
[Serializable]
[XmlType("Led")]
public class LedLayout<TCustomLedData> : ILedLayout
{
#region Properties & Fields

Expand Down Expand Up @@ -61,17 +69,6 @@ public class LedLayout : ILedLayout
[DefaultValue("1.0")]
public string DescriptiveHeight { get; set; } = "1.0";

/// <summary>
/// Gets or sets the internal custom data of this layout.
/// Normally you should use <see cref="CustomData"/> to access or set this data.
/// </summary>
[XmlElement("CustomData")]
public object? InternalCustomData { get; set; }

/// <inheritdoc />
[XmlIgnore]
public object? CustomData { get; set; }

/// <summary>
/// Gets or sets the <see cref="RGB.NET.Core.Shape"/> of the <see cref="LedLayout"/>.
/// </summary>
Expand Down Expand Up @@ -108,6 +105,17 @@ public class LedLayout : ILedLayout
[XmlIgnore]
public float Height { get; private set; }

/// <summary>
/// Gets or sets the custom data of this layout.
/// </summary>
[XmlElement("CustomData")]
public TCustomLedData? CustomData { get; set; }

/// <summary>
/// Gets the untyped custom data of this layout.
/// </summary>
public object? UntypedCustomData => CustomData;

#endregion

#region Methods
Expand All @@ -117,13 +125,14 @@ public class LedLayout : ILedLayout
/// </summary>
/// <param name="device">The <see cref="DeviceLayout"/> this <see cref="LedLayout"/> belongs to.</param>
/// <param name="lastLed">The <see cref="LedLayout"/> previously calculated.</param>
public virtual void CalculateValues(DeviceLayout device, LedLayout? lastLed)
public virtual void CalculateValues(IDeviceLayout device, ILedLayout? lastLed)
{
if (!Enum.TryParse(DescriptiveShape, true, out Shape shape))
{
shape = Shape.Custom;
ShapeData = DescriptiveShape;
}

Shape = shape;

Width = GetSizeValue(DescriptiveWidth, device.LedUnitWidth);
Expand Down Expand Up @@ -204,4 +213,4 @@ protected virtual float GetSizeValue(string value, float unitSize)
}

#endregion
}
}
Loading