mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
UI - Performance improvements
This commit is contained in:
parent
7ad7eaad89
commit
13a16a1830
@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Collections.Specialized;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -9,15 +11,15 @@ using System.Windows.Controls;
|
|||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Threading;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Stylet;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Shared
|
namespace Artemis.UI.Shared
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Visualizes an <see cref="ArtemisDevice" /> with optional per-LED colors
|
/// Visualizes an <see cref="ArtemisDevice" /> with optional per-LED colors
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DeviceVisualizer : FrameworkElement, IDisposable
|
public class DeviceVisualizer : FrameworkElement
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The device to visualize
|
/// The device to visualize
|
||||||
@ -34,14 +36,16 @@ namespace Artemis.UI.Shared
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A list of LEDs to highlight
|
/// A list of LEDs to highlight
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly DependencyProperty HighlightedLedsProperty = DependencyProperty.Register(nameof(HighlightedLeds), typeof(IEnumerable<ArtemisLed>), typeof(DeviceVisualizer),
|
public static readonly DependencyProperty HighlightedLedsProperty = DependencyProperty.Register(nameof(HighlightedLeds), typeof(ObservableCollection<ArtemisLed>), typeof(DeviceVisualizer),
|
||||||
new FrameworkPropertyMetadata(default(IEnumerable<ArtemisLed>)));
|
new FrameworkPropertyMetadata(default(ObservableCollection<ArtemisLed>), HighlightedLedsPropertyChanged));
|
||||||
|
|
||||||
private readonly DrawingGroup _backingStore;
|
private readonly DrawingGroup _backingStore;
|
||||||
private readonly List<DeviceVisualizerLed> _deviceVisualizerLeds;
|
private readonly List<DeviceVisualizerLed> _deviceVisualizerLeds;
|
||||||
private readonly Timer _timer;
|
private readonly DispatcherTimer _timer;
|
||||||
private BitmapImage? _deviceImage;
|
private BitmapImage? _deviceImage;
|
||||||
private ArtemisDevice? _oldDevice;
|
private ArtemisDevice? _oldDevice;
|
||||||
|
private List<DeviceVisualizerLed> _highlightedLeds;
|
||||||
|
private List<DeviceVisualizerLed> _dimmedLeds;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the <see cref="DeviceVisualizer" /> class
|
/// Creates a new instance of the <see cref="DeviceVisualizer" /> class
|
||||||
@ -50,9 +54,10 @@ namespace Artemis.UI.Shared
|
|||||||
{
|
{
|
||||||
_backingStore = new DrawingGroup();
|
_backingStore = new DrawingGroup();
|
||||||
_deviceVisualizerLeds = new List<DeviceVisualizerLed>();
|
_deviceVisualizerLeds = new List<DeviceVisualizerLed>();
|
||||||
|
_dimmedLeds = new List<DeviceVisualizerLed>();
|
||||||
|
|
||||||
// Run an update timer at 25 fps
|
// Run an update timer at 25 fps
|
||||||
_timer = new Timer(40);
|
_timer = new DispatcherTimer(DispatcherPriority.Render) {Interval = TimeSpan.FromMilliseconds(40)};
|
||||||
|
|
||||||
MouseLeftButtonUp += OnMouseLeftButtonUp;
|
MouseLeftButtonUp += OnMouseLeftButtonUp;
|
||||||
Loaded += OnLoaded;
|
Loaded += OnLoaded;
|
||||||
@ -80,9 +85,9 @@ namespace Artemis.UI.Shared
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a list of LEDs to highlight
|
/// Gets or sets a list of LEDs to highlight
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<ArtemisLed>? HighlightedLeds
|
public ObservableCollection<ArtemisLed>? HighlightedLeds
|
||||||
{
|
{
|
||||||
get => (IEnumerable<ArtemisLed>) GetValue(HighlightedLedsProperty);
|
get => (ObservableCollection<ArtemisLed>) GetValue(HighlightedLedsProperty);
|
||||||
set => SetValue(HighlightedLedsProperty, value);
|
set => SetValue(HighlightedLedsProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,10 +163,9 @@ namespace Artemis.UI.Shared
|
|||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
_timer.Dispose();
|
_timer.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static Size ResizeKeepAspect(Size src, double maxWidth, double maxHeight)
|
private static Size ResizeKeepAspect(Size src, double maxWidth, double maxHeight)
|
||||||
{
|
{
|
||||||
double scale;
|
double scale;
|
||||||
@ -191,8 +195,10 @@ namespace Artemis.UI.Shared
|
|||||||
private void OnUnloaded(object? sender, RoutedEventArgs e)
|
private void OnUnloaded(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_timer.Stop();
|
_timer.Stop();
|
||||||
_timer.Elapsed -= TimerOnTick;
|
_timer.Tick -= TimerOnTick;
|
||||||
|
|
||||||
|
if (HighlightedLeds != null)
|
||||||
|
HighlightedLeds.CollectionChanged -= HighlightedLedsChanged;
|
||||||
if (_oldDevice != null)
|
if (_oldDevice != null)
|
||||||
{
|
{
|
||||||
if (Device != null)
|
if (Device != null)
|
||||||
@ -223,16 +229,34 @@ namespace Artemis.UI.Shared
|
|||||||
private void OnLoaded(object? sender, RoutedEventArgs e)
|
private void OnLoaded(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_timer.Start();
|
_timer.Start();
|
||||||
_timer.Elapsed += TimerOnTick;
|
_timer.Tick += TimerOnTick;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TimerOnTick(object? sender, EventArgs e)
|
private void TimerOnTick(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Execute.PostToUIThread(() =>
|
if (ShowColors && Visibility == Visibility.Visible)
|
||||||
|
Render();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Render()
|
||||||
|
{
|
||||||
|
DrawingContext drawingContext = _backingStore.Append();
|
||||||
|
|
||||||
|
if (_highlightedLeds.Any())
|
||||||
{
|
{
|
||||||
if (ShowColors && Visibility == Visibility.Visible)
|
foreach (DeviceVisualizerLed deviceVisualizerLed in _highlightedLeds)
|
||||||
Render();
|
deviceVisualizerLed.RenderColor(_backingStore, drawingContext, false);
|
||||||
});
|
|
||||||
|
foreach (DeviceVisualizerLed deviceVisualizerLed in _dimmedLeds)
|
||||||
|
deviceVisualizerLed.RenderColor(_backingStore, drawingContext, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds)
|
||||||
|
deviceVisualizerLed.RenderColor(_backingStore, drawingContext, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawingContext.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateTransform()
|
private void UpdateTransform()
|
||||||
@ -241,22 +265,12 @@ namespace Artemis.UI.Shared
|
|||||||
InvalidateMeasure();
|
InvalidateMeasure();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DevicePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
DeviceVisualizer deviceVisualizer = (DeviceVisualizer) d;
|
|
||||||
deviceVisualizer.Dispatcher.Invoke(() => { deviceVisualizer.SetupForDevice(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ShowColorsPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
DeviceVisualizer deviceVisualizer = (DeviceVisualizer) d;
|
|
||||||
deviceVisualizer.Dispatcher.Invoke(() => { deviceVisualizer.SetupForDevice(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetupForDevice()
|
private void SetupForDevice()
|
||||||
{
|
{
|
||||||
_deviceImage = null;
|
_deviceImage = null;
|
||||||
_deviceVisualizerLeds.Clear();
|
_deviceVisualizerLeds.Clear();
|
||||||
|
_highlightedLeds = new List<DeviceVisualizerLed>();
|
||||||
|
_dimmedLeds = new List<DeviceVisualizerLed>();
|
||||||
|
|
||||||
if (Device == null)
|
if (Device == null)
|
||||||
return;
|
return;
|
||||||
@ -319,40 +333,47 @@ namespace Artemis.UI.Shared
|
|||||||
|
|
||||||
private void DeviceUpdated(object? sender, EventArgs e)
|
private void DeviceUpdated(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Execute.PostToUIThread(SetupForDevice);
|
Dispatcher.Invoke(SetupForDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DevicePropertyChanged(object? sender, PropertyChangedEventArgs e)
|
private void DevicePropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
Execute.PostToUIThread(SetupForDevice);
|
Dispatcher.Invoke(SetupForDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Render()
|
private static void DevicePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
DrawingContext drawingContext = _backingStore.Append();
|
DeviceVisualizer deviceVisualizer = (DeviceVisualizer) d;
|
||||||
|
deviceVisualizer.Dispatcher.Invoke(() => { deviceVisualizer.SetupForDevice(); });
|
||||||
|
}
|
||||||
|
|
||||||
if (HighlightedLeds != null && HighlightedLeds.Any())
|
private static void ShowColorsPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
DeviceVisualizer deviceVisualizer = (DeviceVisualizer) d;
|
||||||
|
deviceVisualizer.Dispatcher.Invoke(() => { deviceVisualizer.SetupForDevice(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void HighlightedLedsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
DeviceVisualizer deviceVisualizer = (DeviceVisualizer) d;
|
||||||
|
if (e.OldValue is ObservableCollection<ArtemisLed> oldCollection)
|
||||||
|
oldCollection.CollectionChanged -= deviceVisualizer.HighlightedLedsChanged;
|
||||||
|
if (e.NewValue is ObservableCollection<ArtemisLed> newCollection)
|
||||||
|
newCollection.CollectionChanged += deviceVisualizer.HighlightedLedsChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HighlightedLedsChanged(object? sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
|
||||||
|
{
|
||||||
|
if (HighlightedLeds != null)
|
||||||
{
|
{
|
||||||
// Faster on large devices, maybe a bit slower on smaller ones but that's ok
|
_highlightedLeds = _deviceVisualizerLeds.Where(l => HighlightedLeds.Contains(l.Led)).ToList();
|
||||||
ILookup<ArtemisLed, ArtemisLed> toHighlight = HighlightedLeds.ToLookup(l => l);
|
_dimmedLeds = _deviceVisualizerLeds.Where(l => !HighlightedLeds.Contains(l.Led)).ToList();
|
||||||
foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds)
|
|
||||||
deviceVisualizerLed.RenderColor(_backingStore, drawingContext, !toHighlight.Contains(deviceVisualizerLed.Led));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds)
|
_highlightedLeds = new List<DeviceVisualizerLed>();
|
||||||
deviceVisualizerLed.RenderColor(_backingStore, drawingContext, false);
|
_dimmedLeds = new List<DeviceVisualizerLed>();
|
||||||
}
|
}
|
||||||
|
|
||||||
drawingContext.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -12,7 +12,6 @@ using Ninject.Parameters;
|
|||||||
using Serilog;
|
using Serilog;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using SkiaSharp.Views.WPF;
|
using SkiaSharp.Views.WPF;
|
||||||
using Stylet;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Shared.Services
|
namespace Artemis.UI.Shared.Services
|
||||||
{
|
{
|
||||||
@ -45,9 +44,11 @@ namespace Artemis.UI.Shared.Services
|
|||||||
|
|
||||||
private void CoreServiceOnFrameRendered(object? sender, FrameRenderedEventArgs e)
|
private void CoreServiceOnFrameRendered(object? sender, FrameRenderedEventArgs e)
|
||||||
{
|
{
|
||||||
if (!_doTick) return;
|
if (!_doTick)
|
||||||
|
return;
|
||||||
_doTick = false;
|
_doTick = false;
|
||||||
Execute.PostToUIThread(OnProfilePreviewUpdated);
|
|
||||||
|
OnProfilePreviewUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReloadProfile()
|
private void ReloadProfile()
|
||||||
@ -144,6 +145,7 @@ namespace Artemis.UI.Shared.Services
|
|||||||
{
|
{
|
||||||
if (_currentTime.Equals(value)) return;
|
if (_currentTime.Equals(value)) return;
|
||||||
_currentTime = value;
|
_currentTime = value;
|
||||||
|
|
||||||
Tick();
|
Tick();
|
||||||
OnCurrentTimeChanged();
|
OnCurrentTimeChanged();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,8 @@ namespace Artemis.UI.Shared
|
|||||||
HitTestResultBehavior ResultCallback(HitTestResult r) => HitTestResultBehavior.Continue;
|
HitTestResultBehavior ResultCallback(HitTestResult r) => HitTestResultBehavior.Continue;
|
||||||
HitTestFilterBehavior FilterCallback(DependencyObject e)
|
HitTestFilterBehavior FilterCallback(DependencyObject e)
|
||||||
{
|
{
|
||||||
if (e is FrameworkElement fe && fe.DataContext is T context && !result.Contains(context)) result.Add(context);
|
if (e is FrameworkElement fe && fe.DataContext is T context && !result.Contains(context))
|
||||||
|
result.Add(context);
|
||||||
return HitTestFilterBehavior.Continue;
|
return HitTestFilterBehavior.Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -583,30 +583,28 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Execute.PostToUIThread(() =>
|
TimeSpan newTime = ProfileEditorService.CurrentTime.Add(TimeSpan.FromSeconds(e.DeltaTime));
|
||||||
|
if (SelectedProfileElement != null)
|
||||||
{
|
{
|
||||||
TimeSpan newTime = ProfileEditorService.CurrentTime.Add(TimeSpan.FromSeconds(e.DeltaTime));
|
if (Repeating && RepeatTimeline)
|
||||||
if (SelectedProfileElement != null)
|
|
||||||
{
|
{
|
||||||
if (Repeating && RepeatTimeline)
|
if (newTime > SelectedProfileElement.Timeline.Length)
|
||||||
{
|
newTime = TimeSpan.Zero;
|
||||||
if (newTime > SelectedProfileElement.Timeline.Length)
|
|
||||||
newTime = TimeSpan.Zero;
|
|
||||||
}
|
|
||||||
else if (Repeating && RepeatSegment)
|
|
||||||
{
|
|
||||||
if (newTime > GetCurrentSegmentEnd())
|
|
||||||
newTime = GetCurrentSegmentStart();
|
|
||||||
}
|
|
||||||
else if (newTime > SelectedProfileElement.Timeline.Length)
|
|
||||||
{
|
|
||||||
newTime = SelectedProfileElement.Timeline.Length;
|
|
||||||
Pause();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (Repeating && RepeatSegment)
|
||||||
|
{
|
||||||
|
if (newTime > GetCurrentSegmentEnd())
|
||||||
|
newTime = GetCurrentSegmentStart();
|
||||||
|
}
|
||||||
|
else if (newTime > SelectedProfileElement.Timeline.Length)
|
||||||
|
{
|
||||||
|
newTime = SelectedProfileElement.Timeline.Length;
|
||||||
|
Pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ProfileEditorService.CurrentTime = newTime;
|
// Update current time on high priority to keep things buttery smooth as if you're using the mouse ༼ つ ◕_◕ ༽つ
|
||||||
});
|
Execute.OnUIThreadSync(() => ProfileEditorService.CurrentTime = newTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -8,6 +8,8 @@ using Artemis.UI.Extensions;
|
|||||||
using Artemis.UI.Screens.Shared;
|
using Artemis.UI.Screens.Shared;
|
||||||
using Artemis.UI.Services;
|
using Artemis.UI.Services;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
|
using SkiaSharp;
|
||||||
|
using Stylet;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||||
{
|
{
|
||||||
@ -95,6 +97,16 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
|||||||
CreateViewportRectangle();
|
CreateViewportRectangle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Updating
|
||||||
|
|
||||||
|
private LayerShape _lastShape;
|
||||||
|
private Rect _lastBounds;
|
||||||
|
|
||||||
|
private SKPoint _lastAnchor;
|
||||||
|
private SKPoint _lastPosition;
|
||||||
|
private double _lastRotation;
|
||||||
|
private SKSize _lastScale;
|
||||||
|
|
||||||
private void CreateShapeGeometry()
|
private void CreateShapeGeometry()
|
||||||
{
|
{
|
||||||
if (Layer.LayerShape == null || !Layer.Leds.Any())
|
if (Layer.LayerShape == null || !Layer.Leds.Any())
|
||||||
@ -104,21 +116,22 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rect bounds = _layerEditorService.GetLayerBounds(Layer);
|
Rect bounds = _layerEditorService.GetLayerBounds(Layer);
|
||||||
Geometry shapeGeometry = Geometry.Empty;
|
|
||||||
switch (Layer.LayerShape)
|
// Only bother the UI thread for both of these if we're sure
|
||||||
|
if (HasShapeChanged(bounds))
|
||||||
{
|
{
|
||||||
case EllipseShape _:
|
Execute.OnUIThreadSync(() =>
|
||||||
shapeGeometry = new EllipseGeometry(bounds);
|
{
|
||||||
break;
|
if (Layer.LayerShape is RectangleShape)
|
||||||
case RectangleShape _:
|
ShapeGeometry = new RectangleGeometry(bounds);
|
||||||
shapeGeometry = new RectangleGeometry(bounds);
|
if (Layer.LayerShape is EllipseShape)
|
||||||
break;
|
ShapeGeometry = new EllipseGeometry(bounds);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ((Layer.LayerBrush == null || Layer.LayerBrush.SupportsTransformation) && HasTransformationChanged())
|
||||||
|
{
|
||||||
|
Execute.OnUIThreadSync(() => ShapeGeometry.Transform = _layerEditorService.GetLayerTransformGroup(Layer));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Layer.LayerBrush == null || Layer.LayerBrush.SupportsTransformation)
|
|
||||||
shapeGeometry.Transform = _layerEditorService.GetLayerTransformGroup(Layer);
|
|
||||||
|
|
||||||
ShapeGeometry = shapeGeometry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateViewportRectangle()
|
private void CreateViewportRectangle()
|
||||||
@ -132,44 +145,30 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
|||||||
ViewportRectangle = _layerEditorService.GetLayerBounds(Layer);
|
ViewportRectangle = _layerEditorService.GetLayerBounds(Layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Geometry CreateRectangleGeometry(ArtemisLed led)
|
private bool HasShapeChanged(Rect bounds)
|
||||||
{
|
{
|
||||||
Rect rect = led.RgbLed.AbsoluteBoundary.ToWindowsRect(1);
|
bool result = !Equals(_lastBounds, bounds) || !Equals(_lastShape, Layer.LayerShape);
|
||||||
return new RectangleGeometry(rect);
|
_lastShape = Layer.LayerShape;
|
||||||
|
_lastBounds = bounds;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Geometry CreateCircleGeometry(ArtemisLed led)
|
private bool HasTransformationChanged()
|
||||||
{
|
{
|
||||||
Rect rect = led.RgbLed.AbsoluteBoundary.ToWindowsRect(1);
|
bool result = _lastAnchor != Layer.Transform.AnchorPoint.CurrentValue ||
|
||||||
return new EllipseGeometry(rect);
|
_lastPosition != Layer.Transform.Position.CurrentValue ||
|
||||||
|
_lastRotation != Layer.Transform.Rotation.CurrentValue ||
|
||||||
|
_lastScale != Layer.Transform.Scale.CurrentValue;
|
||||||
|
|
||||||
|
_lastAnchor = Layer.Transform.AnchorPoint.CurrentValue;
|
||||||
|
_lastPosition = Layer.Transform.Position.CurrentValue;
|
||||||
|
_lastRotation = Layer.Transform.Rotation.CurrentValue;
|
||||||
|
_lastScale = Layer.Transform.Scale.CurrentValue;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Geometry CreateCustomGeometry(ArtemisLed led, double deflateAmount)
|
#endregion
|
||||||
{
|
|
||||||
Rect rect = led.RgbLed.AbsoluteBoundary.ToWindowsRect(1);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PathGeometry 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 Overrides of Screen
|
#region Overrides of Screen
|
||||||
|
|
||||||
|
|||||||
@ -51,7 +51,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
|||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
if (!(ProfileEditorService.SelectedProfileElement is Layer layer))
|
if (ProfileEditorService.SelectedProfileElement is not Layer layer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ShapePath = _layerEditorService.GetLayerPath(layer, true, true, true);
|
ShapePath = _layerEditorService.GetLayerPath(layer, true, true, true);
|
||||||
|
|||||||
@ -152,11 +152,6 @@ namespace Artemis.UI.Screens.Shared
|
|||||||
PanY = rect.Top * -1 * Zoom;
|
PanY = rect.Top * -1 * Zoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rect TransformContainingRect(Rectangle rect)
|
|
||||||
{
|
|
||||||
return TransformContainingRect(rect.ToWindowsRect(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Rect TransformContainingRect(Rect rect)
|
public Rect TransformContainingRect(Rect rect)
|
||||||
{
|
{
|
||||||
// Create the same transform group the view is using
|
// Create the same transform group the view is using
|
||||||
@ -168,6 +163,17 @@ namespace Artemis.UI.Screens.Shared
|
|||||||
return transformGroup.TransformBounds(rect);
|
return transformGroup.TransformBounds(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Rect UnTransformContainingRect(Rect rect)
|
||||||
|
{
|
||||||
|
// Create the same transform group the view is using
|
||||||
|
TransformGroup transformGroup = new();
|
||||||
|
transformGroup.Children.Add(new TranslateTransform(PanX * -1, PanY * -1));
|
||||||
|
transformGroup.Children.Add(new ScaleTransform(1 / Zoom, 1 / Zoom));
|
||||||
|
|
||||||
|
// Apply it to the device rect
|
||||||
|
return transformGroup.TransformBounds(rect);
|
||||||
|
}
|
||||||
|
|
||||||
public Point GetRelativeMousePosition(object container, MouseEventArgs e)
|
public Point GetRelativeMousePosition(object container, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
// Get the mouse position relative to the panned / zoomed panel, not very MVVM but I can't find a better way
|
// Get the mouse position relative to the panned / zoomed panel, not very MVVM but I can't find a better way
|
||||||
|
|||||||
@ -188,8 +188,7 @@
|
|||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
<Canvas>
|
<Canvas>
|
||||||
<Rectangle ClipToBounds="False"
|
<Rectangle Width="{Binding MaxTextureSize}"
|
||||||
Width="{Binding MaxTextureSize}"
|
|
||||||
Height="{Binding MaxTextureSize}"
|
Height="{Binding MaxTextureSize}"
|
||||||
Stroke="{DynamicResource SecondaryHueMidBrush}"
|
Stroke="{DynamicResource SecondaryHueMidBrush}"
|
||||||
StrokeThickness="{Binding MaxTextureSizeIndicatorThickness}"
|
StrokeThickness="{Binding MaxTextureSizeIndicatorThickness}"
|
||||||
|
|||||||
@ -18,6 +18,7 @@ using Artemis.UI.Screens.SurfaceEditor.Visualization;
|
|||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
using SkiaSharp.Views.WPF;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
using MouseButton = System.Windows.Input.MouseButton;
|
using MouseButton = System.Windows.Input.MouseButton;
|
||||||
|
|
||||||
@ -305,7 +306,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
|||||||
if (e.LeftButton == MouseButtonState.Pressed)
|
if (e.LeftButton == MouseButtonState.Pressed)
|
||||||
StartMouseDrag(sender, position, relative);
|
StartMouseDrag(sender, position, relative);
|
||||||
else
|
else
|
||||||
StopMouseDrag(sender, position);
|
StopMouseDrag(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once UnusedMember.Global - Called from view
|
// ReSharper disable once UnusedMember.Global - Called from view
|
||||||
@ -323,7 +324,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
|||||||
if (_mouseDragStatus == MouseDragStatus.Dragging)
|
if (_mouseDragStatus == MouseDragStatus.Dragging)
|
||||||
MoveSelected(relative);
|
MoveSelected(relative);
|
||||||
else if (_mouseDragStatus == MouseDragStatus.Selecting)
|
else if (_mouseDragStatus == MouseDragStatus.Selecting)
|
||||||
UpdateSelection(sender, position);
|
UpdateSelection(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartMouseDrag(object sender, Point position, Point relative)
|
private void StartMouseDrag(object sender, Point position, Point relative)
|
||||||
@ -360,17 +361,18 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
|||||||
ApplySurfaceSelection();
|
ApplySurfaceSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StopMouseDrag(object sender, Point position)
|
private void StopMouseDrag(Point position)
|
||||||
{
|
{
|
||||||
if (_mouseDragStatus != MouseDragStatus.Dragging)
|
if (_mouseDragStatus != MouseDragStatus.Dragging)
|
||||||
{
|
{
|
||||||
RectangleGeometry selectedRect = new(new Rect(_mouseDragStartPoint, position));
|
SKRect hitTestRect = PanZoomViewModel.UnTransformContainingRect(new Rect(_mouseDragStartPoint, position)).ToSKRect();
|
||||||
List<SurfaceDeviceViewModel> devices = HitTestUtilities.GetHitViewModels<SurfaceDeviceViewModel>((Visual) sender, selectedRect);
|
|
||||||
foreach (SurfaceDeviceViewModel device in SurfaceDeviceViewModels)
|
foreach (SurfaceDeviceViewModel device in SurfaceDeviceViewModels)
|
||||||
if (devices.Contains(device))
|
{
|
||||||
|
if (device.Device.Rectangle.IntersectsWith(hitTestRect))
|
||||||
device.SelectionStatus = SelectionStatus.Selected;
|
device.SelectionStatus = SelectionStatus.Selected;
|
||||||
else if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
|
else if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
|
||||||
device.SelectionStatus = SelectionStatus.None;
|
device.SelectionStatus = SelectionStatus.None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -382,7 +384,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
|||||||
ApplySurfaceSelection();
|
ApplySurfaceSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateSelection(object sender, Point position)
|
private void UpdateSelection(Point position)
|
||||||
{
|
{
|
||||||
if (IsPanKeyDown())
|
if (IsPanKeyDown())
|
||||||
return;
|
return;
|
||||||
@ -390,12 +392,14 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
|||||||
Rect selectedRect = new(_mouseDragStartPoint, position);
|
Rect selectedRect = new(_mouseDragStartPoint, position);
|
||||||
SelectionRectangle.Rect = selectedRect;
|
SelectionRectangle.Rect = selectedRect;
|
||||||
|
|
||||||
List<SurfaceDeviceViewModel> devices = HitTestUtilities.GetHitViewModels<SurfaceDeviceViewModel>((Visual) sender, SelectionRectangle);
|
SKRect hitTestRect = PanZoomViewModel.UnTransformContainingRect(new Rect(_mouseDragStartPoint, position)).ToSKRect();
|
||||||
foreach (SurfaceDeviceViewModel device in SurfaceDeviceViewModels)
|
foreach (SurfaceDeviceViewModel device in SurfaceDeviceViewModels)
|
||||||
if (devices.Contains(device))
|
{
|
||||||
|
if (device.Device.Rectangle.IntersectsWith(hitTestRect))
|
||||||
device.SelectionStatus = SelectionStatus.Selected;
|
device.SelectionStatus = SelectionStatus.Selected;
|
||||||
else if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
|
else if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
|
||||||
device.SelectionStatus = SelectionStatus.None;
|
device.SelectionStatus = SelectionStatus.None;
|
||||||
|
}
|
||||||
|
|
||||||
ApplySurfaceSelection();
|
ApplySurfaceSelection();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user