1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2026-01-01 02:03:32 +00:00

UI - Restructured layer property VMs

This commit is contained in:
Robert 2020-05-01 23:07:21 +02:00
parent 41b3c77210
commit 54081b591b
11 changed files with 163 additions and 234 deletions

View File

@ -125,7 +125,7 @@ namespace Artemis.Core.Models.Profile
General.ApplyToEntity(); General.ApplyToEntity();
Transform.ApplyToEntity(); Transform.ApplyToEntity();
LayerBrush.ApplyToEntity(); LayerBrush.BaseProperties.ApplyToEntity();
// LEDs // LEDs
LayerEntity.Leds.Clear(); LayerEntity.Leds.Clear();
@ -187,7 +187,7 @@ namespace Artemis.Core.Models.Profile
var properties = new List<BaseLayerProperty>(General.GetAllLayerProperties()); var properties = new List<BaseLayerProperty>(General.GetAllLayerProperties());
properties.AddRange(Transform.GetAllLayerProperties()); properties.AddRange(Transform.GetAllLayerProperties());
properties.AddRange(LayerBrush.GetAllLayerProperties()); properties.AddRange(LayerBrush.BaseProperties.GetAllLayerProperties());
// For now, reset all keyframe engines after the last keyframe was hit // For now, reset all keyframe engines after the last keyframe was hit
// This is a placeholder method of repeating the animation until repeat modes are implemented // This is a placeholder method of repeating the animation until repeat modes are implemented
@ -196,13 +196,13 @@ namespace Artemis.Core.Models.Profile
{ {
General.Override(TimeSpan.Zero); General.Override(TimeSpan.Zero);
Transform.Override(TimeSpan.Zero); Transform.Override(TimeSpan.Zero);
LayerBrush.OverrideProperties(TimeSpan.Zero); LayerBrush.BaseProperties.Override(TimeSpan.Zero);
} }
else else
{ {
General.Update(deltaTime); General.Update(deltaTime);
Transform.Update(deltaTime); Transform.Update(deltaTime);
LayerBrush.UpdateProperties(deltaTime); LayerBrush.BaseProperties.Update(deltaTime);
} }
LayerBrush.Update(deltaTime); LayerBrush.Update(deltaTime);
@ -212,7 +212,7 @@ namespace Artemis.Core.Models.Profile
{ {
General.Override(timeOverride); General.Override(timeOverride);
Transform.Override(timeOverride); Transform.Override(timeOverride);
LayerBrush.OverrideProperties(timeOverride); LayerBrush.BaseProperties.Override(timeOverride);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -5,7 +5,7 @@ using Artemis.Storage.Entities.Profile;
namespace Artemis.Core.Models.Profile.LayerProperties namespace Artemis.Core.Models.Profile.LayerProperties
{ {
/// <summary> /// <summary>
/// For internal use only, to implement your own layer property type, extend <see cref="LayerProperty{T}"/> instead. /// For internal use only, to implement your own layer property type, extend <see cref="LayerProperty{T}" /> instead.
/// </summary> /// </summary>
public abstract class BaseLayerProperty public abstract class BaseLayerProperty
{ {
@ -42,11 +42,15 @@ namespace Artemis.Core.Models.Profile.LayerProperties
/// <summary> /// <summary>
/// Used to declare that this property doesn't belong to a plugin and should use the core plugin GUID /// Used to declare that this property doesn't belong to a plugin and should use the core plugin GUID
/// </summary> /// </summary>
internal bool IsCoreProperty { get; set; } public bool IsCoreProperty { get; internal set; }
/// <summary>
/// Gets a list of all the keyframes in their non-generic base form, without their values being available
/// </summary>
public abstract IReadOnlyList<BaseLayerPropertyKeyframe> BaseKeyframes { get; }
internal PropertyEntity PropertyEntity { get; set; } internal PropertyEntity PropertyEntity { get; set; }
internal LayerPropertyGroup LayerPropertyGroup { get; set; } internal LayerPropertyGroup LayerPropertyGroup { get; set; }
internal abstract IReadOnlyList<BaseLayerPropertyKeyframe> BaseKeyframes { get; }
/// <summary> /// <summary>
/// Applies the provided property entity to the layer property by deserializing the JSON base value and keyframe values /// Applies the provided property entity to the layer property by deserializing the JSON base value and keyframe values

View File

@ -70,7 +70,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
/// </summary> /// </summary>
public LayerPropertyKeyframe<T> NextKeyframe { get; protected set; } public LayerPropertyKeyframe<T> NextKeyframe { get; protected set; }
internal override IReadOnlyList<BaseLayerPropertyKeyframe> BaseKeyframes => _keyframes.Cast<BaseLayerPropertyKeyframe>().ToList().AsReadOnly(); public override IReadOnlyList<BaseLayerPropertyKeyframe> BaseKeyframes => _keyframes.Cast<BaseLayerPropertyKeyframe>().ToList().AsReadOnly();
/// <summary> /// <summary>
/// Adds a keyframe to the layer property /// Adds a keyframe to the layer property

View File

@ -14,29 +14,34 @@ namespace Artemis.Core.Models.Profile
public class LayerPropertyGroup public class LayerPropertyGroup
{ {
private ReadOnlyCollection<BaseLayerProperty> _allLayerProperties; private ReadOnlyCollection<BaseLayerProperty> _allLayerProperties;
private readonly List<BaseLayerProperty> _layerProperties;
private readonly List<LayerPropertyGroup> _layerPropertyGroups;
protected LayerPropertyGroup() protected LayerPropertyGroup()
{ {
LayerProperties = new List<BaseLayerProperty>(); _layerProperties = new List<BaseLayerProperty>();
LayerPropertyGroups = new List<LayerPropertyGroup>(); _layerPropertyGroups = new List<LayerPropertyGroup>();
} }
/// <summary>
/// Gets whether this property group's properties are all initialized
/// </summary>
public bool PropertiesInitialized { get; private set; } public bool PropertiesInitialized { get; private set; }
/// <summary> /// <summary>
/// Used to declare that this property group doesn't belong to a plugin and should use the core plugin GUID /// Used to declare that this property group doesn't belong to a plugin and should use the core plugin GUID
/// </summary> /// </summary>
internal bool IsCorePropertyGroup { get; set; } public bool IsCorePropertyGroup { get; internal set; }
/// <summary> /// <summary>
/// A list of all layer properties in this group /// A list of all layer properties in this group
/// </summary> /// </summary>
internal List<BaseLayerProperty> LayerProperties { get; set; } public ReadOnlyCollection<BaseLayerProperty> LayerProperties => _layerProperties.AsReadOnly();
/// <summary> /// <summary>
/// A list of al child groups in this group /// A list of al child groups in this group
/// </summary> /// </summary>
internal List<LayerPropertyGroup> LayerPropertyGroups { get; set; } public ReadOnlyCollection<LayerPropertyGroup> LayerPropertyGroups => _layerPropertyGroups.AsReadOnly();
/// <summary> /// <summary>
/// Called when all layer properties in this property group have been initialized /// Called when all layer properties in this property group have been initialized
@ -63,7 +68,7 @@ namespace Artemis.Core.Models.Profile
var instance = (BaseLayerProperty) Activator.CreateInstance(propertyInfo.PropertyType); var instance = (BaseLayerProperty) Activator.CreateInstance(propertyInfo.PropertyType);
InitializeProperty(layer, path, instance); InitializeProperty(layer, path, instance);
propertyInfo.SetValue(this, instance); propertyInfo.SetValue(this, instance);
LayerProperties.Add(instance); _layerProperties.Add(instance);
} }
else else
{ {
@ -76,7 +81,7 @@ namespace Artemis.Core.Models.Profile
var instance = (LayerPropertyGroup) Activator.CreateInstance(propertyInfo.PropertyType); var instance = (LayerPropertyGroup) Activator.CreateInstance(propertyInfo.PropertyType);
instance.InitializeProperties(layerService, layer, $"{path}{propertyInfo.Name}."); instance.InitializeProperties(layerService, layer, $"{path}{propertyInfo.Name}.");
propertyInfo.SetValue(this, instance); propertyInfo.SetValue(this, instance);
LayerPropertyGroups.Add(instance); _layerPropertyGroups.Add(instance);
} }
} }
} }
@ -121,7 +126,7 @@ namespace Artemis.Core.Models.Profile
/// Recursively gets all layer properties on this group and any subgroups /// Recursively gets all layer properties on this group and any subgroups
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
internal IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties() public IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties()
{ {
if (!PropertiesInitialized) if (!PropertiesInitialized)
return new List<BaseLayerProperty>(); return new List<BaseLayerProperty>();

View File

@ -1,7 +1,5 @@
using System; using System;
using System.Collections.Generic;
using Artemis.Core.Models.Profile; using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Plugins.Models; using Artemis.Core.Plugins.Models;
using Artemis.Core.Services.Interfaces; using Artemis.Core.Services.Interfaces;
using SkiaSharp; using SkiaSharp;
@ -29,7 +27,7 @@ namespace Artemis.Core.Plugins.LayerBrush
/// </summary> /// </summary>
public PluginInfo PluginInfo => Descriptor.LayerBrushProvider.PluginInfo; public PluginInfo PluginInfo => Descriptor.LayerBrushProvider.PluginInfo;
internal virtual LayerPropertyGroup BaseProperties => null; public virtual LayerPropertyGroup BaseProperties => null;
/// <summary> /// <summary>
/// Called when the brush is being removed from the layer /// Called when the brush is being removed from the layer
@ -62,22 +60,5 @@ namespace Artemis.Core.Plugins.LayerBrush
internal virtual void InitializeProperties(ILayerService layerService, string path) internal virtual void InitializeProperties(ILayerService layerService, string path)
{ {
} }
internal virtual void ApplyToEntity()
{
}
internal virtual void UpdateProperties(double deltaTime)
{
}
internal virtual void OverrideProperties(TimeSpan overrideTime)
{
}
internal virtual IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties()
{
return new List<BaseLayerProperty>();
}
} }
} }

