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

@@ -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,