1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Profile editor - Added effect renaming

Core - Fixed effect loading
Core - Fixed some effects not applying on per-LED brushes
This commit is contained in:
Robert 2022-04-23 21:12:06 +02:00
parent 2bf36fbf20
commit cd8656cb0d
18 changed files with 292 additions and 79 deletions

View File

@ -18,9 +18,12 @@
<entry key="Artemis.UI/DefaultTypes/PropertyInput/ColorGradientPropertyInputView.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Dialogs/AddEffectView.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertiesView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/LayerEffectRenameView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/SidebarCategoryEditView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreeGroupView.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreePropertyView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/Settings/Tabs/GeneralTabView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/Sidebar/ContentDialogs/SidebarCategoryEditView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Avalonia/Artemis.UI/Screens/Debugger/Tabs/Render/RenderDebugView.axaml" value="Avalonia/Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Avalonia/Artemis.UI/Styles/Artemis.axaml" value="Avalonia/Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
</map>

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Artemis.Core.JsonConverters;
using Artemis.Core.Services;
using Artemis.Core.Services.Core;
@ -14,6 +15,11 @@ namespace Artemis.Core
/// </summary>
public static class Constants
{
/// <summary>
/// The Artemis.Core assembly
/// </summary>
public static readonly Assembly CoreAssembly = typeof(Constants).Assembly;
/// <summary>
/// The full path to the Artemis application folder
/// </summary>

View File

@ -627,13 +627,12 @@ namespace Artemis.Core
if (LayerBrush == null)
throw new ArtemisCoreException("The layer is not yet ready for rendering");
using SKAutoCanvasRestore _ = new(canvas);
foreach (BaseLayerEffect baseLayerEffect in LayerEffects)
{
if (!baseLayerEffect.Suspended)
baseLayerEffect.InternalPreProcess(canvas, bounds, layerPaint);
}
using SKAutoCanvasRestore _ = new(canvas);
canvas.ClipPath(renderPath);
// Restore the blend mode before doing the actual render

View File

@ -35,7 +35,6 @@ namespace Artemis.Core.LayerBrushes
canvas.SetMatrix(canvas.TotalMatrix.PreConcat(Layer.GetTransformMatrix(true, false, false, true).Invert()));
using SKPath pointsPath = new();
using SKPaint ledPaint = new();
foreach (ArtemisLed artemisLed in Layer.Leds)
{
pointsPath.AddPoly(new[]
@ -61,7 +60,7 @@ namespace Artemis.Core.LayerBrushes
continue;
// Let the brush determine the color
ledPaint.Color = GetColor(artemisLed, renderPoint);
paint.Color = GetColor(artemisLed, renderPoint);
SKRect ledRectangle = SKRect.Create(
artemisLed.AbsoluteRectangle.Left - Layer.Bounds.Left,
@ -70,7 +69,7 @@ namespace Artemis.Core.LayerBrushes
artemisLed.AbsoluteRectangle.Height
);
canvas.DrawRect(ledRectangle, ledPaint);
canvas.DrawRect(ledRectangle, paint);
}
}, "Failed to render");
}

View File

@ -222,8 +222,8 @@ namespace Artemis.Core.LayerEffects
/// <inheritdoc />
public void Load()
{
Name = LayerEffectEntity.Name;
HasBeenRenamed = LayerEffectEntity.HasBeenRenamed;
Name = HasBeenRenamed ? LayerEffectEntity.Name : Descriptor.DisplayName;
Order = LayerEffectEntity.Order;
}

View File

@ -87,6 +87,7 @@ public class LayerEffectDescriptor
else
{
effect.LayerEffectEntity = new LayerEffectEntity();
effect.Name = DisplayName;
effect.Initialize();
effect.Save();
}

View File

@ -51,7 +51,7 @@ namespace Artemis.Core
{
lock (Registrations)
{
return Registrations.FirstOrDefault(d => d.PluginFeature.Id == providerId && d.LayerEffectDescriptor.LayerEffectType?.Name == typeName);
return Registrations.FirstOrDefault(d => d.PluginFeature.Id == providerId && d.LayerEffectDescriptor.LayerEffectType?.FullName == typeName);
}
}

View File