View File

@ -47,7 +47,7 @@ namespace Artemis.Core.Plugins.LayerBrush
} }
/// <inheritdoc/> /// <inheritdoc/>
internal override LayerPropertyGroup BaseProperties => Properties; public override LayerPropertyGroup BaseProperties => Properties;
internal override void InitializeProperties(ILayerService layerService, string path) internal override void InitializeProperties(ILayerService layerService, string path)
{ {
@ -56,22 +56,17 @@ namespace Artemis.Core.Plugins.LayerBrush
PropertiesInitialized = true; PropertiesInitialized = true;
} }
internal override void ApplyToEntity() internal virtual void ApplyToEntity()
{ {
Properties.ApplyToEntity(); Properties.ApplyToEntity();
} }
internal override void UpdateProperties(double deltaTime) internal virtual void OverrideProperties(TimeSpan overrideTime)
{
Properties.Update(deltaTime);
}
internal override void OverrideProperties(TimeSpan overrideTime)
{ {
Properties.Override(overrideTime); Properties.Override(overrideTime);
} }
internal override IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties() internal virtual IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties()
{ {
return Properties.GetAllLayerProperties(); return Properties.GetAllLayerProperties();
} }

View File

@ -76,10 +76,5 @@ namespace Artemis.Core.Services
layer.LayerEntity.PropertyEntities.RemoveAll(p => p.PluginGuid == brush.PluginInfo.Guid); layer.LayerEntity.PropertyEntities.RemoveAll(p => p.PluginGuid == brush.PluginInfo.Guid);
} }
public void GetLayerPropertyGroups(Layer layer)
{
var groups = new List<LayerPropertyGroup> {layer.General, layer.Transform, layer.LayerBrush.BrushProperties};
}
} }
} }

