1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00
Artemis/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs
SpoinkyNL 92a3e0d61b Color brush - Fixed gradient picker not appearing
Gradient picker - Use dialog instead of a popup window
2020-04-17 23:01:42 +02:00

168 lines
6.4 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
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;
namespace Artemis.UI.Shared.Controls
{
public class DeviceVisualizer : FrameworkElement, IDisposable
{
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, ShowColorsPropertyChangedCallback));
private readonly DrawingGroup _backingStore;
private readonly List<DeviceVisualizerLed> _deviceVisualizerLeds;
private BitmapImage _deviceImage;
private bool _subscribed;
public DeviceVisualizer()
{
_backingStore = new DrawingGroup();
_deviceVisualizerLeds = new List<DeviceVisualizerLed>();
Loaded += (sender, args) => SubscribeToUpdate(true);
Unloaded += (sender, args) => SubscribeToUpdate(false);
}
private void SubscribeToUpdate(bool subscribe)
{
if (_subscribed == subscribe)
return;
if (subscribe)
RGBSurface.Instance.Updated += RgbSurfaceOnUpdated;
else
RGBSurface.Instance.Updated -= RgbSurfaceOnUpdated;
_subscribed = subscribe;
}
public ArtemisDevice Device
{
get => (ArtemisDevice) GetValue(DeviceProperty);
set => SetValue(DeviceProperty, value);
}
public bool ShowColors
{
get => (bool) GetValue(ShowColorsProperty);
set => SetValue(ShowColorsProperty, value);
}
public void Dispose()
{
RGBSurface.Instance.Updated -= RgbSurfaceOnUpdated;
}
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.RenderImage(drawingContext);
drawingContext.DrawDrawing(_backingStore);
}
private static void DevicePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var deviceVisualizer = (DeviceVisualizer) d;
deviceVisualizer.Dispatcher.Invoke(() => { deviceVisualizer.SetupForDevice(); });
}
private static void ShowColorsPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var deviceVisualizer = (DeviceVisualizer) d;
deviceVisualizer.Dispatcher.Invoke(() => { deviceVisualizer.SetupForDevice(); });
}
private void SetupForDevice()
{
_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));
if (!ShowColors)
return;
// Create the opacity drawing group
var opacityDrawingGroup = new DrawingGroup();
var drawingContext = opacityDrawingGroup.Open();
foreach (var deviceVisualizerLed in _deviceVisualizerLeds)
deviceVisualizerLed.RenderOpacityMask(drawingContext);
drawingContext.Close();
// Render the store as a bitmap
var drawingImage = new DrawingImage(opacityDrawingGroup);
var image = new Image {Source = drawingImage};
var bitmap = new RenderTargetBitmap(
(int) (opacityDrawingGroup.Bounds.Width * 2.5),
(int) (opacityDrawingGroup.Bounds.Height * 2.5),
96,
96,
PixelFormats.Pbgra32
);
image.Arrange(new Rect(0, 0, bitmap.Width, bitmap.Height));
bitmap.Render(image);
bitmap.Freeze();
// Set the bitmap as the opacity mask for the colors backing store
var bitmapBrush = new ImageBrush(bitmap);
bitmapBrush.Freeze();
_backingStore.OpacityMask = bitmapBrush;
}
private void RgbSurfaceOnUpdated(UpdatedEventArgs e)
{
Dispatcher.Invoke(() =>
{
if (ShowColors && Visibility == Visibility.Visible)
Render();
});
}
private void Render()
{
var drawingContext = _backingStore.Open();
foreach (var deviceVisualizerLed in _deviceVisualizerLeds)
deviceVisualizerLed.RenderColor(drawingContext);
drawingContext.Close();
}
}
}