1
0
mirror of https://github.com/DarthAffe/RGB.NET.git synced 2025-12-13 10:08:31 +00:00

Added base class for location/size-handling and refactored devices and leds to make use of it

This commit is contained in:
Darth Affe 2021-02-09 23:11:01 +01:00
parent 6a4ebb3d2a
commit d44223ee6a
21 changed files with 349 additions and 322 deletions

View File

@ -13,12 +13,25 @@ namespace RGB.NET.Core
/// <summary> /// <summary>
/// Represents a generic RGB-device. /// Represents a generic RGB-device.
/// </summary> /// </summary>
public abstract class AbstractRGBDevice<TDeviceInfo> : AbstractBindable, IRGBDevice<TDeviceInfo> public abstract class AbstractRGBDevice<TDeviceInfo> : Placeable, IRGBDevice<TDeviceInfo>
where TDeviceInfo : class, IRGBDeviceInfo where TDeviceInfo : class, IRGBDeviceInfo
{ {
private RGBSurface? _surface;
#region Properties & Fields #region Properties & Fields
RGBSurface? IRGBDevice.Surface { get; set; } RGBSurface? IRGBDevice.Surface
{
get => _surface;
set
{
if (SetProperty(ref _surface, value))
{
if (value == null) OnDetached();
else OnAttached();
}
}
}
/// <inheritdoc /> /// <inheritdoc />
public abstract TDeviceInfo DeviceInfo { get; } public abstract TDeviceInfo DeviceInfo { get; }
@ -26,70 +39,6 @@ namespace RGB.NET.Core
/// <inheritdoc /> /// <inheritdoc />
IRGBDeviceInfo IRGBDevice.DeviceInfo => DeviceInfo; IRGBDeviceInfo IRGBDevice.DeviceInfo => DeviceInfo;
private Point _location = new(0, 0);
/// <inheritdoc />
public Point Location
{
get => _location;
set
{
if (SetProperty(ref _location, value))
UpdateActualData();
}
}
private Size _size = Size.Invalid;
/// <inheritdoc />
public Size Size
{
get => _size;
set
{
if (SetProperty(ref _size, value))
UpdateActualData();
}
}
private Size _actualSize;
/// <inheritdoc />
public Size ActualSize
{
get => _actualSize;
private set => SetProperty(ref _actualSize, value);
}
private Rectangle _deviceRectangle;
/// <inheritdoc />
public Rectangle DeviceRectangle
{
get => _deviceRectangle;
private set => SetProperty(ref _deviceRectangle, value);
}
private Scale _scale = new(1);
/// <inheritdoc />
public Scale Scale
{
get => _scale;
set
{
if (SetProperty(ref _scale, value))
UpdateActualData();
}
}
private Rotation _rotation = new(0);
/// <inheritdoc />
public Rotation Rotation
{
get => _rotation;
set
{
if (SetProperty(ref _rotation, value))
UpdateActualData();
}
}
/// <summary> /// <summary>
/// Gets or sets if the device needs to be flushed on every update. /// Gets or sets if the device needs to be flushed on every update.
/// </summary> /// </summary>
@ -106,11 +55,11 @@ namespace RGB.NET.Core
Led? IRGBDevice.this[LedId ledId] => LedMapping.TryGetValue(ledId, out Led? led) ? led : null; Led? IRGBDevice.this[LedId ledId] => LedMapping.TryGetValue(ledId, out Led? led) ? led : null;
/// <inheritdoc /> /// <inheritdoc />
Led? IRGBDevice.this[Point location] => LedMapping.Values.FirstOrDefault(x => x.LedRectangle.Contains(location)); Led? IRGBDevice.this[Point location] => LedMapping.Values.FirstOrDefault(x => x.Boundry.Contains(location));
/// <inheritdoc /> /// <inheritdoc />
IEnumerable<Led> IRGBDevice.this[Rectangle referenceRect, double minOverlayPercentage] IEnumerable<Led> IRGBDevice.this[Rectangle referenceRect, double minOverlayPercentage]
=> LedMapping.Values.Where(x => referenceRect.CalculateIntersectPercentage(x.LedRectangle) >= minOverlayPercentage); => LedMapping.Values.Where(x => referenceRect.CalculateIntersectPercentage(x.Boundry) >= minOverlayPercentage);
#endregion #endregion
@ -118,12 +67,6 @@ namespace RGB.NET.Core
#region Methods #region Methods
private void UpdateActualData()
{
ActualSize = Size * Scale;
DeviceRectangle = new Rectangle(Location, new Rectangle(new Rectangle(Location, ActualSize).Rotate(Rotation)).Size);
}
/// <inheritdoc /> /// <inheritdoc />
public virtual void Update(bool flushLeds = false) public virtual void Update(bool flushLeds = false)
{ {
@ -188,6 +131,18 @@ namespace RGB.NET.Core
protected virtual object? GetLedCustomData(LedId ledId) => null; protected virtual object? GetLedCustomData(LedId ledId) => null;
protected virtual void OnAttached()
{
if (Location == Point.Invalid) Location = new Point(0, 0);
if (Size == Size.Invalid)
{
Rectangle ledRectangle = new(this.Select(x => x.Boundry));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
}
protected virtual void OnDetached() { }
#region Enumerator #region Enumerator
/// <inheritdoc /> /// <inheritdoc />

View File

@ -9,7 +9,7 @@ namespace RGB.NET.Core
/// <summary> /// <summary>
/// Represents a generic RGB-device. /// Represents a generic RGB-device.
/// </summary> /// </summary>
public interface IRGBDevice : IEnumerable<Led>, IBindable, IDisposable public interface IRGBDevice : IEnumerable<Led>, IPlaceable, IBindable, IDisposable
{ {
#region Properties #region Properties
@ -20,37 +20,6 @@ namespace RGB.NET.Core
/// </summary> /// </summary>
IRGBDeviceInfo DeviceInfo { get; } IRGBDeviceInfo DeviceInfo { get; }
/// <summary>
/// Gets or sets the location of the <see cref="IRGBDevice"/>.
/// </summary>
Point Location { get; set; }
/// <summary>
/// Gets the <see cref="Size"/> of the <see cref="IRGBDevice"/>.
/// </summary>
Size Size { get; set; }
/// <summary>
/// Gets the actual <see cref="Size"/> of the <see cref="IRGBDevice"/>.
/// This includes the <see cref="Scale"/>.
/// </summary>
Size ActualSize { get; }
/// <summary>
/// Gets a <see cref="Rectangle"/> representing the logical location of the <see cref="DeviceRectangle"/> relative to the <see cref="RGBSurface"/>.
/// </summary>
Rectangle DeviceRectangle { get; }
/// <summary>
/// Gets or sets the scale of the <see cref="IRGBDevice"/>.
/// </summary>
Scale Scale { get; set; }
/// <summary>
/// Gets or sets the rotation of the <see cref="IRGBDevice"/>.
/// </summary>
Rotation Rotation { get; set; }
#endregion #endregion
#region Indexer #region Indexer

View File

@ -17,7 +17,7 @@ namespace RGB.NET.Core
/// <summary> /// <summary>
/// Gets the <see cref="IRGBDevice"/> that caused the change. Returns null if the change isn't caused by a <see cref="IRGBDevice"/>. /// Gets the <see cref="IRGBDevice"/> that caused the change. Returns null if the change isn't caused by a <see cref="IRGBDevice"/>.
/// </summary> /// </summary>
public IEnumerable<IRGBDevice> Devices { get; } public IRGBDevice? Devices { get; }
/// <summary> /// <summary>
/// Gets a value indicating if the event is caused by the addition of a new <see cref="IRGBDevice"/> to the <see cref="RGBSurface"/>. /// Gets a value indicating if the event is caused by the addition of a new <see cref="IRGBDevice"/> to the <see cref="RGBSurface"/>.
@ -25,9 +25,14 @@ namespace RGB.NET.Core
public bool DeviceAdded { get; } public bool DeviceAdded { get; }
/// <summary> /// <summary>
/// Gets a value indicating if the event is caused by a changed location of one of the devices on the <see cref="RGBSurface"/>. /// Gets a value indicating if the event is caused by the removal of a <see cref="IRGBDevice"/> to the <see cref="RGBSurface"/>.
/// </summary> /// </summary>
public bool DeviceLocationChanged { get; } public bool DeviceRemoved { get; }
/// <summary>
/// Gets a value indicating if the event is caused by a changed location or size of one of the <see cref="IRGBDevice"/> on the <see cref="RGBSurface"/>.
/// </summary>
public bool DeviceChanged { get; }
#endregion #endregion
@ -40,13 +45,23 @@ namespace RGB.NET.Core
/// <param name="devices">The <see cref="T:RGB.NET.Core.IRGBDevice" /> that caused the change.</param> /// <param name="devices">The <see cref="T:RGB.NET.Core.IRGBDevice" /> that caused the change.</param>
/// <param name="deviceAdded">A value indicating if the event is caused by the addition of a new <see cref="T:RGB.NET.Core.IRGBDevice" /> to the <see cref="T:RGB.NET.Core.RGBSurface" />.</param> /// <param name="deviceAdded">A value indicating if the event is caused by the addition of a new <see cref="T:RGB.NET.Core.IRGBDevice" /> to the <see cref="T:RGB.NET.Core.RGBSurface" />.</param>
/// <param name="deviceLocationChanged">A value indicating if the event is caused by a changed location of one of the devices on the <see cref="T:RGB.NET.Core.RGBSurface" />.</param> /// <param name="deviceLocationChanged">A value indicating if the event is caused by a changed location of one of the devices on the <see cref="T:RGB.NET.Core.RGBSurface" />.</param>
public SurfaceLayoutChangedEventArgs(IEnumerable<IRGBDevice> devices, bool deviceAdded, bool deviceLocationChanged) private SurfaceLayoutChangedEventArgs(IRGBDevice? devices, bool deviceAdded, bool deviceRemoved, bool deviceChanged)
{ {
this.Devices = devices; this.Devices = devices;
this.DeviceAdded = deviceAdded; this.DeviceAdded = deviceAdded;
this.DeviceLocationChanged = deviceLocationChanged; this.DeviceRemoved = deviceRemoved;
this.DeviceChanged = deviceChanged;
} }
#endregion #endregion
#region Factory
internal static SurfaceLayoutChangedEventArgs FromAddedDevice(IRGBDevice device) => new(device, true, false, false);
internal static SurfaceLayoutChangedEventArgs FromRemovedDevice(IRGBDevice device) => new(device, false, true, false);
internal static SurfaceLayoutChangedEventArgs FromChangedDevice(IRGBDevice device) => new(device, false, false, true);
internal static SurfaceLayoutChangedEventArgs Misc() => new(null, false, false, false);
#endregion
} }
} }

View File

@ -1,7 +1,5 @@
// ReSharper disable MemberCanBePrivate.Global // ReSharper disable MemberCanBePrivate.Global
using System;
using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
namespace RGB.NET.Core namespace RGB.NET.Core
@ -11,7 +9,7 @@ namespace RGB.NET.Core
/// Represents a single LED of a RGB-device. /// Represents a single LED of a RGB-device.
/// </summary> /// </summary>
[DebuggerDisplay("{Id} {Color}")] [DebuggerDisplay("{Id} {Color}")]
public class Led : AbstractBindable public class Led : Placeable
{ {
#region Properties & Fields #region Properties & Fields
@ -45,80 +43,14 @@ namespace RGB.NET.Core
set => SetProperty(ref _shapeData, value); set => SetProperty(ref _shapeData, value);
} }
private Point _location; private Rectangle _absoluteBoundry;
/// <summary>
/// Gets or sets the relative location of the <see cref="Led"/>.
/// </summary>
public Point Location
{
get => _location;
set
{
if (SetProperty(ref _location, value))
{
UpdateActualData();
UpdateAbsoluteData();
}
}
}
private Size _size;
/// <summary>
/// Gets or sets the size of the <see cref="Led"/>.
/// </summary>
public Size Size
{
get => _size;
set
{
if (SetProperty(ref _size, value))
{
UpdateActualData();
UpdateAbsoluteData();
}
}
}
private Point _actualLocation;
/// <summary>
/// Gets the actual location of the <see cref="Led"/>.
/// This includes device-scaling and rotation.
/// </summary>
public Point ActualLocation
{
get => _actualLocation;
private set => SetProperty(ref _actualLocation, value);
}
private Size _actualSize;
/// <summary>
/// Gets the actual size of the <see cref="Led"/>.
/// This includes device-scaling.
/// </summary>
public Size ActualSize
{
get => _actualSize;
private set => SetProperty(ref _actualSize, value);
}
private Rectangle _ledRectangle;
/// <summary>
/// Gets a rectangle representing the logical location of the <see cref="Led"/> relative to the <see cref="Device"/>.
/// </summary>
public Rectangle LedRectangle
{
get => _ledRectangle;
private set => SetProperty(ref _ledRectangle, value);
}
private Rectangle _absoluteLedRectangle;
/// <summary> /// <summary>
/// Gets a rectangle representing the logical location of the <see cref="Led"/> on the <see cref="RGBSurface"/>. /// Gets a rectangle representing the logical location of the <see cref="Led"/> on the <see cref="RGBSurface"/>.
/// </summary> /// </summary>
public Rectangle AbsoluteLedRectangle public Rectangle AbsoluteBoundry
{ {
get => _absoluteLedRectangle; get => _absoluteBoundry;
private set => SetProperty(ref _absoluteLedRectangle, value); private set => SetProperty(ref _absoluteBoundry, value);
} }
/// <summary> /// <summary>
@ -159,11 +91,6 @@ namespace RGB.NET.Core
} }
} }
/// <summary>
/// Gets the URI of an image of the <see cref="Led"/> or null if there is no image.
/// </summary>
public Uri? Image { get; set; }
/// <summary> /// <summary>
/// Gets the provider-specific data associated with this led. /// Gets the provider-specific data associated with this led.
/// </summary> /// </summary>
@ -184,59 +111,24 @@ namespace RGB.NET.Core
/// <param name="size">The size of the <see cref="Led"/>.</param> /// <param name="size">The size of the <see cref="Led"/>.</param>
/// <param name="customData">The provider-specific data associated with this led.</param> /// <param name="customData">The provider-specific data associated with this led.</param>
internal Led(IRGBDevice device, LedId id, Point location, Size size, object? customData = null) internal Led(IRGBDevice device, LedId id, Point location, Size size, object? customData = null)
: base(device)
{ {
this.Device = device; this.Device = device;
this.Id = id; this.Id = id;
this.Location = location; this.Location = location;
this.Size = size; this.Size = size;
this.CustomData = customData; this.CustomData = customData;
device.PropertyChanged += DevicePropertyChanged;
} }
#endregion #endregion
#region Methods #region Methods
private void DevicePropertyChanged(object? sender, PropertyChangedEventArgs e) protected override void UpdateActualPlaceableData()
{ {
switch (e.PropertyName) base.UpdateActualPlaceableData();
{
case nameof(IRGBDevice.Location):
UpdateAbsoluteData();
break;
case nameof(IRGBDevice.DeviceRectangle): AbsoluteBoundry = Boundry.Translate(Device.Location);
UpdateActualData();
UpdateAbsoluteData();
break;
}
}
private void UpdateActualData()
{
ActualSize = Size * Device.Scale;
Point actualLocation = (Location * Device.Scale);
Rectangle ledRectangle = new(Location * Device.Scale, Size * Device.Scale);
if (Device.Rotation.IsRotated)
{
Point deviceCenter = new Rectangle(Device.ActualSize).Center;
Point actualDeviceCenter = new Rectangle(Device.DeviceRectangle.Size).Center;
Point centerOffset = new(actualDeviceCenter.X - deviceCenter.X, actualDeviceCenter.Y - deviceCenter.Y);
actualLocation = actualLocation.Rotate(Device.Rotation, new Rectangle(Device.ActualSize).Center) + centerOffset;
ledRectangle = new Rectangle(ledRectangle.Rotate(Device.Rotation, new Rectangle(Device.ActualSize).Center)).Translate(centerOffset);
}
ActualLocation = actualLocation;
LedRectangle = ledRectangle;
}
private void UpdateAbsoluteData()
{
AbsoluteLedRectangle = LedRectangle.Translate(Device.Location);
} }
/// <summary> /// <summary>
@ -285,7 +177,7 @@ namespace RGB.NET.Core
/// Converts a <see cref="Led" /> to a <see cref="Rectangle" />. /// Converts a <see cref="Led" /> to a <see cref="Rectangle" />.
/// </summary> /// </summary>
/// <param name="led">The <see cref="Led"/> to convert.</param> /// <param name="led">The <see cref="Led"/> to convert.</param>
public static implicit operator Rectangle(Led led) => led.LedRectangle; public static implicit operator Rectangle(Led led) => led.Boundry;
#endregion #endregion
} }

