diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs
index e456e3d64..f363c3d03 100644
--- a/src/Artemis.Core/Models/Profile/Layer.cs
+++ b/src/Artemis.Core/Models/Profile/Layer.cs
@@ -166,6 +166,7 @@ namespace Artemis.Core.Models.Profile
{
var layerEffectEntity = new LayerEffectEntity
{
+ Id = layerEffect.EntityId,
PluginGuid = layerEffect.PluginInfo.Guid,
EffectType = layerEffect.GetType().Name,
Name = layerEffect.Name,
@@ -524,7 +525,7 @@ namespace Artemis.Core.Models.Profile
var index = 0;
foreach (var baseLayerEffect in LayerEffects.OrderBy(e => e.Order))
{
- baseLayerEffect.UpdateOrder(index + 1);
+ baseLayerEffect.Order = Order = index + 1;
index++;
}
diff --git a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs
index d26c7403f..599f1d704 100644
--- a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs
+++ b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs
@@ -78,6 +78,11 @@ namespace Artemis.Core.Models.Profile
}
}
+ ///
+ /// Gets or sets whether the group is expanded in the UI
+ ///
+ public bool IsExpanded { get; set; }
+
///
/// A list of all layer properties in this group
///
@@ -107,21 +112,6 @@ namespace Artemis.Core.Models.Profile
return _allLayerProperties;
}
- public void UpdateOrder(int oldOrder)
- {
- // Expanded state is tied to the path so save it before changing the path
- var expanded = Layer.IsPropertyGroupExpanded(this);
- Layer.SetPropertyGroupExpanded(this, false);
-
- Path = Path.Replace($"LayerEffect.{oldOrder}.", $"LayerEffect.{LayerEffect.Order}.");
- // Restore the expanded state with the new path
- Layer.SetPropertyGroupExpanded(this, expanded);
-
- // Update children
- foreach (var layerPropertyGroup in LayerPropertyGroups)
- layerPropertyGroup.UpdateOrder(oldOrder);
- }
-
///
/// Called before properties are fully initialized to allow you to populate
/// on the properties you want
diff --git a/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs b/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs
index 2c01cbc6d..bd884e2d1 100644
--- a/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs
+++ b/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs
@@ -12,6 +12,11 @@ namespace Artemis.Core.Plugins.LayerEffect.Abstract
///
public abstract class BaseLayerEffect : PropertyChangedBase, IDisposable
{
+ ///
+ /// Gets the unique ID of this effect
+ ///
+ public Guid EntityId { get; internal set; }
+
///
/// Gets the layer this effect is applied to
///
@@ -36,7 +41,7 @@ namespace Artemis.Core.Plugins.LayerEffect.Abstract
///
/// Gets the order in which this effect appears in the update loop and editor
///
- public int Order { get; internal set; }
+ public int Order { get; set; }
///
/// Gets the descriptor of this effect
@@ -53,7 +58,7 @@ namespace Artemis.Core.Plugins.LayerEffect.Abstract
///
public virtual LayerPropertyGroup BaseProperties => null;
- internal string PropertyRootPath => $"LayerEffect.{Order}.{GetType().Name}.";
+ internal string PropertyRootPath => $"LayerEffect.{EntityId}.{GetType().Name}.";
public void Dispose()
{
@@ -85,17 +90,7 @@ namespace Artemis.Core.Plugins.LayerEffect.Abstract
/// Called after the layer of folder has been rendered
///
public abstract void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint);
-
- public void UpdateOrder(int newOrder)
- {
- if (newOrder == Order)
- return;
-
- var oldOrder = Order;
- Order = newOrder;
- BaseProperties.UpdateOrder(oldOrder);
- }
-
+
internal void InternalPreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
{
// Move the canvas to the top-left of the render path
diff --git a/src/Artemis.Core/Services/Interfaces/ILayerService.cs b/src/Artemis.Core/Services/Interfaces/ILayerService.cs
index 1cdc7fc4f..dae95c425 100644
--- a/src/Artemis.Core/Services/Interfaces/ILayerService.cs
+++ b/src/Artemis.Core/Services/Interfaces/ILayerService.cs
@@ -17,6 +17,12 @@ namespace Artemis.Core.Services.Interfaces
///
Layer CreateLayer(Profile profile, ProfileElement parent, string name);
+ ///
+ /// Removes the currently active layer brush from the and deletes any settings
+ ///
+ /// The layer to remove the active brush from
+ void RemoveLayerBrush(Layer layer);
+
///
/// Instantiates and adds the described by the provided
///
diff --git a/src/Artemis.Core/Services/LayerService.cs b/src/Artemis.Core/Services/LayerService.cs
index 2c844a6a0..eb9967fa7 100644
--- a/src/Artemis.Core/Services/LayerService.cs
+++ b/src/Artemis.Core/Services/LayerService.cs
@@ -1,4 +1,5 @@
-using System.Linq;
+using System;
+using System.Linq;
using Artemis.Core.Exceptions;
using Artemis.Core.Models.Profile;
using Artemis.Core.Plugins.Abstract;
@@ -40,6 +41,12 @@ namespace Artemis.Core.Services
return layer;
}
+ public void RemoveLayerBrush(Layer layer)
+ {
+ layer.RemoveLayerBrush();
+ layer.OnLayerBrushUpdated();
+ }
+
public BaseLayerBrush InstantiateLayerBrush(Layer layer)
{
if (layer.LayerBrush != null)
@@ -87,6 +94,7 @@ namespace Artemis.Core.Services
continue;
var effect = (BaseLayerEffect) _kernel.Get(descriptor.LayerEffectType);
+ effect.EntityId = layerEntityLayerEffect.Id;
effect.Layer = layer;
effect.Order = layerEntityLayerEffect.Order;
effect.Name = layerEntityLayerEffect.Name;
@@ -104,6 +112,7 @@ namespace Artemis.Core.Services
public BaseLayerEffect AddLayerEffect(Layer layer, LayerEffectDescriptor layerEffectDescriptor)
{
var effect = (BaseLayerEffect) _kernel.Get(layerEffectDescriptor.LayerEffectType);
+ effect.EntityId = Guid.NewGuid();
effect.Layer = layer;
effect.Order = layer.LayerEffects.Count + 1;
effect.Descriptor = layerEffectDescriptor;
@@ -113,7 +122,7 @@ namespace Artemis.Core.Services
layer.AddLayerEffect(effect);
_logger.Debug("Added layer effect with root path {rootPath}", effect.PropertyRootPath);
-
+
layer.OnLayerEffectsUpdated();
return effect;
}
diff --git a/src/Artemis.Storage/Entities/Profile/LayerEffectEntity.cs b/src/Artemis.Storage/Entities/Profile/LayerEffectEntity.cs
index ce7239258..85d3d1a34 100644
--- a/src/Artemis.Storage/Entities/Profile/LayerEffectEntity.cs
+++ b/src/Artemis.Storage/Entities/Profile/LayerEffectEntity.cs
@@ -4,6 +4,7 @@ namespace Artemis.Storage.Entities.Profile
{
public class LayerEffectEntity
{
+ public Guid Id { get; set; }
public Guid PluginGuid { get; set; }
public string EffectType { get; set; }
public string Name { get; set; }
diff --git a/src/Artemis.UI.Shared/Controls/DraggableFloat.xaml.cs b/src/Artemis.UI.Shared/Controls/DraggableFloat.xaml.cs
index 3e5ec23a6..7d2ba3c10 100644
--- a/src/Artemis.UI.Shared/Controls/DraggableFloat.xaml.cs
+++ b/src/Artemis.UI.Shared/Controls/DraggableFloat.xaml.cs
@@ -80,6 +80,8 @@ namespace Artemis.UI.Shared.Controls
private void InputMouseDown(object sender, MouseButtonEventArgs e)
{
+ e.Handled = true;
+
_startValue = Value;
((IInputElement) sender).CaptureMouse();
_mouseDragStartPoint = e.GetPosition((IInputElement) sender);
@@ -87,6 +89,8 @@ namespace Artemis.UI.Shared.Controls
private void InputMouseUp(object sender, MouseButtonEventArgs e)
{
+ e.Handled = true;
+
var position = e.GetPosition((IInputElement) sender);
if (position == _mouseDragStartPoint)
DisplayInput();
@@ -104,6 +108,8 @@ namespace Artemis.UI.Shared.Controls
if (e.LeftButton != MouseButtonState.Pressed)
return;
+ e.Handled = true;
+
if (!_calledDragStarted)
{
OnDragStarted();
diff --git a/src/Artemis.UI.Shared/Utilities/EnumUtilities.cs b/src/Artemis.UI.Shared/Utilities/EnumUtilities.cs
index 4fe404335..720b6042b 100644
--- a/src/Artemis.UI.Shared/Utilities/EnumUtilities.cs
+++ b/src/Artemis.UI.Shared/Utilities/EnumUtilities.cs
@@ -28,6 +28,11 @@ namespace Artemis.UI.Shared.Utilities
return Enum.GetValues(t).Cast().Select(e => new ValueDescription {Value = e, Description = e.Humanize()}).ToList();
}
+
+ public static string HumanizeValue(Enum value)
+ {
+ return value.Humanize();
+ }
}
public class ValueDescription
diff --git a/src/Artemis.UI/PropertyInput/BrushPropertyInputViewModel.cs b/src/Artemis.UI/PropertyInput/BrushPropertyInputViewModel.cs
index b5784fafb..b62721c9a 100644
--- a/src/Artemis.UI/PropertyInput/BrushPropertyInputViewModel.cs
+++ b/src/Artemis.UI/PropertyInput/BrushPropertyInputViewModel.cs
@@ -52,6 +52,7 @@ namespace Artemis.UI.PropertyInput
protected override void OnInputValueApplied()
{
+ _layerService.RemoveLayerBrush(LayerProperty.Layer);
_layerService.InstantiateLayerBrush(LayerProperty.Layer);
}
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs
index 0b3f878bf..73fcdfbd2 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Input;
@@ -14,13 +15,17 @@ using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerEffects;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree;
+using Artemis.UI.Screens.Module.ProfileEditor.ProfileTree;
+using Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem;
using Artemis.UI.Shared.Events;
using Artemis.UI.Shared.Services.Interfaces;
+using GongSolutions.Wpf.DragDrop;
using Stylet;
+using static Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerPropertyGroupViewModel.ViewModelType;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
{
- public class LayerPropertiesViewModel : ProfileEditorPanelViewModel
+ public class LayerPropertiesViewModel : ProfileEditorPanelViewModel, IDropTarget
{
private readonly ILayerPropertyVmFactory _layerPropertyVmFactory;
private LayerPropertyGroupViewModel _brushPropertyGroup;
@@ -215,6 +220,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
LayerPropertyGroups.Add(_brushPropertyGroup);
}
+ SortProperties();
TimelineViewModel.UpdateKeyframes();
}
@@ -244,9 +250,100 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
LayerPropertyGroups.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(layerEffect.BaseProperties, brushDescription));
}
+ SortProperties();
TimelineViewModel.UpdateKeyframes();
}
+ private void SortProperties()
+ {
+ // Get all non-effect properties
+ var nonEffectProperties = LayerPropertyGroups.Where(l => l.GroupType != LayerEffectRoot).ToList();
+ // Order the effects
+ var effectProperties = LayerPropertyGroups.Where(l => l.GroupType == LayerEffectRoot).OrderBy(l => l.LayerPropertyGroup.LayerEffect.Order).ToList();
+
+ // Put the non-effect properties in front
+ for (var index = 0; index < nonEffectProperties.Count; index++)
+ {
+ var layerPropertyGroupViewModel = nonEffectProperties[index];
+ LayerPropertyGroups.Move(LayerPropertyGroups.IndexOf(layerPropertyGroupViewModel), index);
+ }
+
+ // Put the effect properties after, sorted by their order
+ for (var index = 0; index < effectProperties.Count; index++)
+ {
+ var layerPropertyGroupViewModel = effectProperties[index];
+ LayerPropertyGroups.Move(LayerPropertyGroups.IndexOf(layerPropertyGroupViewModel), index + nonEffectProperties.Count);
+ }
+ }
+
+ #endregion
+
+ #region Drag and drop
+
+ public void DragOver(IDropInfo dropInfo)
+ {
+ // Workaround for https://github.com/punker76/gong-wpf-dragdrop/issues/344
+ // Luckily we know the index can never be 1 so it's an easy enough fix
+ if (dropInfo.InsertIndex == 1)
+ return;
+
+ var source = dropInfo.Data as LayerPropertyGroupViewModel;
+ var target = dropInfo.TargetItem as LayerPropertyGroupViewModel;
+
+ if (source == target || target?.GroupType != LayerEffectRoot || source?.GroupType != LayerEffectRoot)
+ return;
+
+ dropInfo.DropTargetAdorner = DropTargetAdorners.Insert;
+ dropInfo.Effects = DragDropEffects.Move;
+ }
+
+ public void Drop(IDropInfo dropInfo)
+ {
+ // Workaround for https://github.com/punker76/gong-wpf-dragdrop/issues/344
+ // Luckily we know the index can never be 1 so it's an easy enough fix
+ if (dropInfo.InsertIndex == 1)
+ return;
+
+ var source = dropInfo.Data as LayerPropertyGroupViewModel;
+ var target = dropInfo.TargetItem as LayerPropertyGroupViewModel;
+
+ if (source == target || target?.GroupType != LayerEffectRoot || source?.GroupType != LayerEffectRoot)
+ return;
+
+ if (dropInfo.InsertPosition == RelativeInsertPosition.BeforeTargetItem)
+ MoveBefore(source, target);
+ else if (dropInfo.InsertPosition == RelativeInsertPosition.AfterTargetItem)
+ MoveAfter(source, target);
+
+ ApplyCurrentEffectsOrder();
+ ProfileEditorService.UpdateSelectedProfile(true);
+ }
+
+ private void MoveBefore(LayerPropertyGroupViewModel source, LayerPropertyGroupViewModel target)
+ {
+ if (LayerPropertyGroups.IndexOf(target) == LayerPropertyGroups.IndexOf(source) + 1)
+ return;
+
+ LayerPropertyGroups.Move(LayerPropertyGroups.IndexOf(source), LayerPropertyGroups.IndexOf(target));
+ }
+
+ private void MoveAfter(LayerPropertyGroupViewModel source, LayerPropertyGroupViewModel target)
+ {
+ LayerPropertyGroups.Remove(source);
+ LayerPropertyGroups.Insert(LayerPropertyGroups.IndexOf(target) + 1, source);
+ }
+
+ private void ApplyCurrentEffectsOrder()
+ {
+ var order = 1;
+ foreach (var groupViewModel in LayerPropertyGroups.Where(p => p.GroupType == LayerEffectRoot))
+ {
+
+ groupViewModel.UpdateOrder(order);
+ order++;
+ }
+ }
+
#endregion
#region Controls
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyGroupViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyGroupViewModel.cs
index db8dfd445..d1e45882e 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyGroupViewModel.cs
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyGroupViewModel.cs
@@ -155,5 +155,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
{
NotifyOfPropertyChange(nameof(IsVisible));
}
+
+ public void UpdateOrder(int order)
+ {
+ LayerPropertyGroup.LayerEffect.Order = order;
+ NotifyOfPropertyChange(nameof(IsExpanded));
+ }
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml
index 8604092ba..e8a33bc36 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml
@@ -7,6 +7,7 @@
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:converters="clr-namespace:Artemis.UI.Converters"
+ xmlns:dd="urn:gong-wpf-dragdrop"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance local:TreePropertyGroupViewModel}"
d:DesignHeight="450" d:DesignWidth="800">
@@ -16,6 +17,7 @@
-
+
-
+
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreeView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreeView.xaml
index bd84c6cb5..f96b3d4a2 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreeView.xaml
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreeView.xaml
@@ -8,6 +8,7 @@
xmlns:converters="clr-namespace:Artemis.UI.Converters"
xmlns:abstract="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract"
xmlns:layerProperties="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties"
+ xmlns:dd="urn:gong-wpf-dragdrop"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type local:TreeViewModel}}">
@@ -87,6 +88,9 @@
HorizontalContentAlignment="Stretch"
Background="{DynamicResource MaterialDesignToolBarBackground}"
PreviewMouseWheel="{s:Action PropertyTreePreviewMouseWheel}"
+ dd:DragDrop.IsDragSource="True"
+ dd:DragDrop.IsDropTarget="True"
+ dd:DragDrop.DropHandler="{Binding LayerPropertiesViewModel}"
Margin="0 -1">