using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Xml; using System.Xml.Serialization; using RGB.NET.Core; namespace RGB.NET.Layout { /// /// Represents the serializable layout of a . /// [Serializable] [XmlRoot("Device")] public class DeviceLayout : IDeviceLayout { #region Properties & Fields /// /// Gets or sets the name of the . /// [XmlElement("Name")] public string? Name { get; set; } /// /// Gets or sets the description of the . /// [XmlElement("Description")] public string? Description { get; set; } /// /// Gets or sets the author of the . /// [XmlElement("Author")] public string? Author { get; set; } /// /// Gets or sets the of the . /// [XmlElement("Type")] public RGBDeviceType Type { get; set; } /// /// Gets or sets the vendor of the . /// [XmlElement("Vendor")] public string? Vendor { get; set; } /// /// Gets or sets the model of the . /// [XmlElement("Model")] public string? Model { get; set; } /// /// Gets or sets the of the . /// [XmlElement("Shape")] [DefaultValue(Shape.Rectangle)] public Shape Shape { get; set; } = Shape.Rectangle; /// /// Gets or sets the width of the . /// [XmlElement("Width")] public float Width { get; set; } /// /// Gets or sets the height of the . /// [XmlElement("Height")] public float Height { get; set; } /// /// Gets or sets the width of one 'unit' used for the calculation of led positions and sizes. /// [XmlElement("LedUnitWidth")] [DefaultValue(19.0)] public float LedUnitWidth { get; set; } = 19.0f; /// /// Gets or sets the height of one 'unit' used for the calculation of led positions and sizes. /// [XmlElement("LedUnitHeight")] [DefaultValue(19.0)] public float LedUnitHeight { get; set; } = 19.0f; [XmlArray("Leds")] public List InternalLeds { get; set; } = new(); /// /// Gets or sets a list of representing all the of the . /// [XmlIgnore] public IEnumerable Leds => InternalLeds; [XmlElement("CustomData")] public object? InternalCustomData { get; set; } [XmlIgnore] public object? CustomData { get; set; } #endregion #region Methods /// /// Creates a new from the given xml. /// /// The path to the xml file. /// The deserialized . public static DeviceLayout? Load(string path, Type? customDeviceDataType = null, Type? customLedDataType = null) { if (!File.Exists(path)) return null; try { XmlSerializer serializer = new(typeof(DeviceLayout)); using StreamReader reader = new(path); DeviceLayout? layout = serializer.Deserialize(reader) as DeviceLayout; if (layout != null) layout.CustomData = layout.GetCustomData(layout.InternalCustomData, customDeviceDataType); if (layout?.InternalLeds != null) { LedLayout? lastLed = null; foreach (LedLayout led in layout.InternalLeds) { led.CalculateValues(layout, lastLed); lastLed = led; led.CustomData = layout.GetCustomData(led.InternalCustomData, customLedDataType); } } return layout; } catch { return null; } } protected virtual object? GetCustomData(object? customData, Type? type) { XmlNode? node = (customData as XmlNode) ?? (customData as IEnumerable)?.FirstOrDefault()?.ParentNode; //HACK DarthAffe 16.01.2021: This gives us the CustomData-Node if ((node == null) || (type == null)) return null; if (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); } #endregion } }