@ -0,0 +1,48 @@
using System;
using Artemis.Core;
using Artemis.Core.LayerEffects;
namespace Artemis.UI.Shared.Services.ProfileEditor.Commands;
/// <summary>
/// Represents a profile editor command that can be used to remove a layer effect from a profile element.
/// </summary>
public class RemoveLayerEffect : IProfileEditorCommand, IDisposable
{
private readonly RenderProfileElement _renderProfileElement;
private readonly BaseLayerEffect _layerEffect;
private bool _executed;
/// <summary>
/// Creates a new instance of the <see cref="RemoveLayerEffect"/> class.
/// </summary>
public RemoveLayerEffect(BaseLayerEffect layerEffect)
{
_renderProfileElement = layerEffect.ProfileElement;
_layerEffect = layerEffect;
}
/// <inheritdoc />
public string DisplayName => "Remove layer effect";
/// <inheritdoc />
public void Execute()
{
_renderProfileElement.RemoveLayerEffect(_layerEffect);
_executed = true;
}
/// <inheritdoc />
public void Undo()
{
_renderProfileElement.AddLayerEffect(_layerEffect);
_executed = false;
}
/// <inheritdoc />
public void Dispose()
{
if (_executed)
_layerEffect.Dispose();
}
}

View File

@ -0,0 +1,44 @@
using System;
using Artemis.Core;
using Artemis.Core.LayerEffects;
namespace Artemis.UI.Shared.Services.ProfileEditor.Commands;
/// <summary>
/// Represents a profile editor command that can be used to rename a layer effect
/// </summary>
public class RenameLayerEffect : IProfileEditorCommand
{
private readonly BaseLayerEffect _layerEffect;
private readonly string _name;
private readonly string _oldName;
private readonly bool _wasRenamed;
/// <summary>
/// Creates a new instance of the <see cref="RenameLayerEffect"/> class.
/// </summary>
public RenameLayerEffect(BaseLayerEffect layerEffect, string name)
{
_layerEffect = layerEffect;
_name = name;
_oldName = layerEffect.Name;
_wasRenamed = layerEffect.HasBeenRenamed;
}
/// <inheritdoc />
public string DisplayName => "Rename layer effect";
/// <inheritdoc />
public void Execute()
{
_layerEffect.Name = _name;
_layerEffect.HasBeenRenamed = true;
}
/// <inheritdoc />
public void Undo()
{
_layerEffect.Name = _oldName;
_layerEffect.HasBeenRenamed = _wasRenamed;
}
}

View File

@ -68,6 +68,14 @@
<Compile Update="Screens\VisualScripting\NodeScriptWindowView.axaml.cs">
<DependentUpon>NodeScriptWindowView.axaml</DependentUpon>
</Compile>
<Compile Update="Screens\ProfileEditor\Panels\Properties\Tree\ContentDialogs\LayerEffectRenameView.axaml.cs">
<DependentUpon>LayerEffectRenameView.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Update="Screens\ProfileEditor\Panels\Properties\Tree\ContentDialogs\SidebarCategoryEditView.axaml.cs">
<DependentUpon>SidebarCategoryEditView.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<AvaloniaXaml Update="DefaultTypes\PropertyInput\StringPropertyInputView.axaml">

View File