View File

@ -0,0 +1,61 @@
using System;
namespace RGB.NET.Core
{
public interface IPlaceable
{
#region Properties & Fields
/// <summary>
/// Gets or sets the location of the <see cref="IPlaceable"/>.
/// </summary>
Point Location { get; set; }
/// <summary>
/// Gets the size of the <see cref="IPlaceable"/>.
/// </summary>
Size Size { get; set; }
/// <summary>
/// Gets or sets the scale of the <see cref="IPlaceable"/>.
/// </summary>
Scale Scale { get; set; }
/// <summary>
/// Gets or sets the rotation of the <see cref="IPlaceable"/>.
/// </summary>
Rotation Rotation { get; set; }
/// <summary>
/// Gets the actual location of the <see cref="IPlaceable"/>.
/// This includes the <see cref="Rotation"/>.
/// </summary>
Point ActualLocation { get; }
/// <summary>
/// Gets the actual <see cref="Size"/> of the <see cref="IPlaceable"/>.
/// This includes the <see cref="Scale"/>.
/// </summary>
Size ActualSize { get; }
/// <summary>
/// Gets a rectangle containing the whole <see cref="IPlaceable"/>.
/// This includes <see cref="Location"/>, <see cref="Size"/>, <see cref="Scale"/> and <see cref="Rotation"/>.
/// </summary>
Rectangle Boundry { get; }
#endregion
#region Events
event EventHandler<EventArgs> LocationChanged;
event EventHandler<EventArgs> SizeChanged;
event EventHandler<EventArgs> ScaleChanged;
event EventHandler<EventArgs> RotationChanged;
event EventHandler<EventArgs> ActualLocationChanged;
event EventHandler<EventArgs> ActualSizeChanged;
event EventHandler<EventArgs> BoundryChanged;
#endregion
}
}

