mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
UI - Added reusable device visualizer
Settings - Show device LED images in settings Editor - Improved performance on big surfaces
This commit is contained in:
parent
8a45039863
commit
efa0f28231
@ -26,10 +26,12 @@
|
|||||||
<PackageReference Include="Ninject" Version="3.3.4" />
|
<PackageReference Include="Ninject" Version="3.3.4" />
|
||||||
<PackageReference Include="Ninject.Extensions.Conventions" Version="3.3.0" />
|
<PackageReference Include="Ninject.Extensions.Conventions" Version="3.3.0" />
|
||||||
<PackageReference Include="SkiaSharp" Version="1.68.2-preview.29" />
|
<PackageReference Include="SkiaSharp" Version="1.68.2-preview.29" />
|
||||||
|
<PackageReference Include="SkiaSharp.Views.WPF" Version="1.68.2-preview.29" />
|
||||||
<PackageReference Include="Stylet" Version="1.3.1" />
|
<PackageReference Include="Stylet" Version="1.3.1" />
|
||||||
<PackageReference Include="System.Buffers" Version="4.5.0" />
|
<PackageReference Include="System.Buffers" Version="4.5.0" />
|
||||||
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
|
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
|
||||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.7.0" />
|
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.7.0" />
|
||||||
|
<PackageReference Include="WriteableBitmapEx" Version="1.6.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Remove="obj\x64\Debug\ColorPicker.g.cs" />
|
<Compile Remove="obj\x64\Debug\ColorPicker.g.cs" />
|
||||||
@ -50,6 +52,11 @@
|
|||||||
<Private>false</Private>
|
<Private>false</Private>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="RGB.NET.Core">
|
||||||
|
<HintPath>..\..\..\RGB.NET\bin\netstandard2.0\RGB.NET.Core.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Resource Include="Resources\Fonts\RobotoMono-Regular.ttf" />
|
<Resource Include="Resources\Fonts\RobotoMono-Regular.ttf" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters" x:Class="Artemis.UI.Shared.ColorPicker"
|
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters" x:Class="Artemis.UI.Shared.Controls.ColorPicker"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="101.848" d:DesignWidth="242.956">
|
d:DesignHeight="101.848" d:DesignWidth="242.956">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
@ -5,7 +5,7 @@ using System.Windows.Controls;
|
|||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
||||||
namespace Artemis.UI.Shared
|
namespace Artemis.UI.Shared.Controls
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for ColorPicker.xaml
|
/// Interaction logic for ColorPicker.xaml
|
||||||
130
src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs
Normal file
130
src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using Artemis.Core.Models.Surface;
|
||||||
|
using RGB.NET.Core;
|
||||||
|
using Stylet;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.Controls
|
||||||
|
{
|
||||||
|
public class DeviceVisualizer : FrameworkElement
|
||||||
|
{
|
||||||
|
public static readonly DependencyProperty DeviceProperty = DependencyProperty.Register(nameof(Device), typeof(ArtemisDevice), typeof(DeviceVisualizer),
|
||||||
|
new FrameworkPropertyMetadata(default(ArtemisDevice), FrameworkPropertyMetadataOptions.AffectsRender, DevicePropertyChangedCallback));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty ShowColorsProperty = DependencyProperty.Register(nameof(ShowColors), typeof(bool), typeof(DeviceVisualizer),
|
||||||
|
new FrameworkPropertyMetadata(default(bool), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||||
|
|
||||||
|
private BitmapImage _deviceImage;
|
||||||
|
private List<DeviceVisualizerLed> _deviceVisualizerLeds;
|
||||||
|
private DrawingGroup _backingStore;
|
||||||
|
|
||||||
|
private static void DevicePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var deviceVisualizer = (DeviceVisualizer) d;
|
||||||
|
deviceVisualizer.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
deviceVisualizer.SubscribeToSurfaceUpdate((ArtemisDevice) e.OldValue, (ArtemisDevice) e.NewValue);
|
||||||
|
deviceVisualizer.Initialize();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArtemisDevice Device
|
||||||
|
{
|
||||||
|
get => (ArtemisDevice) GetValue(DeviceProperty);
|
||||||
|
set => SetValue(DeviceProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShowColors
|
||||||
|
{
|
||||||
|
get => (bool) GetValue(ShowColorsProperty);
|
||||||
|
set => SetValue(ShowColorsProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceVisualizer()
|
||||||
|
{
|
||||||
|
_backingStore = new DrawingGroup();
|
||||||
|
_deviceVisualizerLeds = new List<DeviceVisualizerLed>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void Initialize()
|
||||||
|
{
|
||||||
|
_deviceImage = null;
|
||||||
|
_deviceVisualizerLeds.Clear();
|
||||||
|
|
||||||
|
if (Device == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Load the device main image
|
||||||
|
if (Device.RgbDevice?.DeviceInfo?.Image?.AbsolutePath != null && File.Exists(Device.RgbDevice.DeviceInfo.Image.AbsolutePath))
|
||||||
|
_deviceImage = new BitmapImage(Device.RgbDevice.DeviceInfo.Image);
|
||||||
|
|
||||||
|
// Create all the LEDs
|
||||||
|
foreach (var artemisLed in Device.Leds)
|
||||||
|
{
|
||||||
|
_deviceVisualizerLeds.Add(new DeviceVisualizerLed(artemisLed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SubscribeToSurfaceUpdate(ArtemisDevice oldValue, ArtemisDevice newValue)
|
||||||
|
{
|
||||||
|
if (oldValue != null)
|
||||||
|
oldValue.Surface.RgbSurface.Updated -= RgbSurfaceOnUpdated;
|
||||||
|
if (newValue != null)
|
||||||
|
newValue.Surface.RgbSurface.Updated += RgbSurfaceOnUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RgbSurfaceOnUpdated(UpdatedEventArgs args)
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
if (ShowColors)
|
||||||
|
{
|
||||||
|
Render();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Render()
|
||||||
|
{
|
||||||
|
var drawingContext = _backingStore.Open();
|
||||||
|
|
||||||
|
foreach (var deviceVisualizerLed in _deviceVisualizerLeds)
|
||||||
|
deviceVisualizerLed.Render(drawingContext, true);
|
||||||
|
|
||||||
|
drawingContext.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnRender(DrawingContext drawingContext)
|
||||||
|
{
|
||||||
|
if (Device == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Determine the scale required to fit the desired size of the control
|
||||||
|
var scale = Math.Min(DesiredSize.Width / Device.RgbDevice.Size.Width, DesiredSize.Height / Device.RgbDevice.Size.Height);
|
||||||
|
var scaledRect = new Rect(0, 0, Device.RgbDevice.Size.Width * scale, Device.RgbDevice.Size.Height * scale);
|
||||||
|
|
||||||
|
// Center and scale the visualization in the desired bounding box
|
||||||
|
if (DesiredSize.Width > 0 && DesiredSize.Height > 0)
|
||||||
|
{
|
||||||
|
drawingContext.PushTransform(new TranslateTransform(DesiredSize.Width / 2 - scaledRect.Width / 2, DesiredSize.Height / 2 - scaledRect.Height / 2));
|
||||||
|
drawingContext.PushTransform(new ScaleTransform(scale, scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render device and LED images
|
||||||
|
if (_deviceImage != null)
|
||||||
|
drawingContext.DrawImage(_deviceImage, new Rect(0, 0, Device.RgbDevice.Size.Width, Device.RgbDevice.Size.Height));
|
||||||
|
|
||||||
|
foreach (var deviceVisualizerLed in _deviceVisualizerLeds)
|
||||||
|
deviceVisualizerLed.Render(drawingContext, false);
|
||||||
|
|
||||||
|
drawingContext.DrawDrawing(_backingStore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
135
src/Artemis.UI.Shared/Controls/DeviceVisualizerLed.cs
Normal file
135
src/Artemis.UI.Shared/Controls/DeviceVisualizerLed.cs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using Artemis.Core.Models.Surface;
|
||||||
|
using RGB.NET.Core;
|
||||||
|
using Color = System.Windows.Media.Color;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.Controls
|
||||||
|
{
|
||||||
|
internal class DeviceVisualizerLed
|
||||||
|
{
|
||||||
|
public DeviceVisualizerLed(ArtemisLed led)
|
||||||
|
{
|
||||||
|
Led = led;
|
||||||
|
if (Led.RgbLed.Image != null && File.Exists(Led.RgbLed.Image.AbsolutePath))
|
||||||
|
LedImage = new BitmapImage(Led.RgbLed.Image);
|
||||||
|
CreateLedGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArtemisLed Led { get; }
|
||||||
|
public BitmapImage LedImage { get; set; }
|
||||||
|
|
||||||
|
public Geometry DisplayGeometry { get; private set; }
|
||||||
|
|
||||||
|
internal void Render(DrawingContext drawingContext, bool renderGeometry)
|
||||||
|
{
|
||||||
|
if (!renderGeometry)
|
||||||
|
RenderImage(drawingContext);
|
||||||
|
else
|
||||||
|
RenderGeometry(drawingContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateLedGeometry()
|
||||||
|
{
|
||||||
|
switch (Led.RgbLed.Shape)
|
||||||
|
{
|
||||||
|
case Shape.Custom:
|
||||||
|
if (Led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keyboard || Led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keypad)
|
||||||
|
CreateCustomGeometry(2.0);
|
||||||
|
else
|
||||||
|
CreateCustomGeometry(1.0);
|
||||||
|
break;
|
||||||
|
case Shape.Rectangle:
|
||||||
|
if (Led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keyboard || Led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keypad)
|
||||||
|
CreateKeyCapGeometry();
|
||||||
|
else
|
||||||
|
CreateRectangleGeometry();
|
||||||
|
break;
|
||||||
|
case Shape.Circle:
|
||||||
|
CreateCircleGeometry();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stroke geometry is the display geometry excluding the inner geometry
|
||||||
|
DisplayGeometry.Transform = new TranslateTransform(Led.RgbLed.LedRectangle.Location.X, Led.RgbLed.LedRectangle.Location.Y);
|
||||||
|
// Try to gain some performance
|
||||||
|
DisplayGeometry = DisplayGeometry.GetFlattenedPathGeometry();
|
||||||
|
DisplayGeometry.Freeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateRectangleGeometry()
|
||||||
|
{
|
||||||
|
DisplayGeometry = new RectangleGeometry(new Rect(0.5, 0.5, Led.RgbLed.Size.Width - 1, Led.RgbLed.Size.Height - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateCircleGeometry()
|
||||||
|
{
|
||||||
|
DisplayGeometry = new EllipseGeometry(new Rect(0.5, 0.5, Led.RgbLed.Size.Width - 1, Led.RgbLed.Size.Height - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateKeyCapGeometry()
|
||||||
|
{
|
||||||
|
DisplayGeometry = new RectangleGeometry(new Rect(1, 1, Led.RgbLed.Size.Width - 2, Led.RgbLed.Size.Height - 2), 1.6, 1.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateCustomGeometry(double deflateAmount)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DisplayGeometry = Geometry.Combine(
|
||||||
|
Geometry.Empty,
|
||||||
|
Geometry.Parse(Led.RgbLed.ShapeData),
|
||||||
|
GeometryCombineMode.Union,
|
||||||
|
new TransformGroup
|
||||||
|
{
|
||||||
|
Children = new TransformCollection
|
||||||
|
{
|
||||||
|
new ScaleTransform(Led.RgbLed.Size.Width - deflateAmount, Led.RgbLed.Size.Height - deflateAmount),
|
||||||
|
new TranslateTransform(deflateAmount / 2, deflateAmount / 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
CreateRectangleGeometry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderGeometry(DrawingContext drawingContext)
|
||||||
|
{
|
||||||
|
if (DisplayGeometry == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var r = Led.RgbLed.Color.GetR();
|
||||||
|
var g = Led.RgbLed.Color.GetG();
|
||||||
|
var b = Led.RgbLed.Color.GetB();
|
||||||
|
|
||||||
|
var fillBrush = new SolidColorBrush(Color.FromArgb(100, r,g,b));
|
||||||
|
fillBrush.Freeze();
|
||||||
|
var penBrush = new SolidColorBrush(Color.FromArgb(255, r, g, b));
|
||||||
|
penBrush.Freeze();
|
||||||
|
|
||||||
|
drawingContext.DrawGeometry(fillBrush, new Pen(penBrush, 1), DisplayGeometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderImage(DrawingContext drawingContext)
|
||||||
|
{
|
||||||
|
if (LedImage == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var ledRect = new Rect(
|
||||||
|
Led.RgbLed.LedRectangle.Location.X,
|
||||||
|
Led.RgbLed.LedRectangle.Location.Y,
|
||||||
|
Led.RgbLed.LedRectangle.Size.Width,
|
||||||
|
Led.RgbLed.LedRectangle.Size.Height
|
||||||
|
);
|
||||||
|
drawingContext.DrawImage(LedImage, ledRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
<UserControl x:Class="Artemis.UI.Shared.DraggableFloat"
|
<UserControl x:Class="Artemis.UI.Shared.Controls.DraggableFloat"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
@ -5,7 +5,7 @@ using System.Windows;
|
|||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
|
||||||
namespace Artemis.UI.Shared
|
namespace Artemis.UI.Shared.Controls
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for DraggableFloat.xaml
|
/// Interaction logic for DraggableFloat.xaml
|
||||||
@ -1,9 +1,8 @@
|
|||||||
<UserControl x:Class="Artemis.UI.Shared.GradientPicker"
|
<UserControl x:Class="Artemis.UI.Shared.Controls.GradientPicker"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Artemis.UI.Shared"
|
|
||||||
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters"
|
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
@ -8,7 +8,7 @@ using Artemis.Core.Models.Profile;
|
|||||||
using Artemis.UI.Shared.Annotations;
|
using Artemis.UI.Shared.Annotations;
|
||||||
using Artemis.UI.Shared.Services.Interfaces;
|
using Artemis.UI.Shared.Services.Interfaces;
|
||||||
|
|
||||||
namespace Artemis.UI.Shared
|
namespace Artemis.UI.Shared.Controls
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for GradientPicker.xaml
|
/// Interaction logic for GradientPicker.xaml
|
||||||
@ -9,6 +9,7 @@
|
|||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:shared="clr-namespace:Artemis.UI.Shared"
|
xmlns:shared="clr-namespace:Artemis.UI.Shared"
|
||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
|
xmlns:controls1="clr-namespace:Artemis.UI.Shared.Controls"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Gradient Editor"
|
Title="Gradient Editor"
|
||||||
Background="{DynamicResource MaterialDesignPaper}"
|
Background="{DynamicResource MaterialDesignPaper}"
|
||||||
@ -80,7 +81,7 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<Label Grid.Column="0" HorizontalAlignment="Right">Color:</Label>
|
<Label Grid.Column="0" HorizontalAlignment="Right">Color:</Label>
|
||||||
<shared:ColorPicker
|
<controls1:ColorPicker
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
x:Name="CurrentColor"
|
x:Name="CurrentColor"
|
||||||
|
|||||||
@ -100,6 +100,7 @@ namespace Artemis.UI.Shared.Services.Dialog
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
DialogHost.CloseDialogCommand.Execute(new object(), null);
|
||||||
await ShowDialog<ExceptionDialogViewModel>(arguments);
|
await ShowDialog<ExceptionDialogViewModel>(arguments);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
|
|||||||
@ -6,12 +6,13 @@
|
|||||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
|
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
|
||||||
xmlns:artemis="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
xmlns:artemis="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||||
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="25" d:DesignWidth="800"
|
d:DesignHeight="25" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance local:ColorGradientPropertyInputViewModel}">
|
d:DataContext="{d:DesignInstance local:ColorGradientPropertyInputViewModel}">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||||
<artemis:GradientPicker Width="132"
|
<controls:GradientPicker Width="132"
|
||||||
Margin="0 2"
|
Margin="0 2"
|
||||||
Padding="0 -1"
|
Padding="0 -1"
|
||||||
ColorGradient="{Binding ColorGradientInputValue}" />
|
ColorGradient="{Binding ColorGradientInputValue}" />
|
||||||
|
|||||||
@ -6,12 +6,13 @@
|
|||||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
|
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
|
||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance local:FloatPropertyInputViewModel}">
|
d:DataContext="{d:DesignInstance local:FloatPropertyInputViewModel}">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||||
<shared:DraggableFloat Value="{Binding FloatInputValue}"
|
<controls:DraggableFloat Value="{Binding FloatInputValue}"
|
||||||
StepSize="{Binding LayerPropertyViewModel.LayerProperty.InputStepSize}"
|
StepSize="{Binding LayerPropertyViewModel.LayerProperty.InputStepSize}"
|
||||||
DragStarted="{s:Action InputDragStarted}"
|
DragStarted="{s:Action InputDragStarted}"
|
||||||
DragEnded="{s:Action InputDragEnded}" />
|
DragEnded="{s:Action InputDragEnded}" />
|
||||||
|
|||||||
@ -6,12 +6,13 @@
|
|||||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
|
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
|
||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance local:IntPropertyInputViewModel}">
|
d:DataContext="{d:DesignInstance local:IntPropertyInputViewModel}">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||||
<shared:DraggableFloat Value="{Binding IntInputValue}"
|
<controls:DraggableFloat Value="{Binding IntInputValue}"
|
||||||
StepSize="{Binding LayerPropertyViewModel.LayerProperty.InputStepSize}"
|
StepSize="{Binding LayerPropertyViewModel.LayerProperty.InputStepSize}"
|
||||||
DragStarted="{s:Action InputDragStarted}"
|
DragStarted="{s:Action InputDragStarted}"
|
||||||
DragEnded="{s:Action InputDragEnded}" />
|
DragEnded="{s:Action InputDragEnded}" />
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
|
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
|
||||||
xmlns:artemis="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
xmlns:artemis="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||||
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="25" d:DesignWidth="800"
|
d:DesignHeight="25" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance local:SKColorPropertyInputViewModel}">
|
d:DataContext="{d:DesignInstance local:SKColorPropertyInputViewModel}">
|
||||||
@ -14,7 +15,7 @@
|
|||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||||
<artemis:ColorPicker Width="132"
|
<controls:ColorPicker Width="132"
|
||||||
Margin="0 -2 0 3"
|
Margin="0 -2 0 3"
|
||||||
Padding="0 -1"
|
Padding="0 -1"
|
||||||
Color="{Binding SKColorInputValue, Converter={StaticResource SKColorToColorConverter}}" />
|
Color="{Binding SKColorInputValue, Converter={StaticResource SKColorToColorConverter}}" />
|
||||||
|
|||||||
@ -6,18 +6,19 @@
|
|||||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
|
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
|
||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="25" d:DesignWidth="800"
|
d:DesignHeight="25" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance local:SKPointPropertyInputViewModel}">
|
d:DataContext="{d:DesignInstance local:SKPointPropertyInputViewModel}">
|
||||||
<StackPanel Orientation="Horizontal" KeyboardNavigation.IsTabStop="True">
|
<StackPanel Orientation="Horizontal" KeyboardNavigation.IsTabStop="True">
|
||||||
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||||
<shared:DraggableFloat ToolTip="X-coordinate (horizontal)"
|
<controls:DraggableFloat ToolTip="X-coordinate (horizontal)"
|
||||||
Value="{Binding X}"
|
Value="{Binding X}"
|
||||||
StepSize="{Binding LayerPropertyViewModel.LayerProperty.InputStepSize}"
|
StepSize="{Binding LayerPropertyViewModel.LayerProperty.InputStepSize}"
|
||||||
DragStarted="{s:Action InputDragStarted}"
|
DragStarted="{s:Action InputDragStarted}"
|
||||||
DragEnded="{s:Action InputDragEnded}" />
|
DragEnded="{s:Action InputDragEnded}" />
|
||||||
<TextBlock Margin="5 0" VerticalAlignment="Bottom">,</TextBlock>
|
<TextBlock Margin="5 0" VerticalAlignment="Bottom">,</TextBlock>
|
||||||
<shared:DraggableFloat ToolTip="Y-coordinate (vertical)"
|
<controls:DraggableFloat ToolTip="Y-coordinate (vertical)"
|
||||||
Value="{Binding Y}"
|
Value="{Binding Y}"
|
||||||
StepSize="{Binding LayerPropertyViewModel.LayerProperty.InputStepSize}"
|
StepSize="{Binding LayerPropertyViewModel.LayerProperty.InputStepSize}"
|
||||||
DragStarted="{s:Action InputDragStarted}"
|
DragStarted="{s:Action InputDragStarted}"
|
||||||
|
|||||||
@ -6,18 +6,19 @@
|
|||||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
|
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
|
||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance local:SKSizePropertyInputViewModel}">
|
d:DataContext="{d:DesignInstance local:SKSizePropertyInputViewModel}">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||||
<shared:DraggableFloat ToolTip="Height"
|
<controls:DraggableFloat ToolTip="Height"
|
||||||
Value="{Binding Height}"
|
Value="{Binding Height}"
|
||||||
StepSize="{Binding LayerPropertyViewModel.LayerProperty.InputStepSize}"
|
StepSize="{Binding LayerPropertyViewModel.LayerProperty.InputStepSize}"
|
||||||
DragStarted="{s:Action InputDragStarted}"
|
DragStarted="{s:Action InputDragStarted}"
|
||||||
DragEnded="{s:Action InputDragEnded}" />
|
DragEnded="{s:Action InputDragEnded}" />
|
||||||
<TextBlock Margin="5 0" VerticalAlignment="Bottom">,</TextBlock>
|
<TextBlock Margin="5 0" VerticalAlignment="Bottom">,</TextBlock>
|
||||||
<shared:DraggableFloat ToolTip="Width"
|
<controls:DraggableFloat ToolTip="Width"
|
||||||
Value="{Binding Width}"
|
Value="{Binding Width}"
|
||||||
StepSize="{Binding LayerPropertyViewModel.LayerProperty.InputStepSize}"
|
StepSize="{Binding LayerPropertyViewModel.LayerProperty.InputStepSize}"
|
||||||
DragStarted="{s:Action InputDragStarted}"
|
DragStarted="{s:Action InputDragStarted}"
|
||||||
|
|||||||
@ -17,7 +17,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
|
|||||||
public static readonly DependencyProperty PixelsPerSecondProperty = DependencyProperty.Register(nameof(PixelsPerSecond), typeof(int), typeof(PropertyTimelineHeader),
|
public static readonly DependencyProperty PixelsPerSecondProperty = DependencyProperty.Register(nameof(PixelsPerSecond), typeof(int), typeof(PropertyTimelineHeader),
|
||||||
new FrameworkPropertyMetadata(default(int), FrameworkPropertyMetadataOptions.AffectsRender));
|
new FrameworkPropertyMetadata(default(int), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||||
|
|
||||||
|
|
||||||
public static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.Register(nameof(HorizontalOffset), typeof(double), typeof(PropertyTimelineHeader),
|
public static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.Register(nameof(HorizontalOffset), typeof(double), typeof(PropertyTimelineHeader),
|
||||||
new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsRender));
|
new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||||
|
|
||||||
|
|||||||
@ -16,14 +16,16 @@
|
|||||||
<DataTrigger.EnterActions>
|
<DataTrigger.EnterActions>
|
||||||
<BeginStoryboard>
|
<BeginStoryboard>
|
||||||
<Storyboard>
|
<Storyboard>
|
||||||
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Opacity)" To="0.8" Duration="0:0:0.25" />
|
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Opacity)" To="0.8"
|
||||||
|
Duration="0:0:0.25" />
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</BeginStoryboard>
|
</BeginStoryboard>
|
||||||
</DataTrigger.EnterActions>
|
</DataTrigger.EnterActions>
|
||||||
<DataTrigger.ExitActions>
|
<DataTrigger.ExitActions>
|
||||||
<BeginStoryboard>
|
<BeginStoryboard>
|
||||||
<Storyboard>
|
<Storyboard>
|
||||||
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Opacity)" To="1" Duration="0:0:0.25" />
|
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Opacity)" To="1"
|
||||||
|
Duration="0:0:0.25" />
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</BeginStoryboard>
|
</BeginStoryboard>
|
||||||
</DataTrigger.ExitActions>
|
</DataTrigger.ExitActions>
|
||||||
@ -33,15 +35,6 @@
|
|||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Canvas Style="{StaticResource SelectedStyle}">
|
<Canvas Style="{StaticResource SelectedStyle}">
|
||||||
|
|
||||||
<!-- The part of the layer's shape that falls outside the layer -->
|
|
||||||
<Path Data="{Binding ShapeGeometry, Mode=OneWay}">
|
|
||||||
<Path.Fill>
|
|
||||||
<SolidColorBrush Color="{StaticResource Accent700}" Opacity="0.05" />
|
|
||||||
</Path.Fill>
|
|
||||||
<Path.Stroke>
|
|
||||||
<SolidColorBrush Color="{StaticResource Accent700}" Opacity="0.15" />
|
|
||||||
</Path.Stroke>
|
|
||||||
</Path>
|
|
||||||
|
|
||||||
<!-- The part of the layer's shape that is inside the layer -->
|
<!-- The part of the layer's shape that is inside the layer -->
|
||||||
<Path Data="{Binding ShapeGeometry, Mode=OneWay}">
|
<Path Data="{Binding ShapeGeometry, Mode=OneWay}">
|
||||||
@ -51,19 +44,18 @@
|
|||||||
<Path.Stroke>
|
<Path.Stroke>
|
||||||
<SolidColorBrush Color="{StaticResource Accent700}" />
|
<SolidColorBrush Color="{StaticResource Accent700}" />
|
||||||
</Path.Stroke>
|
</Path.Stroke>
|
||||||
<Path.OpacityMask>
|
|
||||||
<VisualBrush Viewport="{Binding ViewportRectangle}" ViewportUnits="Absolute">
|
|
||||||
<VisualBrush.Visual>
|
|
||||||
<Path Data="{Binding LayerGeometry, Mode=OneWay}" ClipToBounds="False" Fill="Black" />
|
|
||||||
</VisualBrush.Visual>
|
|
||||||
</VisualBrush>
|
|
||||||
</Path.OpacityMask>
|
|
||||||
</Path>
|
</Path>
|
||||||
|
|
||||||
<Path Data="{Binding LayerGeometry, Mode=OneWay}" ClipToBounds="False" StrokeThickness="1.5" StrokeLineJoin="Round" x:Name="LayerPath">
|
<Rectangle Width="{Binding LayerRect.Width}"
|
||||||
<Path.Stroke>
|
Height="{Binding LayerRect.Height}"
|
||||||
|
Margin="{Binding LayerRectMargin}"
|
||||||
|
StrokeThickness="2"
|
||||||
|
StrokeDashArray="1 1"
|
||||||
|
StrokeLineJoin="Round"
|
||||||
|
x:Name="LayerPath">
|
||||||
|
<Rectangle.Stroke>
|
||||||
<SolidColorBrush Color="{StaticResource Accent400}" />
|
<SolidColorBrush Color="{StaticResource Accent400}" />
|
||||||
</Path.Stroke>
|
</Rectangle.Stroke>
|
||||||
</Path>
|
</Rectangle>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -4,12 +4,8 @@ using System.Windows;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using Artemis.Core.Models.Profile;
|
using Artemis.Core.Models.Profile;
|
||||||
using Artemis.Core.Models.Profile.LayerShapes;
|
using Artemis.Core.Models.Profile.LayerShapes;
|
||||||
using Artemis.Core.Models.Surface;
|
|
||||||
using Artemis.UI.Extensions;
|
|
||||||
using Artemis.UI.Services.Interfaces;
|
using Artemis.UI.Services.Interfaces;
|
||||||
using RGB.NET.Core;
|
|
||||||
using Stylet;
|
using Stylet;
|
||||||
using Rectangle = Artemis.Core.Models.Profile.LayerShapes.Rectangle;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
||||||
{
|
{
|
||||||
@ -32,12 +28,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Layer Layer { get; }
|
public Layer Layer { get; }
|
||||||
|
public Rect LayerRect { get; set; }
|
||||||
public Geometry LayerGeometry { get; set; }
|
public Thickness LayerRectMargin => LayerRect == Rect.Empty ? new Thickness() : new Thickness(LayerRect.Left, LayerRect.Top, 0, 0);
|
||||||
public Geometry OpacityGeometry { get; set; }
|
|
||||||
public Geometry ShapeGeometry { get; set; }
|
|
||||||
public Rect ViewportRectangle { get; set; }
|
|
||||||
public bool IsSelected { get; set; }
|
public bool IsSelected { get; set; }
|
||||||
|
public Geometry ShapeGeometry { get; set; }
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
@ -50,53 +44,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
IsSelected = _profileEditorService.SelectedProfileElement == Layer;
|
IsSelected = _profileEditorService.SelectedProfileElement == Layer;
|
||||||
CreateLayerGeometry();
|
if (!Layer.Leds.Any() || Layer.LayerShape == null)
|
||||||
|
LayerRect = Rect.Empty;
|
||||||
|
else
|
||||||
|
LayerRect = _layerEditorService.GetLayerBounds(Layer);
|
||||||
|
|
||||||
CreateShapeGeometry();
|
CreateShapeGeometry();
|
||||||
CreateViewportRectangle();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CreateLayerGeometry()
|
|
||||||
{
|
|
||||||
if (!Layer.Leds.Any())
|
|
||||||
{
|
|
||||||
LayerGeometry = Geometry.Empty;
|
|
||||||
OpacityGeometry = Geometry.Empty;
|
|
||||||
ViewportRectangle = Rect.Empty;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var group = new GeometryGroup();
|
|
||||||
group.FillRule = FillRule.Nonzero;
|
|
||||||
|
|
||||||
foreach (var led in Layer.Leds)
|
|
||||||
{
|
|
||||||
Geometry geometry;
|
|
||||||
switch (led.RgbLed.Shape)
|
|
||||||
{
|
|
||||||
case Shape.Custom:
|
|
||||||
if (led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keyboard || led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keypad)
|
|
||||||
geometry = CreateCustomGeometry(led, 2);
|
|
||||||
else
|
|
||||||
geometry = CreateCustomGeometry(led, 1);
|
|
||||||
break;
|
|
||||||
case Shape.Rectangle:
|
|
||||||
geometry = CreateRectangleGeometry(led);
|
|
||||||
break;
|
|
||||||
case Shape.Circle:
|
|
||||||
geometry = CreateCircleGeometry(led);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
group.Children.Add(geometry);
|
|
||||||
}
|
|
||||||
|
|
||||||
var layerGeometry = group.GetOutlinedPathGeometry();
|
|
||||||
var opacityGeometry = Geometry.Combine(Geometry.Empty, layerGeometry, GeometryCombineMode.Exclude, new TranslateTransform());
|
|
||||||
|
|
||||||
LayerGeometry = layerGeometry;
|
|
||||||
OpacityGeometry = opacityGeometry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateShapeGeometry()
|
private void CreateShapeGeometry()
|
||||||
@ -126,59 +79,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateViewportRectangle()
|
|
||||||
{
|
|
||||||
if (!Layer.Leds.Any() || Layer.LayerShape == null)
|
|
||||||
{
|
|
||||||
ViewportRectangle = Rect.Empty;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewportRectangle = _layerEditorService.GetLayerBounds(Layer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Geometry CreateRectangleGeometry(ArtemisLed led)
|
|
||||||
{
|
|
||||||
var rect = led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1);
|
|
||||||
rect.Inflate(1, 1);
|
|
||||||
return new RectangleGeometry(rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Geometry CreateCircleGeometry(ArtemisLed led)
|
|
||||||
{
|
|
||||||
var rect = led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1);
|
|
||||||
rect.Inflate(1, 1);
|
|
||||||
return new EllipseGeometry(rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Geometry CreateCustomGeometry(ArtemisLed led, double deflateAmount)
|
|
||||||
{
|
|
||||||
var rect = led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1);
|
|
||||||
rect.Inflate(1, 1);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var geometry = Geometry.Combine(
|
|
||||||
Geometry.Empty,
|
|
||||||
Geometry.Parse(led.RgbLed.ShapeData),
|
|
||||||
GeometryCombineMode.Union,
|
|
||||||
new TransformGroup
|
|
||||||
{
|
|
||||||
Children = new TransformCollection
|
|
||||||
{
|
|
||||||
new ScaleTransform(rect.Width, rect.Height),
|
|
||||||
new TranslateTransform(rect.X, rect.Y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return geometry;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return CreateRectangleGeometry(led);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Event handlers
|
#region Event handlers
|
||||||
|
|
||||||
private void LayerOnRenderPropertiesUpdated(object sender, EventArgs e)
|
private void LayerOnRenderPropertiesUpdated(object sender, EventArgs e)
|
||||||
@ -198,8 +98,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
|
|
||||||
private void ProfileEditorServiceOnProfilePreviewUpdated(object sender, EventArgs e)
|
private void ProfileEditorServiceOnProfilePreviewUpdated(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
CreateShapeGeometry();
|
Update();
|
||||||
CreateViewportRectangle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:profileEditor="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.Visualization"
|
xmlns:profileEditor="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.Visualization"
|
||||||
xmlns:utilities="clr-namespace:Artemis.UI.Shared.Utilities;assembly=Artemis.UI.Shared"
|
xmlns:utilities="clr-namespace:Artemis.UI.Shared.Utilities;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="510.9" d:DesignWidth="800"
|
d:DesignHeight="510.9" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance {x:Type profileEditor:ProfileViewModel}}">
|
d:DataContext="{d:DesignInstance {x:Type profileEditor:ProfileViewModel}}">
|
||||||
@ -107,7 +108,7 @@
|
|||||||
<TranslateTransform X="{Binding PanZoomViewModel.PanX}" Y="{Binding PanZoomViewModel.PanY}" />
|
<TranslateTransform X="{Binding PanZoomViewModel.PanX}" Y="{Binding PanZoomViewModel.PanY}" />
|
||||||
</TransformGroup>
|
</TransformGroup>
|
||||||
</Grid.RenderTransform>
|
</Grid.RenderTransform>
|
||||||
<ItemsControl ItemsSource="{Binding DeviceViewModels}">
|
<ItemsControl ItemsSource="{Binding Devices}">
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsControl.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<Canvas />
|
<Canvas />
|
||||||
@ -121,7 +122,7 @@
|
|||||||
</ItemsControl.ItemContainerStyle>
|
</ItemsControl.ItemContainerStyle>
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<ContentControl s:View.Model="{Binding}" />
|
<controls:DeviceVisualizer Device="{Binding}" ShowColors="True"/>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
@ -154,7 +155,6 @@
|
|||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
<StackPanel ZIndex="1" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="10">
|
<StackPanel ZIndex="1" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="10">
|
||||||
<materialDesign:Card Padding="8">
|
<materialDesign:Card Padding="8">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
|
|||||||
@ -11,6 +11,7 @@ using Artemis.Core.Plugins.Models;
|
|||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.Core.Services.Storage.Interfaces;
|
using Artemis.Core.Services.Storage.Interfaces;
|
||||||
using Artemis.UI.Events;
|
using Artemis.UI.Events;
|
||||||
|
using Artemis.UI.Extensions;
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
using Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools;
|
using Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools;
|
||||||
using Artemis.UI.Screens.Shared;
|
using Artemis.UI.Screens.Shared;
|
||||||
@ -30,7 +31,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
private int _activeToolIndex;
|
private int _activeToolIndex;
|
||||||
private VisualizationToolViewModel _activeToolViewModel;
|
private VisualizationToolViewModel _activeToolViewModel;
|
||||||
private int _previousTool;
|
private int _previousTool;
|
||||||
private TimerUpdateTrigger _updateTrigger;
|
|
||||||
|
|
||||||
public ProfileViewModel(IProfileEditorService profileEditorService,
|
public ProfileViewModel(IProfileEditorService profileEditorService,
|
||||||
ILayerEditorService layerEditorService,
|
ILayerEditorService layerEditorService,
|
||||||
@ -47,14 +47,16 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
|
|
||||||
Execute.OnUIThreadSync(() =>
|
Execute.OnUIThreadSync(() =>
|
||||||
{
|
{
|
||||||
CanvasViewModels = new ObservableCollection<CanvasViewModel>();
|
|
||||||
DeviceViewModels = new ObservableCollection<ProfileDeviceViewModel>();
|
|
||||||
PanZoomViewModel = new PanZoomViewModel {LimitToZero = false};
|
PanZoomViewModel = new PanZoomViewModel {LimitToZero = false};
|
||||||
|
|
||||||
|
CanvasViewModels = new BindableCollection<CanvasViewModel>();
|
||||||
|
Devices = new BindableCollection<ArtemisDevice>();
|
||||||
|
DimmedLeds = new BindableCollection<ArtemisLed>();
|
||||||
|
SelectedLeds = new BindableCollection<ArtemisLed>();
|
||||||
});
|
});
|
||||||
|
|
||||||
ApplySurfaceConfiguration(_surfaceService.ActiveSurface);
|
ApplySurfaceConfiguration(_surfaceService.ActiveSurface);
|
||||||
ApplyActiveProfile();
|
ApplyActiveProfile();
|
||||||
CreateUpdateTrigger();
|
|
||||||
ActivateToolByIndex(0);
|
ActivateToolByIndex(0);
|
||||||
|
|
||||||
eventAggregator.Subscribe(this);
|
eventAggregator.Subscribe(this);
|
||||||
@ -62,9 +64,14 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
|
|
||||||
|
|
||||||
public bool IsInitializing { get; private set; }
|
public bool IsInitializing { get; private set; }
|
||||||
public ObservableCollection<CanvasViewModel> CanvasViewModels { get; set; }
|
|
||||||
public ObservableCollection<ProfileDeviceViewModel> DeviceViewModels { get; set; }
|
|
||||||
public PanZoomViewModel PanZoomViewModel { get; set; }
|
public PanZoomViewModel PanZoomViewModel { get; set; }
|
||||||
|
|
||||||
|
public BindableCollection<CanvasViewModel> CanvasViewModels { get; set; }
|
||||||
|
public BindableCollection<ArtemisDevice> Devices { get; set; }
|
||||||
|
public BindableCollection<ArtemisLed> DimmedLeds { get; set; }
|
||||||
|
public BindableCollection<ArtemisLed> SelectedLeds { get; set; }
|
||||||
|
|
||||||
public PluginSetting<bool> HighlightSelectedLayer { get; set; }
|
public PluginSetting<bool> HighlightSelectedLayer { get; set; }
|
||||||
public PluginSetting<bool> PauseRenderingOnFocusLoss { get; set; }
|
public PluginSetting<bool> PauseRenderingOnFocusLoss { get; set; }
|
||||||
|
|
||||||
@ -122,7 +129,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
_profileEditorService.ProfileElementSelected += OnProfileElementSelected;
|
_profileEditorService.ProfileElementSelected += OnProfileElementSelected;
|
||||||
_profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated;
|
_profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated;
|
||||||
|
|
||||||
_updateTrigger.Start();
|
|
||||||
base.OnInitialActivate();
|
base.OnInitialActivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,28 +143,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
HighlightSelectedLayer.Save();
|
HighlightSelectedLayer.Save();
|
||||||
PauseRenderingOnFocusLoss.Save();
|
PauseRenderingOnFocusLoss.Save();
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_updateTrigger.Stop();
|
|
||||||
}
|
|
||||||
catch (NullReferenceException)
|
|
||||||
{
|
|
||||||
// TODO: Remove when fixed in RGB.NET, or avoid double stopping
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnClose();
|
base.OnClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateUpdateTrigger()
|
|
||||||
{
|
|
||||||
// Borrow RGB.NET's update trigger but limit the FPS
|
|
||||||
var targetFpsSetting = _settingsService.GetSetting("Core.TargetFrameRate", 25);
|
|
||||||
var editorTargetFpsSetting = _settingsService.GetSetting("ProfileEditor.TargetFrameRate", 15);
|
|
||||||
var targetFps = Math.Min(targetFpsSetting.Value, editorTargetFpsSetting.Value);
|
|
||||||
_updateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / targetFps};
|
|
||||||
_updateTrigger.Update += UpdateLeds;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnActiveSurfaceConfigurationSelected(object sender, SurfaceConfigurationEventArgs e)
|
private void OnActiveSurfaceConfigurationSelected(object sender, SurfaceConfigurationEventArgs e)
|
||||||
{
|
{
|
||||||
ApplySurfaceConfiguration(e.Surface);
|
ApplySurfaceConfiguration(e.Surface);
|
||||||
@ -193,61 +180,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
|
|
||||||
private void ApplySurfaceConfiguration(ArtemisSurface surface)
|
private void ApplySurfaceConfiguration(ArtemisSurface surface)
|
||||||
{
|
{
|
||||||
// Make sure all devices have an up-to-date VM
|
Devices.Clear();
|
||||||
Execute.PostToUIThread(() =>
|
Devices.AddRange(surface.Devices);
|
||||||
{
|
|
||||||
lock (DeviceViewModels)
|
|
||||||
{
|
|
||||||
var existing = DeviceViewModels.ToList();
|
|
||||||
var deviceViewModels = new List<ProfileDeviceViewModel>();
|
|
||||||
|
|
||||||
// Add missing/update existing
|
|
||||||
foreach (var surfaceDeviceConfiguration in surface.Devices.OrderBy(d => d.ZIndex).ToList())
|
|
||||||
{
|
|
||||||
// Create VMs for missing devices
|
|
||||||
var viewModel = existing.FirstOrDefault(vm => vm.Device.RgbDevice == surfaceDeviceConfiguration.RgbDevice);
|
|
||||||
if (viewModel == null)
|
|
||||||
{
|
|
||||||
IsInitializing = true;
|
|
||||||
viewModel = new ProfileDeviceViewModel(surfaceDeviceConfiguration);
|
|
||||||
}
|
|
||||||
// Update existing devices
|
|
||||||
else
|
|
||||||
viewModel.Device = surfaceDeviceConfiguration;
|
|
||||||
|
|
||||||
// Add the viewModel to the list of VMs we want to keep
|
|
||||||
deviceViewModels.Add(viewModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceViewModels = new ObservableCollection<ProfileDeviceViewModel>(deviceViewModels);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateLeds(object sender, CustomUpdateData customUpdateData)
|
|
||||||
{
|
|
||||||
lock (DeviceViewModels)
|
|
||||||
{
|
|
||||||
if (IsInitializing)
|
|
||||||
IsInitializing = DeviceViewModels.Any(d => !d.AddedLeds);
|
|
||||||
|
|
||||||
foreach (var profileDeviceViewModel in DeviceViewModels)
|
|
||||||
profileDeviceViewModel.Update();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateLedsDimStatus()
|
private void UpdateLedsDimStatus()
|
||||||
{
|
{
|
||||||
|
DimmedLeds.Clear();
|
||||||
if (HighlightSelectedLayer.Value && _profileEditorService.SelectedProfileElement is Layer layer)
|
if (HighlightSelectedLayer.Value && _profileEditorService.SelectedProfileElement is Layer layer)
|
||||||
{
|
DimmedLeds.AddRange(layer.Leds);
|
||||||
foreach (var led in DeviceViewModels.SelectMany(d => d.Leds))
|
|
||||||
led.IsDimmed = !layer.Leds.Contains(led.Led);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var led in DeviceViewModels.SelectMany(d => d.Leds))
|
|
||||||
led.IsDimmed = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Buttons
|
#region Buttons
|
||||||
@ -322,27 +263,27 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
layer.ClearLeds();
|
layer.ClearLeds();
|
||||||
layer.AddLeds(DeviceViewModels.SelectMany(d => d.Leds).Where(vm => vm.IsSelected).Select(vm => vm.Led));
|
layer.AddLeds(SelectedLeds);
|
||||||
|
|
||||||
_profileEditorService.UpdateSelectedProfileElement();
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SelectAll()
|
public void SelectAll()
|
||||||
{
|
{
|
||||||
foreach (var ledVm in DeviceViewModels.SelectMany(d => d.Leds))
|
SelectedLeds.Clear();
|
||||||
ledVm.IsSelected = true;
|
SelectedLeds.AddRange(Devices.SelectMany(d => d.Leds));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InverseSelection()
|
public void InverseSelection()
|
||||||
{
|
{
|
||||||
foreach (var ledVm in DeviceViewModels.SelectMany(d => d.Leds))
|
var current = SelectedLeds.ToList();
|
||||||
ledVm.IsSelected = !ledVm.IsSelected;
|
SelectedLeds.Clear();
|
||||||
|
SelectedLeds.AddRange(Devices.SelectMany(d => d.Leds).Except(current));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearSelection()
|
public void ClearSelection()
|
||||||
{
|
{
|
||||||
foreach (var ledVm in DeviceViewModels.SelectMany(d => d.Leds))
|
SelectedLeds.Clear();
|
||||||
ledVm.IsSelected = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -374,20 +315,20 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
|
|
||||||
public void Handle(MainWindowFocusChangedEvent message)
|
public void Handle(MainWindowFocusChangedEvent message)
|
||||||
{
|
{
|
||||||
if (PauseRenderingOnFocusLoss == null || ScreenState != ScreenState.Active)
|
// if (PauseRenderingOnFocusLoss == null || ScreenState != ScreenState.Active)
|
||||||
return;
|
// return;
|
||||||
|
//
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
if (PauseRenderingOnFocusLoss.Value && !message.IsFocused)
|
// if (PauseRenderingOnFocusLoss.Value && !message.IsFocused)
|
||||||
_updateTrigger.Stop();
|
// _updateTrigger.Stop();
|
||||||
else if (PauseRenderingOnFocusLoss.Value && message.IsFocused)
|
// else if (PauseRenderingOnFocusLoss.Value && message.IsFocused)
|
||||||
_updateTrigger.Start();
|
// _updateTrigger.Start();
|
||||||
}
|
// }
|
||||||
catch (NullReferenceException)
|
// catch (NullReferenceException)
|
||||||
{
|
// {
|
||||||
// TODO: Remove when fixed in RGB.NET, or avoid double stopping
|
// // TODO: Remove when fixed in RGB.NET, or avoid double stopping
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Handle(MainWindowKeyEvent message)
|
public void Handle(MainWindowKeyEvent message)
|
||||||
@ -413,5 +354,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public List<ArtemisLed> GetLedsInRectangle(Rect selectedRect)
|
||||||
|
{
|
||||||
|
return Devices.SelectMany(d => d.Leds)
|
||||||
|
.Where(led => led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1).IntersectsWith(selectedRect))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,11 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using System.IO;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Artemis.Core.Models.Profile;
|
using Artemis.Core.Models.Profile;
|
||||||
using Artemis.Core.Models.Surface;
|
|
||||||
using Artemis.UI.Extensions;
|
|
||||||
using Artemis.UI.Properties;
|
using Artemis.UI.Properties;
|
||||||
using Artemis.UI.Services.Interfaces;
|
using Artemis.UI.Services.Interfaces;
|
||||||
|
|
||||||
@ -31,17 +28,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
|
|||||||
var selectedRect = new Rect(MouseDownStartPosition, position);
|
var selectedRect = new Rect(MouseDownStartPosition, position);
|
||||||
|
|
||||||
// Get selected LEDs
|
// Get selected LEDs
|
||||||
var selectedLeds = new List<ArtemisLed>();
|
var selectedLeds = ProfileViewModel.GetLedsInRectangle(selectedRect);
|
||||||
foreach (var device in ProfileViewModel.DeviceViewModels)
|
ProfileViewModel.SelectedLeds.Clear();
|
||||||
{
|
ProfileViewModel.SelectedLeds.AddRange(selectedLeds);
|
||||||
foreach (var ledViewModel in device.Leds)
|
|
||||||
{
|
|
||||||
if (ledViewModel.Led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1).IntersectsWith(selectedRect))
|
|
||||||
selectedLeds.Add(ledViewModel.Led);
|
|
||||||
// Unselect everything
|
|
||||||
ledViewModel.IsSelected = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the selection to the selected layer layer
|
// Apply the selection to the selected layer layer
|
||||||
if (ProfileEditorService.SelectedProfileElement is Layer layer)
|
if (ProfileEditorService.SelectedProfileElement is Layer layer)
|
||||||
@ -65,17 +54,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
|
|||||||
|
|
||||||
var position = ProfileViewModel.PanZoomViewModel.GetRelativeMousePosition(sender, e);
|
var position = ProfileViewModel.PanZoomViewModel.GetRelativeMousePosition(sender, e);
|
||||||
var selectedRect = new Rect(MouseDownStartPosition, position);
|
var selectedRect = new Rect(MouseDownStartPosition, position);
|
||||||
|
var selectedLeds = ProfileViewModel.GetLedsInRectangle(selectedRect);
|
||||||
|
|
||||||
foreach (var device in ProfileViewModel.DeviceViewModels)
|
// Unless shift is held down, clear the current selection
|
||||||
{
|
if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
|
||||||
foreach (var ledViewModel in device.Leds)
|
ProfileViewModel.SelectedLeds.Clear();
|
||||||
{
|
ProfileViewModel.SelectedLeds.AddRange(selectedLeds.Except(ProfileViewModel.SelectedLeds));
|
||||||
if (ledViewModel.Led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1).IntersectsWith(selectedRect))
|
|
||||||
ledViewModel.IsSelected = true;
|
|
||||||
else if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
|
|
||||||
ledViewModel.IsSelected = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DragRectangle = selectedRect;
|
DragRectangle = selectedRect;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using System.IO;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Artemis.Core.Models.Profile;
|
using Artemis.Core.Models.Profile;
|
||||||
using Artemis.Core.Models.Surface;
|
|
||||||
using Artemis.UI.Extensions;
|
|
||||||
using Artemis.UI.Properties;
|
using Artemis.UI.Properties;
|
||||||
using Artemis.UI.Services.Interfaces;
|
using Artemis.UI.Services.Interfaces;
|
||||||
|
|
||||||
@ -31,17 +28,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
|
|||||||
var selectedRect = new Rect(MouseDownStartPosition, position);
|
var selectedRect = new Rect(MouseDownStartPosition, position);
|
||||||
|
|
||||||
// Get selected LEDs
|
// Get selected LEDs
|
||||||
var selectedLeds = new List<ArtemisLed>();
|
var selectedLeds = ProfileViewModel.GetLedsInRectangle(selectedRect);
|
||||||
foreach (var device in ProfileViewModel.DeviceViewModels)
|
|
||||||
{
|
|
||||||
foreach (var ledViewModel in device.Leds)
|
|
||||||
{
|
|
||||||
if (ledViewModel.Led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1).IntersectsWith(selectedRect))
|
|
||||||
selectedLeds.Add(ledViewModel.Led);
|
|
||||||
// Unselect everything
|
|
||||||
ledViewModel.IsSelected = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the selection to the selected layer layer
|
// Apply the selection to the selected layer layer
|
||||||
if (ProfileEditorService.SelectedProfileElement is Layer layer)
|
if (ProfileEditorService.SelectedProfileElement is Layer layer)
|
||||||
@ -87,17 +74,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
|
|||||||
|
|
||||||
var position = ProfileViewModel.PanZoomViewModel.GetRelativeMousePosition(sender, e);
|
var position = ProfileViewModel.PanZoomViewModel.GetRelativeMousePosition(sender, e);
|
||||||
var selectedRect = new Rect(MouseDownStartPosition, position);
|
var selectedRect = new Rect(MouseDownStartPosition, position);
|
||||||
|
var selectedLeds = ProfileViewModel.GetLedsInRectangle(selectedRect);
|
||||||
|
|
||||||
foreach (var device in ProfileViewModel.DeviceViewModels)
|
// Unless shift is held down, clear the current selection
|
||||||
{
|
if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
|
||||||
foreach (var ledViewModel in device.Leds)
|
ProfileViewModel.SelectedLeds.Clear();
|
||||||
{
|
ProfileViewModel.SelectedLeds.AddRange(selectedLeds.Except(ProfileViewModel.SelectedLeds));
|
||||||
if (ledViewModel.Led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1).IntersectsWith(selectedRect))
|
|
||||||
ledViewModel.IsSelected = true;
|
|
||||||
else if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
|
|
||||||
ledViewModel.IsSelected = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DragRectangle = selectedRect;
|
DragRectangle = selectedRect;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
xmlns:devices="clr-namespace:Artemis.UI.Screens.Settings.Tabs.Devices"
|
xmlns:devices="clr-namespace:Artemis.UI.Screens.Settings.Tabs.Devices"
|
||||||
|
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||||
d:DataContext="{d:DesignInstance devices:DeviceSettingsViewModel}"
|
d:DataContext="{d:DesignInstance devices:DeviceSettingsViewModel}"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
@ -29,8 +30,7 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Rectangle Grid.Row="0" Height="140" Width="196" Fill="{DynamicResource MaterialDesignPaper}" />
|
<Rectangle Grid.Row="0" Height="140" Width="196" Fill="{DynamicResource MaterialDesignPaper}" />
|
||||||
<Image Grid.Row="0" Source="{Binding Device.RgbDevice.DeviceInfo.Image}" Height="130" Width="190"
|
<controls:DeviceVisualizer Device="{Binding Device}" RenderOptions.BitmapScalingMode="HighQuality" Grid.Row="0" Height="130" Width="190" />
|
||||||
RenderOptions.BitmapScalingMode="HighQuality" />
|
|
||||||
<Button Grid.Row="0"
|
<Button Grid.Row="0"
|
||||||
Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
|
Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
using System.Diagnostics;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
using Artemis.Core.Models.Surface;
|
using Artemis.Core.Models.Surface;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Shared.Services.Interfaces;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Settings.Tabs.Devices
|
namespace Artemis.UI.Screens.Settings.Tabs.Devices
|
||||||
@ -8,10 +11,12 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
|
|||||||
public class DeviceSettingsViewModel
|
public class DeviceSettingsViewModel
|
||||||
{
|
{
|
||||||
private readonly IDeviceService _deviceService;
|
private readonly IDeviceService _deviceService;
|
||||||
|
private readonly IDialogService _dialogService;
|
||||||
|
|
||||||
public DeviceSettingsViewModel(ArtemisDevice device, IDeviceService deviceService)
|
public DeviceSettingsViewModel(ArtemisDevice device, IDeviceService deviceService, IDialogService dialogService)
|
||||||
{
|
{
|
||||||
_deviceService = deviceService;
|
_deviceService = deviceService;
|
||||||
|
_dialogService = dialogService;
|
||||||
Device = device;
|
Device = device;
|
||||||
|
|
||||||
Type = Device.RgbDevice.DeviceInfo.DeviceType.ToString().Humanize();
|
Type = Device.RgbDevice.DeviceInfo.DeviceType.ToString().Humanize();
|
||||||
@ -36,9 +41,16 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OpenPluginDirectory()
|
public async void OpenPluginDirectory()
|
||||||
{
|
{
|
||||||
Process.Start(Device.Plugin.PluginInfo.Directory.FullName);
|
try
|
||||||
|
{
|
||||||
|
Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Device.Plugin.PluginInfo.Directory.FullName);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
await _dialogService.ShowExceptionDialog("Welp, we couldn't open the device's plugin folder for you", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7,6 +7,7 @@
|
|||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||||
xmlns:surfaceEditor="clr-namespace:Artemis.UI.Screens.SurfaceEditor.Visualization"
|
xmlns:surfaceEditor="clr-namespace:Artemis.UI.Screens.SurfaceEditor.Visualization"
|
||||||
|
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DataContext="{d:DesignInstance {x:Type surfaceEditor:SurfaceDeviceViewModel}}"
|
d:DataContext="{d:DesignInstance {x:Type surfaceEditor:SurfaceDeviceViewModel}}"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
@ -25,10 +26,7 @@
|
|||||||
<RotateTransform Angle="{Binding Device.Rotation}" />
|
<RotateTransform Angle="{Binding Device.Rotation}" />
|
||||||
</Grid.LayoutTransform>
|
</Grid.LayoutTransform>
|
||||||
|
|
||||||
<!-- Device image with fallback -->
|
<controls:DeviceVisualizer Device="{Binding Device}"></controls:DeviceVisualizer>
|
||||||
<Image VerticalAlignment="Stretch"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Source="{Binding Device.RgbDevice.DeviceInfo.Image, Converter={StaticResource NullToImageConverter}}" />
|
|
||||||
|
|
||||||
<Rectangle Fill="{DynamicResource MaterialDesignCardBackground}"
|
<Rectangle Fill="{DynamicResource MaterialDesignCardBackground}"
|
||||||
Stroke="{DynamicResource MaterialDesignTextBoxBorder}"
|
Stroke="{DynamicResource MaterialDesignTextBoxBorder}"
|
||||||
@ -40,26 +38,6 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
|
|
||||||
<!-- LEDs -->
|
|
||||||
<ItemsControl ItemsSource="{Binding Leds}">
|
|
||||||
<ItemsControl.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<Canvas />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
<ItemsControl.ItemContainerStyle>
|
|
||||||
<Style TargetType="{x:Type ContentPresenter}">
|
|
||||||
<Setter Property="Canvas.Left" Value="{Binding X}" />
|
|
||||||
<Setter Property="Canvas.Top" Value="{Binding Y}" />
|
|
||||||
</Style>
|
|
||||||
</ItemsControl.ItemContainerStyle>
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<ContentControl s:View.Model="{Binding}" />
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
</ItemsControl>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- Selection rectangle -->
|
<!-- Selection rectangle -->
|
||||||
|
|||||||
@ -9,28 +9,18 @@ namespace Artemis.UI.Screens.SurfaceEditor.Visualization
|
|||||||
{
|
{
|
||||||
public class SurfaceDeviceViewModel : PropertyChangedBase
|
public class SurfaceDeviceViewModel : PropertyChangedBase
|
||||||
{
|
{
|
||||||
private readonly List<SurfaceLedViewModel> _leds;
|
|
||||||
private double _dragOffsetX;
|
private double _dragOffsetX;
|
||||||
private double _dragOffsetY;
|
private double _dragOffsetY;
|
||||||
|
|
||||||
public SurfaceDeviceViewModel(ArtemisDevice device)
|
public SurfaceDeviceViewModel(ArtemisDevice device)
|
||||||
{
|
{
|
||||||
Device = device;
|
Device = device;
|
||||||
_leds = new List<SurfaceLedViewModel>();
|
|
||||||
|
|
||||||
if (Device.RgbDevice != null)
|
|
||||||
{
|
|
||||||
foreach (var led in Device.RgbDevice)
|
|
||||||
_leds.Add(new SurfaceLedViewModel(led));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArtemisDevice Device { get; set; }
|
public ArtemisDevice Device { get; set; }
|
||||||
public SelectionStatus SelectionStatus { get; set; }
|
public SelectionStatus SelectionStatus { get; set; }
|
||||||
public Cursor Cursor { get; set; }
|
public Cursor Cursor { get; set; }
|
||||||
|
|
||||||
public IReadOnlyCollection<SurfaceLedViewModel> Leds => _leds.AsReadOnly();
|
|
||||||
|
|
||||||
public Rect DeviceRectangle => Device.RgbDevice == null
|
public Rect DeviceRectangle => Device.RgbDevice == null
|
||||||
? new Rect()
|
? new Rect()
|
||||||
: new Rect(Device.X, Device.Y, Device.RgbDevice.DeviceRectangle.Size.Width, Device.RgbDevice.DeviceRectangle.Size.Height);
|
: new Rect(Device.X, Device.Y, Device.RgbDevice.DeviceRectangle.Size.Width, Device.RgbDevice.DeviceRectangle.Size.Height);
|
||||||
|
|||||||
@ -1,21 +0,0 @@
|
|||||||
<UserControl
|
|
||||||
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:Converters="clr-namespace:Artemis.UI.Converters"
|
|
||||||
xmlns:surfaceEditor="clr-namespace:Artemis.UI.Screens.SurfaceEditor.Visualization"
|
|
||||||
x:Class="Artemis.UI.Screens.SurfaceEditor.Visualization.SurfaceLedView"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
d:DataContext="{d:DesignInstance {x:Type surfaceEditor:SurfaceLedViewModel}}"
|
|
||||||
d:DesignHeight="25" d:DesignWidth="25">
|
|
||||||
<UserControl.Resources>
|
|
||||||
<Converters:NullToImageConverter x:Key="NullToImageConverter" />
|
|
||||||
</UserControl.Resources>
|
|
||||||
<Grid Width="{Binding Width}" Height="{Binding Height}">
|
|
||||||
<Grid.Background>
|
|
||||||
<ImageBrush AlignmentX="Center" AlignmentY="Center" Stretch="Fill"
|
|
||||||
ImageSource="{Binding Led.Image, Converter={StaticResource NullToImageConverter}}" />
|
|
||||||
</Grid.Background>
|
|
||||||
</Grid>
|
|
||||||
</UserControl>
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using RGB.NET.Core;
|
|
||||||
using Stylet;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.SurfaceEditor.Visualization
|
|
||||||
{
|
|
||||||
public class SurfaceLedViewModel : PropertyChangedBase
|
|
||||||
{
|
|
||||||
public SurfaceLedViewModel(Led led)
|
|
||||||
{
|
|
||||||
Led = led;
|
|
||||||
ApplyLedToViewModel();
|
|
||||||
|
|
||||||
Led.PropertyChanged += ApplyViewModelOnLedChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Led Led { get; set; }
|
|
||||||
|
|
||||||
public double X { get; set; }
|
|
||||||
public double Y { get; set; }
|
|
||||||
public double Width { get; set; }
|
|
||||||
public double Height { get; set; }
|
|
||||||
|
|
||||||
public void ApplyLedToViewModel()
|
|
||||||
{
|
|
||||||
// Don't want ActualLocation here since rotation is done in XAML
|
|
||||||
X = Led.Location.X * Led.Device.Scale.Horizontal;
|
|
||||||
Y = Led.Location.Y * Led.Device.Scale.Vertical;
|
|
||||||
Width = Led.ActualSize.Width;
|
|
||||||
Height = Led.ActualSize.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyViewModelOnLedChange(object sender, PropertyChangedEventArgs args)
|
|
||||||
{
|
|
||||||
if (args.PropertyName == "Location" || args.PropertyName == "ActualSize") ApplyLedToViewModel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -7,6 +7,7 @@ using Artemis.UI.Shared;
|
|||||||
using Artemis.UI.Shared.Services.Interfaces;
|
using Artemis.UI.Shared.Services.Interfaces;
|
||||||
using Ninject;
|
using Ninject;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
|
using GradientPicker = Artemis.UI.Shared.Controls.GradientPicker;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens
|
namespace Artemis.UI.Screens
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user