1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Core - Change default rendering to Software, quicker in most setups

Surface editor - Added remaining missing functionality
This commit is contained in:
Robert 2022-05-17 23:29:07 +02:00
parent a06bc68046
commit 4809ebf969
7 changed files with 240 additions and 139 deletions

View File

@ -43,7 +43,7 @@ namespace Artemis.Core.Services
_deviceRepository = deviceRepository; _deviceRepository = deviceRepository;
_targetFrameRateSetting = settingsService.GetSetting("Core.TargetFrameRate", 30); _targetFrameRateSetting = settingsService.GetSetting("Core.TargetFrameRate", 30);
_renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 0.25); _renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 0.25);
_preferredGraphicsContext = _settingsService.GetSetting("Core.PreferredGraphicsContext", "Vulkan"); _preferredGraphicsContext = _settingsService.GetSetting("Core.PreferredGraphicsContext", "Software");
Surface = new RGBSurface(); Surface = new RGBSurface();
Utilities.RenderScaleMultiplier = (int) (1 / _renderScaleSetting.Value); Utilities.RenderScaleMultiplier = (int) (1 / _renderScaleSetting.Value);

View File

@ -133,7 +133,7 @@ namespace Artemis.UI.Screens.Settings
public PluginSetting<ApplicationColorScheme> UIColorScheme => _settingsService.GetSetting("UI.ColorScheme", ApplicationColorScheme.Automatic); public PluginSetting<ApplicationColorScheme> UIColorScheme => _settingsService.GetSetting("UI.ColorScheme", ApplicationColorScheme.Automatic);
public PluginSetting<bool> ProfileEditorShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false); public PluginSetting<bool> ProfileEditorShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false);
public PluginSetting<LogEventLevel> CoreLoggingLevel => _settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Information); public PluginSetting<LogEventLevel> CoreLoggingLevel => _settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Information);
public PluginSetting<string> CorePreferredGraphicsContext => _settingsService.GetSetting("Core.PreferredGraphicsContext", "Vulkan"); public PluginSetting<string> CorePreferredGraphicsContext => _settingsService.GetSetting("Core.PreferredGraphicsContext", "Software");
public PluginSetting<double> CoreRenderScale => _settingsService.GetSetting("Core.RenderScale", 0.25); public PluginSetting<double> CoreRenderScale => _settingsService.GetSetting("Core.RenderScale", 0.25);
public PluginSetting<int> CoreTargetFrameRate => _settingsService.GetSetting("Core.TargetFrameRate", 30); public PluginSetting<int> CoreTargetFrameRate => _settingsService.GetSetting("Core.TargetFrameRate", 30);
public PluginSetting<int> WebServerPort => _settingsService.GetSetting("WebServer.Port", 9696); public PluginSetting<int> WebServerPort => _settingsService.GetSetting("WebServer.Port", 9696);

View File

@ -2,7 +2,16 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
xmlns:surfaceEditor="clr-namespace:Artemis.UI.Screens.SurfaceEditor"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.SurfaceEditor.ListDeviceView"> x:Class="Artemis.UI.Screens.SurfaceEditor.ListDeviceView"
Welcome to Avalonia! x:DataType="surfaceEditor:ListDeviceViewModel">
<Grid ColumnDefinitions="Auto,*,Auto" RowDefinitions="*,*">
<Border Grid.Column="0" Grid.RowSpan="2" Width="64" Height="50" Margin="0 0 10 0">
<shared:DeviceVisualizer Device="{CompiledBinding Device}" ShowColors="True" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
<TextBlock Grid.Column="1" Grid.Row="0" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.DeviceName}" VerticalAlignment="Bottom" />
<TextBlock Grid.Column="1" Grid.Row="1" Classes="subtitle" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.Manufacturer}" VerticalAlignment="Top" />
</Grid>
</UserControl> </UserControl>

View File