@ -1,4 +1,5 @@
using Artemis.Core;
using System;
using Artemis.Core;
using Artemis.UI.Shared.Services.ProfileEditor;
using Artemis.UI.Shared.Services.PropertyInput;
using ReactiveUI;
@ -14,17 +15,17 @@ public class SKPointPropertyInputViewModel : PropertyInputViewModel<SKPoint>
{
if (LayerProperty.PropertyDescription.MinInputValue.IsNumber())
{
this.ValidationRule(vm => vm.X, i => i >= (float) LayerProperty.PropertyDescription.MinInputValue,
this.ValidationRule(vm => vm.X, i => i >= Convert.ToSingle(LayerProperty.PropertyDescription.MinInputValue),
$"X must be equal to or greater than {LayerProperty.PropertyDescription.MinInputValue}.");
this.ValidationRule(vm => vm.Y, i => i >= (float) LayerProperty.PropertyDescription.MinInputValue,
this.ValidationRule(vm => vm.Y, i => i >= Convert.ToSingle(LayerProperty.PropertyDescription.MinInputValue),
$"Y must be equal to or greater than {LayerProperty.PropertyDescription.MinInputValue}.");
}
if (LayerProperty.PropertyDescription.MaxInputValue.IsNumber())
{
this.ValidationRule(vm => vm.X, i => i <= (float) LayerProperty.PropertyDescription.MaxInputValue,
this.ValidationRule(vm => vm.X, i => i <= Convert.ToSingle(LayerProperty.PropertyDescription.MaxInputValue),
$"X must be equal to or smaller than {LayerProperty.PropertyDescription.MaxInputValue}.");
this.ValidationRule(vm => vm.Y, i => i <= (float) LayerProperty.PropertyDescription.MaxInputValue,
this.ValidationRule(vm => vm.Y, i => i <= Convert.ToSingle(LayerProperty.PropertyDescription.MaxInputValue),
$"Y must be equal to or smaller than {LayerProperty.PropertyDescription.MaxInputValue}.");
}
}

View File

@ -1,4 +1,5 @@
using Artemis.Core;
using System;
using Artemis.Core;
using Artemis.UI.Shared.Services.ProfileEditor;
using Artemis.UI.Shared.Services.PropertyInput;
using ReactiveUI;
@ -16,17 +17,17 @@ public class SKSizePropertyInputViewModel : PropertyInputViewModel<SKSize>
{
if (LayerProperty.PropertyDescription.MinInputValue.IsNumber())
{
this.ValidationRule(vm => vm.Width, i => i >= (float) LayerProperty.PropertyDescription.MinInputValue,
this.ValidationRule(vm => vm.Width, i => i >= Convert.ToSingle(LayerProperty.PropertyDescription.MinInputValue),
$"Width must be equal to or greater than {LayerProperty.PropertyDescription.MinInputValue}.");
this.ValidationRule(vm => vm.Height, i => i >= (float) LayerProperty.PropertyDescription.MinInputValue,
this.ValidationRule(vm => vm.Height, i => i >= Convert.ToSingle(LayerProperty.PropertyDescription.MinInputValue),
$"Height must be equal to or greater than {LayerProperty.PropertyDescription.MinInputValue}.");
}
if (LayerProperty.PropertyDescription.MaxInputValue.IsNumber())
{
this.ValidationRule(vm => vm.Width, i => i <= (float) LayerProperty.PropertyDescription.MaxInputValue,
this.ValidationRule(vm => vm.Width, i => i <= Convert.ToSingle(LayerProperty.PropertyDescription.MaxInputValue),
$"Width must be equal to or smaller than {LayerProperty.PropertyDescription.MaxInputValue}.");
this.ValidationRule(vm => vm.Height, i => i <= (float) LayerProperty.PropertyDescription.MaxInputValue,
this.ValidationRule(vm => vm.Height, i => i <= Convert.ToSingle(LayerProperty.PropertyDescription.MaxInputValue),
$"Height must be equal to or smaller than {LayerProperty.PropertyDescription.MaxInputValue}.");
}
}

View File

@ -117,7 +117,8 @@ public class PropertyGroupViewModel : ViewModelBase, IDisposable
{
// Get all properties and property groups and create VMs for them
// The group has methods for getting this without reflection but then we lose the order of the properties as they are defined on the group
foreach (PropertyInfo propertyInfo in LayerPropertyGroup.GetType().GetProperties())
// Sorting is done to ensure properties defined by the Core (such as on layers) are always on top.
foreach (PropertyInfo propertyInfo in LayerPropertyGroup.GetType().GetProperties().OrderBy(p => p.DeclaringType?.Assembly != Constants.CoreAssembly))
{
if (Attribute.IsDefined(propertyInfo, typeof(LayerPropertyIgnoreAttribute)))
continue;

View File

@ -0,0 +1,15 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:contentDialogs="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties.Tree.ContentDialogs"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Tree.ContentDialogs.LayerEffectRenameView"
x:DataType="contentDialogs:LayerEffectRenameViewModel">
<StackPanel>
<StackPanel.KeyBindings>
<KeyBinding Gesture="Enter" Command="{CompiledBinding Confirm}" />
</StackPanel.KeyBindings>
<TextBox Name="NameTextBox" Text="{CompiledBinding LayerEffectName}" Watermark="Layer effect name"/>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,35 @@
using System.Threading.Tasks;
using Artemis.UI.Shared.Extensions;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using Avalonia.Threading;
using ReactiveUI;
namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree.ContentDialogs;
public class LayerEffectRenameView : ReactiveUserControl<LayerEffectRenameViewModel>
{
public LayerEffectRenameView()
{
InitializeComponent();
this.WhenActivated(_ =>
{
this.ClearAllDataValidationErrors();
Dispatcher.UIThread.Post(DelayedAutoFocus);
});
}
private async void DelayedAutoFocus()
{
// Don't ask
await Task.Delay(200);
this.Get<TextBox>("NameTextBox").SelectAll();
this.Get<TextBox>("NameTextBox").Focus();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

View File

@ -0,0 +1,45 @@
using System.Reactive;
using Artemis.Core.LayerEffects;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services.ProfileEditor;
using Artemis.UI.Shared.Services.ProfileEditor.Commands;
using FluentAvalonia.UI.Controls;
using ReactiveUI;
using ReactiveUI.Validation.Extensions;
namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree.ContentDialogs
{
public class LayerEffectRenameViewModel : ContentDialogViewModelBase
{
private readonly IProfileEditorService _profileEditorService;
private readonly BaseLayerEffect _layerEffect;
private string? _layerEffectName;
public LayerEffectRenameViewModel(IProfileEditorService profileEditorService, BaseLayerEffect layerEffect)
{
_profileEditorService = profileEditorService;
_layerEffect = layerEffect;
_layerEffectName = layerEffect.Name;
Confirm = ReactiveCommand.Create(ExecuteConfirm, ValidationContext.Valid);
this.ValidationRule(vm => vm.LayerEffectName, categoryName => !string.IsNullOrWhiteSpace(categoryName), "You must specify a valid name");
}
public string? LayerEffectName
{
get => _layerEffectName;
set => this.RaiseAndSetIfChanged(ref _layerEffectName, value);
}
public ReactiveCommand<Unit, Unit> Confirm { get; }
private void ExecuteConfirm()
{
if (LayerEffectName == null)
return;
_profileEditorService.ExecuteCommand(new RenameLayerEffect(_layerEffect, LayerEffectName));
ContentDialog?.Hide(ContentDialogResult.Primary);
}
}
}

View File

@ -9,7 +9,8 @@
xmlns:properties="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties"
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Tree.TreeGroupView">
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Tree.TreeGroupView"
x:DataType="viewModel:TreeGroupViewModel">
<UserControl.Resources>
<converters:PropertyTreeMarginConverter x:Key="PropertyTreeMarginConverter" Length="20" />
<sharedConverters:EnumToBooleanConverter x:Key="EnumBoolConverter" />
@ -26,8 +27,8 @@
Height="29">
<Grid Margin="{Binding Converter={StaticResource PropertyTreeMarginConverter}}" ColumnDefinitions="19,*">
<avalonia:MaterialIcon Classes.chevron-collapsed="{Binding !PropertyGroupViewModel.IsExpanded}"
IsVisible="{Binding PropertyGroupViewModel.HasChildren}"
<avalonia:MaterialIcon Classes.chevron-collapsed="{CompiledBinding !PropertyGroupViewModel.IsExpanded}"
IsVisible="{CompiledBinding PropertyGroupViewModel.HasChildren}"
Kind="ChevronDown"
Grid.Column="0"
Margin="5 0"
@ -42,59 +43,59 @@
<StackPanel Grid.Column="1">
<!-- Type: None -->
<TextBlock Text="{Binding LayerPropertyGroup.GroupDescription.Name}"
ToolTip.Tip="{Binding LayerPropertyGroup.GroupDescription.Description}"
<TextBlock Text="{CompiledBinding LayerPropertyGroup.GroupDescription.Name}"
ToolTip.Tip="{CompiledBinding LayerPropertyGroup.GroupDescription.Description}"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="3 5 0 5"
IsVisible="{Binding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.None}}" />
IsVisible="{CompiledBinding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.None}}" />
<!-- Type: General -->
<StackPanel Orientation="Horizontal"
Margin="0 5"
IsVisible="{Binding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.General}}">
IsVisible="{CompiledBinding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.General}}">
<avalonia:MaterialIcon Kind="HammerWrench" Margin="0 0 5 0" />
<TextBlock ToolTip.Tip="{Binding LayerPropertyGroup.GroupDescription.Description}">General</TextBlock>
<TextBlock ToolTip.Tip="{CompiledBinding LayerPropertyGroup.GroupDescription.Description}">General</TextBlock>
</StackPanel>
<!-- Type: Transform -->
<StackPanel Orientation="Horizontal"
Margin="0 5"
IsVisible="{Binding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.Transform}}">
IsVisible="{CompiledBinding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.Transform}}">
<avalonia:MaterialIcon Kind="TransitConnectionVariant" Margin="0 0 5 0" />
<TextBlock ToolTip.Tip="{Binding LayerPropertyGroup.GroupDescription.Description}">Transform</TextBlock>
<TextBlock ToolTip.Tip="{CompiledBinding LayerPropertyGroup.GroupDescription.Description}">Transform</TextBlock>
</StackPanel>
<!-- Type: LayerBrushRoot -->
<Grid IsVisible="{Binding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.LayerBrushRoot}}"
<Grid IsVisible="{CompiledBinding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.LayerBrushRoot}}"
Height="29"
ColumnDefinitions="Auto,Auto,Auto,*">
<shared:ArtemisIcon Grid.Column="0"
Icon="{Binding LayerBrush.Descriptor.Icon}"
Icon="{CompiledBinding LayerBrush.Descriptor.Icon}"
Width="16"
Height="16"
Margin="0 0 5 0" />
<TextBlock Grid.Column="1"
ToolTip.Tip="{Binding LayerBrush.Descriptor.Description}"
ToolTip.Tip="{CompiledBinding LayerBrush.Descriptor.Description}"
Margin="0 5 5 0">
Brush -
</TextBlock>
<TextBlock Grid.Column="2"
Text="{Binding LayerBrush.Descriptor.DisplayName}"
ToolTip.Tip="{Binding LayerBrush.Descriptor.Description}"
Text="{CompiledBinding LayerBrush.Descriptor.DisplayName}"
ToolTip.Tip="{CompiledBinding LayerBrush.Descriptor.Description}"
Margin="0 5 0 0" />
<StackPanel Grid.Column="3"
Orientation="Horizontal"
HorizontalAlignment="Right"
IsVisible="{Binding LayerBrush.ConfigurationDialog, Converter={x:Static ObjectConverters.IsNotNull}}">
IsVisible="{CompiledBinding LayerBrush.ConfigurationDialog, Converter={x:Static ObjectConverters.IsNotNull}}">
<TextBlock VerticalAlignment="Center">Extra options available!</TextBlock>
<avalonia:MaterialIcon Kind="ChevronRight" VerticalAlignment="Center">
<avalonia:MaterialIcon.RenderTransform>
<TranslateTransform X="0" />
</avalonia:MaterialIcon.RenderTransform>
</avalonia:MaterialIcon>
<Button Classes="icon-button" ToolTip.Tip="Open brush settings" Width="24" Height="24" HorizontalAlignment="Right" Command="{Binding OpenBrushSettings}">
<Button Classes="icon-button" ToolTip.Tip="Open brush settings" Width="24" Height="24" HorizontalAlignment="Right" Command="{CompiledBinding OpenBrushSettings}">
<avalonia:MaterialIcon Kind="Settings" Height="16" Width="16" />
</Button>
</StackPanel>
@ -102,61 +103,45 @@
</Grid>
<!-- Type: LayerEffectRoot -->
<Grid IsVisible="{Binding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.LayerEffectRoot}}"
<Grid IsVisible="{CompiledBinding GroupType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static viewModel:LayerPropertyGroupType.LayerEffectRoot}}"
Height="29"
ColumnDefinitions="Auto,Auto,Auto,Auto,*,Auto">
<shared:ArtemisIcon
Grid.Column="0"
Cursor="SizeNorthSouth"
Icon="{Binding LayerEffect.Descriptor.Icon}"
Icon="{CompiledBinding LayerEffect.Descriptor.Icon}"
Width="16"
Height="16"
Margin="0 0 5 0"
Background="Transparent" />
<TextBlock Grid.Column="1" ToolTip.Tip="{Binding LayerEffect.Descriptor.Description}" Margin="0 5 0 0">
<TextBlock Grid.Column="1" ToolTip.Tip="{CompiledBinding LayerEffect.Descriptor.Description}" Margin="0 5 0 0">
Effect
</TextBlock>
<TextBlock Grid.Column="2"
ToolTip.Tip="{Binding LayerEffect.Descriptor.Description}"
ToolTip.Tip="{CompiledBinding LayerEffect.Descriptor.Description}"
Margin="3 5">
-
</TextBlock>
<!-- Show either the descriptors display name or, if set, the effect name -->
<TextBlock Grid.Column="3"
Text="{Binding LayerEffect.Descriptor.DisplayName}"
ToolTip.Tip="{Binding LayerEffect.Descriptor.Description}"
Text="{CompiledBinding LayerEffect.Descriptor.DisplayName}"
ToolTip.Tip="{CompiledBinding LayerEffect.Descriptor.Description}"
Margin="0 5"
IsVisible="{Binding !LayerEffect.Name, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
IsVisible="{CompiledBinding !LayerEffect.HasBeenRenamed}" />
<TextBlock Grid.Column="4"
Text="{Binding LayerEffect.Name}"
ToolTip.Tip="{Binding LayerEffect.Descriptor.Description}"
Text="{CompiledBinding LayerEffect.Name}"
ToolTip.Tip="{CompiledBinding LayerEffect.Descriptor.Description}"
Margin="0 5"
IsVisible="{Binding LayerEffect.Name, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
IsVisible="{CompiledBinding LayerEffect.HasBeenRenamed}" />
<StackPanel Grid.Column="5" Orientation="Horizontal" Spacing="2">
<Button Classes="icon-button"
ToolTip.Tip="Toggle suspended state"
Width="24"
Height="24"
VerticalAlignment="Center"
Command="{Binding SuspendedToggled}">
<avalonia:MaterialIcon Kind="EyeOff" Height="16" Width="16" IsVisible="True" />
</Button>
<Button Classes="icon-button"
ToolTip.Tip="Toggle suspended state"
Width="24"
Height="24"
VerticalAlignment="Center"
Command="{Binding SuspendedToggled}">
<avalonia:MaterialIcon Kind="Eye" Height="16" Width="16" IsVisible="True" />
</Button>
<Button Classes="icon-button"
ToolTip.Tip="Rename"
Width="24"
Height="24"
VerticalAlignment="Center"
Command="{Binding RenameEffect}">
Command="{CompiledBinding RenameEffect}">
<avalonia:MaterialIcon Kind="RenameBox" Height="16" Width="16" />
</Button>
<Button Classes="icon-button"
@ -164,8 +149,8 @@
Width="24"
Height="24"
VerticalAlignment="Center"
Command="{Binding OpenEffectSettings}"
IsVisible="{Binding LayerEffect.ConfigurationDialog, Converter={x:Static ObjectConverters.IsNotNull}}">
Command="{CompiledBinding OpenEffectSettings}"
IsVisible="{CompiledBinding LayerEffect.ConfigurationDialog, Converter={x:Static ObjectConverters.IsNotNull}}">
<avalonia:MaterialIcon Kind="Settings" Height="16" Width="16" />
</Button>
<Button Classes="icon-button"
@ -173,7 +158,7 @@
Width="24"
Height="24"
VerticalAlignment="Center"
Command="{Binding DeleteEffect}">
Command="{CompiledBinding DeleteEffect}">
<avalonia:MaterialIcon Kind="TrashCan" Height="16" Width="16" />
</Button>
</StackPanel>
@ -186,15 +171,15 @@
Do not bind directly to the PropertyGroupViewModel.Children collection
Instead use a reference provided by the VM that is null when collapsed, virtualization for noobs
-->
<ItemsControl Items="{Binding Children}"
IsVisible="{Binding PropertyGroupViewModel.IsExpanded}"
<ItemsControl Items="{CompiledBinding Children}"
IsVisible="{CompiledBinding PropertyGroupViewModel.IsExpanded}"
HorizontalAlignment="Stretch">
<ItemsControl.DataTemplates>
<DataTemplate DataType="properties:PropertyGroupViewModel">
<ContentControl Content="{Binding TreeGroupViewModel}" IsVisible="{Binding IsVisible}" />
<ContentControl Content="{CompiledBinding TreeGroupViewModel}" IsVisible="{CompiledBinding IsVisible}" />
</DataTemplate>
<DataTemplate DataType="properties:PropertyViewModel">
<ContentControl Content="{Binding TreePropertyViewModel}" IsVisible="{Binding IsVisible}" />
<ContentControl Content="{CompiledBinding TreePropertyViewModel}" IsVisible="{CompiledBinding IsVisible}" />
</DataTemplate>
</ItemsControl.DataTemplates>
</ItemsControl>

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reflection;
using System.Threading.Tasks;
@ -8,12 +9,15 @@ using Artemis.Core;
using Artemis.Core.LayerBrushes;
using Artemis.Core.LayerEffects;
using Artemis.UI.Exceptions;
using Artemis.UI.Screens.ProfileEditor.Properties.Tree.ContentDialogs;
using Artemis.UI.Screens.ProfileEditor.Properties.Windows;
using Artemis.UI.Shared;
using Artemis.UI.Shared.LayerBrushes;
using Artemis.UI.Shared.LayerEffects;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Builders;
using Artemis.UI.Shared.Services.ProfileEditor;
using Artemis.UI.Shared.Services.ProfileEditor.Commands;
using Ninject;
using Ninject.Parameters;
using ReactiveUI;
@ -41,19 +45,25 @@ public class TreeGroupViewModel : ActivatableViewModelBase
});
// TODO: Update ProfileElementPropertyGroupViewModel visibility on change (can remove the sub on line 41 as well then)
OpenBrushSettings = ReactiveCommand.CreateFromTask(ExecuteOpenBrushSettings);
OpenEffectSettings = ReactiveCommand.CreateFromTask(ExecuteOpenEffectSettings);
RenameEffect = ReactiveCommand.CreateFromTask(ExecuteRenameEffect);
DeleteEffect = ReactiveCommand.Create(ExecuteDeleteEffect);
}
public PropertyGroupViewModel PropertyGroupViewModel { get; }
public LayerPropertyGroup LayerPropertyGroup => PropertyGroupViewModel.LayerPropertyGroup;
public BaseLayerBrush? LayerBrush => PropertyGroupViewModel.LayerBrush;
public BaseLayerEffect? LayerEffect => PropertyGroupViewModel.LayerEffect;
public ObservableCollection<ViewModelBase>? Children => PropertyGroupViewModel.IsExpanded ? PropertyGroupViewModel.Children : null;
public LayerPropertyGroupType GroupType { get; private set; }
public ObservableCollection<ViewModelBase>? Children => PropertyGroupViewModel.IsExpanded ? PropertyGroupViewModel.Children : null;
public ReactiveCommand<Unit, Unit> OpenBrushSettings { get; }
public ReactiveCommand<Unit, Unit> OpenEffectSettings { get; }
public ReactiveCommand<Unit, Unit> RenameEffect { get; }
public ReactiveCommand<Unit, Unit> DeleteEffect { get; }
public async Task OpenBrushSettings()
private async Task ExecuteOpenBrushSettings()
{
if (LayerBrush?.ConfigurationDialog is not LayerBrushConfigurationDialog configurationViewModel)
return;
@ -83,7 +93,7 @@ public class TreeGroupViewModel : ActivatableViewModelBase
}
}
public async Task OpenEffectSettings()
private async Task ExecuteOpenEffectSettings()
{
if (LayerEffect?.ConfigurationDialog is not LayerEffectConfigurationDialog configurationViewModel)
return;
@ -113,14 +123,26 @@ public class TreeGroupViewModel : ActivatableViewModelBase
}
}
public async Task RenameEffect()
private async Task ExecuteRenameEffect()
{
await _windowService.ShowConfirmContentDialog("Not yet implemented", "Try again later :p");
if (LayerEffect == null)
return;
await _windowService.CreateContentDialog()
.WithTitle("Rename layer effect")
.WithViewModel(out LayerEffectRenameViewModel vm, ("layerEffect", LayerEffect))
.HavingPrimaryButton(b => b.WithText("Confirm").WithCommand(vm.Confirm))
.WithCloseButtonText("Cancel")
.WithDefaultButton(ContentDialogButton.Primary)
.ShowAsync();
}
public async Task DeleteEffect()
private void ExecuteDeleteEffect()
{
await _windowService.ShowConfirmContentDialog("Not yet implemented", "Try again later :p");
if (LayerEffect == null)
return;
_profileEditorService.ExecuteCommand(new RemoveLayerEffect(LayerEffect));
}
public double GetDepth()