View File

@ -0,0 +1,11 @@
using System.Collections.Generic;
using Artemis.Core.Models.Profile.LayerProperties;
using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract
{
public abstract class LayerPropertyBaseViewModel : PropertyChangedBase
{
public abstract List<BaseLayerPropertyKeyframe> GetKeyframes(bool visibleOnly);
}
}

View File

@ -7,6 +7,7 @@ using System.Windows.Media;
using Artemis.Core.Events; using Artemis.Core.Events;
using Artemis.Core.Models.Profile; using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerProperties; using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.Core.Services.Interfaces; using Artemis.Core.Services.Interfaces;
using Artemis.UI.Events; using Artemis.UI.Events;
@ -21,28 +22,22 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
public class LayerPropertiesViewModel : ProfileEditorPanelViewModel public class LayerPropertiesViewModel : ProfileEditorPanelViewModel
{ {
private readonly ICoreService _coreService; private readonly ICoreService _coreService;
private readonly List<LayerPropertyViewModel> _layerPropertyViewModels;
private readonly ILayerPropertyVmFactory _layerPropertyVmFactory;
private readonly IPropertyTreeVmFactory _propertyTreeVmFactory; private readonly IPropertyTreeVmFactory _propertyTreeVmFactory;
private readonly IPropertyTimelineVmFactory _propertyTimelineVmFactory; private readonly IPropertyTimelineVmFactory _propertyTimelineVmFactory;
private readonly IProfileEditorService _profileEditorService; private readonly IProfileEditorService _profileEditorService;
private readonly ISettingsService _settingsService; private readonly ISettingsService _settingsService;
private Layer _lastSelectedLayer;
public LayerPropertiesViewModel(IProfileEditorService profileEditorService, public LayerPropertiesViewModel(IProfileEditorService profileEditorService,
ICoreService coreService, ICoreService coreService,
ISettingsService settingsService, ISettingsService settingsService,
ILayerPropertyVmFactory layerPropertyVmFactory,
IPropertyTreeVmFactory propertyTreeVmFactory, IPropertyTreeVmFactory propertyTreeVmFactory,
IPropertyTimelineVmFactory propertyTimelineVmFactory) IPropertyTimelineVmFactory propertyTimelineVmFactory)
{ {
_profileEditorService = profileEditorService; _profileEditorService = profileEditorService;
_coreService = coreService; _coreService = coreService;
_settingsService = settingsService; _settingsService = settingsService;
_layerPropertyVmFactory = layerPropertyVmFactory;
_propertyTreeVmFactory = propertyTreeVmFactory; _propertyTreeVmFactory = propertyTreeVmFactory;
_propertyTimelineVmFactory = propertyTimelineVmFactory; _propertyTimelineVmFactory = propertyTimelineVmFactory;
_layerPropertyViewModels = new List<LayerPropertyViewModel>();
PixelsPerSecond = 31; PixelsPerSecond = 31;
} }
@ -67,6 +62,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
set => _profileEditorService.CurrentTime = TimeSpan.FromSeconds(value.Left / PixelsPerSecond); set => _profileEditorService.CurrentTime = TimeSpan.FromSeconds(value.Left / PixelsPerSecond);
} }
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; set; }
public PropertyTreeViewModel PropertyTree { get; set; } public PropertyTreeViewModel PropertyTree { get; set; }
public PropertyTimelineViewModel PropertyTimeline { get; set; } public PropertyTimelineViewModel PropertyTimeline { get; set; }
@ -88,12 +84,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
_profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected; _profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
_profileEditorService.CurrentTimeChanged -= ProfileEditorServiceOnCurrentTimeChanged; _profileEditorService.CurrentTimeChanged -= ProfileEditorServiceOnCurrentTimeChanged;
if (_lastSelectedLayer != null)
{
_lastSelectedLayer.Properties.LayerPropertyRegistered -= LayerOnPropertyRegistered;
_lastSelectedLayer.Properties.LayerPropertyRemoved -= LayerOnPropertyRemoved;
}
PropertyTree?.Dispose(); PropertyTree?.Dispose();
PropertyTimeline?.Dispose(); PropertyTimeline?.Dispose();
PropertyTree = null; PropertyTree = null;
@ -122,78 +112,30 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
private void PopulateProperties(ProfileElement profileElement) private void PopulateProperties(ProfileElement profileElement)
{ {
if (_lastSelectedLayer != null) LayerPropertyGroups.Clear();
{
_lastSelectedLayer.Properties.LayerPropertyRegistered -= LayerOnPropertyRegistered;
_lastSelectedLayer.Properties.LayerPropertyRemoved -= LayerOnPropertyRemoved;
}
if (profileElement is Layer layer) if (profileElement is Layer layer)
{ {
// Create VMs for missing properties // Add the built-in root groups of the layer
foreach (var baseLayerProperty in layer.Properties) var generalAttribute = Attribute.GetCustomAttribute(
layer.GetType().GetProperty(nameof(layer.General)),
typeof(PropertyGroupDescriptionAttribute)
);
var transformAttribute = Attribute.GetCustomAttribute(
layer.GetType().GetProperty(nameof(layer.Transform)),
typeof(PropertyGroupDescriptionAttribute)
);
LayerPropertyGroups.Add(new LayerPropertyGroupViewModel(layer.General, (PropertyGroupDescriptionAttribute) generalAttribute));
LayerPropertyGroups.Add(new LayerPropertyGroupViewModel(layer.Transform, (PropertyGroupDescriptionAttribute) transformAttribute));
// Add the rout group of the brush
// The root group of the brush has no attribute so let's pull one out of our sleeve
var brushDescription = new PropertyGroupDescriptionAttribute
{ {
if (_layerPropertyViewModels.All(vm => vm.LayerProperty != baseLayerProperty)) Name = layer.LayerBrush.Descriptor.DisplayName,
CreatePropertyViewModel(baseLayerProperty); Description = layer.LayerBrush.Descriptor.Description
} };
LayerPropertyGroups.Add(new LayerPropertyGroupViewModel(layer.LayerBrush.BaseProperties, brushDescription));
// Remove VMs for extra properties
foreach (var layerPropertyViewModel in _layerPropertyViewModels.ToList())
{
if (layer.Properties.All(p => p != layerPropertyViewModel.LayerProperty))
RemovePropertyViewModel(layerPropertyViewModel);
}
_lastSelectedLayer = layer;
layer.Properties.LayerPropertyRegistered += LayerOnPropertyRegistered;
layer.Properties.LayerPropertyRemoved += LayerOnPropertyRemoved;
} }
else
{
foreach (var layerPropertyViewModel in _layerPropertyViewModels.ToList())
RemovePropertyViewModel(layerPropertyViewModel);
_lastSelectedLayer = null;
}
}
private void LayerOnPropertyRegistered(object sender, LayerPropertyEventArgs e)
{
Console.WriteLine("LayerOnPropertyRegistered");
PopulateProperties(e.LayerProperty.Layer);
}
private void LayerOnPropertyRemoved(object sender, LayerPropertyEventArgs e)
{
Console.WriteLine("LayerOnPropertyRemoved");
PopulateProperties(e.LayerProperty.Layer);
}
private LayerPropertyViewModel CreatePropertyViewModel(BaseLayerProperty layerProperty)
{
LayerPropertyViewModel parent = null;
// If the property has a parent, find it's VM
if (layerProperty.Parent != null)
{
parent = _layerPropertyViewModels.FirstOrDefault(vm => vm.LayerProperty == layerProperty.Parent);
// If no VM is found, create it
if (parent == null)
parent = CreatePropertyViewModel(layerProperty.Parent);
}
var createdViewModel = _layerPropertyVmFactory.Create(layerProperty, parent);
_layerPropertyViewModels.Add(createdViewModel);
PropertyTree.AddLayerProperty(createdViewModel);
PropertyTimeline.AddLayerProperty(createdViewModel);
return createdViewModel;
}
private void RemovePropertyViewModel(LayerPropertyViewModel layerPropertyViewModel)
{
PropertyTree.RemoveLayerProperty(layerPropertyViewModel);
PropertyTimeline.RemoveLayerProperty(layerPropertyViewModel);
_layerPropertyViewModels.Remove(layerPropertyViewModel);
} }
#endregion #endregion
@ -259,9 +201,16 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
private TimeSpan CalculateEndTime() private TimeSpan CalculateEndTime()
{ {
// End time is the last keyframe + 10 sec if (!(_profileEditorService.SelectedProfileElement is Layer layer))
var lastKeyFrame = PropertyTimeline.PropertyTrackViewModels.SelectMany(r => r.KeyframeViewModels).OrderByDescending(t => t.Keyframe.Position).FirstOrDefault(); return TimeSpan.MaxValue;
return lastKeyFrame?.Keyframe.Position.Add(new TimeSpan(0, 0, 0, 10)) ?? TimeSpan.MaxValue;
var keyframes = GetKeyframes(false);
// If there are no keyframes, don't stop at all
if (!keyframes.Any())
return TimeSpan.MaxValue;
// If there are keyframes, stop after the last keyframe + 10 sec
return keyframes.Max(k => k.Position).Add(TimeSpan.FromSeconds(10));
} }
private void CoreServiceOnFrameRendering(object sender, FrameRenderingEventArgs e) private void CoreServiceOnFrameRendering(object sender, FrameRenderingEventArgs e)
@ -323,19 +272,24 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
return; return;
} }
// If shift is held, snap to closest keyframe var visibleKeyframes = GetKeyframes(true);
var visibleKeyframes = PropertyTimeline.PropertyTrackViewModels
.Where(t => t.LayerPropertyViewModel.Parent != null && t.LayerPropertyViewModel.Parent.IsExpanded)
.SelectMany(t => t.KeyframeViewModels);
// Take a tolerance of 5 pixels (half a keyframe width) // Take a tolerance of 5 pixels (half a keyframe width)
var tolerance = 1000f / PixelsPerSecond * 5; var tolerance = 1000f / PixelsPerSecond * 5;
var closeKeyframe = visibleKeyframes.FirstOrDefault( var closeKeyframe = visibleKeyframes.FirstOrDefault(k => Math.Abs(k.Position.TotalMilliseconds - newTime.TotalMilliseconds) < tolerance);
kf => Math.Abs(kf.Keyframe.Position.TotalMilliseconds - newTime.TotalMilliseconds) < tolerance _profileEditorService.CurrentTime = closeKeyframe?.Position ?? newTime;
);
_profileEditorService.CurrentTime = closeKeyframe?.Keyframe.Position ?? newTime;
} }
} }
private List<BaseLayerPropertyKeyframe> GetKeyframes(bool visibleOnly)
{
var result = new List<BaseLayerPropertyKeyframe>();
foreach (var layerPropertyGroupViewModel in LayerPropertyGroups)
result.AddRange(layerPropertyGroupViewModel.GetKeyframes(visibleOnly));
return result;
}
#endregion #endregion
#region Events #region Events

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
{
public class LayerPropertyGroupViewModel : LayerPropertyBaseViewModel
{
public LayerPropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, PropertyGroupDescriptionAttribute propertyGroupDescription)
{
LayerPropertyGroup = layerPropertyGroup;
PropertyGroupDescription = propertyGroupDescription;
IsExpanded = PropertyGroupDescription.ExpandByDefault;
Children = new List<LayerPropertyBaseViewModel>();
PopulateChildren();
}
public LayerPropertyGroup LayerPropertyGroup { get; }
public PropertyGroupDescriptionAttribute PropertyGroupDescription { get; }
public bool IsExpanded { get; set; }
public List<LayerPropertyBaseViewModel> Children { get; set; }
private void PopulateChildren()
{
// Get all properties and property groups and create VMs for them
foreach (var propertyInfo in LayerPropertyGroup.GetType().GetProperties())
{
var propertyAttribute = (PropertyDescriptionAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof(PropertyDescriptionAttribute));
var groupAttribute = (PropertyGroupDescriptionAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof(PropertyGroupDescriptionAttribute));
var value = propertyInfo.GetValue(LayerPropertyGroup);
// Create VMs for properties on the group
if (propertyAttribute != null && value is BaseLayerProperty)
{
// Go through the pain of instantiating a generic type VM now via reflection to make things a lot simpler down the line
var genericType = propertyInfo.PropertyType.GetGenericArguments()[0];
var genericViewModel = typeof(LayerPropertyViewModel<>).MakeGenericType(genericType);
var instance = Activator.CreateInstance(genericViewModel, value, propertyAttribute);
Children.Add((LayerPropertyBaseViewModel) instance);
}
// Create VMs for child groups on this group, resulting in a nested structure
else if (groupAttribute != null && value is LayerPropertyGroup layerPropertyGroup)
{
Children.Add(new LayerPropertyGroupViewModel(layerPropertyGroup, groupAttribute));
}
}
}
public override List<BaseLayerPropertyKeyframe> GetKeyframes(bool visibleOnly)
{
var result = new List<BaseLayerPropertyKeyframe>();
if (!IsExpanded)
return result;
foreach (var layerPropertyBaseViewModel in Children)
result.AddRange(layerPropertyBaseViewModel.GetKeyframes(visibleOnly));
return result;
}
}
}