@ -1,4 +1,5 @@
using Artemis.Core; using System;
using Artemis.Core;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using SkiaSharp; using SkiaSharp;
@ -6,6 +7,8 @@ namespace Artemis.UI.Screens.SurfaceEditor;
public class ListDeviceViewModel : ViewModelBase public class ListDeviceViewModel : ViewModelBase
{ {
private static readonly Random Random = new();
private SKColor _color; private SKColor _color;
private bool _isSelected; private bool _isSelected;
@ -13,6 +16,7 @@ public class ListDeviceViewModel : ViewModelBase
{ {
Device = device; Device = device;
SurfaceEditorViewModel = surfaceEditorViewModel; SurfaceEditorViewModel = surfaceEditorViewModel;
Color = SKColor.FromHsv(Random.NextSingle() * 360, 95, 100);
} }
public ArtemisDevice Device { get; } public ArtemisDevice Device { get; }

View File

@ -1,14 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive;
using System.Threading.Tasks;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using ReactiveUI;
using RGB.NET.Core; using RGB.NET.Core;
using SkiaSharp; using SkiaSharp;
using Point = Avalonia.Point; using Point = Avalonia.Point;
@ -17,35 +12,21 @@ namespace Artemis.UI.Screens.SurfaceEditor;
public class SurfaceDeviceViewModel : ActivatableViewModelBase public class SurfaceDeviceViewModel : ActivatableViewModelBase
{ {
private readonly IDeviceService _deviceService;
private readonly IDeviceVmFactory _deviceVmFactory;
private readonly IRgbService _rgbService; private readonly IRgbService _rgbService;
private readonly ISettingsService _settingsService; private readonly ISettingsService _settingsService;
private readonly IWindowService _windowService;
private double _dragOffsetX; private double _dragOffsetX;
private double _dragOffsetY; private double _dragOffsetY;
private bool _isSelected; private bool _isSelected;
public SurfaceDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel, IRgbService rgbService, IDeviceService deviceService, ISettingsService settingsService, public SurfaceDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel, IRgbService rgbService, ISettingsService settingsService)
IDeviceVmFactory deviceVmFactory,
IWindowService windowService)
{ {
_rgbService = rgbService; _rgbService = rgbService;
_deviceService = deviceService;
_settingsService = settingsService; _settingsService = settingsService;
_deviceVmFactory = deviceVmFactory;
_windowService = windowService;
Device = device; Device = device;
SurfaceEditorViewModel = surfaceEditorViewModel; SurfaceEditorViewModel = surfaceEditorViewModel;
IdentifyDevice = ReactiveCommand.Create<ArtemisDevice>(ExecuteIdentifyDevice);
ViewProperties = ReactiveCommand.CreateFromTask<ArtemisDevice>(ExecuteViewProperties);
} }
public ReactiveCommand<ArtemisDevice, Unit> IdentifyDevice { get; }
public ReactiveCommand<ArtemisDevice, Unit> ViewProperties { get; }
public ArtemisDevice Device { get; } public ArtemisDevice Device { get; }
public SurfaceEditorViewModel SurfaceEditorViewModel { get; } public SurfaceEditorViewModel SurfaceEditorViewModel { get; }
@ -96,16 +77,6 @@ public class SurfaceDeviceViewModel : ActivatableViewModelBase
} }
} }
private void ExecuteIdentifyDevice(ArtemisDevice device)
{
_deviceService.IdentifyDevice(device);
}
private async Task ExecuteViewProperties(ArtemisDevice device)
{
await _windowService.ShowDialogAsync(_deviceVmFactory.DevicePropertiesViewModel(device));
}
private bool Fits(float x, float y, bool ignoreOverlap) private bool Fits(float x, float y, bool ignoreOverlap)
{ {
if (x < 0 || y < 0) if (x < 0 || y < 0)

View File

@ -5,8 +5,10 @@
xmlns:paz="clr-namespace:Avalonia.Controls.PanAndZoom;assembly=Avalonia.Controls.PanAndZoom" xmlns:paz="clr-namespace:Avalonia.Controls.PanAndZoom;assembly=Avalonia.Controls.PanAndZoom"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared" xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
xmlns:surfaceEditor="clr-namespace:Artemis.UI.Screens.SurfaceEditor"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.SurfaceEditor.SurfaceEditorView"> x:Class="Artemis.UI.Screens.SurfaceEditor.SurfaceEditorView"
x:DataType="surfaceEditor:SurfaceEditorViewModel">
<UserControl.Resources> <UserControl.Resources>
<VisualBrush x:Key="LargeCheckerboardBrush" TileMode="Tile" Stretch="Uniform" SourceRect="0,0,20,20"> <VisualBrush x:Key="LargeCheckerboardBrush" TileMode="Tile" Stretch="Uniform" SourceRect="0,0,20,20">
<VisualBrush.Visual> <VisualBrush.Visual>
@ -18,8 +20,51 @@
</Canvas> </Canvas>
</VisualBrush.Visual> </VisualBrush.Visual>
</VisualBrush> </VisualBrush>
<MenuFlyout x:Key="DeviceMenuFlyout">
<MenuItem Header="Identify" Command="{Binding $parent[surfaceEditor:SurfaceEditorView].DataContext.IdentifyDevice}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="AlarmLight" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="-" />
<MenuItem Header="Bring to Front" Command="{Binding $parent[surfaceEditor:SurfaceEditorView].DataContext.BringToFront}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="ArrangeBringToFront" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Bring Forward" Command="{Binding $parent[surfaceEditor:SurfaceEditorView].DataContext.BringForward}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="ArrangeBringForward" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Send to Back" Command="{Binding $parent[surfaceEditor:SurfaceEditorView].DataContext.SendToBack}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="ArrangeSendToBack" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Send Backward" Command="{Binding $parent[surfaceEditor:SurfaceEditorView].DataContext.SendBackward}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="ArrangeSendBackward" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="-" />
<MenuItem Header="Identify input"
Command="{Binding DetectInput}"
CommandParameter="{Binding Device}"
ToolTip.Tip="Teach Artemis which keypresses and/or button presses belong to this device">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="GestureDoubleTap" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="View properties" Command="{Binding $parent[surfaceEditor:SurfaceEditorView].DataContext.ViewProperties}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="Gear" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</UserControl.Resources> </UserControl.Resources>
<Border Classes="router-container"> <Grid Margin="0 0 15 15" ColumnDefinitions="*,400">
<Border Grid.Column="0" Classes="card-condensed">
<paz:ZoomBorder Name="ZoomBorder" <paz:ZoomBorder Name="ZoomBorder"
Stretch="None" Stretch="None"
ClipToBounds="True" ClipToBounds="True"
@ -35,7 +80,7 @@
<TransformOperationsTransition Property="RenderTransform" Duration="0:0:0.2" Easing="CubicEaseOut" /> <TransformOperationsTransition Property="RenderTransform" Duration="0:0:0.2" Easing="CubicEaseOut" />
</Transitions> </Transitions>
</Grid.Transitions> </Grid.Transitions>
<ItemsControl Name="DeviceContainer" Items="{Binding SurfaceDeviceViewModels}" ClipToBounds="False"> <ItemsControl Name="DeviceContainer" Items="{CompiledBinding SurfaceDeviceViewModels}" ClipToBounds="False">
<ItemsControl.Styles> <ItemsControl.Styles>
<Style Selector="ContentPresenter"> <Style Selector="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Device.X}" /> <Setter Property="Canvas.Left" Value="{Binding Device.X}" />
@ -49,52 +94,7 @@
</ItemsControl.ItemsPanel> </ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate> <DataTemplate>
<ContentControl Content="{Binding}"> <ContentControl Content="{Binding}" ContextFlyout="{StaticResource DeviceMenuFlyout}" />
<ContentControl.ContextFlyout>
<MenuFlyout>
<MenuItem Header="Identify" Command="{Binding IdentifyDevice}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="AlarmLight" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="-" />
<MenuItem Header="Bring to Front" Command="{Binding $parent[4].DataContext.BringToFront}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="ArrangeBringToFront" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Bring Forward" Command="{Binding $parent[4].DataContext.BringForward}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="ArrangeBringForward" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Send to Back" Command="{Binding $parent[4].DataContext.SendToBack}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="ArrangeSendToBack" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Send Backward" Command="{Binding $parent[4].DataContext.SendBackward}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="ArrangeSendBackward" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="-" />
<MenuItem Header="Identify input"
Command="{Binding DetectInput}"
CommandParameter="{Binding Device}"
ToolTip.Tip="Teach Artemis which keypresses and/or button presses belong to this device">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="GestureDoubleTap" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="View properties" Command="{Binding ViewProperties}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="Gear" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</ContentControl.ContextFlyout>
</ContentControl>
</DataTemplate> </DataTemplate>
</ItemsControl.ItemTemplate> </ItemsControl.ItemTemplate>
</ItemsControl> </ItemsControl>
@ -115,9 +115,37 @@
Width="{Binding MaxTextureSize}" Width="{Binding MaxTextureSize}"
Height="{Binding MaxTextureSize}" Height="{Binding MaxTextureSize}"
BorderThickness="2" BorderThickness="2"
BorderBrush="{DynamicResource SystemAccentColorLight3}" BorderBrush="{DynamicResource SystemAccentColorLight1}"
CornerRadius="8" /> BorderDashArray="6,2"
Opacity="0.5" />
</Grid> </Grid>
</paz:ZoomBorder> </paz:ZoomBorder>
</Border> </Border>
<Border Grid.Column="1" Classes="card-condensed" Margin="15 0 0 0">
<Grid RowDefinitions="*,Auto,Auto" ColumnDefinitions="*,*">
<ListBox Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Items="{CompiledBinding ListDeviceViewModels}">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}" ContextFlyout="{StaticResource DeviceMenuFlyout}"></ContentControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<CheckBox Grid.Row="1"
Grid.Column="0"
IsChecked="{CompiledBinding ColorDevices}"
ToolTip.Tip="Draws a random color on each device allowing you to identify them">
Color overlay devices
</CheckBox>
<CheckBox Grid.Row="1"
Grid.Column="1"
IsChecked="{CompiledBinding ColorFirstLedOnly}"
IsEnabled="{CompiledBinding ColorDevices}"
ToolTip.Tip="Draws the overlay only on the first LED of each device">
Overlay first LED only
</CheckBox>
<Button Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" Margin="0 10 0 0" Command="{CompiledBinding AutoArrange}">Auto-arrange</Button>
</Grid>
</Border>
</Grid>
</UserControl> </UserControl>

View File

@ -3,13 +3,16 @@ using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Reactive; using System.Reactive;
using System.Reactive.Disposables;
using System.Threading.Tasks; using System.Threading.Tasks;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.Extensions; using Artemis.UI.Extensions;
using Artemis.UI.Ninject.Factories; using Artemis.UI.Ninject.Factories;
using Artemis.UI.Shared.Services;
using Avalonia; using Avalonia;
using ReactiveUI; using ReactiveUI;
using SkiaSharp;
namespace Artemis.UI.Screens.SurfaceEditor; namespace Artemis.UI.Screens.SurfaceEditor;
@ -17,29 +20,67 @@ public class SurfaceEditorViewModel : MainScreenViewModel
{ {
private readonly IRgbService _rgbService; private readonly IRgbService _rgbService;
private readonly ISettingsService _settingsService; private readonly ISettingsService _settingsService;
private readonly IDeviceVmFactory _deviceVmFactory;
private readonly IWindowService _windowService;
private readonly IDeviceService _deviceService;
private List<SurfaceDeviceViewModel>? _initialSelection; private List<SurfaceDeviceViewModel>? _initialSelection;
private bool _saving; private bool _saving;
private bool _colorFirstLedOnly;
private bool _colorDevices;
private double _overlayOpacity;
public SurfaceEditorViewModel(IScreen hostScreen, public SurfaceEditorViewModel(IScreen hostScreen,
ICoreService coreService,
IRgbService rgbService, IRgbService rgbService,
ISurfaceVmFactory surfaceVmFactory, ISurfaceVmFactory surfaceVmFactory,
ISettingsService settingsService) : base(hostScreen, "surface-editor") ISettingsService settingsService,
IDeviceVmFactory deviceVmFactory,
IWindowService windowService,
IDeviceService deviceService) : base(hostScreen, "surface-editor")
{ {
_rgbService = rgbService; _rgbService = rgbService;
_settingsService = settingsService; _settingsService = settingsService;
_deviceVmFactory = deviceVmFactory;
_windowService = windowService;
_deviceService = deviceService;
DisplayName = "Surface Editor"; DisplayName = "Surface Editor";
SurfaceDeviceViewModels = new ObservableCollection<SurfaceDeviceViewModel>(rgbService.EnabledDevices.OrderBy(d => d.ZIndex).Select(d => surfaceVmFactory.SurfaceDeviceViewModel(d, this))); SurfaceDeviceViewModels = new ObservableCollection<SurfaceDeviceViewModel>(rgbService.EnabledDevices.OrderBy(d => d.ZIndex).Select(d => surfaceVmFactory.SurfaceDeviceViewModel(d, this)));
ListDeviceViewModels = new ObservableCollection<ListDeviceViewModel>(rgbService.EnabledDevices.OrderBy(d => d.ZIndex).Select(d => surfaceVmFactory.ListDeviceViewModel(d, this))); ListDeviceViewModels = new ObservableCollection<ListDeviceViewModel>(rgbService.EnabledDevices.OrderBy(d => d.ZIndex).Select(d => surfaceVmFactory.ListDeviceViewModel(d, this)));
AutoArrange = ReactiveCommand.CreateFromTask(ExecuteAutoArrange);
IdentifyDevice = ReactiveCommand.Create<ArtemisDevice>(ExecuteIdentifyDevice);
ViewProperties = ReactiveCommand.CreateFromTask<ArtemisDevice>(ExecuteViewProperties);
BringToFront = ReactiveCommand.Create<ArtemisDevice>(ExecuteBringToFront); BringToFront = ReactiveCommand.Create<ArtemisDevice>(ExecuteBringToFront);
BringForward = ReactiveCommand.Create<ArtemisDevice>(ExecuteBringForward); BringForward = ReactiveCommand.Create<ArtemisDevice>(ExecuteBringForward);
SendToBack = ReactiveCommand.Create<ArtemisDevice>(ExecuteSendToBack); SendToBack = ReactiveCommand.Create<ArtemisDevice>(ExecuteSendToBack);
SendBackward = ReactiveCommand.Create<ArtemisDevice>(ExecuteSendBackward); SendBackward = ReactiveCommand.Create<ArtemisDevice>(ExecuteSendBackward);
this.WhenActivated(d =>
{
coreService.FrameRendering += CoreServiceOnFrameRendering;
Disposable.Create(() => coreService.FrameRendering -= CoreServiceOnFrameRendering).DisposeWith(d);
});
}
public bool ColorDevices
{
get => _colorDevices;
set => RaiseAndSetIfChanged(ref _colorDevices, value);
}
public bool ColorFirstLedOnly
{
get => _colorFirstLedOnly;
set => RaiseAndSetIfChanged(ref _colorFirstLedOnly, value);
} }
public ObservableCollection<SurfaceDeviceViewModel> SurfaceDeviceViewModels { get; } public ObservableCollection<SurfaceDeviceViewModel> SurfaceDeviceViewModels { get; }
public ObservableCollection<ListDeviceViewModel> ListDeviceViewModels { get; } public ObservableCollection<ListDeviceViewModel> ListDeviceViewModels { get; }
public ReactiveCommand<Unit, Unit> AutoArrange { get; }
public ReactiveCommand<ArtemisDevice, Unit> IdentifyDevice { get; }
public ReactiveCommand<ArtemisDevice, Unit> ViewProperties { get; }
public ReactiveCommand<ArtemisDevice, Unit> BringToFront { get; } public ReactiveCommand<ArtemisDevice, Unit> BringToFront { get; }
public ReactiveCommand<ArtemisDevice, Unit> BringForward { get; } public ReactiveCommand<ArtemisDevice, Unit> BringForward { get; }
public ReactiveCommand<ArtemisDevice, Unit> SendToBack { get; } public ReactiveCommand<ArtemisDevice, Unit> SendToBack { get; }
@ -109,14 +150,62 @@ public class SurfaceEditorViewModel : MainScreenViewModel
surfaceDeviceViewModel.UpdateMouseDrag(mousePosition, round, ignoreOverlap); surfaceDeviceViewModel.UpdateMouseDrag(mousePosition, round, ignoreOverlap);
} }
private void ApplySurfaceSelection() private async Task ExecuteAutoArrange()
{ {
foreach (ListDeviceViewModel viewModel in ListDeviceViewModels) bool confirmed = await _windowService.ShowConfirmContentDialog("Auto-arrange layout", "Are you sure you want to auto-arrange your layout? Your current settings will be overwritten.");
viewModel.IsSelected = SurfaceDeviceViewModels.Any(s => s.Device == viewModel.Device && s.IsSelected); if (!confirmed)
return;
_rgbService.AutoArrangeDevices();
}
private void CoreServiceOnFrameRendering(object? sender, FrameRenderingEventArgs e)
{
// Animate the overlay because I'm vain
if (ColorDevices && _overlayOpacity < 1)
_overlayOpacity = Math.Min(1, _overlayOpacity + e.DeltaTime * 3);
else if (!ColorDevices && _overlayOpacity > 0)
_overlayOpacity = Math.Max(0, _overlayOpacity - e.DeltaTime * 3);
if (_overlayOpacity == 0)
return;
using SKPaint paint = new();
byte alpha = (byte) (Easings.CubicEaseInOut(_overlayOpacity) * 255);
// Fill the entire canvas with a black backdrop
paint.Color = SKColors.Black.WithAlpha(alpha);
e.Canvas.DrawRect(e.Canvas.LocalClipBounds, paint);
// Draw a rectangle for each LED
foreach (ListDeviceViewModel listDeviceViewModel in ListDeviceViewModels)
{
// Order by position to accurately get the first LED
List<ArtemisLed> leds = listDeviceViewModel.Device.Leds.OrderBy(l => l.RgbLed.Location.Y).ThenBy(l => l.RgbLed.Location.X).ToList();
for (int index = 0; index < leds.Count; index++)
{
ArtemisLed artemisLed = leds[index];
if (ColorFirstLedOnly && index == 0 || !ColorFirstLedOnly)
{
paint.Color = listDeviceViewModel.Color.WithAlpha(alpha);
e.Canvas.DrawRect(artemisLed.AbsoluteRectangle, paint);
}
}
}
} }
#region Context menu commands #region Context menu commands
private void ExecuteIdentifyDevice(ArtemisDevice device)
{
_deviceService.IdentifyDevice(device);
}
private async Task ExecuteViewProperties(ArtemisDevice device)
{
await _windowService.ShowDialogAsync(_deviceVmFactory.DevicePropertiesViewModel(device));
}
private void ExecuteBringToFront(ArtemisDevice device) private void ExecuteBringToFront(ArtemisDevice device)
{ {
SurfaceDeviceViewModel surfaceDeviceViewModel = SurfaceDeviceViewModels.First(d => d.Device == device); SurfaceDeviceViewModel surfaceDeviceViewModel = SurfaceDeviceViewModels.First(d => d.Device == device);