From 376a9142d31a53a5a07d001f3b657359ca9d0833 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 9 Mar 2022 00:10:41 +0100 Subject: [PATCH] Profile editor - Fixed new elements not rendering while paused Profile editor - Use default brush on new layers Profile tree - Implement drag & drop --- src/Artemis.Core/Models/Profile/Folder.cs | 4 +- .../Interfaces/ILayerBrushService.cs | 2 + .../Registration/LayerBrushService.cs | 8 + .../Commands/AddProfileElement.cs | 2 + .../PropertyInput/PropertyInputViewModel.cs | 2 +- .../Converters/ColorOpacityConverter.cs | 23 ++ .../SKColorPropertyInputView.axaml | 4 +- .../SKColorPropertyInputView.axaml.cs | 12 + .../Behaviors/ProfileTreeViewDropHandler.cs | 41 +- .../ProfileTree/FolderTreeItemViewModel.cs | 10 +- .../ProfileTree/LayerTreeItemViewModel.cs | 10 +- .../Panels/ProfileTree/ProfileTreeView.axaml | 50 ++- .../ProfileTree/ProfileTreeViewModel.cs | 12 +- .../Panels/ProfileTree/TreeItemViewModel.cs | 384 +++++++++--------- 14 files changed, 335 insertions(+), 229 deletions(-) create mode 100644 src/Avalonia/Artemis.UI/Converters/ColorOpacityConverter.cs diff --git a/src/Artemis.Core/Models/Profile/Folder.cs b/src/Artemis.Core/Models/Profile/Folder.cs index 96dd20416..463ddfbb4 100644 --- a/src/Artemis.Core/Models/Profile/Folder.cs +++ b/src/Artemis.Core/Models/Profile/Folder.cs @@ -185,7 +185,7 @@ namespace Artemis.Core // No point rendering if all children are disabled if (!Children.Any(c => c is RenderProfileElement {Enabled: true})) return; - + SKPaint layerPaint = new() {FilterQuality = SKFilterQuality.Low}; try { @@ -266,7 +266,7 @@ namespace Artemis.Core /// Occurs when a property affecting the rendering properties of this folder has been updated /// public event EventHandler? RenderPropertiesUpdated; - + /// protected override void Dispose(bool disposing) { diff --git a/src/Artemis.Core/Services/Registration/Interfaces/ILayerBrushService.cs b/src/Artemis.Core/Services/Registration/Interfaces/ILayerBrushService.cs index d0f6167e4..648495a55 100644 --- a/src/Artemis.Core/Services/Registration/Interfaces/ILayerBrushService.cs +++ b/src/Artemis.Core/Services/Registration/Interfaces/ILayerBrushService.cs @@ -27,5 +27,7 @@ namespace Artemis.Core.Services /// Returns the descriptor of the default layer brush /// LayerBrushDescriptor? GetDefaultLayerBrush(); + + void ApplyDefaultBrush(Layer layer); } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/Registration/LayerBrushService.cs b/src/Artemis.Core/Services/Registration/LayerBrushService.cs index c3bb68a59..0c3d7a998 100644 --- a/src/Artemis.Core/Services/Registration/LayerBrushService.cs +++ b/src/Artemis.Core/Services/Registration/LayerBrushService.cs @@ -46,5 +46,13 @@ namespace Artemis.Core.Services defaultReference.Value.BrushType ??= "SolidBrush"; return LayerBrushStore.Get(defaultReference.Value.LayerBrushProviderId, defaultReference.Value.BrushType)?.LayerBrushDescriptor; } + + /// + public void ApplyDefaultBrush(Layer layer) + { + LayerBrushDescriptor? brush = GetDefaultLayerBrush(); + if (brush != null) + layer.ChangeLayerBrush(brush.CreateInstance(layer, null)); + } } } \ No newline at end of file diff --git a/src/Avalonia/Artemis.UI.Shared/Services/ProfileEditor/Commands/AddProfileElement.cs b/src/Avalonia/Artemis.UI.Shared/Services/ProfileEditor/Commands/AddProfileElement.cs index eab84bd7f..a7dad90e7 100644 --- a/src/Avalonia/Artemis.UI.Shared/Services/ProfileEditor/Commands/AddProfileElement.cs +++ b/src/Avalonia/Artemis.UI.Shared/Services/ProfileEditor/Commands/AddProfileElement.cs @@ -47,6 +47,8 @@ public class AddProfileElement : IProfileEditorCommand, IDisposable { _isAdded = true; _target.AddChild(_subject, _index); + + _subject.Enable(); } /// diff --git a/src/Avalonia/Artemis.UI.Shared/Services/PropertyInput/PropertyInputViewModel.cs b/src/Avalonia/Artemis.UI.Shared/Services/PropertyInput/PropertyInputViewModel.cs index 469758d88..742675c7e 100644 --- a/src/Avalonia/Artemis.UI.Shared/Services/PropertyInput/PropertyInputViewModel.cs +++ b/src/Avalonia/Artemis.UI.Shared/Services/PropertyInput/PropertyInputViewModel.cs @@ -134,7 +134,7 @@ public abstract class PropertyInputViewModel : PropertyInputViewModel return; if (_preview.DiscardPreview() && _preview.PreviewValue != null) - ProfileEditorService.ExecuteCommand(new UpdateLayerProperty(LayerProperty, _inputValue, _preview.PreviewValue, Time)); + ProfileEditorService.ExecuteCommand(new UpdateLayerProperty(LayerProperty, _inputValue, _preview.OriginalValue, Time)); _preview = null; } diff --git a/src/Avalonia/Artemis.UI/Converters/ColorOpacityConverter.cs b/src/Avalonia/Artemis.UI/Converters/ColorOpacityConverter.cs new file mode 100644 index 000000000..e69ed58f5 --- /dev/null +++ b/src/Avalonia/Artemis.UI/Converters/ColorOpacityConverter.cs @@ -0,0 +1,23 @@ +using System; +using System.Globalization; +using Avalonia.Data.Converters; +using Avalonia.Media; + +namespace Artemis.UI.Converters; + +public class ColorOpacityConverter : IValueConverter +{ + /// + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is Color color && double.TryParse(parameter?.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture, out double multiplier)) + return new Color((byte) (color.A * multiplier), color.R, color.G, color.B); + return value; + } + + /// + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + return value; + } +} \ No newline at end of file diff --git a/src/Avalonia/Artemis.UI/DefaultTypes/PropertyInput/SKColorPropertyInputView.axaml b/src/Avalonia/Artemis.UI/DefaultTypes/PropertyInput/SKColorPropertyInputView.axaml index a46f7fa29..eadb2ff57 100644 --- a/src/Avalonia/Artemis.UI/DefaultTypes/PropertyInput/SKColorPropertyInputView.axaml +++ b/src/Avalonia/Artemis.UI/DefaultTypes/PropertyInput/SKColorPropertyInputView.axaml @@ -55,7 +55,9 @@ + ShowAcceptDismissButtons="False" + FlyoutOpened="ColorPickerButton_OnFlyoutOpened" + FlyoutClosed="ColorPickerButton_OnFlyoutClosed" /> \ No newline at end of file diff --git a/src/Avalonia/Artemis.UI/DefaultTypes/PropertyInput/SKColorPropertyInputView.axaml.cs b/src/Avalonia/Artemis.UI/DefaultTypes/PropertyInput/SKColorPropertyInputView.axaml.cs index 13922a4fc..8240df3f0 100644 --- a/src/Avalonia/Artemis.UI/DefaultTypes/PropertyInput/SKColorPropertyInputView.axaml.cs +++ b/src/Avalonia/Artemis.UI/DefaultTypes/PropertyInput/SKColorPropertyInputView.axaml.cs @@ -1,8 +1,10 @@ +using System; using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; +using FluentAvalonia.UI.Controls; namespace Artemis.UI.DefaultTypes.PropertyInput { @@ -17,5 +19,15 @@ namespace Artemis.UI.DefaultTypes.PropertyInput { AvaloniaXamlLoader.Load(this); } + + private void ColorPickerButton_OnFlyoutOpened(ColorPickerButton sender, EventArgs args) + { + ViewModel?.StartPreview(); + } + + private void ColorPickerButton_OnFlyoutClosed(ColorPickerButton sender, EventArgs args) + { + ViewModel?.ApplyPreview(); + } } } \ No newline at end of file diff --git a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Behaviors/ProfileTreeViewDropHandler.cs b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Behaviors/ProfileTreeViewDropHandler.cs index 42eb776f6..7958869d9 100644 --- a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Behaviors/ProfileTreeViewDropHandler.cs +++ b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Behaviors/ProfileTreeViewDropHandler.cs @@ -1,15 +1,11 @@ -using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Generators; -using Avalonia.Controls.Primitives; -using Avalonia.Controls.Shapes; using Avalonia.Input; using Avalonia.Interactivity; -using Avalonia.Media; using Avalonia.VisualTree; using Avalonia.Xaml.Interactions.DragAndDrop; @@ -34,7 +30,7 @@ public class ProfileTreeViewDropHandler : DropHandlerBase if (sender is ItemsControl itemsControl) { foreach (TreeViewItem treeViewItem in GetFlattenedTreeView(itemsControl)) - SetDraggingPseudoClasses(treeViewItem, TreeDropType.After, false); + SetDraggingPseudoClasses(treeViewItem, TreeDropType.None); } return result; @@ -42,8 +38,11 @@ public class ProfileTreeViewDropHandler : DropHandlerBase public override void Cancel(object? sender, RoutedEventArgs e) { - if (e.Source is IControl control && control.FindAncestorOfType() != null) - SetDraggingPseudoClasses(control.FindAncestorOfType(), TreeDropType.After, false); + if (sender is ItemsControl itemsControl) + { + foreach (TreeViewItem treeViewItem in GetFlattenedTreeView(itemsControl)) + SetDraggingPseudoClasses(treeViewItem, TreeDropType.None); + } base.Cancel(sender, e); } @@ -102,6 +101,9 @@ public class ProfileTreeViewDropHandler : DropHandlerBase if (e.DragEffects != DragDropEffects.Move) return false; + foreach (TreeViewItem treeViewItem in GetFlattenedTreeView(treeView)) + SetDraggingPseudoClasses(treeViewItem, TreeDropType.None); + if (bExecute) { if (dropType == TreeDropType.Into) @@ -118,7 +120,7 @@ public class ProfileTreeViewDropHandler : DropHandlerBase } else { - SetDraggingPseudoClasses((IControl) targetVisual, dropType, true); + SetDraggingPseudoClasses((IControl) targetVisual, dropType); } return true; @@ -130,7 +132,7 @@ public class ProfileTreeViewDropHandler : DropHandlerBase foreach (ItemContainerInfo containerInfo in currentNode.ItemContainerGenerator.Containers) { - if (containerInfo.ContainerControl is TreeViewItem treeViewItem && containerInfo.Item is TreeItemViewModel viewModel) + if (containerInfo.ContainerControl is TreeViewItem treeViewItem && containerInfo.Item is TreeItemViewModel) { result.Add(treeViewItem); if (treeViewItem.ItemContainerGenerator.Containers.Any()) @@ -141,9 +143,16 @@ public class ProfileTreeViewDropHandler : DropHandlerBase return result; } - private void SetDraggingPseudoClasses(IControl control, TreeDropType type, bool isDragging) + private void SetDraggingPseudoClasses(IControl control, TreeDropType type) { - if (isDragging) + if (type == TreeDropType.None) + { + ((IPseudoClasses) control.Classes).Remove(":dragging"); + ((IPseudoClasses) control.Classes).Remove(":dragging-before"); + ((IPseudoClasses) control.Classes).Remove(":dragging-after"); + ((IPseudoClasses) control.Classes).Remove(":dragging-into"); + } + else { ((IPseudoClasses) control.Classes).Add(":dragging"); if (type == TreeDropType.Before) @@ -165,19 +174,13 @@ public class ProfileTreeViewDropHandler : DropHandlerBase ((IPseudoClasses) control.Classes).Add(":dragging-into"); } } - else - { - ((IPseudoClasses) control.Classes).Remove(":dragging"); - ((IPseudoClasses) control.Classes).Remove(":dragging-before"); - ((IPseudoClasses) control.Classes).Remove(":dragging-after"); - ((IPseudoClasses) control.Classes).Remove(":dragging-into"); - } } private enum TreeDropType { Before, After, - Into + Into, + None } } \ No newline at end of file diff --git a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs index 2ae36aae5..e8e3f3558 100644 --- a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs +++ b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs @@ -8,8 +8,14 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree { public class FolderTreeItemViewModel : TreeItemViewModel { - public FolderTreeItemViewModel(TreeItemViewModel? parent, Folder folder, IWindowService windowService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory, IRgbService rgbService) - : base(parent, folder, windowService, profileEditorService, rgbService, profileEditorVmFactory) + public FolderTreeItemViewModel(TreeItemViewModel? parent, + Folder folder, + IWindowService windowService, + IProfileEditorService profileEditorService, + ILayerBrushService layerBrushService, + IProfileEditorVmFactory profileEditorVmFactory, + IRgbService rgbService) + : base(parent, folder, windowService, profileEditorService, rgbService, layerBrushService, profileEditorVmFactory) { Folder = folder; } diff --git a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs index e53af8eed..918339c72 100644 --- a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs +++ b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs @@ -8,8 +8,14 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree { public class LayerTreeItemViewModel : TreeItemViewModel { - public LayerTreeItemViewModel(TreeItemViewModel? parent, Layer layer, IWindowService windowService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory, IRgbService rgbService) - : base(parent, layer, windowService, profileEditorService, rgbService, profileEditorVmFactory) + public LayerTreeItemViewModel(TreeItemViewModel? parent, + Layer layer, + IWindowService windowService, + IProfileEditorService profileEditorService, + IRgbService rgbService, + ILayerBrushService layerBrushService, + IProfileEditorVmFactory profileEditorVmFactory) + : base(parent, layer, windowService, profileEditorService, rgbService, layerBrushService, profileEditorVmFactory) { Layer = layer; } diff --git a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeView.axaml b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeView.axaml index f52ed381e..d3a5cb1e8 100644 --- a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeView.axaml +++ b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeView.axaml @@ -6,14 +6,18 @@ xmlns:profileTree="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree" xmlns:profileBehaviors="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree.Behaviors" xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors" + xmlns:converters="clr-namespace:Artemis.UI.Converters" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.ProfileTreeView" x:DataType="profileTree:ProfileTreeViewModel"> + + + - + - +