diff --git a/RGB.NET.Groups/Extensions/LedGroupExtension.cs b/RGB.NET.Groups/Extensions/LedGroupExtension.cs
new file mode 100644
index 0000000..3992e42
--- /dev/null
+++ b/RGB.NET.Groups/Extensions/LedGroupExtension.cs
@@ -0,0 +1,79 @@
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable UnusedMember.Global
+
+using RGB.NET.Core;
+
+namespace RGB.NET.Groups
+{
+ ///
+ /// Offers some extensions and helper-methods for related things.
+ ///
+ public static class LedGroupExtension
+ {
+ ///
+ /// Converts the given to a .
+ ///
+ /// The to convert.
+ /// The converted .
+ public static ListLedGroup ToListLedGroup(this ILedGroup ledGroup)
+ {
+ ListLedGroup listLedGroup = ledGroup as ListLedGroup;
+ // ReSharper disable once InvertIf
+ if (listLedGroup == null)
+ {
+ bool wasAttached = ledGroup.Detach();
+ listLedGroup = new ListLedGroup(wasAttached, ledGroup.GetLeds()) { Brush = ledGroup.Brush };
+ }
+ return listLedGroup;
+ }
+
+ ///
+ /// Returns a new which contains all from the given excluding the specified ones.
+ ///
+ /// The base .
+ /// The ids of the to exclude.
+ /// The new .
+ public static ListLedGroup Exclude(this ILedGroup ledGroup, params ILedId[] ledIds)
+ {
+ ListLedGroup listLedGroup = ledGroup.ToListLedGroup();
+ foreach (ILedId ledId in ledIds)
+ listLedGroup.RemoveLed(ledId);
+ return listLedGroup;
+ }
+
+ ///
+ /// Returns a new which contains all from the given excluding the specified ones.
+ ///
+ /// The base .
+ /// The to exclude.
+ /// The new .
+ public static ListLedGroup Exclude(this ILedGroup ledGroup, params Led[] ledIds)
+ {
+ ListLedGroup listLedGroup = ledGroup.ToListLedGroup();
+ foreach (Led led in ledIds)
+ listLedGroup.RemoveLed(led);
+ return listLedGroup;
+ }
+
+ // ReSharper disable once UnusedMethodReturnValue.Global
+ ///
+ /// Attaches the given to the .
+ ///
+ /// The to attach.
+ /// true if the could be attached; otherwise, false.
+ public static bool Attach(this ILedGroup ledGroup)
+ {
+ return RGBSurface.AttachLedGroup(ledGroup);
+ }
+
+ ///
+ /// Detaches the given from the .
+ ///
+ /// The to attach.
+ /// true if the could be detached; otherwise, false.
+ public static bool Detach(this ILedGroup ledGroup)
+ {
+ return RGBSurface.DetachLedGroup(ledGroup);
+ }
+ }
+}
diff --git a/RGB.NET.Groups/Groups/ListLedGroup.cs b/RGB.NET.Groups/Groups/ListLedGroup.cs
new file mode 100644
index 0000000..ccb6062
--- /dev/null
+++ b/RGB.NET.Groups/Groups/ListLedGroup.cs
@@ -0,0 +1,244 @@
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable UnusedMember.Global
+
+using System.Collections.Generic;
+using RGB.NET.Core;
+
+namespace RGB.NET.Groups
+{
+ ///
+ /// Represents a ledgroup containing arbitrary .
+ ///
+ public class ListLedGroup : AbstractLedGroup
+ {
+ #region Properties & Fields
+
+ ///
+ protected override ILedGroup EffectTarget => this;
+
+ ///
+ /// Gets the list containing the of this .
+ ///
+ protected IList GroupLeds { get; } = new List();
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Specifies whether this should be automatically attached or not.
+ public ListLedGroup(bool autoAttach = true)
+ : base(autoAttach)
+ { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The initial of this .
+ public ListLedGroup(params Led[] leds)
+ : this(true, leds)
+ { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The initial of this .
+ public ListLedGroup(IEnumerable leds)
+ : this(true, leds)
+ { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Specifies whether this should be automatically attached or not.
+ /// The initial of this .
+ public ListLedGroup(bool autoAttach, IEnumerable leds)
+ : base(autoAttach)
+ {
+ AddLeds(leds);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Specifies whether this should be automatically attached or not.
+ /// The initial of this .
+ public ListLedGroup(bool autoAttach, params Led[] leds)
+ : base(autoAttach)
+ {
+ AddLeds(leds);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The IDs of the initial of this .
+ public ListLedGroup(params ILedId[] leds)
+ : this(true, leds)
+ { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The IDs of the initial of this .
+ public ListLedGroup(IEnumerable leds)
+ : this(true, leds)
+ { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Specifies whether this should be automatically attached or not.
+ /// The IDs of the initial of this .
+ public ListLedGroup(bool autoAttach, params ILedId[] leds)
+ : base(autoAttach)
+ {
+ AddLeds(leds);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Specifies whether this should be automatically attached or not.
+ /// The IDs of the initial of this .
+ public ListLedGroup(bool autoAttach, IEnumerable leds)
+ : base(autoAttach)
+ {
+ AddLeds(leds);
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Adds the given LED(s) to this .
+ ///
+ /// The LED(s) to add.
+ public void AddLed(params Led[] leds)
+ {
+ AddLeds(leds);
+ }
+
+ ///
+ /// Adds the given LED(s) to this .
+ ///
+ /// The ID(s) of the LED(s) to add.
+ public void AddLed(params ILedId[] ledIds)
+ {
+ AddLeds(ledIds);
+ }
+
+ ///
+ /// Adds the given to this .
+ ///
+ /// The to add.
+ public void AddLeds(IEnumerable leds)
+ {
+ if (leds == null) return;
+
+ foreach (Led led in leds)
+ if ((led != null) && !ContainsLed(led))
+ GroupLeds.Add(led);
+ }
+
+ ///
+ /// Adds the given to this .
+ ///
+ /// The IDs of the to add.
+ public void AddLeds(IEnumerable ledIds)
+ {
+ if (ledIds == null) return;
+
+ foreach (ILedId ledId in ledIds)
+ AddLed(ledId.Device[ledId]);
+ }
+
+ ///
+ /// Removes the given LED(s) from this .
+ ///
+ /// The LED(s) to remove.
+ public void RemoveLed(params Led[] leds)
+ {
+ RemoveLeds(leds);
+ }
+
+ ///
+ /// Removes the given LED(s) from this .
+ ///
+ /// The ID(s) of the LED(s) to remove.
+ public void RemoveLed(params ILedId[] ledIds)
+ {
+ RemoveLeds(ledIds);
+ }
+
+ ///
+ /// Removes the given from this .
+ ///
+ /// The to remove.
+ public void RemoveLeds(IEnumerable leds)
+ {
+ if (leds == null) return;
+
+ foreach (Led led in leds)
+ if (led != null)
+ GroupLeds.Remove(led);
+ }
+
+ ///
+ /// Removes the given from this .
+ ///
+ /// The IDs of the to remove.
+ public void RemoveLeds(IEnumerable ledIds)
+ {
+ if (ledIds == null) return;
+
+ foreach (ILedId ledId in ledIds)
+ RemoveLed(ledId.Device[ledId]);
+ }
+
+ ///
+ /// Checks if a given LED is contained by this ledgroup.
+ ///
+ /// The LED which should be checked.
+ /// true if the LED is contained by this ledgroup; otherwise, false.
+ public bool ContainsLed(Led led)
+ {
+ return (led != null) && GroupLeds.Contains(led);
+ }
+
+ ///
+ /// Checks if a given LED is contained by this ledgroup.
+ ///
+ /// The ID of the LED which should be checked.
+ /// true if the LED is contained by this ledgroup; otherwise, false.
+ public bool ContainsLed(ILedId ledId)
+ {
+ return ContainsLed(ledId.Device[ledId]);
+ }
+
+ ///
+ /// Merges the from the given ledgroup in this ledgroup.
+ ///
+ /// The ledgroup to merge.
+ public void MergeLeds(ILedGroup groupToMerge)
+ {
+ foreach (Led led in groupToMerge.GetLeds())
+ if (!GroupLeds.Contains(led))
+ GroupLeds.Add(led);
+ }
+
+ ///
+ /// Gets a list containing the from this group.
+ ///
+ /// The list containing the .
+ public override IEnumerable GetLeds()
+ {
+ return GroupLeds;
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Groups/Groups/RectangleLedGroup.cs b/RGB.NET.Groups/Groups/RectangleLedGroup.cs
new file mode 100644
index 0000000..d5d9e73
--- /dev/null
+++ b/RGB.NET.Groups/Groups/RectangleLedGroup.cs
@@ -0,0 +1,135 @@
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedMember.Global
+
+using System.Collections.Generic;
+using System.Linq;
+using RGB.NET.Core;
+
+namespace RGB.NET.Groups
+{
+ ///
+ /// Represents a containing which physically lay inside a .
+ ///
+ public class RectangleLedGroup : AbstractLedGroup
+ {
+ #region Properties & Fields
+
+ private IList _ledCache;
+
+ private Rectangle _rectangle;
+ ///
+ /// Gets or sets the the should be taken from.
+ ///
+ public Rectangle Rectangle
+ {
+ get { return _rectangle; }
+ set
+ {
+ _rectangle = value;
+ InvalidateCache();
+ }
+ }
+
+ private double _minOverlayPercentage;
+ ///
+ /// Gets or sets the minimal percentage overlay a must have with the to be taken into the .
+ ///
+ public double MinOverlayPercentage
+ {
+ get { return _minOverlayPercentage; }
+ set
+ {
+ _minOverlayPercentage = value;
+ InvalidateCache();
+ }
+ }
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// They ID of the first to calculate the of this from.
+ /// They ID of the second to calculate the of this from.
+ /// (optional) The minimal percentage overlay a must have with the to be taken into the . (default: 0.5)
+ /// (optional) Specifies whether this should be automatically attached or not. (default: true)
+ public RectangleLedGroup(ILedId fromLed, ILedId toLed, double minOverlayPercentage = 0.5, bool autoAttach = true)
+ : this(fromLed.Device[fromLed], toLed.Device[toLed], minOverlayPercentage, autoAttach)
+ { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// They first to calculate the of this from.
+ /// They second to calculate the of this from.
+ /// (optional) The minimal percentage overlay a must have with the to be taken into the . (default: 0.5)
+ /// (optional) Specifies whether this should be automatically attached or not. (default: true)
+ public RectangleLedGroup(Led fromLed, Led toLed, double minOverlayPercentage = 0.5, bool autoAttach = true)
+ : this(new Rectangle(fromLed.LedRectangle, toLed.LedRectangle), minOverlayPercentage, autoAttach)
+ { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// They first point to calculate the of this from.
+ /// They second point to calculate the of this from.
+ /// (optional) The minimal percentage overlay a must have with the to be taken into the . (default: 0.5)
+ /// (optional) Specifies whether this should be automatically attached or not. (default: true)
+ public RectangleLedGroup(Point fromPoint, Point toPoint, double minOverlayPercentage = 0.5, bool autoAttach = true)
+ : this(new Rectangle(fromPoint, toPoint), minOverlayPercentage, autoAttach)
+ { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The of this .
+ /// (optional) The minimal percentage overlay a must have with the to be taken into the . (default: 0.5)
+ /// (optional) Specifies whether this should be automatically attached or not. (default: true)
+ public RectangleLedGroup(Rectangle rectangle, double minOverlayPercentage = 0.5, bool autoAttach = true)
+ : base(autoAttach)
+ {
+ this.Rectangle = rectangle;
+ this.MinOverlayPercentage = minOverlayPercentage;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ public override void OnAttach()
+ {
+ RGBSurface.SurfaceLayoutChanged += RGBSurfaceOnSurfaceLayoutChanged;
+ }
+
+ ///
+ public override void OnDetach()
+ {
+ RGBSurface.SurfaceLayoutChanged -= RGBSurfaceOnSurfaceLayoutChanged;
+ }
+
+ private void RGBSurfaceOnSurfaceLayoutChanged(SurfaceLayoutChangedEventArgs args)
+ {
+ InvalidateCache();
+ }
+
+ ///
+ /// Gets a list containing all of this .
+ ///
+ /// The list containing all of this .
+ public override IEnumerable GetLeds()
+ {
+ return _ledCache ?? (_ledCache = RGBSurface.Leds.Where(x => x.LedRectangle.CalculateIntersectPercentage(Rectangle) >= MinOverlayPercentage).ToList());
+ }
+
+ private void InvalidateCache()
+ {
+ _ledCache = null;
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Groups/RGB.NET.Groups.csproj b/RGB.NET.Groups/RGB.NET.Groups.csproj
index 27904cb..7611d73 100644
--- a/RGB.NET.Groups/RGB.NET.Groups.csproj
+++ b/RGB.NET.Groups/RGB.NET.Groups.csproj
@@ -31,6 +31,10 @@
4
+
+ ..\packages\RGB.NET.Core.1.0.0\lib\net45\RGB.NET.Core.dll
+ True
+
@@ -41,8 +45,14 @@
+
+
+
+
+
+