View File

@ -1,108 +1,25 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Artemis.Core.Models.Profile.LayerProperties; using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Utilities; using Artemis.Core.Models.Profile.LayerProperties.Attributes;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput; using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
using Artemis.UI.Services.Interfaces;
using Ninject;
using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
{ {
public class LayerPropertyViewModel<T> : LayerPropertyViewModel public class LayerPropertyViewModel<T> : LayerPropertyBaseViewModel
{ {
private readonly IKernel _kernel; public LayerPropertyViewModel(LayerProperty<T> layerProperty, PropertyDescriptionAttribute propertyDescription)
private readonly IProfileEditorService _profileEditorService;
private bool _keyframesEnabled;
private bool _isExpanded;
public LayerPropertyViewModel(LayerProperty<T> layerProperty, LayerPropertyViewModel parent, IKernel kernel, IProfileEditorService profileEditorService)
{ {
_kernel = kernel;
_profileEditorService = profileEditorService;
_keyframesEnabled = layerProperty.KeyframesEnabled;
LayerProperty = layerProperty; LayerProperty = layerProperty;
Parent = parent; PropertyDescription = propertyDescription;
Children = new List<LayerPropertyViewModel>();
// TODO: Get from attribute
IsExpanded = false;
Parent?.Children.Add(this);
} }
public LayerProperty<T> LayerProperty { get; } public LayerProperty<T> LayerProperty { get; }
public PropertyDescriptionAttribute PropertyDescription { get; }
public bool IsExpanded public override List<BaseLayerPropertyKeyframe> GetKeyframes(bool visibleOnly)
{ {
get => _isExpanded; return LayerProperty.BaseKeyframes.ToList();
set
{
_isExpanded = value;
OnExpandedStateChanged();
}
} }
public bool KeyframesEnabled
{
get => _keyframesEnabled;
set
{
_keyframesEnabled = value;
UpdateKeyframes();
}
}
public PropertyInputViewModel GetPropertyInputViewModel()
{
// If the type is an enum type, search for Enum instead.
var type = typeof(T);
if (type.IsEnum)
type = typeof(Enum);
var match = _kernel.Get<List<PropertyInputViewModel>>().FirstOrDefault(p => p.CompatibleTypes.Contains(type));
if (match == null)
return null;
match.Initialize(this);
return match;
}
private void UpdateKeyframes()
{
// Either create a new first keyframe or clear all the keyframes
if (_keyframesEnabled)
LayerProperty.AddKeyframe(new LayerPropertyKeyframe<T>(LayerProperty.CurrentValue, _profileEditorService.CurrentTime, Easings.Functions.Linear));
else
LayerProperty.ClearKeyframes();
// Force the keyframe engine to update, the new keyframe is the current keyframe
LayerProperty.KeyframesEnabled = _keyframesEnabled;
LayerProperty.Update(0);
_profileEditorService.UpdateSelectedProfileElement();
}
#region Events
public event EventHandler<EventArgs> ExpandedStateChanged;
protected virtual void OnExpandedStateChanged()
{
ExpandedStateChanged?.Invoke(this, EventArgs.Empty);
foreach (var layerPropertyViewModel in Children)
layerPropertyViewModel.OnExpandedStateChanged();
}
#endregion
}
public class LayerPropertyViewModel : PropertyChangedBase
{
public LayerPropertyViewModel Parent { get; protected set; }
public List<LayerPropertyViewModel> Children { get; protected set; }
} }
} }