// ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedMember.Global using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; namespace RGB.NET.Core { /// /// Represents a RGB-surface containing multiple devices. /// public partial class RGBSurface : AbstractBindable, IDisposable { #region Properties & Fields /// /// Gets the singelot-instance of the class. /// public static RGBSurface Instance { get; } = new RGBSurface(); private DateTime _lastUpdate; private IList _deviceProvider = new List(); private IList _devices = new List(); // ReSharper disable InconsistentNaming private readonly LinkedList _ledGroups = new LinkedList(); private readonly Rectangle _surfaceRectangle = new Rectangle(); // ReSharper restore InconsistentNaming /// /// Gets a readonly list containing all loaded . /// public IEnumerable Devices => new ReadOnlyCollection(_devices); /// /// Gets a copy of the representing this . /// public Rectangle SurfaceRectangle => new Rectangle(_surfaceRectangle); /// /// Gets a list of all on this . /// public IEnumerable Leds => _devices.SelectMany(x => x); #endregion #region Constructors /// /// Initializes a new instance of the class. /// private RGBSurface() { _lastUpdate = DateTime.Now; } #endregion #region Methods /// /// Perform an update for all dirty , or all , if flushLeds is set to true. /// /// Specifies whether all , (including clean ones) should be updated. public void Update(bool flushLeds = false) { try { OnUpdating(); lock (_ledGroups) { // Update effects foreach (ILedGroup ledGroup in _ledGroups) try { ledGroup.UpdateEffects(); } catch (Exception ex) { OnException(ex); } // Render brushes foreach (ILedGroup ledGroup in _ledGroups.OrderBy(x => x.ZIndex)) try { Render(ledGroup); } catch (Exception ex) { OnException(ex); } } foreach (IRGBDevice device in Devices) try { device.Update(flushLeds); } catch (Exception ex) { OnException(ex); } OnUpdated(); } catch (Exception ex) { OnException(ex); } } /// public void Dispose() { foreach (IRGBDevice device in _devices) try { device.Dispose(); } catch { /* We do what we can */ } _ledGroups.Clear(); _devices = null; _deviceProvider = null; } /// /// Renders a ledgroup. /// /// The led group to render. private void Render(ILedGroup ledGroup) { IList leds = ledGroup.GetLeds().ToList(); IBrush brush = ledGroup.Brush; if ((brush == null) || !brush.IsEnabled) return; switch (brush.BrushCalculationMode) { case BrushCalculationMode.Relative: Rectangle brushRectangle = new Rectangle(leds.Select(x => GetDeviceLedLocation(x))); Point offset = new Point(-brushRectangle.Location.X, -brushRectangle.Location.Y); brushRectangle.Location.X = 0; brushRectangle.Location.Y = 0; brush.PerformRender(brushRectangle, leds.Select(x => new BrushRenderTarget(x, GetDeviceLedLocation(x, offset)))); break; case BrushCalculationMode.Absolute: brush.PerformRender(SurfaceRectangle, leds.Select(x => new BrushRenderTarget(x, GetDeviceLedLocation(x)))); break; default: throw new ArgumentException(); } brush.UpdateEffects(); brush.PerformFinalize(); foreach (KeyValuePair renders in brush.RenderedTargets) renders.Key.Led.Color = renders.Value; } private Rectangle GetDeviceLedLocation(Led led, Point extraOffset = null) { return extraOffset != null ? new Rectangle(led.LedRectangle.Location + led.Device.Location + extraOffset, led.LedRectangle.Size) : new Rectangle(led.LedRectangle.Location + led.Device.Location, led.LedRectangle.Size); } /// /// Attaches the given . /// /// The to attach. /// true if the could be attached; otherwise, false. public bool AttachLedGroup(ILedGroup ledGroup) { if (ledGroup == null) return false; lock (_ledGroups) { if (_ledGroups.Contains(ledGroup)) return false; _ledGroups.AddLast(ledGroup); ledGroup.OnAttach(); return true; } } /// /// Detaches the given . /// /// The to detached. /// true if the could be detached; otherwise, false. public bool DetachLedGroup(ILedGroup ledGroup) { if (ledGroup == null) return false; lock (_ledGroups) { LinkedListNode node = _ledGroups.Find(ledGroup); if (node == null) return false; _ledGroups.Remove(node); node.Value.OnDetach(); return true; } } private void UpdateSurfaceRectangle() { Rectangle devicesRectangle = new Rectangle(_devices.Select(d => new Rectangle(d.Location, d.Size))); _surfaceRectangle.Size.Width = devicesRectangle.Location.X + devicesRectangle.Size.Width; _surfaceRectangle.Size.Height = devicesRectangle.Location.Y + devicesRectangle.Size.Height; } #endregion } }