diff --git a/src/Artemis.Core/Services/Storage/Interfaces/ISurfaceService.cs b/src/Artemis.Core/Services/Storage/Interfaces/ISurfaceService.cs
index 8258b3e19..23a6c87bf 100644
--- a/src/Artemis.Core/Services/Storage/Interfaces/ISurfaceService.cs
+++ b/src/Artemis.Core/Services/Storage/Interfaces/ISurfaceService.cs
@@ -44,6 +44,11 @@ namespace Artemis.Core.Services
/// The surface entity to delete, may not be the active surface entity
void DeleteSurfaceConfiguration(ArtemisSurface surface);
+ ///
+ /// Applies auto-arranging logic to the current active surface
+ ///
+ void AutoArrange();
+
///
/// Occurs when the active device entity has been changed
///
diff --git a/src/Artemis.Core/Services/Storage/Models/SurfaceArrangement.cs b/src/Artemis.Core/Services/Storage/Models/SurfaceArrangement.cs
index 464a78519..3f7d726ac 100644
--- a/src/Artemis.Core/Services/Storage/Models/SurfaceArrangement.cs
+++ b/src/Artemis.Core/Services/Storage/Models/SurfaceArrangement.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using RGB.NET.Core;
namespace Artemis.Core.Services.Models
@@ -7,18 +8,108 @@ namespace Artemis.Core.Services.Models
{
public SurfaceArrangement()
{
- Devices = new List();
+ Types = new List();
}
- public List Devices { get; }
+ public List Types { get; }
internal static SurfaceArrangement GetDefaultArrangement()
{
SurfaceArrangement arrangement = new SurfaceArrangement();
- arrangement.Devices.Add(new SurfaceArrangementDevice(null, RGBDeviceType.Keyboard, ArrangementPosition.Right));
+
+ SurfaceArrangementType keypad = new SurfaceArrangementType(RGBDeviceType.Keypad);
+ keypad.Configurations.Add(new SurfaceArrangementConfiguration(null, HorizontalArrangementPosition.Equal, VerticalArrangementPosition.Equal, 20));
+ arrangement.Types.Add(keypad);
+
+ SurfaceArrangementType keyboard = new SurfaceArrangementType(RGBDeviceType.Keyboard);
+ keyboard.Configurations.Add(new SurfaceArrangementConfiguration(keypad, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Equal, 20));
+ arrangement.Types.Add(keyboard);
+
+ SurfaceArrangementType mousepad = new SurfaceArrangementType(RGBDeviceType.Mousepad);
+ mousepad.Configurations.Add(new SurfaceArrangementConfiguration(keyboard, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Equal, 10));
+ arrangement.Types.Add(mousepad);
+
+ SurfaceArrangementType mouse = new SurfaceArrangementType(RGBDeviceType.Mouse);
+ mouse.Configurations.Add(new SurfaceArrangementConfiguration(mousepad, HorizontalArrangementPosition.Center, VerticalArrangementPosition.Center, 0));
+ mouse.Configurations.Add(new SurfaceArrangementConfiguration(keyboard, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Center, 100));
+ arrangement.Types.Add(mouse);
+
+ SurfaceArrangementType headset = new SurfaceArrangementType(RGBDeviceType.Headset);
+ headset.Configurations.Add(new SurfaceArrangementConfiguration(keyboard, HorizontalArrangementPosition.Center, VerticalArrangementPosition.Bottom, 100));
+ arrangement.Types.Add(headset);
+
+ SurfaceArrangementType headsetStand = new SurfaceArrangementType(RGBDeviceType.HeadsetStand);
+ headsetStand.Configurations.Add(new SurfaceArrangementConfiguration(mousepad, HorizontalArrangementPosition.Center, VerticalArrangementPosition.Top, 100));
+ headsetStand.Configurations.Add(new SurfaceArrangementConfiguration(mouse, HorizontalArrangementPosition.Center, VerticalArrangementPosition.Top, 100));
+ headsetStand.Configurations.Add(new SurfaceArrangementConfiguration(keyboard, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Top, 100));
+ arrangement.Types.Add(headsetStand);
+
+ SurfaceArrangementType mainboard = new SurfaceArrangementType(RGBDeviceType.Mainboard);
+ mainboard.Configurations.Add(new SurfaceArrangementConfiguration(mousepad, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Bottom, 500));
+ mainboard.Configurations.Add(new SurfaceArrangementConfiguration(mouse, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Bottom, 500));
+ mainboard.Configurations.Add(new SurfaceArrangementConfiguration(keyboard, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Bottom, 500));
+ arrangement.Types.Add(mainboard);
+
+ SurfaceArrangementType cooler = new SurfaceArrangementType(RGBDeviceType.Cooler);
+ cooler.Configurations.Add(new SurfaceArrangementConfiguration(mainboard, HorizontalArrangementPosition.Center, VerticalArrangementPosition.Center, 0));
+ arrangement.Types.Add(cooler);
+
+ SurfaceArrangementType dram = new SurfaceArrangementType(RGBDeviceType.DRAM);
+ dram.Configurations.Add(new SurfaceArrangementConfiguration(cooler, HorizontalArrangementPosition.Left, VerticalArrangementPosition.Equal, 10));
+ dram.Configurations.Add(new SurfaceArrangementConfiguration(mainboard, HorizontalArrangementPosition.Center, VerticalArrangementPosition.Center, 0));
+ arrangement.Types.Add(dram);
+
+ SurfaceArrangementType graphicsCard = new SurfaceArrangementType(RGBDeviceType.GraphicsCard);
+ graphicsCard.Configurations.Add(new SurfaceArrangementConfiguration(cooler, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Bottom, 10));
+ graphicsCard.Configurations.Add(new SurfaceArrangementConfiguration(dram, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Bottom, 10));
+ graphicsCard.Configurations.Add(new SurfaceArrangementConfiguration(mainboard, HorizontalArrangementPosition.Center, VerticalArrangementPosition.Center, 0));
+ arrangement.Types.Add(graphicsCard);
+
+ SurfaceArrangementType fan = new SurfaceArrangementType(RGBDeviceType.Fan);
+ fan.Configurations.Add(new SurfaceArrangementConfiguration(mainboard, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Equal, 100));
+ arrangement.Types.Add(fan);
+
+ SurfaceArrangementType ledStripe = new SurfaceArrangementType(RGBDeviceType.LedStripe);
+ ledStripe.Configurations.Add(new SurfaceArrangementConfiguration(fan, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Equal, 100));
+ arrangement.Types.Add(ledStripe);
+
+ SurfaceArrangementType speaker = new SurfaceArrangementType(RGBDeviceType.Speaker);
+ arrangement.Types.Add(speaker);
+
return arrangement;
}
+
+ public void Arrange(ArtemisSurface surface)
+ {
+ foreach (ArtemisDevice surfaceDevice in surface.Devices)
+ {
+ surfaceDevice.X = 0;
+ surfaceDevice.X = 0;
+ surfaceDevice.ApplyToRgbDevice();
+ }
+
+ foreach (SurfaceArrangementType surfaceArrangementType in Types)
+ surfaceArrangementType.Arrange(surface);
+
+ // See if we need to move the surface to keep X and Y values positive
+ double x = surface.Devices.Min(d => d.RgbDevice.Location.X);
+ double y = surface.Devices.Min(d => d.RgbDevice.Location.Y);
+ if (x < 0)
+ {
+ foreach (ArtemisDevice surfaceDevice in surface.Devices)
+ {
+ surfaceDevice.X += x * -1;
+ surfaceDevice.ApplyToRgbDevice();
+ }
+ }
+ if (y < 0)
+ {
+ foreach (ArtemisDevice surfaceDevice in surface.Devices)
+ {
+ surfaceDevice.Y += y * -1;
+ surfaceDevice.ApplyToRgbDevice();
+ }
+ }
+ }
}
-
-
-}
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/Storage/Models/SurfaceArrangementConfiguration.cs b/src/Artemis.Core/Services/Storage/Models/SurfaceArrangementConfiguration.cs
new file mode 100644
index 000000000..c35a0cce1
--- /dev/null
+++ b/src/Artemis.Core/Services/Storage/Models/SurfaceArrangementConfiguration.cs
@@ -0,0 +1,99 @@
+using System.Collections.Generic;
+using System.Linq;
+using RGB.NET.Core;
+
+namespace Artemis.Core.Services.Models
+{
+ internal class SurfaceArrangementConfiguration
+ {
+ public SurfaceArrangementConfiguration(SurfaceArrangementType? anchor, HorizontalArrangementPosition horizontalPosition, VerticalArrangementPosition verticalPosition,
+ int margin)
+ {
+ Anchor = anchor;
+ HorizontalPosition = horizontalPosition;
+ VerticalPosition = verticalPosition;
+
+ MarginLeft = margin;
+ MarginTop = margin;
+ MarginRight = margin;
+ MarginBottom = margin;
+ }
+
+ public SurfaceArrangementConfiguration(SurfaceArrangementType? anchor, HorizontalArrangementPosition horizontalPosition, VerticalArrangementPosition verticalPosition,
+ int marginLeft, int marginTop, int marginRight, int marginBottom)
+ {
+ Anchor = anchor;
+ HorizontalPosition = horizontalPosition;
+ VerticalPosition = verticalPosition;
+
+ MarginLeft = marginLeft;
+ MarginTop = marginTop;
+ MarginRight = marginRight;
+ MarginBottom = marginBottom;
+ }
+
+ public SurfaceArrangementType? Anchor { get; }
+ public HorizontalArrangementPosition HorizontalPosition { get; }
+ public VerticalArrangementPosition VerticalPosition { get; }
+
+ public int MarginLeft { get; }
+ public int MarginTop { get; }
+ public int MarginRight { get; }
+ public int MarginBottom { get; }
+
+ public bool Apply(List devices, ArtemisSurface surface)
+ {
+ if (Anchor != null && !Anchor.HasDevices(surface))
+ return false;
+
+ // Start at the edge of the anchor, if there is no anchor start at any device
+ Point startPoint = Anchor?.GetEdge(HorizontalPosition, VerticalPosition, surface) ??
+ new SurfaceArrangementType(RGBDeviceType.All).GetEdge(HorizontalPosition, VerticalPosition, surface);
+
+ // Stack multiple devices of the same type vertically if they are wider than they are tall
+ bool stackVertically = devices.Average(d => d.RgbDevice.Size.Width) >= devices.Average(d => d.RgbDevice.Size.Height);
+
+ ArtemisDevice? previous = null;
+ foreach (ArtemisDevice artemisDevice in devices)
+ {
+ if (previous != null)
+ {
+ if (stackVertically)
+ {
+ artemisDevice.X = previous.X;
+ artemisDevice.Y = previous.RgbDevice.Location.Y + previous.RgbDevice.Size.Height + MarginTop / 2.0;
+ }
+ else
+ {
+ artemisDevice.X = previous.RgbDevice.Location.X + previous.RgbDevice.Size.Width + MarginLeft / 2.0;
+ artemisDevice.Y = previous.Y;
+ }
+ }
+ else
+ {
+ artemisDevice.X = HorizontalPosition switch
+ {
+ HorizontalArrangementPosition.Left => startPoint.X - artemisDevice.RgbDevice.Size.Width - MarginRight,
+ HorizontalArrangementPosition.Right => startPoint.X + MarginLeft,
+ HorizontalArrangementPosition.Center => startPoint.X - artemisDevice.RgbDevice.Size.Width / 2,
+ HorizontalArrangementPosition.Equal => startPoint.X,
+ _ => artemisDevice.X
+ };
+ artemisDevice.Y = VerticalPosition switch
+ {
+ VerticalArrangementPosition.Top => startPoint.Y - artemisDevice.RgbDevice.Size.Height - MarginBottom,
+ VerticalArrangementPosition.Bottom => startPoint.Y + MarginTop,
+ VerticalArrangementPosition.Center => startPoint.Y - artemisDevice.RgbDevice.Size.Height / 2,
+ VerticalArrangementPosition.Equal => startPoint.Y,
+ _ => artemisDevice.X
+ };
+ }
+
+ artemisDevice.ApplyToRgbDevice();
+ previous = artemisDevice;
+ }
+
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/Storage/Models/SurfaceArrangementDevice.cs b/src/Artemis.Core/Services/Storage/Models/SurfaceArrangementDevice.cs
deleted file mode 100644
index 945f03754..000000000
--- a/src/Artemis.Core/Services/Storage/Models/SurfaceArrangementDevice.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using RGB.NET.Core;
-
-namespace Artemis.Core.Services.Models
-{
- internal class SurfaceArrangementDevice
- {
- public SurfaceArrangementDevice? Anchor { get; }
- public RGBDeviceType DeviceType { get; }
- public ArrangementPosition Position { get; }
-
- public SurfaceArrangementDevice(SurfaceArrangementDevice? anchor, RGBDeviceType deviceType, ArrangementPosition position)
- {
- Anchor = anchor;
- DeviceType = deviceType;
- Position = position;
- }
-
- public void Apply(ArtemisSurface surface)
- {
- List devices = surface.Devices.Where(d => d.RgbDevice.DeviceInfo.DeviceType == DeviceType).ToList();
- ArtemisDevice? previous = null;
- foreach (ArtemisDevice artemisDevice in devices)
- {
- if (previous != null)
- {
-
- }
- previous = artemisDevice;
- }
- }
- }
-
- internal enum ArrangementPosition
- {
- Left,
- Right,
- Top,
- Bottom,
- Center
- }
-}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/Storage/Models/SurfaceArrangementType.cs b/src/Artemis.Core/Services/Storage/Models/SurfaceArrangementType.cs
new file mode 100644
index 000000000..47d92fac9
--- /dev/null
+++ b/src/Artemis.Core/Services/Storage/Models/SurfaceArrangementType.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using RGB.NET.Core;
+
+namespace Artemis.Core.Services.Models
+{
+ internal class SurfaceArrangementType
+ {
+ public SurfaceArrangementType(RGBDeviceType deviceType)
+ {
+ DeviceType = deviceType;
+ Configurations = new List();
+ }
+
+ public RGBDeviceType DeviceType { get; }
+ public List Configurations { get; }
+ public SurfaceArrangementConfiguration? AppliedConfiguration { get; set; }
+
+ public bool HasDevices(ArtemisSurface surface)
+ {
+ return surface.Devices.Any(d => d.RgbDevice.DeviceInfo.DeviceType == DeviceType);
+ }
+
+ public void Arrange(ArtemisSurface surface)
+ {
+ List devices = surface.Devices.Where(d => d.RgbDevice.DeviceInfo.DeviceType == DeviceType).ToList();
+ if (!devices.Any())
+ return;
+
+ AppliedConfiguration = null;
+ foreach (SurfaceArrangementConfiguration configuration in Configurations)
+ {
+ bool applied = configuration.Apply(devices, surface);
+ if (applied)
+ {
+ AppliedConfiguration = configuration;
+ return;
+ }
+ }
+
+ // If nothing applied fall back to just basing on whatever is the furthers to the right
+ SurfaceArrangementConfiguration fallback = new SurfaceArrangementConfiguration(
+ null,
+ HorizontalArrangementPosition.Right,
+ VerticalArrangementPosition.Equal,
+ 10
+ );
+ fallback.Apply(devices, surface);
+ AppliedConfiguration = fallback;
+ }
+
+ public Point GetEdge(HorizontalArrangementPosition horizontalPosition, VerticalArrangementPosition verticalPosition, ArtemisSurface surface)
+ {
+ List devices = surface.Devices.Where(d => d.RgbDevice.DeviceInfo.DeviceType == DeviceType || DeviceType == RGBDeviceType.All).ToList();
+ if (!devices.Any())
+ return new Point();
+
+ double x = horizontalPosition switch
+ {
+ HorizontalArrangementPosition.Left => devices.Min(d => d.RgbDevice.Location.X) - (AppliedConfiguration?.MarginLeft ?? 0.0),
+ HorizontalArrangementPosition.Right => devices.Max(d => d.RgbDevice.Location.X + d.RgbDevice.Size.Width) + (AppliedConfiguration?.MarginRight ?? 0.0),
+ HorizontalArrangementPosition.Center => devices.First().RgbDevice.DeviceRectangle.Center.X,
+ HorizontalArrangementPosition.Equal => devices.First().RgbDevice.Location.X,
+ _ => throw new ArgumentOutOfRangeException(nameof(horizontalPosition), horizontalPosition, null)
+ };
+ double y = verticalPosition switch
+ {
+ VerticalArrangementPosition.Top => devices.Min(d => d.RgbDevice.Location.Y) - (AppliedConfiguration?.MarginTop ?? 0.0),
+ VerticalArrangementPosition.Bottom => devices.Max(d => d.RgbDevice.Location.Y + d.RgbDevice.Size.Height) + (AppliedConfiguration?.MarginBottom ?? 0.0),
+ VerticalArrangementPosition.Center => devices.First().RgbDevice.DeviceRectangle.Center.Y,
+ VerticalArrangementPosition.Equal => devices.First().RgbDevice.Location.Y,
+ _ => throw new ArgumentOutOfRangeException(nameof(verticalPosition), verticalPosition, null)
+ };
+
+ return new Point(x, y);
+ }
+ }
+
+ internal enum HorizontalArrangementPosition
+ {
+ Left,
+ Right,
+ Equal,
+ Center
+ }
+
+ internal enum VerticalArrangementPosition
+ {
+ Top,
+ Bottom,
+ Equal,
+ Center
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/Storage/SurfaceService.cs b/src/Artemis.Core/Services/Storage/SurfaceService.cs
index efccae435..21eab6998 100644
--- a/src/Artemis.Core/Services/Storage/SurfaceService.cs
+++ b/src/Artemis.Core/Services/Storage/SurfaceService.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Artemis.Core.DeviceProviders;
+using Artemis.Core.Services.Models;
using Artemis.Storage.Entities.Surface;
using Artemis.Storage.Repositories.Interfaces;
using RGB.NET.Core;
@@ -202,13 +203,11 @@ namespace Artemis.Core.Services
#region AutoLayout
- public void AutoLayout()
+ public void AutoArrange()
{
- // Phase one, bottom layer
- // Keyboard
-
- // Phase two, top layer
-
+ SurfaceArrangement surfaceArrangement = SurfaceArrangement.GetDefaultArrangement();
+ surfaceArrangement.Arrange(ActiveSurface);
+ UpdateSurfaceConfiguration(ActiveSurface, true);
}
#endregion
diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.xaml b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.xaml
index 233224940..dea9900c5 100644
--- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.xaml
+++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.xaml
@@ -178,23 +178,32 @@
-
-
-
+
diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs
index 2d0d4d2f1..ab3098cab 100644
--- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs
+++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs
@@ -114,6 +114,16 @@ namespace Artemis.UI.Screens.SurfaceEditor
return config;
}
+ public async Task AutoArrange()
+ {
+ bool confirmed = await _dialogService.ShowConfirmDialog("Auto-arrange layout", "Are you sure you want to auto-arrange your layout? Your current settings will be overwritten.");
+ if (!confirmed)
+ return;
+
+ _surfaceService.AutoArrange();
+
+ }
+
private void LoadWorkspaceSettings()
{
SurfaceListWidth = _settingsService.GetSetting("SurfaceEditor.SurfaceListWidth", new GridLength(300.0));