mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Surface editor - Refactor selection/movement code to match nodes
Device visualizer - Fixed exception when updating devices during render
This commit is contained in:
parent
52f2338154
commit
e5ba48c7f4
@ -32,7 +32,7 @@ namespace Artemis.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The full path to the Artemis data folder
|
/// The full path to the Artemis data folder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly string DataFolder = Path.Combine(BaseFolder, "Artemis.Avalonia");
|
public static readonly string DataFolder = Path.Combine(BaseFolder, "Artemis");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The full path to the Artemis logs folder
|
/// The full path to the Artemis logs folder
|
||||||
|
|||||||
@ -81,8 +81,11 @@ namespace Artemis.UI.Shared
|
|||||||
if (!ShowColors)
|
if (!ShowColors)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds)
|
lock (_deviceVisualizerLeds)
|
||||||
deviceVisualizerLed.RenderGeometry(drawingContext, false);
|
{
|
||||||
|
foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds)
|
||||||
|
deviceVisualizerLed.RenderGeometry(drawingContext, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -244,10 +247,14 @@ namespace Artemis.UI.Shared
|
|||||||
{
|
{
|
||||||
_deviceImage?.Dispose();
|
_deviceImage?.Dispose();
|
||||||
_deviceImage = null;
|
_deviceImage = null;
|
||||||
_deviceVisualizerLeds.Clear();
|
|
||||||
_highlightedLeds = new List<DeviceVisualizerLed>();
|
_highlightedLeds = new List<DeviceVisualizerLed>();
|
||||||
_dimmedLeds = new List<DeviceVisualizerLed>();
|
_dimmedLeds = new List<DeviceVisualizerLed>();
|
||||||
|
|
||||||
|
lock (_deviceVisualizerLeds)
|
||||||
|
{
|
||||||
|
_deviceVisualizerLeds.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
if (_oldDevice != null)
|
if (_oldDevice != null)
|
||||||
{
|
{
|
||||||
_oldDevice.RgbDevice.PropertyChanged -= DevicePropertyChanged;
|
_oldDevice.RgbDevice.PropertyChanged -= DevicePropertyChanged;
|
||||||
@ -264,8 +271,11 @@ namespace Artemis.UI.Shared
|
|||||||
Device.DeviceUpdated += DeviceUpdated;
|
Device.DeviceUpdated += DeviceUpdated;
|
||||||
|
|
||||||
// Create all the LEDs
|
// Create all the LEDs
|
||||||
foreach (ArtemisLed artemisLed in Device.Leds)
|
lock (_deviceVisualizerLeds)
|
||||||
_deviceVisualizerLeds.Add(new DeviceVisualizerLed(artemisLed));
|
{
|
||||||
|
foreach (ArtemisLed artemisLed in Device.Leds)
|
||||||
|
_deviceVisualizerLeds.Add(new DeviceVisualizerLed(artemisLed));
|
||||||
|
}
|
||||||
|
|
||||||
// Load the device main image on a background thread
|
// Load the device main image on a background thread
|
||||||
ArtemisDevice? device = Device;
|
ArtemisDevice? device = Device;
|
||||||
@ -282,8 +292,11 @@ namespace Artemis.UI.Shared
|
|||||||
using IDrawingContextImpl context = renderTargetBitmap.CreateDrawingContext(new ImmediateRenderer(this));
|
using IDrawingContextImpl context = renderTargetBitmap.CreateDrawingContext(new ImmediateRenderer(this));
|
||||||
using Bitmap bitmap = new(device.Layout.Image.LocalPath);
|
using Bitmap bitmap = new(device.Layout.Image.LocalPath);
|
||||||
context.DrawBitmap(bitmap.PlatformImpl, 1, new Rect(bitmap.Size), new Rect(renderTargetBitmap.Size), BitmapInterpolationMode.HighQuality);
|
context.DrawBitmap(bitmap.PlatformImpl, 1, new Rect(bitmap.Size), new Rect(renderTargetBitmap.Size), BitmapInterpolationMode.HighQuality);
|
||||||
foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds)
|
lock (_deviceVisualizerLeds)
|
||||||
deviceVisualizerLed.DrawBitmap(context);
|
{
|
||||||
|
foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds)
|
||||||
|
deviceVisualizerLed.DrawBitmap(context);
|
||||||
|
}
|
||||||
|
|
||||||
_deviceImage = renderTargetBitmap;
|
_deviceImage = renderTargetBitmap;
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,6 @@ using Artemis.UI.Screens.ProfileEditor.ProfileTree;
|
|||||||
using Artemis.UI.Screens.ProfileEditor.Properties;
|
using Artemis.UI.Screens.ProfileEditor.Properties;
|
||||||
using Artemis.UI.Screens.ProfileEditor.Properties.DataBinding;
|
using Artemis.UI.Screens.ProfileEditor.Properties.DataBinding;
|
||||||
using Artemis.UI.Screens.ProfileEditor.Properties.Timeline;
|
using Artemis.UI.Screens.ProfileEditor.Properties.Timeline;
|
||||||
using Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Segments;
|
|
||||||
using Artemis.UI.Screens.ProfileEditor.Properties.Tree;
|
using Artemis.UI.Screens.ProfileEditor.Properties.Tree;
|
||||||
using Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers;
|
using Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers;
|
||||||
using Artemis.UI.Screens.Settings;
|
using Artemis.UI.Screens.Settings;
|
||||||
@ -18,103 +17,101 @@ using Artemis.UI.Screens.Sidebar;
|
|||||||
using Artemis.UI.Screens.SurfaceEditor;
|
using Artemis.UI.Screens.SurfaceEditor;
|
||||||
using Artemis.UI.Screens.VisualScripting;
|
using Artemis.UI.Screens.VisualScripting;
|
||||||
using Artemis.UI.Screens.VisualScripting.Pins;
|
using Artemis.UI.Screens.VisualScripting.Pins;
|
||||||
using Artemis.UI.Services;
|
|
||||||
using DynamicData.Binding;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Ninject.Factories
|
namespace Artemis.UI.Ninject.Factories;
|
||||||
|
|
||||||
|
public interface IVmFactory
|
||||||
{
|
{
|
||||||
public interface IVmFactory
|
}
|
||||||
{
|
|
||||||
}
|
public interface IDeviceVmFactory : IVmFactory
|
||||||
|
{
|
||||||
public interface IDeviceVmFactory : IVmFactory
|
DevicePropertiesViewModel DevicePropertiesViewModel(ArtemisDevice device);
|
||||||
{
|
DeviceSettingsViewModel DeviceSettingsViewModel(ArtemisDevice device, DevicesTabViewModel devicesTabViewModel);
|
||||||
DevicePropertiesViewModel DevicePropertiesViewModel(ArtemisDevice device);
|
DeviceDetectInputViewModel DeviceDetectInputViewModel(ArtemisDevice device);
|
||||||
DeviceSettingsViewModel DeviceSettingsViewModel(ArtemisDevice device, DevicesTabViewModel devicesTabViewModel);
|
DevicePropertiesTabViewModel DevicePropertiesTabViewModel(ArtemisDevice device);
|
||||||
DeviceDetectInputViewModel DeviceDetectInputViewModel(ArtemisDevice device);
|
DeviceInfoTabViewModel DeviceInfoTabViewModel(ArtemisDevice device);
|
||||||
DevicePropertiesTabViewModel DevicePropertiesTabViewModel(ArtemisDevice device);
|
DeviceLedsTabViewModel DeviceLedsTabViewModel(ArtemisDevice device, ObservableCollection<ArtemisLed> selectedLeds);
|
||||||
DeviceInfoTabViewModel DeviceInfoTabViewModel(ArtemisDevice device);
|
InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection<ArtemisLed> selectedLeds);
|
||||||
DeviceLedsTabViewModel DeviceLedsTabViewModel(ArtemisDevice device, ObservableCollection<ArtemisLed> selectedLeds);
|
}
|
||||||
InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection<ArtemisLed> selectedLeds);
|
|
||||||
}
|
public interface ISettingsVmFactory : IVmFactory
|
||||||
|
{
|
||||||
public interface ISettingsVmFactory : IVmFactory
|
PluginSettingsViewModel CreatePluginSettingsViewModel(Plugin plugin);
|
||||||
{
|
|
||||||
PluginSettingsViewModel CreatePluginSettingsViewModel(Plugin plugin);
|
PluginFeatureViewModel CreatePluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo, bool showShield);
|
||||||
PluginFeatureViewModel CreatePluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo, bool showShield);
|
// DeviceSettingsViewModel CreateDeviceSettingsViewModel(ArtemisDevice device);
|
||||||
// DeviceSettingsViewModel CreateDeviceSettingsViewModel(ArtemisDevice device);
|
}
|
||||||
}
|
|
||||||
|
public interface ISidebarVmFactory : IVmFactory
|
||||||
public interface ISidebarVmFactory : IVmFactory
|
{
|
||||||
{
|
SidebarViewModel? SidebarViewModel(IScreen hostScreen);
|
||||||
SidebarViewModel? SidebarViewModel(IScreen hostScreen);
|
SidebarCategoryViewModel SidebarCategoryViewModel(SidebarViewModel sidebarViewModel, ProfileCategory profileCategory);
|
||||||
SidebarCategoryViewModel SidebarCategoryViewModel(SidebarViewModel sidebarViewModel, ProfileCategory profileCategory);
|
SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(SidebarViewModel sidebarViewModel, ProfileConfiguration profileConfiguration);
|
||||||
SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(SidebarViewModel sidebarViewModel, ProfileConfiguration profileConfiguration);
|
}
|
||||||
}
|
|
||||||
|
public interface ISurfaceVmFactory : IVmFactory
|
||||||
public interface ISurfaceVmFactory : IVmFactory
|
{
|
||||||
{
|
SurfaceDeviceViewModel SurfaceDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel);
|
||||||
SurfaceDeviceViewModel SurfaceDeviceViewModel(ArtemisDevice device);
|
ListDeviceViewModel ListDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel);
|
||||||
ListDeviceViewModel ListDeviceViewModel(ArtemisDevice device);
|
}
|
||||||
}
|
|
||||||
|
public interface IPrerequisitesVmFactory : IVmFactory
|
||||||
public interface IPrerequisitesVmFactory : IVmFactory
|
{
|
||||||
{
|
PluginPrerequisiteViewModel PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall);
|
||||||
PluginPrerequisiteViewModel PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall);
|
}
|
||||||
}
|
|
||||||
|
public interface IProfileEditorVmFactory : IVmFactory
|
||||||
public interface IProfileEditorVmFactory : IVmFactory
|
{
|
||||||
{
|
ProfileEditorViewModel ProfileEditorViewModel(IScreen hostScreen);
|
||||||
ProfileEditorViewModel ProfileEditorViewModel(IScreen hostScreen);
|
FolderTreeItemViewModel FolderTreeItemViewModel(TreeItemViewModel? parent, Folder folder);
|
||||||
FolderTreeItemViewModel FolderTreeItemViewModel(TreeItemViewModel? parent, Folder folder);
|
LayerTreeItemViewModel LayerTreeItemViewModel(TreeItemViewModel? parent, Layer layer);
|
||||||
LayerTreeItemViewModel LayerTreeItemViewModel(TreeItemViewModel? parent, Layer layer);
|
LayerShapeVisualizerViewModel LayerShapeVisualizerViewModel(Layer layer);
|
||||||
LayerShapeVisualizerViewModel LayerShapeVisualizerViewModel(Layer layer);
|
LayerVisualizerViewModel LayerVisualizerViewModel(Layer layer);
|
||||||
LayerVisualizerViewModel LayerVisualizerViewModel(Layer layer);
|
}
|
||||||
}
|
|
||||||
|
public interface ILayerPropertyVmFactory : IVmFactory
|
||||||
public interface ILayerPropertyVmFactory : IVmFactory
|
{
|
||||||
{
|
PropertyViewModel PropertyViewModel(ILayerProperty layerProperty);
|
||||||
PropertyViewModel PropertyViewModel(ILayerProperty layerProperty);
|
PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup);
|
||||||
PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup);
|
PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerBrush layerBrush);
|
||||||
PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerBrush layerBrush);
|
PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerEffect layerEffect);
|
||||||
PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerEffect layerEffect);
|
|
||||||
|
TreeGroupViewModel TreeGroupViewModel(PropertyGroupViewModel propertyGroupViewModel);
|
||||||
TreeGroupViewModel TreeGroupViewModel(PropertyGroupViewModel propertyGroupViewModel);
|
|
||||||
|
TimelineViewModel TimelineViewModel(ObservableCollection<PropertyGroupViewModel> propertyGroupViewModels);
|
||||||
TimelineViewModel TimelineViewModel(ObservableCollection<PropertyGroupViewModel> propertyGroupViewModels);
|
TimelineGroupViewModel TimelineGroupViewModel(PropertyGroupViewModel propertyGroupViewModel);
|
||||||
TimelineGroupViewModel TimelineGroupViewModel(PropertyGroupViewModel propertyGroupViewModel);
|
}
|
||||||
}
|
|
||||||
|
public interface IDataBindingVmFactory : IVmFactory
|
||||||
public interface IDataBindingVmFactory : IVmFactory
|
{
|
||||||
{
|
DataBindingViewModel DataBindingViewModel();
|
||||||
DataBindingViewModel DataBindingViewModel();
|
}
|
||||||
}
|
|
||||||
|
public interface IPropertyVmFactory
|
||||||
public interface IPropertyVmFactory
|
{
|
||||||
{
|
ITreePropertyViewModel TreePropertyViewModel(ILayerProperty layerProperty, PropertyViewModel propertyViewModel);
|
||||||
ITreePropertyViewModel TreePropertyViewModel(ILayerProperty layerProperty, PropertyViewModel propertyViewModel);
|
ITimelinePropertyViewModel TimelinePropertyViewModel(ILayerProperty layerProperty, PropertyViewModel propertyViewModel);
|
||||||
ITimelinePropertyViewModel TimelinePropertyViewModel(ILayerProperty layerProperty, PropertyViewModel propertyViewModel);
|
}
|
||||||
}
|
|
||||||
|
public interface INodeVmFactory : IVmFactory
|
||||||
public interface INodeVmFactory : IVmFactory
|
{
|
||||||
{
|
NodeScriptViewModel NodeScriptViewModel(NodeScript nodeScript, bool isPreview);
|
||||||
NodeScriptViewModel NodeScriptViewModel(NodeScript nodeScript, bool isPreview);
|
NodePickerViewModel NodePickerViewModel(NodeScript nodeScript);
|
||||||
NodePickerViewModel NodePickerViewModel(NodeScript nodeScript);
|
NodeViewModel NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node);
|
||||||
NodeViewModel NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node);
|
CableViewModel CableViewModel(NodeScriptViewModel nodeScriptViewModel, IPin from, IPin to);
|
||||||
CableViewModel CableViewModel(NodeScriptViewModel nodeScriptViewModel, IPin from, IPin to);
|
DragCableViewModel DragCableViewModel(PinViewModel pinViewModel);
|
||||||
DragCableViewModel DragCableViewModel(PinViewModel pinViewModel);
|
InputPinViewModel InputPinViewModel(IPin inputPin);
|
||||||
InputPinViewModel InputPinViewModel(IPin inputPin);
|
OutputPinViewModel OutputPinViewModel(IPin outputPin);
|
||||||
OutputPinViewModel OutputPinViewModel(IPin outputPin);
|
InputPinCollectionViewModel InputPinCollectionViewModel(IPinCollection inputPinCollection, NodeScriptViewModel nodeScriptViewModel);
|
||||||
InputPinCollectionViewModel InputPinCollectionViewModel(IPinCollection inputPinCollection, NodeScriptViewModel nodeScriptViewModel);
|
OutputPinCollectionViewModel OutputPinCollectionViewModel(IPinCollection outputPinCollection, NodeScriptViewModel nodeScriptViewModel);
|
||||||
OutputPinCollectionViewModel OutputPinCollectionViewModel(IPinCollection outputPinCollection, NodeScriptViewModel nodeScriptViewModel);
|
}
|
||||||
}
|
|
||||||
|
public interface IConditionVmFactory : IVmFactory
|
||||||
public interface IConditionVmFactory : IVmFactory
|
{
|
||||||
{
|
AlwaysOnConditionViewModel AlwaysOnConditionViewModel(AlwaysOnCondition alwaysOnCondition);
|
||||||
AlwaysOnConditionViewModel AlwaysOnConditionViewModel(AlwaysOnCondition alwaysOnCondition);
|
PlayOnceConditionViewModel PlayOnceConditionViewModel(PlayOnceCondition playOnceCondition);
|
||||||
PlayOnceConditionViewModel PlayOnceConditionViewModel(PlayOnceCondition playOnceCondition);
|
StaticConditionViewModel StaticConditionViewModel(StaticCondition staticCondition);
|
||||||
StaticConditionViewModel StaticConditionViewModel(StaticCondition staticCondition);
|
EventConditionViewModel EventConditionViewModel(EventCondition eventCondition);
|
||||||
EventConditionViewModel EventConditionViewModel(EventCondition eventCondition);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -4,5 +4,5 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
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!
|
Welcome to Avalonia!
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,18 +1,17 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.SurfaceEditor
|
namespace Artemis.UI.Screens.SurfaceEditor;
|
||||||
{
|
|
||||||
public partial class ListDeviceView : UserControl
|
|
||||||
{
|
|
||||||
public ListDeviceView()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeComponent()
|
public class ListDeviceView : UserControl
|
||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
public ListDeviceView()
|
||||||
}
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,32 +1,32 @@
|
|||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using ReactiveUI;
|
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.SurfaceEditor
|
namespace Artemis.UI.Screens.SurfaceEditor;
|
||||||
|
|
||||||
|
public class ListDeviceViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
public class ListDeviceViewModel : ViewModelBase
|
private SKColor _color;
|
||||||
|
private bool _isSelected;
|
||||||
|
|
||||||
|
public ListDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel)
|
||||||
{
|
{
|
||||||
private SKColor _color;
|
Device = device;
|
||||||
private bool _isSelected;
|
SurfaceEditorViewModel = surfaceEditorViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
public ListDeviceViewModel(ArtemisDevice device)
|
public ArtemisDevice Device { get; }
|
||||||
{
|
public SurfaceEditorViewModel SurfaceEditorViewModel { get; }
|
||||||
Device = device;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArtemisDevice Device { get; }
|
public bool IsSelected
|
||||||
|
{
|
||||||
|
get => _isSelected;
|
||||||
|
set => RaiseAndSetIfChanged(ref _isSelected, value);
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsSelected
|
public SKColor Color
|
||||||
{
|
{
|
||||||
get => _isSelected;
|
get => _color;
|
||||||
set => RaiseAndSetIfChanged(ref _isSelected, value);
|
set => RaiseAndSetIfChanged(ref _color, value);
|
||||||
}
|
|
||||||
|
|
||||||
public SKColor Color
|
|
||||||
{
|
|
||||||
get => _color;
|
|
||||||
set => RaiseAndSetIfChanged(ref _color, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,9 +3,13 @@
|
|||||||
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: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.SurfaceDeviceView">
|
x:Class="Artemis.UI.Screens.SurfaceEditor.SurfaceDeviceView"
|
||||||
<Grid>
|
x:DataType="surfaceEditor:SurfaceDeviceViewModel">
|
||||||
|
<Grid PointerMoved="InputElement_OnPointerMoved"
|
||||||
|
PointerReleased="InputElement_OnPointerReleased"
|
||||||
|
Cursor="Hand">
|
||||||
<Grid.Styles>
|
<Grid.Styles>
|
||||||
<Style Selector="Border.selection-border">
|
<Style Selector="Border.selection-border">
|
||||||
<Setter Property="Opacity" Value="0" />
|
<Setter Property="Opacity" Value="0" />
|
||||||
@ -15,22 +19,26 @@
|
|||||||
</Transitions>
|
</Transitions>
|
||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Border.selection-border-selected">
|
<Style Selector="Border.deselected:pointerover">
|
||||||
|
<Setter Property="Opacity" Value="0.5" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="Border.selected">
|
||||||
<Setter Property="Opacity" Value="1" />
|
<Setter Property="Opacity" Value="1" />
|
||||||
</Style>
|
</Style>
|
||||||
</Grid.Styles>
|
</Grid.Styles>
|
||||||
|
|
||||||
<shared:DeviceVisualizer Device="{Binding Device}" ShowColors="True"/>
|
<shared:DeviceVisualizer Device="{CompiledBinding Device}" ShowColors="True" />
|
||||||
<Border x:Name="SurfaceDeviceBorder"
|
<Border x:Name="SurfaceDeviceBorder"
|
||||||
Classes="selection-border"
|
Classes="selection-border"
|
||||||
Classes.selection-border-selected="{Binding Highlighted}"
|
Classes.selected="{CompiledBinding IsSelected}"
|
||||||
|
Classes.deselected="{CompiledBinding !IsSelected}"
|
||||||
BorderThickness="1">
|
BorderThickness="1">
|
||||||
<Border.BorderBrush>
|
<Border.BorderBrush>
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorLight2}"></SolidColorBrush>
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorLight2}" />
|
||||||
</Border.BorderBrush>
|
</Border.BorderBrush>
|
||||||
<Border.Background>
|
<Border.Background>
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorLight2}" Opacity="0.2"></SolidColorBrush>
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorLight2}" Opacity="0.2" />
|
||||||
</Border.Background>
|
</Border.Background>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|||||||
@ -1,43 +1,68 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
using Avalonia.VisualTree;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.SurfaceEditor
|
namespace Artemis.UI.Screens.SurfaceEditor;
|
||||||
|
|
||||||
|
public class SurfaceDeviceView : ReactiveUserControl<SurfaceDeviceViewModel>
|
||||||
{
|
{
|
||||||
public class SurfaceDeviceView : ReactiveUserControl<SurfaceDeviceViewModel>
|
private bool _dragging;
|
||||||
|
|
||||||
|
public SurfaceDeviceView()
|
||||||
{
|
{
|
||||||
public SurfaceDeviceView()
|
InitializeComponent();
|
||||||
{
|
}
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
private void InitializeComponent()
|
||||||
protected override void OnPointerEnter(PointerEventArgs e)
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InputElement_OnPointerMoved(object? sender, PointerEventArgs e)
|
||||||
|
{
|
||||||
|
PointerPoint point = e.GetCurrentPoint(this.FindAncestorOfType<Canvas>());
|
||||||
|
if (ViewModel == null || !point.Properties.IsLeftButtonPressed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_dragging)
|
||||||
{
|
{
|
||||||
if (ViewModel?.SelectionStatus == SelectionStatus.None)
|
_dragging = true;
|
||||||
|
|
||||||
|
if (!ViewModel.IsSelected)
|
||||||
{
|
{
|
||||||
ViewModel.SelectionStatus = SelectionStatus.Hover;
|
ViewModel.SurfaceEditorViewModel.UpdateSelection(new List<SurfaceDeviceViewModel> {ViewModel}, false, false);
|
||||||
Cursor = new Cursor(StandardCursorType.Hand);
|
ViewModel.SurfaceEditorViewModel.FinishSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnPointerEnter(e);
|
ViewModel.SurfaceEditorViewModel.StartMouseDrag(point.Position);
|
||||||
|
e.Pointer.Capture((IInputElement?) sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
ViewModel.SurfaceEditorViewModel.UpdateMouseDrag(point.Position, e.KeyModifiers.HasFlag(KeyModifiers.Shift), e.KeyModifiers.HasFlag(KeyModifiers.Alt));
|
||||||
protected override void OnPointerLeave(PointerEventArgs e)
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||||
|
{
|
||||||
|
if (ViewModel == null || e.InitialPressMouseButton != MouseButton.Left)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_dragging)
|
||||||
{
|
{
|
||||||
if (ViewModel?.SelectionStatus == SelectionStatus.Hover)
|
_dragging = false;
|
||||||
{
|
ViewModel.SurfaceEditorViewModel.FinishSelection();
|
||||||
ViewModel.SelectionStatus = SelectionStatus.None;
|
e.Pointer.Capture(null);
|
||||||
Cursor = new Cursor(StandardCursorType.Arrow);
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnPointerLeave(e);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
ViewModel.SurfaceEditorViewModel.UpdateSelection(new List<SurfaceDeviceViewModel> {ViewModel}, e.KeyModifiers.HasFlag(KeyModifiers.Shift), e.KeyModifiers.HasFlag(KeyModifiers.Control));
|
||||||
|
ViewModel.SurfaceEditorViewModel.FinishSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8,143 +8,123 @@ using Artemis.Core.Services;
|
|||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Avalonia.Input;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using Point = Avalonia.Point;
|
using Point = Avalonia.Point;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.SurfaceEditor
|
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 ISettingsService _settingsService;
|
||||||
|
private readonly IWindowService _windowService;
|
||||||
|
private double _dragOffsetX;
|
||||||
|
private double _dragOffsetY;
|
||||||
|
private bool _isSelected;
|
||||||
|
|
||||||
|
public SurfaceDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel, IRgbService rgbService, IDeviceService deviceService, ISettingsService settingsService,
|
||||||
|
IDeviceVmFactory deviceVmFactory,
|
||||||
|
IWindowService windowService)
|
||||||
{
|
{
|
||||||
private readonly IRgbService _rgbService;
|
_rgbService = rgbService;
|
||||||
private readonly IDeviceService _deviceService;
|
_deviceService = deviceService;
|
||||||
private readonly ISettingsService _settingsService;
|
_settingsService = settingsService;
|
||||||
private readonly IDeviceVmFactory _deviceVmFactory;
|
_deviceVmFactory = deviceVmFactory;
|
||||||
private readonly IWindowService _windowService;
|
_windowService = windowService;
|
||||||
private Cursor _cursor;
|
|
||||||
private double _dragOffsetX;
|
|
||||||
private double _dragOffsetY;
|
|
||||||
private SelectionStatus _selectionStatus;
|
|
||||||
|
|
||||||
public SurfaceDeviceViewModel(ArtemisDevice device, IRgbService rgbService, IDeviceService deviceService, ISettingsService settingsService, IDeviceVmFactory deviceVmFactory,
|
Device = device;
|
||||||
IWindowService windowService)
|
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 SurfaceEditorViewModel SurfaceEditorViewModel { get; }
|
||||||
|
|
||||||
|
public bool IsSelected
|
||||||
|
{
|
||||||
|
get => _isSelected;
|
||||||
|
set => RaiseAndSetIfChanged(ref _isSelected, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanDetectInput => Device.DeviceType == RGBDeviceType.Keyboard || Device.DeviceType == RGBDeviceType.Mouse;
|
||||||
|
|
||||||
|
public void StartMouseDrag(Point mouseStartPosition)
|
||||||
|
{
|
||||||
|
if (!IsSelected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_dragOffsetX = Device.X - mouseStartPosition.X;
|
||||||
|
_dragOffsetY = Device.Y - mouseStartPosition.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateMouseDrag(Point mousePosition, bool round, bool ignoreOverlap)
|
||||||
|
{
|
||||||
|
if (!IsSelected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float x = (float) (mousePosition.X + _dragOffsetX);
|
||||||
|
float y = (float) (mousePosition.Y + _dragOffsetY);
|
||||||
|
|
||||||
|
if (round)
|
||||||
{
|
{
|
||||||
_rgbService = rgbService;
|
x = (float) Math.Round(x / 10d, 0, MidpointRounding.AwayFromZero) * 10f;
|
||||||
_deviceService = deviceService;
|
y = (float) Math.Round(y / 10d, 0, MidpointRounding.AwayFromZero) * 10f;
|
||||||
_settingsService = settingsService;
|
|
||||||
_deviceVmFactory = deviceVmFactory;
|
|
||||||
_windowService = windowService;
|
|
||||||
_cursor = Cursor.Default;
|
|
||||||
|
|
||||||
Device = device;
|
|
||||||
|
|
||||||
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; }
|
if (Fits(x, y, ignoreOverlap))
|
||||||
|
|
||||||
public SelectionStatus SelectionStatus
|
|
||||||
{
|
{
|
||||||
get => _selectionStatus;
|
Device.X = x;
|
||||||
set
|
Device.Y = y;
|
||||||
{
|
|
||||||
RaiseAndSetIfChanged(ref _selectionStatus, value);
|
|
||||||
this.RaisePropertyChanged(nameof(Highlighted));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (Fits(x, Device.Y, ignoreOverlap))
|
||||||
public bool Highlighted => SelectionStatus != SelectionStatus.None;
|
|
||||||
|
|
||||||
public bool CanDetectInput => Device.DeviceType == RGBDeviceType.Keyboard || Device.DeviceType == RGBDeviceType.Mouse;
|
|
||||||
|
|
||||||
public Cursor Cursor
|
|
||||||
{
|
{
|
||||||
get => _cursor;
|
Device.X = x;
|
||||||
set => RaiseAndSetIfChanged(ref _cursor, value);
|
|
||||||
}
|
}
|
||||||
|
else if (Fits(Device.X, y, ignoreOverlap))
|
||||||
public void StartMouseDrag(Point mouseStartPosition)
|
|
||||||
{
|
{
|
||||||
if (SelectionStatus != SelectionStatus.Selected)
|
Device.Y = y;
|
||||||
return;
|
|
||||||
|
|
||||||
_dragOffsetX = Device.X - mouseStartPosition.X;
|
|
||||||
_dragOffsetY = Device.Y - mouseStartPosition.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateMouseDrag(Point mousePosition, bool round, bool ignoreOverlap)
|
|
||||||
{
|
|
||||||
if (SelectionStatus != SelectionStatus.Selected)
|
|
||||||
return;
|
|
||||||
|
|
||||||
float x = (float) (mousePosition.X + _dragOffsetX);
|
|
||||||
float y = (float) (mousePosition.Y + _dragOffsetY);
|
|
||||||
|
|
||||||
if (round)
|
|
||||||
{
|
|
||||||
x = (float) Math.Round(x / 10d, 0, MidpointRounding.AwayFromZero) * 10f;
|
|
||||||
y = (float) Math.Round(y / 10d, 0, MidpointRounding.AwayFromZero) * 10f;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (Fits(x, y, ignoreOverlap))
|
|
||||||
{
|
|
||||||
Device.X = x;
|
|
||||||
Device.Y = y;
|
|
||||||
}
|
|
||||||
else if (Fits(x, Device.Y, ignoreOverlap))
|
|
||||||
{
|
|
||||||
Device.X = x;
|
|
||||||
}
|
|
||||||
else if (Fits(Device.X, y, ignoreOverlap))
|
|
||||||
{
|
|
||||||
Device.Y = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (x < 0 || y < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
double maxTextureSize = 4096 / _settingsService.GetSetting("Core.RenderScale", 0.25).Value;
|
|
||||||
if (x + Device.Rectangle.Width > maxTextureSize || y + Device.Rectangle.Height > maxTextureSize)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (ignoreOverlap)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
IEnumerable<SKRect> own = Device.Leds
|
|
||||||
.Select(l => SKRect.Create(l.Rectangle.Left + x, l.Rectangle.Top + y, l.Rectangle.Width, l.Rectangle.Height));
|
|
||||||
IEnumerable<SKRect> others = _rgbService.EnabledDevices
|
|
||||||
.Where(d => d != Device && d.IsEnabled)
|
|
||||||
.SelectMany(d => d.Leds)
|
|
||||||
.Select(l => SKRect.Create(l.Rectangle.Left + l.Device.X, l.Rectangle.Top + l.Device.Y, l.Rectangle.Width, l.Rectangle.Height));
|
|
||||||
|
|
||||||
return !own.Any(o => others.Any(l => l.IntersectsWith(o)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SelectionStatus
|
private void ExecuteIdentifyDevice(ArtemisDevice device)
|
||||||
{
|
{
|
||||||
None,
|
_deviceService.IdentifyDevice(device);
|
||||||
Hover,
|
}
|
||||||
Selected
|
|
||||||
|
private async Task ExecuteViewProperties(ArtemisDevice device)
|
||||||
|
{
|
||||||
|
await _windowService.ShowDialogAsync(_deviceVmFactory.DevicePropertiesViewModel(device));
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Fits(float x, float y, bool ignoreOverlap)
|
||||||
|
{
|
||||||
|
if (x < 0 || y < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
double maxTextureSize = 4096 / _settingsService.GetSetting("Core.RenderScale", 0.25).Value;
|
||||||
|
if (x + Device.Rectangle.Width > maxTextureSize || y + Device.Rectangle.Height > maxTextureSize)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ignoreOverlap)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
IEnumerable<SKRect> own = Device.Leds
|
||||||
|
.Select(l => SKRect.Create(l.Rectangle.Left + x, l.Rectangle.Top + y, l.Rectangle.Width, l.Rectangle.Height));
|
||||||
|
IEnumerable<SKRect> others = _rgbService.EnabledDevices
|
||||||
|
.Where(d => d != Device && d.IsEnabled)
|
||||||
|
.SelectMany(d => d.Leds)
|
||||||
|
.Select(l => SKRect.Create(l.Rectangle.Left + l.Device.X, l.Rectangle.Top + l.Device.Y, l.Rectangle.Width, l.Rectangle.Height));
|
||||||
|
|
||||||
|
return !own.Any(o => others.Any(l => l.IntersectsWith(o)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -28,16 +28,14 @@
|
|||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Background="{StaticResource LargeCheckerboardBrush}"
|
Background="{StaticResource LargeCheckerboardBrush}"
|
||||||
ZoomChanged="ZoomBorder_OnZoomChanged"
|
ZoomChanged="ZoomBorder_OnZoomChanged"
|
||||||
PointerPressed="ZoomBorder_OnPointerPressed"
|
|
||||||
PointerMoved="ZoomBorder_OnPointerMoved"
|
|
||||||
PointerReleased="ZoomBorder_OnPointerReleased">
|
PointerReleased="ZoomBorder_OnPointerReleased">
|
||||||
<Grid Name="ContainerGrid" Background="Transparent">
|
<Grid Name="ContainerGrid" Background="Transparent">
|
||||||
<Grid.Transitions>
|
<Grid.Transitions>
|
||||||
<Transitions>
|
<Transitions>
|
||||||
<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 Items="{Binding SurfaceDeviceViewModels}" ClipToBounds="False">
|
<ItemsControl Name="DeviceContainer" Items="{Binding 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}" />
|
||||||
@ -102,12 +100,12 @@
|
|||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|
||||||
<shared:SelectionRectangle Name="SelectionRectangle"
|
<shared:SelectionRectangle Name="SelectionRectangle"
|
||||||
InputElement="{Binding #ZoomBorder}"
|
InputElement="{Binding #ZoomBorder}"
|
||||||
SelectionUpdated="SelectionRectangle_OnSelectionUpdated"
|
SelectionUpdated="SelectionRectangle_OnSelectionUpdated"
|
||||||
BorderBrush="{DynamicResource SystemAccentColor}"
|
BorderBrush="{DynamicResource SystemAccentColor}"
|
||||||
BorderRadius="8">
|
BorderRadius="8">
|
||||||
<shared:SelectionRectangle.Background>
|
<shared:SelectionRectangle.Background>
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorLight1}" Opacity="0.2"></SolidColorBrush>
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorLight1}" Opacity="0.2" />
|
||||||
</shared:SelectionRectangle.Background>
|
</shared:SelectionRectangle.Background>
|
||||||
</shared:SelectionRectangle>
|
</shared:SelectionRectangle>
|
||||||
|
|
||||||
|
|||||||
@ -1,112 +1,72 @@
|
|||||||
using System.Reactive;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Events;
|
using Artemis.UI.Shared.Events;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Generators;
|
||||||
using Avalonia.Controls.PanAndZoom;
|
using Avalonia.Controls.PanAndZoom;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.SurfaceEditor
|
namespace Artemis.UI.Screens.SurfaceEditor;
|
||||||
|
|
||||||
|
public class SurfaceEditorView : ReactiveUserControl<SurfaceEditorViewModel>
|
||||||
{
|
{
|
||||||
public class SurfaceEditorView : ReactiveUserControl<SurfaceEditorViewModel>
|
private readonly ItemsControl _deviceContainer;
|
||||||
|
private readonly SelectionRectangle _selectionRectangle;
|
||||||
|
private readonly Border _surfaceBounds;
|
||||||
|
private readonly ZoomBorder _zoomBorder;
|
||||||
|
|
||||||
|
public SurfaceEditorView()
|
||||||
{
|
{
|
||||||
private readonly Grid _containerGrid;
|
InitializeComponent();
|
||||||
private readonly SelectionRectangle _selectionRectangle;
|
|
||||||
private readonly Border _surfaceBounds;
|
|
||||||
private readonly ZoomBorder _zoomBorder;
|
|
||||||
private bool _dragging;
|
|
||||||
|
|
||||||
public SurfaceEditorView()
|
_zoomBorder = this.Find<ZoomBorder>("ZoomBorder");
|
||||||
{
|
_deviceContainer = this.Find<ItemsControl>("DeviceContainer");
|
||||||
InitializeComponent();
|
_selectionRectangle = this.Find<SelectionRectangle>("SelectionRectangle");
|
||||||
|
_surfaceBounds = this.Find<Border>("SurfaceBounds");
|
||||||
|
|
||||||
_zoomBorder = this.Find<ZoomBorder>("ZoomBorder");
|
_zoomBorder.PropertyChanged += ZoomBorderOnPropertyChanged;
|
||||||
_containerGrid = this.Find<Grid>("ContainerGrid");
|
UpdateZoomBorderBackground();
|
||||||
_selectionRectangle = this.Find<SelectionRectangle>("SelectionRectangle");
|
}
|
||||||
_surfaceBounds = this.Find<Border>("SurfaceBounds");
|
|
||||||
|
|
||||||
_zoomBorder.PropertyChanged += ZoomBorderOnPropertyChanged;
|
private void ZoomBorderOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Property.Name == nameof(_zoomBorder.Background))
|
||||||
UpdateZoomBorderBackground();
|
UpdateZoomBorderBackground();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ZoomBorderOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
if (e.Property.Name == nameof(_zoomBorder.Background))
|
AvaloniaXamlLoader.Load(this);
|
||||||
UpdateZoomBorderBackground();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeComponent()
|
private void ZoomBorder_OnZoomChanged(object sender, ZoomChangedEventArgs e)
|
||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
UpdateZoomBorderBackground();
|
||||||
}
|
_selectionRectangle.BorderThickness = 1 / _zoomBorder.ZoomX;
|
||||||
|
_surfaceBounds.BorderThickness = new Thickness(2 / _zoomBorder.ZoomX);
|
||||||
|
}
|
||||||
|
|
||||||
private void ZoomBorder_OnZoomChanged(object sender, ZoomChangedEventArgs e)
|
private void SelectionRectangle_OnSelectionUpdated(object? sender, SelectionRectangleEventArgs e)
|
||||||
{
|
{
|
||||||
UpdateZoomBorderBackground();
|
List<ItemContainerInfo> itemContainerInfos = _deviceContainer.ItemContainerGenerator.Containers.Where(c => c.ContainerControl.Bounds.Intersects(e.Rectangle)).ToList();
|
||||||
_selectionRectangle.BorderThickness = 1 / _zoomBorder.ZoomX;
|
List<SurfaceDeviceViewModel> viewModels = itemContainerInfos.Where(c => c.Item is SurfaceDeviceViewModel).Select(c => (SurfaceDeviceViewModel) c.Item).ToList();
|
||||||
_surfaceBounds.BorderThickness = new Thickness(2 / _zoomBorder.ZoomX);
|
ViewModel?.UpdateSelection(viewModels, e.KeyModifiers.HasFlag(KeyModifiers.Shift), e.KeyModifiers.HasFlag(KeyModifiers.Control));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ZoomBorder_OnPointerPressed(object? sender, PointerPressedEventArgs e)
|
private void ZoomBorder_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||||
{
|
{
|
||||||
if (!e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
if (!_selectionRectangle.IsSelecting && e.InitialPressMouseButton == MouseButton.Left)
|
||||||
return;
|
ViewModel?.ClearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
_dragging = false;
|
private void UpdateZoomBorderBackground()
|
||||||
|
{
|
||||||
if (e.Source is Border {Name: "SurfaceDeviceBorder"})
|
if (_zoomBorder.Background is VisualBrush visualBrush)
|
||||||
{
|
visualBrush.DestinationRect = new RelativeRect(_zoomBorder.OffsetX * -1, _zoomBorder.OffsetY * -1, 20, 20, RelativeUnit.Absolute);
|
||||||
e.Pointer.Capture(_zoomBorder);
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ZoomBorder_OnPointerMoved(object? sender, PointerEventArgs e)
|
|
||||||
{
|
|
||||||
if (!e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ReferenceEquals(e.Pointer.Captured, sender))
|
|
||||||
{
|
|
||||||
if (!_dragging)
|
|
||||||
ViewModel?.StartMouseDrag(e.GetPosition(_containerGrid));
|
|
||||||
ViewModel?.UpdateMouseDrag(e.GetPosition(_containerGrid), e.KeyModifiers.HasFlag(KeyModifiers.Shift), e.KeyModifiers.HasFlag(KeyModifiers.Alt));
|
|
||||||
}
|
|
||||||
|
|
||||||
_dragging = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ZoomBorder_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.InitialPressMouseButton != MouseButton.Left)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// If the mouse didn't move, apply selection
|
|
||||||
if (!_dragging)
|
|
||||||
{
|
|
||||||
ViewModel?.SelectFirstDeviceAtPoint(e.GetPosition(_containerGrid), e.KeyModifiers.HasFlag(KeyModifiers.Shift));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ReferenceEquals(e.Pointer.Captured, sender))
|
|
||||||
{
|
|
||||||
ViewModel?.StopMouseDrag(e.GetPosition(_containerGrid), e.KeyModifiers.HasFlag(KeyModifiers.Shift), e.KeyModifiers.HasFlag(KeyModifiers.Alt));
|
|
||||||
e.Pointer.Capture(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SelectionRectangle_OnSelectionUpdated(object? sender, SelectionRectangleEventArgs e)
|
|
||||||
{
|
|
||||||
ViewModel?.UpdateSelection(e.Rectangle, e.KeyModifiers.HasFlag(KeyModifiers.Shift));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateZoomBorderBackground()
|
|
||||||
{
|
|
||||||
if (_zoomBorder.Background is VisualBrush visualBrush)
|
|
||||||
visualBrush.DestinationRect = new RelativeRect(_zoomBorder.OffsetX * -1, _zoomBorder.OffsetY * -1, 20, 20, RelativeUnit.Absolute);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
@ -8,201 +9,178 @@ using Artemis.Core.Services;
|
|||||||
using Artemis.UI.Extensions;
|
using Artemis.UI.Extensions;
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Skia;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.SurfaceEditor
|
namespace Artemis.UI.Screens.SurfaceEditor;
|
||||||
|
|
||||||
|
public class SurfaceEditorViewModel : MainScreenViewModel
|
||||||
{
|
{
|
||||||
public class SurfaceEditorViewModel : MainScreenViewModel
|
private readonly IRgbService _rgbService;
|
||||||
|
private readonly ISettingsService _settingsService;
|
||||||
|
private List<SurfaceDeviceViewModel>? _initialSelection;
|
||||||
|
private bool _saving;
|
||||||
|
|
||||||
|
public SurfaceEditorViewModel(IScreen hostScreen,
|
||||||
|
IRgbService rgbService,
|
||||||
|
ISurfaceVmFactory surfaceVmFactory,
|
||||||
|
ISettingsService settingsService) : base(hostScreen, "surface-editor")
|
||||||
{
|
{
|
||||||
private readonly IRgbService _rgbService;
|
_rgbService = rgbService;
|
||||||
private readonly ISettingsService _settingsService;
|
_settingsService = settingsService;
|
||||||
private bool _saving;
|
DisplayName = "Surface Editor";
|
||||||
|
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)));
|
||||||
|
|
||||||
public SurfaceEditorViewModel(IScreen hostScreen,
|
BringToFront = ReactiveCommand.Create<ArtemisDevice>(ExecuteBringToFront);
|
||||||
IRgbService rgbService,
|
BringForward = ReactiveCommand.Create<ArtemisDevice>(ExecuteBringForward);
|
||||||
ISurfaceVmFactory surfaceVmFactory,
|
SendToBack = ReactiveCommand.Create<ArtemisDevice>(ExecuteSendToBack);
|
||||||
ISettingsService settingsService) : base(hostScreen, "surface-editor")
|
SendBackward = ReactiveCommand.Create<ArtemisDevice>(ExecuteSendBackward);
|
||||||
{
|
|
||||||
_rgbService = rgbService;
|
|
||||||
_settingsService = settingsService;
|
|
||||||
DisplayName = "Surface Editor";
|
|
||||||
SurfaceDeviceViewModels = new ObservableCollection<SurfaceDeviceViewModel>(rgbService.Devices.OrderBy(d => d.ZIndex).Select(surfaceVmFactory.SurfaceDeviceViewModel));
|
|
||||||
ListDeviceViewModels = new ObservableCollection<ListDeviceViewModel>(rgbService.Devices.OrderBy(d => d.ZIndex).Select(surfaceVmFactory.ListDeviceViewModel));
|
|
||||||
|
|
||||||
BringToFront = ReactiveCommand.Create<ArtemisDevice>(ExecuteBringToFront);
|
|
||||||
BringForward = ReactiveCommand.Create<ArtemisDevice>(ExecuteBringForward);
|
|
||||||
SendToBack = ReactiveCommand.Create<ArtemisDevice>(ExecuteSendToBack);
|
|
||||||
SendBackward = ReactiveCommand.Create<ArtemisDevice>(ExecuteSendBackward);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableCollection<SurfaceDeviceViewModel> SurfaceDeviceViewModels { get; }
|
|
||||||
public ObservableCollection<ListDeviceViewModel> ListDeviceViewModels { get; }
|
|
||||||
|
|
||||||
public ReactiveCommand<ArtemisDevice, Unit> BringToFront { get; }
|
|
||||||
public ReactiveCommand<ArtemisDevice, Unit> BringForward { get; }
|
|
||||||
public ReactiveCommand<ArtemisDevice, Unit> SendToBack { get; }
|
|
||||||
public ReactiveCommand<ArtemisDevice, Unit> SendBackward { get; }
|
|
||||||
|
|
||||||
public double MaxTextureSize => 4096 / _settingsService.GetSetting("Core.RenderScale", 0.25).Value;
|
|
||||||
|
|
||||||
public void ClearSelection()
|
|
||||||
{
|
|
||||||
foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in SurfaceDeviceViewModels)
|
|
||||||
surfaceDeviceViewModel.SelectionStatus = SelectionStatus.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StartMouseDrag(Point mousePosition)
|
|
||||||
{
|
|
||||||
SurfaceDeviceViewModel? startedOn = GetViewModelAtPoint(mousePosition);
|
|
||||||
if (startedOn != null && startedOn.SelectionStatus != SelectionStatus.Selected)
|
|
||||||
{
|
|
||||||
startedOn.SelectionStatus = SelectionStatus.Selected;
|
|
||||||
foreach (SurfaceDeviceViewModel device in SurfaceDeviceViewModels.Where(vm => vm != startedOn))
|
|
||||||
device.SelectionStatus = SelectionStatus.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in SurfaceDeviceViewModels)
|
|
||||||
surfaceDeviceViewModel.StartMouseDrag(mousePosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateMouseDrag(Point mousePosition, bool round, bool ignoreOverlap)
|
|
||||||
{
|
|
||||||
foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in SurfaceDeviceViewModels)
|
|
||||||
surfaceDeviceViewModel.UpdateMouseDrag(mousePosition, round, ignoreOverlap);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StopMouseDrag(Point mousePosition, bool round, bool ignoreOverlap)
|
|
||||||
{
|
|
||||||
foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in SurfaceDeviceViewModels)
|
|
||||||
surfaceDeviceViewModel.UpdateMouseDrag(mousePosition, round, ignoreOverlap);
|
|
||||||
|
|
||||||
if (_saving)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_saving = true;
|
|
||||||
_rgbService.SaveDevices();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_saving = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SelectFirstDeviceAtPoint(Point point, bool expand)
|
|
||||||
{
|
|
||||||
SurfaceDeviceViewModel? toSelect = GetViewModelAtPoint(point);
|
|
||||||
if (toSelect != null)
|
|
||||||
toSelect.SelectionStatus = SelectionStatus.Selected;
|
|
||||||
|
|
||||||
if (!expand)
|
|
||||||
{
|
|
||||||
foreach (SurfaceDeviceViewModel device in SurfaceDeviceViewModels.Where(vm => vm != toSelect))
|
|
||||||
device.SelectionStatus = SelectionStatus.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
ApplySurfaceSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
private SurfaceDeviceViewModel? GetViewModelAtPoint(Point point)
|
|
||||||
{
|
|
||||||
SKPoint hitTestPoint = point.ToSKPoint();
|
|
||||||
return SurfaceDeviceViewModels.OrderByDescending(vm => vm.Device.ZIndex).FirstOrDefault(d => d.Device.Rectangle.Contains(hitTestPoint));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateSelection(Rect rect, bool expand)
|
|
||||||
{
|
|
||||||
SKRect hitTestRect = rect.ToSKRect();
|
|
||||||
foreach (SurfaceDeviceViewModel device in SurfaceDeviceViewModels)
|
|
||||||
{
|
|
||||||
if (device.Device.Rectangle.IntersectsWith(hitTestRect))
|
|
||||||
device.SelectionStatus = SelectionStatus.Selected;
|
|
||||||
else if (!expand)
|
|
||||||
device.SelectionStatus = SelectionStatus.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
ApplySurfaceSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplySurfaceSelection()
|
|
||||||
{
|
|
||||||
foreach (ListDeviceViewModel viewModel in ListDeviceViewModels)
|
|
||||||
viewModel.IsSelected = SurfaceDeviceViewModels.Any(s => s.Device == viewModel.Device && s.SelectionStatus == SelectionStatus.Selected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Context menu commands
|
|
||||||
|
|
||||||
private void ExecuteBringToFront(ArtemisDevice device)
|
|
||||||
{
|
|
||||||
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 = SurfaceDeviceViewModels[i];
|
|
||||||
deviceViewModel.Device.ZIndex = i + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1);
|
|
||||||
|
|
||||||
_rgbService.SaveDevices();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExecuteBringForward(ArtemisDevice device)
|
|
||||||
{
|
|
||||||
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 < SurfaceDeviceViewModels.Count; i++)
|
|
||||||
{
|
|
||||||
SurfaceDeviceViewModel deviceViewModel = SurfaceDeviceViewModels[i];
|
|
||||||
deviceViewModel.Device.ZIndex = i + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1);
|
|
||||||
|
|
||||||
_rgbService.SaveDevices();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExecuteSendToBack(ArtemisDevice device)
|
|
||||||
{
|
|
||||||
SurfaceDeviceViewModel surfaceDeviceViewModel = SurfaceDeviceViewModels.First(d => d.Device == device);
|
|
||||||
SurfaceDeviceViewModels.Move(SurfaceDeviceViewModels.IndexOf(surfaceDeviceViewModel), 0);
|
|
||||||
for (int i = 0; i < SurfaceDeviceViewModels.Count; i++)
|
|
||||||
{
|
|
||||||
SurfaceDeviceViewModel deviceViewModel = SurfaceDeviceViewModels[i];
|
|
||||||
deviceViewModel.Device.ZIndex = i + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1);
|
|
||||||
|
|
||||||
_rgbService.SaveDevices();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExecuteSendBackward(ArtemisDevice device)
|
|
||||||
{
|
|
||||||
SurfaceDeviceViewModel surfaceDeviceViewModel = SurfaceDeviceViewModels.First(d => d.Device == device);
|
|
||||||
int currentIndex = SurfaceDeviceViewModels.IndexOf(surfaceDeviceViewModel);
|
|
||||||
int newIndex = Math.Max(currentIndex - 1, 0);
|
|
||||||
SurfaceDeviceViewModels.Move(currentIndex, newIndex);
|
|
||||||
for (int i = 0; i < SurfaceDeviceViewModels.Count; i++)
|
|
||||||
{
|
|
||||||
SurfaceDeviceViewModel deviceViewModel = SurfaceDeviceViewModels[i];
|
|
||||||
deviceViewModel.Device.ZIndex = i + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1);
|
|
||||||
|
|
||||||
_rgbService.SaveDevices();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ObservableCollection<SurfaceDeviceViewModel> SurfaceDeviceViewModels { get; }
|
||||||
|
public ObservableCollection<ListDeviceViewModel> ListDeviceViewModels { get; }
|
||||||
|
|
||||||
|
public ReactiveCommand<ArtemisDevice, Unit> BringToFront { get; }
|
||||||
|
public ReactiveCommand<ArtemisDevice, Unit> BringForward { get; }
|
||||||
|
public ReactiveCommand<ArtemisDevice, Unit> SendToBack { get; }
|
||||||
|
public ReactiveCommand<ArtemisDevice, Unit> SendBackward { get; }
|
||||||
|
|
||||||
|
public double MaxTextureSize => 4096 / _settingsService.GetSetting("Core.RenderScale", 0.25).Value;
|
||||||
|
|
||||||
|
public void UpdateSelection(List<SurfaceDeviceViewModel> devices, bool expand, bool invert)
|
||||||
|
{
|
||||||
|
_initialSelection ??= SurfaceDeviceViewModels.Where(d => d.IsSelected).ToList();
|
||||||
|
|
||||||
|
if (expand)
|
||||||
|
{
|
||||||
|
foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in devices)
|
||||||
|
surfaceDeviceViewModel.IsSelected = true;
|
||||||
|
}
|
||||||
|
else if (invert)
|
||||||
|
{
|
||||||
|
foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in devices)
|
||||||
|
surfaceDeviceViewModel.IsSelected = !_initialSelection.Contains(surfaceDeviceViewModel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in devices)
|
||||||
|
surfaceDeviceViewModel.IsSelected = true;
|
||||||
|
foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in SurfaceDeviceViewModels.Except(devices))
|
||||||
|
surfaceDeviceViewModel.IsSelected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FinishSelection()
|
||||||
|
{
|
||||||
|
_initialSelection = null;
|
||||||
|
|
||||||
|
if (_saving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_saving = true;
|
||||||
|
_rgbService.SaveDevices();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_saving = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearSelection()
|
||||||
|
{
|
||||||
|
foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in SurfaceDeviceViewModels)
|
||||||
|
surfaceDeviceViewModel.IsSelected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartMouseDrag(Point mousePosition)
|
||||||
|
{
|
||||||
|
foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in SurfaceDeviceViewModels)
|
||||||
|
surfaceDeviceViewModel.StartMouseDrag(mousePosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateMouseDrag(Point mousePosition, bool round, bool ignoreOverlap)
|
||||||
|
{
|
||||||
|
foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in SurfaceDeviceViewModels)
|
||||||
|
surfaceDeviceViewModel.UpdateMouseDrag(mousePosition, round, ignoreOverlap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplySurfaceSelection()
|
||||||
|
{
|
||||||
|
foreach (ListDeviceViewModel viewModel in ListDeviceViewModels)
|
||||||
|
viewModel.IsSelected = SurfaceDeviceViewModels.Any(s => s.Device == viewModel.Device && s.IsSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Context menu commands
|
||||||
|
|
||||||
|
private void ExecuteBringToFront(ArtemisDevice device)
|
||||||
|
{
|
||||||
|
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 = SurfaceDeviceViewModels[i];
|
||||||
|
deviceViewModel.Device.ZIndex = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1);
|
||||||
|
|
||||||
|
_rgbService.SaveDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteBringForward(ArtemisDevice device)
|
||||||
|
{
|
||||||
|
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 < SurfaceDeviceViewModels.Count; i++)
|
||||||
|
{
|
||||||
|
SurfaceDeviceViewModel deviceViewModel = SurfaceDeviceViewModels[i];
|
||||||
|
deviceViewModel.Device.ZIndex = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1);
|
||||||
|
|
||||||
|
_rgbService.SaveDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteSendToBack(ArtemisDevice device)
|
||||||
|
{
|
||||||
|
SurfaceDeviceViewModel surfaceDeviceViewModel = SurfaceDeviceViewModels.First(d => d.Device == device);
|
||||||
|
SurfaceDeviceViewModels.Move(SurfaceDeviceViewModels.IndexOf(surfaceDeviceViewModel), 0);
|
||||||
|
for (int i = 0; i < SurfaceDeviceViewModels.Count; i++)
|
||||||
|
{
|
||||||
|
SurfaceDeviceViewModel deviceViewModel = SurfaceDeviceViewModels[i];
|
||||||
|
deviceViewModel.Device.ZIndex = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1);
|
||||||
|
|
||||||
|
_rgbService.SaveDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteSendBackward(ArtemisDevice device)
|
||||||
|
{
|
||||||
|
SurfaceDeviceViewModel surfaceDeviceViewModel = SurfaceDeviceViewModels.First(d => d.Device == device);
|
||||||
|
int currentIndex = SurfaceDeviceViewModels.IndexOf(surfaceDeviceViewModel);
|
||||||
|
int newIndex = Math.Max(currentIndex - 1, 0);
|
||||||
|
SurfaceDeviceViewModels.Move(currentIndex, newIndex);
|
||||||
|
for (int i = 0; i < SurfaceDeviceViewModels.Count; i++)
|
||||||
|
{
|
||||||
|
SurfaceDeviceViewModel deviceViewModel = SurfaceDeviceViewModels[i];
|
||||||
|
deviceViewModel.Device.ZIndex = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1);
|
||||||
|
|
||||||
|
_rgbService.SaveDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@ -2,10 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Mixins;
|
|
||||||
using Avalonia.Controls.Presenters;
|
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.LogicalTree;
|
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
using Avalonia.VisualTree;
|
using Avalonia.VisualTree;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user