mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-12 21:38:38 +00:00
Surface editor - Added auto-arrange
This commit is contained in:
parent
f05740a5f1
commit
220222d102
@ -44,6 +44,11 @@ namespace Artemis.Core.Services
|
||||
/// <param name="surface">The surface entity to delete, may not be the active surface entity</param>
|
||||
void DeleteSurfaceConfiguration(ArtemisSurface surface);
|
||||
|
||||
/// <summary>
|
||||
/// Applies auto-arranging logic to the current active surface
|
||||
/// </summary>
|
||||
void AutoArrange();
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the active device entity has been changed
|
||||
/// </summary>
|
||||
|
||||
@ -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<SurfaceArrangementDevice>();
|
||||
Types = new List<SurfaceArrangementType>();
|
||||
}
|
||||
|
||||
public List<SurfaceArrangementDevice> Devices { get; }
|
||||
public List<SurfaceArrangementType> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -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<ArtemisDevice> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<ArtemisDevice> 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
|
||||
}
|
||||
}
|
||||
@ -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<SurfaceArrangementConfiguration>();
|
||||
}
|
||||
|
||||
public RGBDeviceType DeviceType { get; }
|
||||
public List<SurfaceArrangementConfiguration> 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<ArtemisDevice> 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<ArtemisDevice> 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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -178,23 +178,32 @@
|
||||
</Path.Fill>
|
||||
</Path>
|
||||
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Bottom" HorizontalAlignment="Right"
|
||||
Margin="0, 0, 15, 15">
|
||||
<Slider Margin="0,0,14,0"
|
||||
Orientation="Vertical"
|
||||
Minimum="10"
|
||||
Maximum="400"
|
||||
Height="100"
|
||||
FocusVisualStyle="{x:Null}"
|
||||
Value="{Binding PanZoomViewModel.ZoomPercentage}"
|
||||
Style="{StaticResource MaterialDesignDiscreteSlider}" />
|
||||
<Button Command="{s:Action ResetZoomAndPan}"
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="0, 0, 15, 15">
|
||||
<Button Command="{s:Action AutoArrange}"
|
||||
Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
|
||||
HorizontalAlignment="Right"
|
||||
ToolTip="Reset zoom & position">
|
||||
<materialDesign:PackIcon Kind="ImageFilterCenterFocus" Height="24" Width="24" />
|
||||
ToolTip="Apply auto-arrange"
|
||||
VerticalAlignment="Bottom">
|
||||
<materialDesign:PackIcon Kind="Wand" Height="24" Width="24" />
|
||||
</Button>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Slider Margin="0,0,14,0"
|
||||
Orientation="Vertical"
|
||||
Minimum="10"
|
||||
Maximum="400"
|
||||
Height="100"
|
||||
FocusVisualStyle="{x:Null}"
|
||||
Value="{Binding PanZoomViewModel.ZoomPercentage}"
|
||||
Style="{StaticResource MaterialDesignDiscreteSlider}" />
|
||||
<Button Command="{s:Action ResetZoomAndPan}"
|
||||
Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
|
||||
HorizontalAlignment="Right"
|
||||
ToolTip="Reset zoom & position">
|
||||
<materialDesign:PackIcon Kind="ImageFilterCenterFocus" Height="24" Width="24" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
|
||||
|
||||
@ -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));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user