mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Core - Streamlined public parts of profile creation
UI - Started adjusting the VMs for the layer refactor
This commit is contained in:
1 parent
1de6fefc2a
commit
c07ea09c9d
58 files changed
+694
-1196
No files matched your search
@@ -1,60 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.Visualization.ProfileDeviceView"
|
||||
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:s="https://github.com/canton7/Stylet"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||
xmlns:visualization1="clr-namespace:Artemis.UI.Screens.ProfileEditor.Visualization"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type visualization1:ProfileDeviceViewModel}}">
|
||||
<UserControl.Resources>
|
||||
<converters:NullToImageConverter x:Key="NullToImageConverter" />
|
||||
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid Width="{Binding Device.RgbDevice.ActualSize.Width}" Height="{Binding Device.RgbDevice.ActualSize.Height}">
|
||||
<Grid.RenderTransform>
|
||||
<RotateTransform Angle="{Binding Device.Rotation}" />
|
||||
</Grid.RenderTransform>
|
||||
|
||||
<!-- Device image with fallback -->
|
||||
<Image VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
Source="{Binding Device.RgbDevice.DeviceInfo.Image, Converter={StaticResource NullToImageConverter}}" />
|
||||
|
||||
<Rectangle Fill="{DynamicResource MaterialDesignCardBackground}"
|
||||
Stroke="{DynamicResource MaterialDesignTextBoxBorder}"
|
||||
Margin="-5"
|
||||
StrokeThickness="1"
|
||||
Visibility="{Binding Device.RgbDevice.DeviceInfo.Image, ConverterParameter=Inverted, Converter={StaticResource NullToVisibilityConverter}}" />
|
||||
<TextBlock Text="{Binding Device.RgbDevice.DeviceInfo.DeviceName}"
|
||||
Visibility="{Binding Device.RgbDevice.DeviceInfo.Image, ConverterParameter=Inverted, Converter={StaticResource NullToVisibilityConverter}}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
TextWrapping="Wrap"
|
||||
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 Width="{Binding Width}" Height="{Binding Height}" s:View.Model="{Binding}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,96 +0,0 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Artemis.Core;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
{
|
||||
public class ProfileDeviceViewModel : CanvasViewModel
|
||||
{
|
||||
private bool _addedLeds;
|
||||
private ArtemisDevice _device;
|
||||
private ObservableCollection<ProfileLedViewModel> _leds;
|
||||
|
||||
public ProfileDeviceViewModel(ArtemisDevice device)
|
||||
{
|
||||
Device = device;
|
||||
Leds = new ObservableCollection<ProfileLedViewModel>();
|
||||
|
||||
Task.Run(AddLedsAsync);
|
||||
}
|
||||
|
||||
public ObservableCollection<ProfileLedViewModel> Leds
|
||||
{
|
||||
get => _leds;
|
||||
set => SetAndNotify(ref _leds, value);
|
||||
}
|
||||
|
||||
public ArtemisDevice Device
|
||||
{
|
||||
get => _device;
|
||||
set => SetAndNotify(ref _device, value);
|
||||
}
|
||||
|
||||
public bool AddedLeds
|
||||
{
|
||||
get => _addedLeds;
|
||||
private set => SetAndNotify(ref _addedLeds, value);
|
||||
}
|
||||
|
||||
public new double X
|
||||
{
|
||||
get => Device.X;
|
||||
set => Device.X = value;
|
||||
}
|
||||
|
||||
public new double Y
|
||||
{
|
||||
get => Device.Y;
|
||||
set => Device.Y = value;
|
||||
}
|
||||
|
||||
public int ZIndex
|
||||
{
|
||||
get => Device.ZIndex;
|
||||
set => Device.ZIndex = value;
|
||||
}
|
||||
|
||||
|
||||
public Rect DeviceRectangle => Device.RgbDevice == null
|
||||
? new Rect()
|
||||
: new Rect(X, Y, Device.RgbDevice.Size.Width, Device.RgbDevice.Size.Height);
|
||||
|
||||
/// <summary>
|
||||
/// Update the color of all LEDs if finished adding
|
||||
/// </summary>
|
||||
public void Update()
|
||||
{
|
||||
if (!AddedLeds)
|
||||
return;
|
||||
|
||||
foreach (var ledViewModel in Leds)
|
||||
ledViewModel.Update();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds LEDs in batches of 5 to avoid UI freezes
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task AddLedsAsync()
|
||||
{
|
||||
var index = 0;
|
||||
foreach (var led in Device.Leds.ToList())
|
||||
{
|
||||
Execute.OnUIThreadSync(() => Leds.Add(new ProfileLedViewModel(led)));
|
||||
if (index % 5 == 0)
|
||||
await Task.Delay(1);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
AddedLeds = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.Visualization.ProfileLedView"
|
||||
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:visualization1="clr-namespace:Artemis.UI.Screens.ProfileEditor.Visualization"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance {x:Type visualization1:ProfileLedViewModel}}"
|
||||
d:DesignHeight="25" d:DesignWidth="25">
|
||||
<UserControl.Resources>
|
||||
<converters:NullToImageConverter x:Key="NullToImageConverter" />
|
||||
<Style TargetType="{x:Type Path}" x:Key="DimStyle">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsDimmed}" Value="True">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="(Shape.Opacity)" To="0.2" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="(Shape.Opacity)" To="1" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
<Canvas Width="{Binding Led.RgbLed.ActualSize.Width, Mode=OneWay}" Height="{Binding Led.RgbLed.ActualSize.Height, Mode=OneWay}">
|
||||
<Canvas.Background>
|
||||
<ImageBrush AlignmentX="Center" AlignmentY="Center" Stretch="Fill"
|
||||
ImageSource="{Binding Led.RgbLed.Image, Converter={StaticResource NullToImageConverter}, Mode=OneWay}" />
|
||||
</Canvas.Background>
|
||||
|
||||
<Path Data="{Binding DisplayGeometry, Mode=OneWay}" ClipToBounds="False" Style="{StaticResource DimStyle}">
|
||||
<Path.Fill>
|
||||
<SolidColorBrush Color="{Binding DisplayColor, Mode=OneWay}" Opacity="0.333" />
|
||||
</Path.Fill>
|
||||
</Path>
|
||||
<Path Data="{Binding StrokeGeometry, Mode=OneWay}" ClipToBounds="False" Style="{StaticResource DimStyle}">
|
||||
<Path.Fill>
|
||||
<SolidColorBrush Color="{Binding DisplayColor, Mode=OneWay}" />
|
||||
</Path.Fill>
|
||||
</Path>
|
||||
|
||||
<!-- Selection -->
|
||||
<Path Data="{Binding DisplayGeometry, Mode=OneWay}" ClipToBounds="False" StrokeThickness="1" StrokeLineJoin="Round">
|
||||
<Path.Style>
|
||||
<Style TargetType="{x:Type Path}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsSelected}" Value="True">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard x:Name="ToSelected">
|
||||
<Storyboard>
|
||||
<ColorAnimation
|
||||
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
|
||||
To="{StaticResource Accent700}" Duration="0:0:0.25" />
|
||||
<ColorAnimation
|
||||
Storyboard.TargetProperty="(Shape.Stroke).(SolidColorBrush.Color)"
|
||||
To="{StaticResource Accent400}" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<ColorAnimation
|
||||
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
|
||||
To="Transparent" Duration="0:0:0.25" />
|
||||
<ColorAnimation
|
||||
Storyboard.TargetProperty="(Shape.Stroke).(SolidColorBrush.Color)"
|
||||
To="Transparent" Duration="0:0:0.25" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Path.Style>
|
||||
<Path.Fill>
|
||||
<SolidColorBrush Opacity="0.25" />
|
||||
</Path.Fill>
|
||||
<Path.Stroke>
|
||||
<SolidColorBrush Opacity="0.5" />
|
||||
</Path.Stroke>
|
||||
</Path>
|
||||
</Canvas>
|
||||
</UserControl>
|
||||
@@ -1,148 +0,0 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Extensions;
|
||||
using RGB.NET.Core;
|
||||
using Stylet;
|
||||
using Color = System.Windows.Media.Color;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
{
|
||||
public class ProfileLedViewModel : PropertyChangedBase
|
||||
{
|
||||
private Color _displayColor;
|
||||
private Geometry _displayGeometry;
|
||||
private bool _isDimmed;
|
||||
private bool _isSelected;
|
||||
private Geometry _strokeGeometry;
|
||||
|
||||
public ProfileLedViewModel(ArtemisLed led)
|
||||
{
|
||||
Led = led;
|
||||
|
||||
// Don't want ActualLocation here since rotation is done in XAML
|
||||
X = led.RgbLed.Location.X * led.RgbLed.Device.Scale.Horizontal;
|
||||
Y = led.RgbLed.Location.Y * led.RgbLed.Device.Scale.Vertical;
|
||||
Width = led.RgbLed.ActualSize.Width;
|
||||
Height = led.RgbLed.ActualSize.Height;
|
||||
|
||||
Execute.PostToUIThread(CreateLedGeometry);
|
||||
}
|
||||
|
||||
public ArtemisLed Led { get; }
|
||||
|
||||
public double X { get; }
|
||||
public double Y { get; }
|
||||
public double Width { get; }
|
||||
public double Height { get; }
|
||||
|
||||
public bool IsSelected
|
||||
{
|
||||
get => _isSelected;
|
||||
set => SetAndNotify(ref _isSelected, value);
|
||||
}
|
||||
|
||||
public bool IsDimmed
|
||||
{
|
||||
get => _isDimmed;
|
||||
set => SetAndNotify(ref _isDimmed, value);
|
||||
}
|
||||
|
||||
public Geometry DisplayGeometry
|
||||
{
|
||||
get => _displayGeometry;
|
||||
private set => SetAndNotify(ref _displayGeometry, value);
|
||||
}
|
||||
|
||||
public Geometry StrokeGeometry
|
||||
{
|
||||
get => _strokeGeometry;
|
||||
private set => SetAndNotify(ref _strokeGeometry, value);
|
||||
}
|
||||
|
||||
public Color DisplayColor
|
||||
{
|
||||
get => _displayColor;
|
||||
private set => SetAndNotify(ref _displayColor, value);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
var newColor = Led.RgbLed.Color.ToMediaColor();
|
||||
Execute.PostToUIThread(() =>
|
||||
{
|
||||
if (!DisplayColor.Equals(newColor))
|
||||
DisplayColor = newColor;
|
||||
});
|
||||
}
|
||||
|
||||
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
|
||||
StrokeGeometry = DisplayGeometry.GetWidenedPathGeometry(new Pen(null, 1.0), 0.1, ToleranceType.Absolute);
|
||||
DisplayGeometry.Freeze();
|
||||
StrokeGeometry.Freeze();
|
||||
}
|
||||
|
||||
private void CreateRectangleGeometry()
|
||||
{
|
||||
DisplayGeometry = new RectangleGeometry(new Rect(0.5, 0.5, Width - 1, Height - 1));
|
||||
}
|
||||
|
||||
private void CreateCircleGeometry()
|
||||
{
|
||||
DisplayGeometry = new EllipseGeometry(new Rect(0.5, 0.5, Width - 1, Height - 1));
|
||||
}
|
||||
|
||||
private void CreateKeyCapGeometry()
|
||||
{
|
||||
DisplayGeometry = new RectangleGeometry(new Rect(1, 1, Width - 2, 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(Width - deflateAmount, Height - deflateAmount),
|
||||
new TranslateTransform(deflateAmount / 2, deflateAmount / 2)
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CreateRectangleGeometry();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
{
|
||||
public class ProfileViewModel : ProfileEditorPanelViewModel, IHandle<MainWindowFocusChangedEvent>, IHandle<MainWindowKeyEvent>
|
||||
public class ProfileViewModel : Screen, IProfileEditorPanelViewModel, IHandle<MainWindowFocusChangedEvent>, IHandle<MainWindowKeyEvent>
|
||||
{
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private readonly IProfileLayerVmFactory _profileLayerVmFactory;
|
||||
|
||||
Reference in new issue
Block a user