View File

@ -0,0 +1,199 @@
using System;
namespace RGB.NET.Core
{
public class Placeable : AbstractBindable, IPlaceable
{
#region Properties & Fields
protected IPlaceable? Parent { get; }
private Point _location = Point.Invalid;
/// <inheritdoc />
public Point Location
{
get => _location;
set
{
if (SetProperty(ref _location, value))
OnLocationChanged();
}
}
private Size _size = Size.Invalid;
/// <inheritdoc />
public Size Size
{
get => _size;
set
{
if (SetProperty(ref _size, value))
OnSizeChanged();
}
}
private Scale _scale = new(1);
/// <inheritdoc />
public Scale Scale
{
get => _scale;
set
{
if (SetProperty(ref _scale, value))
OnScaleChanged();
}
}
private Rotation _rotation = new(0);
/// <inheritdoc />
public Rotation Rotation
{
get => _rotation;
set
{
if (SetProperty(ref _rotation, value))
OnRotationChanged();
}
}
private Point _actualLocation = Point.Invalid;
/// <inheritdoc />
public Point ActualLocation
{
get => _actualLocation;
private set
{
if (SetProperty(ref _actualLocation, value))
OnActualLocationChanged();
}
}
private Size _actualSize = Size.Invalid;
/// <inheritdoc />
public Size ActualSize
{
get => _actualSize;
private set
{
if (SetProperty(ref _actualSize, value))
OnActualSizeChanged();
}
}
private Rectangle _boundry = new(Point.Invalid, Point.Invalid);
/// <inheritdoc />
public Rectangle Boundry
{
get => _boundry;
private set
{
if (SetProperty(ref _boundry, value))
OnBoundryChanged();
}
}
#endregion
#region Events
public event EventHandler<EventArgs>? LocationChanged;
public event EventHandler<EventArgs>? SizeChanged;
public event EventHandler<EventArgs>? ScaleChanged;
public event EventHandler<EventArgs>? RotationChanged;
public event EventHandler<EventArgs>? ActualLocationChanged;
public event EventHandler<EventArgs>? ActualSizeChanged;
public event EventHandler<EventArgs>? BoundryChanged;
#endregion
#region Constructors
public Placeable() { }
public Placeable(IPlaceable parent)
{
this.Parent = parent;
Parent.BoundryChanged += (_, _) => UpdateActualPlaceableData();
}
public Placeable(Point location, Size size)
{
this.Location = location;
this.Size = size;
}
public Placeable(IPlaceable parent, Point location, Size size)
{
this.Parent = parent;
this.Location = location;
this.Size = size;
Parent.BoundryChanged += (_, _) => UpdateActualPlaceableData();
}
#endregion
#region Methods
protected virtual void UpdateActualPlaceableData()
{
if (Parent != null)
{
Size actualSize = Size * Parent.Scale;
Point actualLocation = (Location * Parent.Scale);
Rectangle boundry = new(actualLocation, actualSize);
if (Parent.Rotation.IsRotated)
{
Point parentCenter = new Rectangle(Parent.ActualSize).Center;
Point actualParentCenter = new Rectangle(Parent.Boundry.Size).Center;
Point centerOffset = new(actualParentCenter.X - parentCenter.X, actualParentCenter.Y - parentCenter.Y);
actualLocation = actualLocation.Rotate(Parent.Rotation, new Rectangle(Parent.ActualSize).Center) + centerOffset;
boundry = new Rectangle(boundry.Rotate(Parent.Rotation, new Rectangle(Parent.ActualSize).Center)).Translate(centerOffset);
}
ActualLocation = actualLocation;
ActualSize = actualSize;
Boundry = boundry;
}
else
{
ActualLocation = Location;
ActualSize = Size * Scale;
Boundry = new Rectangle(Location, new Rectangle(new Rectangle(Location, ActualSize).Rotate(Rotation)).Size);
}
}
protected virtual void OnLocationChanged()
{
LocationChanged?.Invoke(this, new EventArgs());
UpdateActualPlaceableData();
}
protected virtual void OnSizeChanged()
{
SizeChanged?.Invoke(this, new EventArgs());
UpdateActualPlaceableData();
}
protected virtual void OnScaleChanged()
{
ScaleChanged?.Invoke(this, new EventArgs());
UpdateActualPlaceableData();
}
protected virtual void OnRotationChanged()
{
RotationChanged?.Invoke(this, new EventArgs());
UpdateActualPlaceableData();
}
protected virtual void OnActualLocationChanged() => ActualLocationChanged?.Invoke(this, new EventArgs());
protected virtual void OnActualSizeChanged() => ActualSizeChanged?.Invoke(this, new EventArgs());
protected virtual void OnBoundryChanged() => BoundryChanged?.Invoke(this, new EventArgs());
#endregion
}
}

