Surface - Removed the ArtemisSurface and reworked device loading

This commit is contained in:
Robert committed 2021-02-16 21:46:08 +01:00
1 parent 7ccc9c54fb
commit 056b2bface
50 files changed
+1292 -1506

No files matched your search

@@ -9,12 +9,12 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
{
// I hate this about DI, oh well
public FolderViewModel(ProfileElement folder,
IRgbService rgbService,
IProfileEditorService profileEditorService,
IDialogService dialogService,
IProfileTreeVmFactory profileTreeVmFactory,
ILayerBrushService layerBrushService,
ISurfaceService surfaceService) :
base(folder, profileEditorService, dialogService, profileTreeVmFactory, layerBrushService, surfaceService)
ILayerBrushService layerBrushService) :
base(folder, rgbService, profileEditorService, dialogService, profileTreeVmFactory, layerBrushService)
{
}
@@ -8,12 +8,12 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
public class LayerViewModel : TreeItemViewModel
{
public LayerViewModel(ProfileElement layer,
IRgbService rgbService,
IProfileEditorService profileEditorService,
IDialogService dialogService,
IProfileTreeVmFactory profileTreeVmFactory,
ILayerBrushService layerBrushService,
ISurfaceService surfaceService) :
base(layer, profileEditorService, dialogService, profileTreeVmFactory, layerBrushService, surfaceService)
ILayerBrushService layerBrushService) :
base(layer, rgbService, profileEditorService, dialogService, profileTreeVmFactory, layerBrushService)
{
}
@@ -18,23 +18,23 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
{
private readonly IDialogService _dialogService;
private readonly ILayerBrushService _layerBrushService;
private readonly IRgbService _rgbService;
private readonly IProfileEditorService _profileEditorService;
private readonly IProfileTreeVmFactory _profileTreeVmFactory;
private readonly ISurfaceService _surfaceService;
private ProfileElement _profileElement;
protected TreeItemViewModel(ProfileElement profileElement,
IRgbService rgbService,
IProfileEditorService profileEditorService,
IDialogService dialogService,
IProfileTreeVmFactory profileTreeVmFactory,
ILayerBrushService layerBrushService,
ISurfaceService surfaceService)
ILayerBrushService layerBrushService)
{
_rgbService = rgbService;
_profileEditorService = profileEditorService;
_dialogService = dialogService;
_profileTreeVmFactory = profileTreeVmFactory;
_layerBrushService = layerBrushService;
_surfaceService = surfaceService;
ProfileElement = profileElement;
@@ -144,7 +144,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
if (brush != null)
layer.ChangeLayerBrush(brush);
layer.AddLeds(_surfaceService.ActiveSurface.Devices.SelectMany(d => d.Leds));
layer.AddLeds(_rgbService.EnabledDevices.SelectMany(d => d.Leds));
_profileEditorService.UpdateSelectedProfile();
_profileEditorService.ChangeSelectedProfileElement(layer);
}
@@ -99,7 +99,10 @@
</ItemsControl>
</Grid>
<Grid Name="EditorDisplayGrid">
<Grid Name="EditorDisplayGrid"
shared:SizeObserver.Observe="True"
shared:SizeObserver.ObservedHeight="{Binding PanZoomViewModel.CanvasHeight}"
shared:SizeObserver.ObservedWidth="{Binding PanZoomViewModel.CanvasWidth}">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="{Binding PanZoomViewModel.Zoom}" ScaleY="{Binding PanZoomViewModel.Zoom}" />
@@ -6,48 +6,48 @@ using System.Windows.Input;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Events;
using Artemis.UI.Extensions;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.ProfileEditor.Visualization.Tools;
using Artemis.UI.Screens.Shared;
using Artemis.UI.Shared.Services;
using SkiaSharp;
using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.Visualization
{
public class ProfileViewModel : Conductor<CanvasViewModel>.Collection.AllActive, IProfileEditorPanelViewModel, IHandle<MainWindowFocusChangedEvent>, IHandle<MainWindowKeyEvent>
{
private readonly IProfileEditorService _profileEditorService;
private readonly ICoreService _coreService;
private readonly IProfileEditorService _profileEditorService;
private readonly IProfileLayerVmFactory _profileLayerVmFactory;
private readonly IRgbService _rgbService;
private readonly ISettingsService _settingsService;
private readonly ISurfaceService _surfaceService;
private readonly IVisualizationToolVmFactory _visualizationToolVmFactory;
private int _activeToolIndex;
private VisualizationToolViewModel _activeToolViewModel;
private PluginSetting<bool> _alwaysApplyDataBindings;
private bool _canApplyToLayer;
private bool _canSelectEditTool;
private BindableCollection<ArtemisDevice> _devices;
private BindableCollection<ArtemisLed> _highlightedLeds;
private PluginSetting<bool> _highlightSelectedLayer;
private PluginSetting<bool> _alwaysApplyDataBindings;
private DateTime _lastUpdate;
private PanZoomViewModel _panZoomViewModel;
private Layer _previousSelectedLayer;
private int _previousTool;
private DateTime _lastUpdate;
public ProfileViewModel(IProfileEditorService profileEditorService,
IRgbService rgbService,
ICoreService coreService,
ISurfaceService surfaceService,
ISettingsService settingsService,
IEventAggregator eventAggregator,
IVisualizationToolVmFactory visualizationToolVmFactory,
IProfileLayerVmFactory profileLayerVmFactory)
{
_profileEditorService = profileEditorService;
_rgbService = rgbService;
_coreService = coreService;
_surfaceService = surfaceService;
_settingsService = settingsService;
_visualizationToolVmFactory = visualizationToolVmFactory;
_profileLayerVmFactory = profileLayerVmFactory;
@@ -99,25 +99,21 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
{
// Remove the tool from the canvas
if (_activeToolViewModel != null)
{
lock (Items)
{
Items.Remove(_activeToolViewModel);
NotifyOfPropertyChange(() => Items);
}
}
// Set the new tool
SetAndNotify(ref _activeToolViewModel, value);
// Add the new tool to the canvas
if (_activeToolViewModel != null)
{
lock (Items)
{
Items.Add(_activeToolViewModel);
NotifyOfPropertyChange(() => Items);
}
}
}
}
@@ -144,7 +140,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
Devices = new BindableCollection<ArtemisDevice>();
HighlightedLeds = new BindableCollection<ArtemisLed>();
ApplySurfaceConfiguration(_surfaceService.ActiveSurface);
ApplyDevices();
ActivateToolByIndex(0);
ApplyActiveProfile();
@@ -156,7 +152,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
_coreService.FrameRendered += OnFrameRendered;
HighlightSelectedLayer.SettingChanged += HighlightSelectedLayerOnSettingChanged;
_surfaceService.ActiveSurfaceConfigurationSelected += OnActiveSurfaceConfigurationSelected;
_rgbService.DeviceAdded += RgbServiceOnDevicesModified;
_rgbService.DeviceRemoved += RgbServiceOnDevicesModified;
_profileEditorService.ProfileSelected += OnProfileSelected;
_profileEditorService.ProfileElementSelected += OnProfileElementSelected;
_profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated;
@@ -168,7 +165,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
{
_coreService.FrameRendered -= OnFrameRendered;
HighlightSelectedLayer.SettingChanged -= HighlightSelectedLayerOnSettingChanged;
_surfaceService.ActiveSurfaceConfigurationSelected -= OnActiveSurfaceConfigurationSelected;
_rgbService.DeviceAdded -= RgbServiceOnDevicesModified;
_rgbService.DeviceRemoved -= RgbServiceOnDevicesModified;
_profileEditorService.ProfileSelected -= OnProfileSelected;
_profileEditorService.ProfileElementSelected -= OnProfileElementSelected;
_profileEditorService.SelectedProfileElementUpdated -= OnSelectedProfileElementUpdated;
@@ -181,9 +179,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
base.OnClose();
}
private void OnActiveSurfaceConfigurationSelected(object sender, SurfaceConfigurationEventArgs e)
private void RgbServiceOnDevicesModified(object? sender, DeviceEventArgs e)
{
ApplySurfaceConfiguration(e.Surface);
ApplyDevices();
}
private void ApplyActiveProfile()
@@ -193,10 +191,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
// Add new layers missing a VM
foreach (Layer layer in layers)
{
if (layerViewModels.All(vm => vm.Layer != layer))
Items.Add(_profileLayerVmFactory.Create(layer, PanZoomViewModel));
}
// Remove layers that no longer exist
IEnumerable<ProfileLayerViewModel> toRemove = layerViewModels.Where(vm => !layers.Contains(vm.Layer));
@@ -204,10 +200,10 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
Items.Remove(profileLayerViewModel);
}
private void ApplySurfaceConfiguration(ArtemisSurface surface)
private void ApplyDevices()
{
Devices.Clear();
Devices.AddRange(surface.Devices.Where(d => d.IsEnabled).OrderBy(d => d.ZIndex));
Devices.AddRange(_rgbService.EnabledDevices.Where(d => d.IsEnabled).OrderBy(d => d.ZIndex));
}
private void UpdateLedsDimStatus()
@@ -259,7 +255,15 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
public void ResetZoomAndPan()
{
PanZoomViewModel.Reset();
// Create a rect surrounding all devices
SKRect rect = new SKRect(
Devices.Min(d => d.Rectangle.Left),
Devices.Min(d => d.Rectangle.Top),
Devices.Max(d => d.Rectangle.Right),
Devices.Max(d => d.Rectangle.Bottom)
);
PanZoomViewModel.Reset(rect);
}
#endregion
@@ -339,7 +343,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
_previousSelectedLayer.Transform.LayerPropertyOnCurrentValueSet += TransformValueChanged;
}
else
{
_previousSelectedLayer = null;
}
ApplyActiveProfile();
UpdateLedsDimStatus();
@@ -42,6 +42,7 @@
<StackPanel>
<Button Content="Open plugin directory" Command="{s:Action OpenPluginDirectory}" />
<Button Content="Open image directory" Command="{s:Action OpenImageDirectory}" />
<Button Content="Reload layout" Command="{s:Action ReloadLayout}" />
</StackPanel>
</materialDesign:PopupBox>
</StackPanel>
@@ -12,12 +12,14 @@ namespace Artemis.UI.Screens.Settings.Debug
public class DeviceDebugViewModel : Screen
{
private readonly IDeviceService _deviceService;
private readonly IRgbService _rgbService;
private readonly IDialogService _dialogService;
private ArtemisLed _selectedLed;
public DeviceDebugViewModel(ArtemisDevice device, IDeviceService deviceService, IDialogService dialogService)
public DeviceDebugViewModel(ArtemisDevice device, IDeviceService deviceService, IRgbService rgbService, IDialogService dialogService)
{
_deviceService = deviceService;
_rgbService = rgbService;
_dialogService = dialogService;
Device = device;
}
@@ -78,6 +80,17 @@ namespace Artemis.UI.Screens.Settings.Debug
}
}
public void ReloadLayout()
{
if (Device.Layout == null)
_rgbService.ApplyBestDeviceLayout(Device);
else
{
Device.Layout.ReloadFromDisk();
_rgbService.ApplyDeviceLayout(Device, Device.Layout);
}
}
#endregion
// ReSharper restore UnusedMember.Global
@@ -11,15 +11,15 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
public class DeviceSettingsTabViewModel : Conductor<DeviceSettingsViewModel>.Collection.AllActive
{
private readonly ISettingsVmFactory _settingsVmFactory;
private readonly ISurfaceService _surfaceService;
private readonly IRgbService _rgbService;
private readonly IDialogService _dialogService;
private bool _confirmedDisable;
public DeviceSettingsTabViewModel(ISurfaceService surfaceService, IDialogService dialogService, ISettingsVmFactory settingsVmFactory)
public DeviceSettingsTabViewModel(IRgbService rgbService, IDialogService dialogService, ISettingsVmFactory settingsVmFactory)
{
DisplayName = "DEVICES";
_surfaceService = surfaceService;
_rgbService = rgbService;
_dialogService = dialogService;
_settingsVmFactory = settingsVmFactory;
}
@@ -32,7 +32,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
Items.Clear();
await Task.Delay(200);
List<DeviceSettingsViewModel> instances = _surfaceService.ActiveSurface.Devices.Select(d => _settingsVmFactory.CreateDeviceSettingsViewModel(d)).ToList();
List<DeviceSettingsViewModel> instances = _rgbService.Devices.Select(d => _settingsVmFactory.CreateDeviceSettingsViewModel(d)).ToList();
foreach (DeviceSettingsViewModel deviceSettingsViewModel in instances)
Items.Add(deviceSettingsViewModel);
});
@@ -6,7 +6,6 @@ using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.SurfaceEditor.Dialogs;
using Artemis.UI.Screens.SurfaceEditor.Visualization;
using Artemis.UI.Shared.Services;
using Humanizer;
using RGB.NET.Core;
@@ -17,9 +16,9 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
public class DeviceSettingsViewModel : Screen
{
private readonly IDeviceDebugVmFactory _deviceDebugVmFactory;
private readonly ISurfaceService _surfaceService;
private readonly IDeviceService _deviceService;
private readonly IDialogService _dialogService;
private readonly IRgbService _rgbService;
private readonly IWindowManager _windowManager;
public DeviceSettingsViewModel(ArtemisDevice device,
@@ -27,13 +26,13 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
IDialogService dialogService,
IWindowManager windowManager,
IDeviceDebugVmFactory deviceDebugVmFactory,
ISurfaceService surfaceService)
IRgbService rgbService)
{
_deviceService = deviceService;
_dialogService = dialogService;
_windowManager = windowManager;
_deviceDebugVmFactory = deviceDebugVmFactory;
_surfaceService = surfaceService;
_rgbService = rgbService;
Device = device;
Type = Device.RgbDevice.DeviceInfo.DeviceType.ToString().Humanize();
@@ -53,26 +52,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
public bool IsDeviceEnabled
{
get => Device.IsEnabled;
set
{
Task.Run(() => UpdateIsDeviceEnabled(value));
}
}
private async Task UpdateIsDeviceEnabled(bool value)
{
if (!value)
value = !await ((DeviceSettingsTabViewModel)Parent).ShowDeviceDisableDialog();
Device.IsEnabled = value;
NotifyOfPropertyChange(nameof(IsDeviceEnabled));
SaveDevice();
}
private void SaveDevice()
{
_surfaceService.UpdateSurfaceConfiguration(_surfaceService.ActiveSurface, true);
set { Task.Run(() => UpdateIsDeviceEnabled(value)); }
}
public void IdentifyDevice()
@@ -104,7 +84,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
);
if ((bool) madeChanges)
_surfaceService.UpdateSurfaceConfiguration(_surfaceService.ActiveSurface, true);
_rgbService.SaveDevice(Device);
}
public async Task ViewProperties()
@@ -114,7 +94,25 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
);
if ((bool) madeChanges)
_surfaceService.UpdateSurfaceConfiguration(_surfaceService.ActiveSurface, true);
_rgbService.SaveDevice(Device);
}
private async Task UpdateIsDeviceEnabled(bool value)
{
if (!value)
value = !await ((DeviceSettingsTabViewModel) Parent).ShowDeviceDisableDialog();
if (value)
_rgbService.EnableDevice(Device);
else
_rgbService.DisableDevice(Device);
NotifyOfPropertyChange(nameof(IsDeviceEnabled));
SaveDevice();
}
private void SaveDevice()
{
_rgbService.SaveDevice(Device);
}
}
}
@@ -5,6 +5,7 @@ using System.Windows.Input;
using System.Windows.Media;
using Artemis.UI.Extensions;
using RGB.NET.Core;
using SkiaSharp;
using Stylet;
using Point = System.Windows.Point;
@@ -144,6 +145,13 @@ namespace Artemis.UI.Screens.Shared
PanY = 0;
}
public void Reset(SKRect rect)
{
Zoom = Math.Min(CanvasWidth / rect.Width, CanvasHeight / rect.Height);
PanX = rect.Left * -1 * Zoom;
PanY = rect.Top * -1 * Zoom;
}
public Rect TransformContainingRect(Rectangle rect)
{
return TransformContainingRect(rect.ToWindowsRect(1));
@@ -168,11 +176,15 @@ namespace Artemis.UI.Screens.Shared
private void SetZoomFromPercentage(double value)
{
double newZoom = value / 100;
// Focus towards the center of the zoomed area
PanX += newZoom - Zoom;
PanY += newZoom - Zoom;
Point relative = new((PanX * -1 + CanvasWidth / 2) / Zoom, (PanY * -1 + CanvasHeight / 2) / Zoom);
double absoluteX = relative.X * Zoom + PanX;
double absoluteY = relative.Y * Zoom + PanY;
Zoom = value / 100;
// Focus towards the center of the zoomed area
PanX = absoluteX - relative.X * Zoom;
PanY = absoluteY - relative.Y * Zoom;
}
}
}
@@ -16,7 +16,7 @@
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Style="{StaticResource MaterialDesignBody1TextBlock}" TextWrapping="Wrap">
Devices are supported through the use of device providers. <LineBreak />
EnabledDevices are supported through the use of device providers. <LineBreak />
In the list below you can enable device providers for each brand you own by checking <Run Text="Feature enabled" FontWeight="Bold" />.
</TextBlock>
@@ -5,23 +5,23 @@ namespace Artemis.UI.Screens.StartupWizard.Steps
{
public class LayoutStepViewModel : Screen
{
private readonly ISurfaceService _surfaceService;
private readonly IRgbService _rgbService;
public LayoutStepViewModel(ISurfaceService surfaceService)
public LayoutStepViewModel(IRgbService rgbService)
{
_surfaceService = surfaceService;
_rgbService = rgbService;
}
public void ApplyLeftHandedPreset()
{
_surfaceService.AutoArrange();
_rgbService.AutoArrangeDevices();
StartupWizardViewModel startupWizardViewModel = (StartupWizardViewModel) Parent;
startupWizardViewModel.Continue();
}
public void ApplyRightHandedPreset()
{
_surfaceService.AutoArrange();
_rgbService.AutoArrangeDevices();
StartupWizardViewModel startupWizardViewModel = (StartupWizardViewModel) Parent;
startupWizardViewModel.Continue();
}
@@ -5,11 +5,12 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:Converters="clr-namespace:Artemis.UI.Converters"
xmlns:models="clr-namespace:Artemis.Core;assembly=Artemis.Core"
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
xmlns:local="clr-namespace:Artemis.UI.Screens.SurfaceEditor"
x:Class="Artemis.UI.Screens.SurfaceEditor.SurfaceEditorView"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="600">
d:DesignHeight="600" d:DesignWidth="600"
d:DataContext="{d:DesignInstance {x:Type local:SurfaceEditorViewModel}}">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
@@ -18,7 +19,6 @@
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
</ResourceDictionary.MergedDictionaries>
<Converters:InverseBooleanConverter x:Key="InverseBooleanConverter" />
</ResourceDictionary>
</UserControl.Resources>
<Grid Margin="16">
@@ -113,14 +113,17 @@
</EventTrigger>
</Grid.Triggers>
<Grid x:Name="EditorDisplayGrid">
<Grid x:Name="EditorDisplayGrid"
shared:SizeObserver.Observe="True"
shared:SizeObserver.ObservedHeight="{Binding PanZoomViewModel.CanvasHeight, Mode=TwoWay}"
shared:SizeObserver.ObservedWidth="{Binding PanZoomViewModel.CanvasWidth, Mode=TwoWay}">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="{Binding PanZoomViewModel.Zoom}" ScaleY="{Binding PanZoomViewModel.Zoom}" />
<TranslateTransform X="{Binding PanZoomViewModel.PanX}" Y="{Binding PanZoomViewModel.PanY}" />
</TransformGroup>
</Grid.RenderTransform>
<ItemsControl ItemsSource="{Binding Devices}">
<ItemsControl ItemsSource="{Binding SurfaceDeviceViewModels}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
@@ -137,28 +140,28 @@
<ContentControl s:View.Model="{Binding}">
<ContentControl.ContextMenu>
<ContextMenu>
<MenuItem Header="Identify" Command="{s:Action IdentifyDevice}" CommandParameter="{Binding}">
<MenuItem Header="Identify" Command="{s:Action IdentifyDevice}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="AlarmLight" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Bring to Front" Command="{s:Action BringToFront}" CommandParameter="{Binding}">
<MenuItem Header="Bring to Front" Command="{s:Action BringToFront}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="ArrangeBringToFront" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Bring Forward" Command="{s:Action BringForward}" CommandParameter="{Binding}">
<MenuItem Header="Bring Forward" Command="{s:Action BringForward}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="ArrangeBringForward" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Send to Back" Command="{s:Action SendToBack}" CommandParameter="{Binding}">
<MenuItem Header="Send to Back" Command="{s:Action SendToBack}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="ArrangeSendToBack" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Send Backward" Command="{s:Action SendBackward}" CommandParameter="{Binding}">
<MenuItem Header="Send Backward" Command="{s:Action SendBackward}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="ArrangeSendBackward" />
</MenuItem.Icon>
@@ -167,14 +170,14 @@
<!-- Stylet can't disable it for us here, do it ourselves -->
<MenuItem Header="Identify input"
Command="{s:Action DetectInput}"
CommandParameter="{Binding}"
CommandParameter="{Binding Device}"
IsEnabled="{Binding CanDetectInput}"
ToolTip="Teach Artemis which keypresses and/or button presses belong to this device">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="GestureDoubleTap" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="View properties" Command="{s:Action ViewProperties}" CommandParameter="{Binding}">
<MenuItem Header="View properties" Command="{s:Action ViewProperties}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Gear" />
</MenuItem.Icon>
@@ -236,29 +239,65 @@
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox Grid.Row="0" HorizontalContentAlignment="Stretch" ItemsSource="{Binding SurfaceConfigurations}" SelectedItem="{Binding SelectedSurface}">
<ListBox.Resources>
<DataTemplate DataType="{x:Type models:ArtemisSurface}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" ToolTip="{Binding Name}"
HorizontalAlignment="Left" VerticalAlignment="Center" />
<Button Grid.Column="1"
Command="{s:Action DeleteSurfaceConfiguration}"
CommandParameter="{Binding}"
IsEnabled="{Binding IsActive, Converter={StaticResource InverseBooleanConverter}}"
Style="{StaticResource MaterialDesignIconForegroundButton}"
ToolTip="Delete layout configuration"
HorizontalAlignment="Right">
<materialDesign:PackIcon Kind="Trashcan" />
</Button>
</Grid>
<ListBox Grid.Row="0" HorizontalContentAlignment="Stretch" ItemsSource="{Binding ListDeviceViewModels}" SelectionMode="Multiple">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False">
<ContentControl.ContextMenu>
<ContextMenu>
<MenuItem Header="Identify" Command="{s:Action IdentifyDevice}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="AlarmLight" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Bring to Front" Command="{s:Action BringToFront}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="ArrangeBringToFront" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Bring Forward" Command="{s:Action BringForward}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="ArrangeBringForward" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Send to Back" Command="{s:Action SendToBack}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="ArrangeSendToBack" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Send Backward" Command="{s:Action SendBackward}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="ArrangeSendBackward" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<!-- Stylet can't disable it for us here, do it ourselves -->
<MenuItem Header="Identify input"
Command="{s:Action DetectInput}"
CommandParameter="{Binding Device}"
IsEnabled="{Binding CanDetectInput}"
ToolTip="Teach Artemis which keypresses and/or button presses belong to this device">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="GestureDoubleTap" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="View properties" Command="{s:Action ViewProperties}" CommandParameter="{Binding Device}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Gear" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ContentControl.ContextMenu>
</ContentControl>
</DataTemplate>
</ListBox.Resources>
</ListBox.ItemTemplate>
</ListBox>
<Button Grid.Row="0"
Style="{StaticResource MaterialDesignFloatingActionButton}"
@@ -10,6 +10,7 @@ using System.Windows.Media;
using System.Windows.Navigation;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Extensions;
using Artemis.UI.Screens.Shared;
using Artemis.UI.Screens.SurfaceEditor.Dialogs;
using Artemis.UI.Screens.SurfaceEditor.Visualization;
@@ -27,49 +28,34 @@ namespace Artemis.UI.Screens.SurfaceEditor
private readonly IDialogService _dialogService;
private readonly IRgbService _rgbService;
private readonly ISettingsService _settingsService;
private readonly ISurfaceService _surfaceService;
private Cursor _cursor;
private ObservableCollection<SurfaceDeviceViewModel> _devices;
private PanZoomViewModel _panZoomViewModel;
private ArtemisSurface _selectedSurface;
private RectangleGeometry _selectionRectangle;
private ObservableCollection<ArtemisSurface> _surfaceConfigurations;
private PluginSetting<GridLength> _surfaceListWidth;
public SurfaceEditorViewModel(IRgbService rgbService,
ISurfaceService surfaceService,
IDialogService dialogService,
ISettingsService settingsService,
IDeviceService deviceService,
IInputService inputService)
{
DisplayName = "Surface Editor";
Devices = new ObservableCollection<SurfaceDeviceViewModel>();
SurfaceConfigurations = new ObservableCollection<ArtemisSurface>();
SelectionRectangle = new RectangleGeometry();
PanZoomViewModel = new PanZoomViewModel();
Cursor = null;
SurfaceDeviceViewModels = new BindableCollection<SurfaceDeviceViewModel>();
ListDeviceViewModels = new BindableCollection<ListDeviceViewModel>();
_rgbService = rgbService;
_surfaceService = surfaceService;
_dialogService = dialogService;
_settingsService = settingsService;
_deviceService = deviceService;
_inputService = inputService;
}
public ObservableCollection<SurfaceDeviceViewModel> Devices
{
get => _devices;
set => SetAndNotify(ref _devices, value);
}
public ObservableCollection<ArtemisSurface> SurfaceConfigurations
{
get => _surfaceConfigurations;
set => SetAndNotify(ref _surfaceConfigurations, value);
}
public BindableCollection<SurfaceDeviceViewModel> SurfaceDeviceViewModels { get; }
public BindableCollection<ListDeviceViewModel> ListDeviceViewModels { get; }
public RectangleGeometry SelectionRectangle
{
@@ -95,26 +81,6 @@ namespace Artemis.UI.Screens.SurfaceEditor
set => SetAndNotify(ref _cursor, value);
}
public ArtemisSurface SelectedSurface
{
get => _selectedSurface;
set
{
if (value == null)
return;
SetAndNotify(ref _selectedSurface, value);
ApplySelectedSurfaceConfiguration();
}
}
public ArtemisSurface CreateSurfaceConfiguration(string name)
{
ArtemisSurface config = _surfaceService.CreateSurfaceConfiguration(name);
Execute.PostToUIThread(() => SurfaceConfigurations.Add(config));
return config;
}
public void OpenHyperlink(object sender, RequestNavigateEventArgs e)
{
Core.Utilities.OpenUrl(e.Uri.AbsoluteUri);
@@ -126,7 +92,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
if (!confirmed)
return;
_surfaceService.AutoArrange();
_rgbService.AutoArrangeDevices();
}
private void LoadWorkspaceSettings()
@@ -139,184 +105,112 @@ namespace Artemis.UI.Screens.SurfaceEditor
SurfaceListWidth.Save();
}
private void LoadSurfaceConfigurations()
{
// Get surface configs
List<ArtemisSurface> configs = _surfaceService.SurfaceConfigurations.ToList();
// Get the active config, if empty, create a default config
ArtemisSurface activeConfig = _surfaceService.ActiveSurface;
if (activeConfig == null)
{
activeConfig = CreateSurfaceConfiguration("Default");
configs.Add(activeConfig);
_surfaceService.SetActiveSurfaceConfiguration(activeConfig);
}
Execute.PostToUIThread(() =>
{
// Populate the UI collection
SurfaceConfigurations.Clear();
foreach (ArtemisSurface surfaceConfiguration in configs)
SurfaceConfigurations.Add(surfaceConfiguration);
// Set the active config
SelectedSurface = activeConfig;
});
}
private void ApplySelectedSurfaceConfiguration()
{
// Make sure all devices have an up-to-date VM
Execute.PostToUIThread(() =>
{
lock (Devices)
{
List<SurfaceDeviceViewModel> existing = Devices.ToList();
List<SurfaceDeviceViewModel> deviceViewModels = new();
// Add missing/update existing
foreach (ArtemisDevice surfaceDeviceConfiguration in SelectedSurface.Devices.Where(d => d.IsEnabled).OrderBy(d => d.ZIndex).ToList())
{
// Create VMs for missing devices
SurfaceDeviceViewModel viewModel = existing.FirstOrDefault(vm => vm.Device.RgbDevice == surfaceDeviceConfiguration.RgbDevice);
if (viewModel == null)
viewModel = new SurfaceDeviceViewModel(surfaceDeviceConfiguration);
// Update existing devices
else
viewModel.Device = surfaceDeviceConfiguration;
// Add the viewModel to the list of VMs we want to keep
deviceViewModels.Add(viewModel);
}
Devices = new ObservableCollection<SurfaceDeviceViewModel>(deviceViewModels);
}
});
_surfaceService.SetActiveSurfaceConfiguration(SelectedSurface);
}
#region Overrides of Screen
protected override void OnInitialActivate()
{
LoadSurfaceConfigurations();
LoadWorkspaceSettings();
SurfaceDeviceViewModels.AddRange(_rgbService.EnabledDevices.OrderBy(d => d.ZIndex).Select(d => new SurfaceDeviceViewModel(d, _rgbService)));
ListDeviceViewModels.AddRange(_rgbService.EnabledDevices.OrderBy(d => d.ZIndex * -1).Select(d => new ListDeviceViewModel(d)));
base.OnInitialActivate();
}
protected override void OnClose()
{
SaveWorkspaceSettings();
SurfaceDeviceViewModels.Clear();
ListDeviceViewModels.Clear();
base.OnClose();
}
#endregion
#region Configuration management
public async Task DeleteSurfaceConfiguration(ArtemisSurface surface)
{
bool result = await _dialogService.ShowConfirmDialogAt(
"SurfaceListDialogHost",
"Delete surface configuration",
"Are you sure you want to delete\nthis surface configuration?"
);
if (result)
{
SurfaceConfigurations.Remove(surface);
_surfaceService.DeleteSurfaceConfiguration(surface);
}
}
public async Task AddSurfaceConfiguration()
{
object result = await _dialogService.ShowDialogAt<SurfaceCreateViewModel>("SurfaceListDialogHost");
if (result is string name)
CreateSurfaceConfiguration(name);
}
#endregion
#region Context menu actions
public void IdentifyDevice(SurfaceDeviceViewModel surfaceDeviceViewModel)
public void IdentifyDevice(ArtemisDevice device)
{
_deviceService.IdentifyDevice(surfaceDeviceViewModel.Device);
_deviceService.IdentifyDevice(device);
}
public void BringToFront(SurfaceDeviceViewModel surfaceDeviceViewModel)
public void BringToFront(ArtemisDevice device)
{
Devices.Move(Devices.IndexOf(surfaceDeviceViewModel), Devices.Count - 1);
for (int i = 0; i < Devices.Count; i++)
SurfaceDeviceViewModel surfaceDeviceViewModel = SurfaceDeviceViewModels.First(d => d.Device == device);
SurfaceDeviceViewModels.Move(SurfaceDeviceViewModels.IndexOf(surfaceDeviceViewModel), SurfaceDeviceViewModels.Count - 1);
for (int i = 0; i < SurfaceDeviceViewModels.Count; i++)
{
SurfaceDeviceViewModel deviceViewModel = Devices[i];
SurfaceDeviceViewModel deviceViewModel = SurfaceDeviceViewModels[i];
deviceViewModel.Device.ZIndex = i + 1;
}
ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1);
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
_rgbService.SaveDevices();
}
public void BringForward(SurfaceDeviceViewModel surfaceDeviceViewModel)
public void BringForward(ArtemisDevice device)
{
int currentIndex = Devices.IndexOf(surfaceDeviceViewModel);
int newIndex = Math.Min(currentIndex + 1, Devices.Count - 1);
Devices.Move(currentIndex, newIndex);
SurfaceDeviceViewModel surfaceDeviceViewModel = SurfaceDeviceViewModels.First(d => d.Device == device);
int currentIndex = SurfaceDeviceViewModels.IndexOf(surfaceDeviceViewModel);
int newIndex = Math.Min(currentIndex + 1, SurfaceDeviceViewModels.Count - 1);
SurfaceDeviceViewModels.Move(currentIndex, newIndex);
for (int i = 0; i < Devices.Count; i++)
for (int i = 0; i < SurfaceDeviceViewModels.Count; i++)
{
SurfaceDeviceViewModel deviceViewModel = Devices[i];
SurfaceDeviceViewModel deviceViewModel = SurfaceDeviceViewModels[i];
deviceViewModel.Device.ZIndex = i + 1;
}
ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1);
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
_rgbService.SaveDevices();
}
public void SendToBack(SurfaceDeviceViewModel surfaceDeviceViewModel)
public void SendToBack(ArtemisDevice device)
{
Devices.Move(Devices.IndexOf(surfaceDeviceViewModel), 0);
for (int i = 0; i < Devices.Count; i++)
SurfaceDeviceViewModel surfaceDeviceViewModel = SurfaceDeviceViewModels.First(d => d.Device == device);
SurfaceDeviceViewModels.Move(SurfaceDeviceViewModels.IndexOf(surfaceDeviceViewModel), 0);
for (int i = 0; i < SurfaceDeviceViewModels.Count; i++)
{
SurfaceDeviceViewModel deviceViewModel = Devices[i];
SurfaceDeviceViewModel deviceViewModel = SurfaceDeviceViewModels[i];
deviceViewModel.Device.ZIndex = i + 1;
}
ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1);
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
_rgbService.SaveDevices();
}
public void SendBackward(SurfaceDeviceViewModel surfaceDeviceViewModel)
public void SendBackward(ArtemisDevice device)
{
int currentIndex = Devices.IndexOf(surfaceDeviceViewModel);
SurfaceDeviceViewModel surfaceDeviceViewModel = SurfaceDeviceViewModels.First(d => d.Device == device);
int currentIndex = SurfaceDeviceViewModels.IndexOf(surfaceDeviceViewModel);
int newIndex = Math.Max(currentIndex - 1, 0);
Devices.Move(currentIndex, newIndex);
for (int i = 0; i < Devices.Count; i++)
SurfaceDeviceViewModels.Move(currentIndex, newIndex);
for (int i = 0; i < SurfaceDeviceViewModels.Count; i++)
{
SurfaceDeviceViewModel deviceViewModel = Devices[i];
SurfaceDeviceViewModel deviceViewModel = SurfaceDeviceViewModels[i];
deviceViewModel.Device.ZIndex = i + 1;
}
ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1);
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
_rgbService.SaveDevices();
}
public async Task ViewProperties(SurfaceDeviceViewModel surfaceDeviceViewModel)
public async Task ViewProperties(ArtemisDevice device)
{
object madeChanges = await _dialogService.ShowDialog<SurfaceDeviceConfigViewModel>(
new Dictionary<string, object> {{"device", surfaceDeviceViewModel.Device}}
new Dictionary<string, object> {{"device", device}}
);
if ((bool) madeChanges)
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
_rgbService.SaveDevice(device);
}
public async Task DetectInput(SurfaceDeviceViewModel surfaceDeviceViewModel)
public async Task DetectInput(ArtemisDevice device)
{
object madeChanges = await _dialogService.ShowDialog<SurfaceDeviceDetectInputViewModel>(
new Dictionary<string, object> {{"device", surfaceDeviceViewModel.Device}}
new Dictionary<string, object> {{"device", device}}
);
if ((bool) madeChanges)
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
_rgbService.SaveDevice(device);
}
#endregion
@@ -377,13 +271,15 @@ namespace Artemis.UI.Screens.SurfaceEditor
if (device.SelectionStatus != SelectionStatus.Selected)
{
if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
foreach (SurfaceDeviceViewModel others in Devices)
{
foreach (SurfaceDeviceViewModel others in SurfaceDeviceViewModels)
others.SelectionStatus = SelectionStatus.None;
}
device.SelectionStatus = SelectionStatus.Selected;
}
foreach (SurfaceDeviceViewModel selectedDevice in Devices.Where(d => d.SelectionStatus == SelectionStatus.Selected))
foreach (SurfaceDeviceViewModel selectedDevice in SurfaceDeviceViewModels.Where(d => d.SelectionStatus == SelectionStatus.Selected))
selectedDevice.StartMouseDrag(relative);
}
// Start multi-selection
@@ -395,6 +291,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
// Any time dragging starts, start with a new rect
SelectionRectangle.Rect = new Rect();
ApplySurfaceSelection();
}
private void StopMouseDrag(object sender, Point position)
@@ -403,17 +300,22 @@ namespace Artemis.UI.Screens.SurfaceEditor
{
RectangleGeometry selectedRect = new(new Rect(_mouseDragStartPoint, position));
List<SurfaceDeviceViewModel> devices = HitTestUtilities.GetHitViewModels<SurfaceDeviceViewModel>((Visual) sender, selectedRect);
foreach (SurfaceDeviceViewModel device in Devices)
foreach (SurfaceDeviceViewModel device in SurfaceDeviceViewModels)
{
if (devices.Contains(device))
device.SelectionStatus = SelectionStatus.Selected;
else if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
device.SelectionStatus = SelectionStatus.None;
}
}
else
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
{
_rgbService.SaveDevices();
}
_mouseDragStatus = MouseDragStatus.None;
_rgbService.IsRenderPaused = false;
ApplySurfaceSelection();
}
private void UpdateSelection(object sender, Point position)
@@ -425,19 +327,29 @@ namespace Artemis.UI.Screens.SurfaceEditor
SelectionRectangle.Rect = selectedRect;
List<SurfaceDeviceViewModel> devices = HitTestUtilities.GetHitViewModels<SurfaceDeviceViewModel>((Visual) sender, SelectionRectangle);
foreach (SurfaceDeviceViewModel device in Devices)
foreach (SurfaceDeviceViewModel device in SurfaceDeviceViewModels)
{
if (devices.Contains(device))
device.SelectionStatus = SelectionStatus.Selected;
else if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
device.SelectionStatus = SelectionStatus.None;
}
ApplySurfaceSelection();
}
private void MoveSelected(Point position)
{
foreach (SurfaceDeviceViewModel device in Devices.Where(d => d.SelectionStatus == SelectionStatus.Selected))
foreach (SurfaceDeviceViewModel device in SurfaceDeviceViewModels.Where(d => d.SelectionStatus == SelectionStatus.Selected))
device.UpdateMouseDrag(position);
}
private void ApplySurfaceSelection()
{
foreach (ListDeviceViewModel viewModel in ListDeviceViewModels)
viewModel.IsSelected = SurfaceDeviceViewModels.Any(s => s.Device == viewModel.Device && s.SelectionStatus == SelectionStatus.Selected);
}
#endregion
#region Panning and zooming
@@ -0,0 +1,19 @@
<UserControl x:Class="Artemis.UI.Screens.SurfaceEditor.Visualization.ListDeviceView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.SurfaceEditor.Visualization"
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type local:ListDeviceViewModel}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<shared:DeviceVisualizer Device="{Binding Device}" Width="30" Height="30" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Text="{Binding Device.RgbDevice.DeviceInfo.DeviceName}" Grid.Column="1" VerticalAlignment="Center" />
</Grid>
</UserControl>
@@ -0,0 +1,22 @@
using Artemis.Core;
using Stylet;
namespace Artemis.UI.Screens.SurfaceEditor.Visualization
{
public class ListDeviceViewModel : PropertyChangedBase
{
private bool _isSelected;
public ArtemisDevice Device { get; }
public bool IsSelected
{
get => _isSelected;
set => SetAndNotify(ref _isSelected, value);
}
public ListDeviceViewModel(ArtemisDevice device)
{
Device = device;
}
}
}
@@ -5,10 +5,10 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:converters="clr-namespace:Artemis.UI.Converters"
xmlns:surfaceEditor="clr-namespace:Artemis.UI.Screens.SurfaceEditor.Visualization"
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
xmlns:local="clr-namespace:Artemis.UI.Screens.SurfaceEditor.Visualization"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance {x:Type surfaceEditor:SurfaceDeviceViewModel}}"
d:DataContext="{d:DesignInstance {x:Type local:SurfaceDeviceViewModel}}"
d:DesignHeight="450" d:DesignWidth="800"
Cursor="{Binding Cursor}"
MouseEnter="{s:Action MouseEnter}"
@@ -20,21 +20,22 @@
<Grid>
<!-- Content -->
<Grid>
<shared:DeviceVisualizer Device="{Binding Device}" ShowColors="True" VerticalAlignment="Top" HorizontalAlignment="Left" />
<Rectangle Fill="{DynamicResource MaterialDesignCardBackground}"
Stroke="{DynamicResource MaterialDesignTextBoxBorder}"
StrokeThickness="1"
Visibility="{Binding Device.RgbDevice.DeviceInfo.Image, ConverterParameter=Inverted, Converter={StaticResource NullToVisibilityConverter}}"
Visibility="{Binding Device.Layout.Image, ConverterParameter=Inverted, Converter={StaticResource NullToVisibilityConverter}}"
IsHitTestVisible="False"/>
<TextBlock Text="{Binding Device.RgbDevice.DeviceInfo.DeviceName}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextWrapping="Wrap"
TextAlignment="Center"
Visibility="{Binding Device.RgbDevice.DeviceInfo.Image, ConverterParameter=Inverted, Converter={StaticResource NullToVisibilityConverter}}"
Visibility="{Binding Device.Layout.Image, ConverterParameter=Inverted, Converter={StaticResource NullToVisibilityConverter}}"
IsHitTestVisible="False"/>
</Grid>
<shared:DeviceVisualizer Device="{Binding Device}" ShowColors="True" VerticalAlignment="Top" HorizontalAlignment="Left" />
</Grid>
<!-- Selection rectangle -->
<Rectangle Width="Auto" Height="Auto" StrokeThickness="2">
@@ -47,7 +48,7 @@
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Style.Triggers>
<DataTrigger Binding="{Binding SelectionStatus}" Value="{x:Static surfaceEditor:SelectionStatus.Hover}">
<DataTrigger Binding="{Binding SelectionStatus}" Value="{x:Static local:SelectionStatus.Hover}">
<DataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="ToSelected" />
<BeginStoryboard x:Name="ToHover">
@@ -62,7 +63,7 @@
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding SelectionStatus}" Value="{x:Static surfaceEditor:SelectionStatus.Selected}">
<DataTrigger Binding="{Binding SelectionStatus}" Value="{x:Static local:SelectionStatus.Selected}">
<DataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="ToHover" />
<BeginStoryboard x:Name="ToSelected">
@@ -77,7 +78,7 @@
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding SelectionStatus}" Value="{x:Static surfaceEditor:SelectionStatus.None}">
<DataTrigger Binding="{Binding SelectionStatus}" Value="{x:Static local:SelectionStatus.None}">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using Artemis.Core;
using Artemis.Core.Services;
using RGB.NET.Core;
using SkiaSharp;
using Stylet;
@@ -13,26 +13,19 @@ namespace Artemis.UI.Screens.SurfaceEditor.Visualization
{
public class SurfaceDeviceViewModel : PropertyChangedBase
{
private readonly IRgbService _rgbService;
private Cursor _cursor;
private ArtemisDevice _device;
private double _dragOffsetX;
private double _dragOffsetY;
private SelectionStatus _selectionStatus;
public SurfaceDeviceViewModel(ArtemisDevice device)
public SurfaceDeviceViewModel(ArtemisDevice device, IRgbService rgbService)
{
Device = device;
_rgbService = rgbService;
}
public ArtemisDevice Device
{
get => _device;
set
{
if (SetAndNotify(ref _device, value)) return;
NotifyOfPropertyChange(nameof(DeviceRectangle));
}
}
public ArtemisDevice Device { get; }
public SelectionStatus SelectionStatus
{
@@ -40,19 +33,15 @@ namespace Artemis.UI.Screens.SurfaceEditor.Visualization
set => SetAndNotify(ref _selectionStatus, value);
}
public bool CanDetectInput => Device.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Keyboard ||
Device.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Mouse;
public Cursor Cursor
{
get => _cursor;
set => SetAndNotify(ref _cursor, value);
}
public Rect DeviceRectangle => Device.RgbDevice == null
? new Rect()
: new Rect(Device.X, Device.Y, Device.RgbDevice.Boundary.Size.Width, Device.RgbDevice.Boundary.Size.Height);
public bool CanDetectInput => Device.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Keyboard ||
Device.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Mouse;
public void StartMouseDrag(Point mouseStartPosition)
{
_dragOffsetX = Device.X - mouseStartPosition.X;
@@ -115,7 +104,7 @@ namespace Artemis.UI.Screens.SurfaceEditor.Visualization
List<SKRect> own = Device.Leds
.Select(l => SKRect.Create(l.Rectangle.Left + x, l.Rectangle.Top + y, l.Rectangle.Width, l.Rectangle.Height))
.ToList();
List<SKRect> others = Device.Surface.Devices
List<SKRect> others = _rgbService.EnabledDevices
.Where(d => d != Device && d.IsEnabled)
.SelectMany(d => d.Leds)
.Select(l => SKRect.Create(l.Rectangle.Left + (float) l.Device.X, l.Rectangle.Top + (float) l.Device.Y, l.Rectangle.Width, l.Rectangle.Height))
@@ -133,7 +122,7 @@ namespace Artemis.UI.Screens.SurfaceEditor.Visualization
BottomLeft,
BottomRight
}
public enum SelectionStatus
{
None,