View File

@ -9,6 +9,7 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=devices_005Cupdate/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=devices_005Cupdate/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=effects/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=effects/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=events/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=events/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=events_005Cplaceable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=exceptions/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=exceptions/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=extensions/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=extensions/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=groups/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=groups/@EntryIndexedValue">True</s:Boolean>

View File

@ -4,7 +4,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@ -212,13 +211,13 @@ namespace RGB.NET.Core
switch (brush.BrushCalculationMode) switch (brush.BrushCalculationMode)
{ {
case BrushCalculationMode.Relative: case BrushCalculationMode.Relative:
Rectangle brushRectangle = new(leds.Select(led => led.AbsoluteLedRectangle)); Rectangle brushRectangle = new(leds.Select(led => led.AbsoluteBoundry));
Point offset = new(-brushRectangle.Location.X, -brushRectangle.Location.Y); Point offset = new(-brushRectangle.Location.X, -brushRectangle.Location.Y);
brushRectangle = brushRectangle.SetLocation(new Point(0, 0)); brushRectangle = brushRectangle.SetLocation(new Point(0, 0));
brush.PerformRender(brushRectangle, leds.Select(led => new BrushRenderTarget(led, led.AbsoluteLedRectangle.Translate(offset)))); brush.PerformRender(brushRectangle, leds.Select(led => new BrushRenderTarget(led, led.AbsoluteBoundry.Translate(offset))));
break; break;
case BrushCalculationMode.Absolute: case BrushCalculationMode.Absolute:
brush.PerformRender(SurfaceRectangle, leds.Select(led => new BrushRenderTarget(led, led.AbsoluteLedRectangle))); brush.PerformRender(SurfaceRectangle, leds.Select(led => new BrushRenderTarget(led, led.AbsoluteBoundry)));
break; break;
default: default:
throw new ArgumentException(); throw new ArgumentException();
@ -281,11 +280,13 @@ namespace RGB.NET.Core
{ {
lock (_devices) lock (_devices)
{ {
if (_devices.Contains(device)) throw new RGBSurfaceException($"The device '{device.DeviceInfo.Manufacturer} {device.DeviceInfo.Model}' is already attached."); if (device.Surface != null) throw new RGBSurfaceException($"The device '{device.DeviceInfo.Manufacturer} {device.DeviceInfo.Model}' is already attached to a surface.");
device.Surface = this; device.Surface = this;
device.BoundryChanged += DeviceOnBoundryChanged;
_devices.Add(device); _devices.Add(device);
OnSurfaceLayoutChanged(SurfaceLayoutChangedEventArgs.FromAddedDevice(device));
} }
} }
@ -302,11 +303,14 @@ namespace RGB.NET.Core
{ {
lock (_devices) lock (_devices)
{ {
if (!_devices.Contains(device)) throw new RGBSurfaceException($"The device '{device.DeviceInfo.Manufacturer} {device.DeviceInfo.Model}' isn't attached."); if (!_devices.Contains(device)) throw new RGBSurfaceException($"The device '{device.DeviceInfo.Manufacturer} {device.DeviceInfo.Model}' isn't not attached to this surface.");
device.BoundryChanged -= DeviceOnBoundryChanged;
device.Surface = null; device.Surface = null;
_devices.Remove(device); _devices.Remove(device);
OnSurfaceLayoutChanged(SurfaceLayoutChangedEventArgs.FromRemovedDevice(device));
} }
} }
@ -325,17 +329,21 @@ namespace RGB.NET.Core
// ReSharper restore UnusedMember.Global // ReSharper restore UnusedMember.Global
private void DeviceOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) private void DeviceOnBoundryChanged(object? sender, EventArgs args)
=> OnSurfaceLayoutChanged((sender is IRGBDevice device) ? SurfaceLayoutChangedEventArgs.FromChangedDevice(device) : SurfaceLayoutChangedEventArgs.Misc());
private void OnSurfaceLayoutChanged(SurfaceLayoutChangedEventArgs args)
{ {
UpdateSurfaceRectangle(); UpdateSurfaceRectangle();
SurfaceLayoutChanged?.Invoke(new SurfaceLayoutChangedEventArgs((sender is IRGBDevice device) ? new[] { device } : Array.Empty<IRGBDevice>(), false, true));
SurfaceLayoutChanged?.Invoke(args);
} }
private void UpdateSurfaceRectangle() private void UpdateSurfaceRectangle()
{ {
lock (_devices) lock (_devices)
{ {
Rectangle devicesRectangle = new(_devices.Select(d => d.DeviceRectangle)); Rectangle devicesRectangle = new(_devices.Select(d => d.Boundry));
SurfaceRectangle = SurfaceRectangle.SetSize(new Size(devicesRectangle.Location.X + devicesRectangle.Size.Width, devicesRectangle.Location.Y + devicesRectangle.Size.Height)); SurfaceRectangle = SurfaceRectangle.SetSize(new Size(devicesRectangle.Location.X + devicesRectangle.Size.Width, devicesRectangle.Location.Y + devicesRectangle.Size.Height));
} }
} }

View File

@ -50,12 +50,6 @@ namespace RGB.NET.Devices.Asus
{ {
InitializeLayout(); InitializeLayout();
if (Size == Size.Invalid)
{
Rectangle ledRectangle = new(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
UpdateQueue = new AsusUpdateQueue(updateTrigger); UpdateQueue = new AsusUpdateQueue(updateTrigger);
UpdateQueue.Initialize(DeviceInfo.Device); UpdateQueue.Initialize(DeviceInfo.Device);
} }

View File

@ -53,12 +53,6 @@ namespace RGB.NET.Devices.CoolerMaster
{ {
InitializeLayout(); InitializeLayout();
if (Size == Size.Invalid)
{
Rectangle ledRectangle = new(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
UpdateQueue = new CoolerMasterUpdateQueue(updateTrigger, DeviceInfo.DeviceIndex); UpdateQueue = new CoolerMasterUpdateQueue(updateTrigger, DeviceInfo.DeviceIndex);
} }

View File

@ -75,12 +75,6 @@ namespace RGB.NET.Devices.Corsair
if (led.CustomData is CorsairLedId ledId && (ledId != CorsairLedId.Invalid)) if (led.CustomData is CorsairLedId ledId && (ledId != CorsairLedId.Invalid))
InternalLedMapping.Add(ledId, led); InternalLedMapping.Add(ledId, led);
} }
if (Size == Size.Invalid)
{
Rectangle ledRectangle = new(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
} }
/// <summary> /// <summary>

View File

@ -40,12 +40,6 @@ namespace RGB.NET.Devices.DMX.E131
foreach (LedId id in _ledMappings.Keys) foreach (LedId id in _ledMappings.Keys)
AddLed(id, new Point((count++) * 10, 0), new Size(10, 10)); AddLed(id, new Point((count++) * 10, 0), new Size(10, 10));
if (Size == Size.Invalid)
{
Rectangle ledRectangle = new(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
_updateQueue = new E131UpdateQueue(updateTrigger, DeviceInfo.Hostname, DeviceInfo.Port); _updateQueue = new E131UpdateQueue(updateTrigger, DeviceInfo.Hostname, DeviceInfo.Port);
_updateQueue.DataPacket.SetCID(DeviceInfo.CID); _updateQueue.DataPacket.SetCID(DeviceInfo.CID);
_updateQueue.DataPacket.SetUniverse(DeviceInfo.Universe); _updateQueue.DataPacket.SetUniverse(DeviceInfo.Universe);

View File

@ -51,12 +51,6 @@ namespace RGB.NET.Devices.Msi
DeviceUpdateQueue = updateQueue; DeviceUpdateQueue = updateQueue;
InitializeLayout(ledCount); InitializeLayout(ledCount);
if (Size == Size.Invalid)
{
Rectangle ledRectangle = new(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
} }
/// <summary> /// <summary>

View File

@ -51,12 +51,6 @@ namespace RGB.NET.Devices.Novation
{ {
InitializeLayout(); InitializeLayout();
if (Size == Size.Invalid)
{
Rectangle ledRectangle = new(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
UpdateQueue = DeviceInfo.ColorCapabilities switch UpdateQueue = DeviceInfo.ColorCapabilities switch
{ {
NovationColorCapabilities.LimitedRG => new LimitedColorUpdateQueue(updateTrigger, DeviceInfo.DeviceId), NovationColorCapabilities.LimitedRG => new LimitedColorUpdateQueue(updateTrigger, DeviceInfo.DeviceId),

View File

@ -52,12 +52,6 @@ namespace RGB.NET.Devices.Razer
{ {
InitializeLayout(); InitializeLayout();
if (Size == Size.Invalid)
{
Rectangle ledRectangle = new(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
UpdateQueue = CreateUpdateQueue(updateTrigger); UpdateQueue = CreateUpdateQueue(updateTrigger);
} }

View File

@ -55,12 +55,6 @@ namespace RGB.NET.Devices.SteelSeries
foreach (KeyValuePair<LedId, SteelSeriesLedId> mapping in ledMapping) foreach (KeyValuePair<LedId, SteelSeriesLedId> mapping in ledMapping)
AddLed(mapping.Key, new Point((counter++) * 10, 0), new Size(10, 10)); AddLed(mapping.Key, new Point((counter++) * 10, 0), new Size(10, 10));
if (Size == Size.Invalid)
{
Rectangle ledRectangle = new(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
UpdateQueue = updateQueue; UpdateQueue = updateQueue;
} }

View File

@ -54,12 +54,6 @@ namespace RGB.NET.Devices.WS281X.Arduino
{ {
for (int i = 0; i < ledCount; i++) for (int i = 0; i < ledCount; i++)
AddLed(LedId.LedStripe1 + i, new Point(i * 10, 0), new Size(10, 10)); AddLed(LedId.LedStripe1 + i, new Point(i * 10, 0), new Size(10, 10));
if (Size == Size.Invalid)
{
Rectangle ledRectangle = new(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -51,12 +51,6 @@ namespace RGB.NET.Devices.WS281X.Bitwizard
{ {
for (int i = 0; i < ledCount; i++) for (int i = 0; i < ledCount; i++)
AddLed(LedId.LedStripe1 + i, new Point(i * 10, 0), new Size(10, 10)); AddLed(LedId.LedStripe1 + i, new Point(i * 10, 0), new Size(10, 10));
if (Size == Size.Invalid)
{
Rectangle ledRectangle = new(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -54,12 +54,6 @@ namespace RGB.NET.Devices.WS281X.NodeMCU
{ {
for (int i = 0; i < ledCount; i++) for (int i = 0; i < ledCount; i++)
AddLed(LedId.LedStripe1 + i, new Point(i * 10, 0), new Size(10, 10)); AddLed(LedId.LedStripe1 + i, new Point(i * 10, 0), new Size(10, 10));
if (Size == Size.Invalid)
{
Rectangle ledRectangle = new(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -1,5 +1,4 @@
using System.Linq; using RGB.NET.Core;
using RGB.NET.Core;
namespace RGB.NET.Devices.Wooting.Generic namespace RGB.NET.Devices.Wooting.Generic
{ {
@ -49,12 +48,6 @@ namespace RGB.NET.Devices.Wooting.Generic
{ {
InitializeLayout(); InitializeLayout();
if (Size == Size.Invalid)
{
Rectangle ledRectangle = new(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
UpdateQueue = new WootingUpdateQueue(updateTrigger); UpdateQueue = new WootingUpdateQueue(updateTrigger);
} }

View File

@ -59,7 +59,7 @@ namespace RGB.NET.Groups
/// <param name="minOverlayPercentage">(optional) The minimal percentage overlay a <see cref="T:RGB.NET.Core.Led" /> must have with the <see cref="P:RGB.NET.Groups.RectangleLedGroup.Rectangle" /> to be taken into the <see cref="T:RGB.NET.Groups.RectangleLedGroup" />. (default: 0.5)</param> /// <param name="minOverlayPercentage">(optional) The minimal percentage overlay a <see cref="T:RGB.NET.Core.Led" /> must have with the <see cref="P:RGB.NET.Groups.RectangleLedGroup.Rectangle" /> to be taken into the <see cref="T:RGB.NET.Groups.RectangleLedGroup" />. (default: 0.5)</param>
/// <param name="autoAttach">(optional) Specifies whether this <see cref="T:RGB.NET.Groups.RectangleLedGroup" /> should be automatically attached or not. (default: true)</param> /// <param name="autoAttach">(optional) Specifies whether this <see cref="T:RGB.NET.Groups.RectangleLedGroup" /> should be automatically attached or not. (default: true)</param>
public RectangleLedGroup(RGBSurface? surface, Led fromLed, Led toLed, double minOverlayPercentage = 0.5) public RectangleLedGroup(RGBSurface? surface, Led fromLed, Led toLed, double minOverlayPercentage = 0.5)
: this(surface, new Rectangle(fromLed.LedRectangle, toLed.LedRectangle), minOverlayPercentage) : this(surface, new Rectangle(fromLed.Boundry, toLed.Boundry), minOverlayPercentage)
{ } { }
/// <inheritdoc /> /// <inheritdoc />
@ -117,7 +117,7 @@ namespace RGB.NET.Groups
/// Gets a list containing all <see cref="T:RGB.NET.Core.Led" /> of this <see cref="T:RGB.NET.Groups.RectangleLedGroup" />. /// Gets a list containing all <see cref="T:RGB.NET.Core.Led" /> of this <see cref="T:RGB.NET.Groups.RectangleLedGroup" />.
/// </summary> /// </summary>
/// <returns>The list containing all <see cref="T:RGB.NET.Core.Led" /> of this <see cref="T:RGB.NET.Groups.RectangleLedGroup" />.</returns> /// <returns>The list containing all <see cref="T:RGB.NET.Core.Led" /> of this <see cref="T:RGB.NET.Groups.RectangleLedGroup" />.</returns>
public override IList<Led> GetLeds() => _ledCache ??= (Surface?.Leds.Where(led => led.AbsoluteLedRectangle.CalculateIntersectPercentage(Rectangle) >= MinOverlayPercentage).ToList() ?? new List<Led>()); public override IList<Led> GetLeds() => _ledCache ??= (Surface?.Leds.Where(led => led.AbsoluteBoundry.CalculateIntersectPercentage(Rectangle) >= MinOverlayPercentage).ToList() ?? new List<Led>());
private void InvalidateCache() => _ledCache = null; private void InvalidateCache() => _ledCache = null;