mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
UI - Restructured layer property VMs
This commit is contained in:
parent
41b3c77210
commit
54081b591b
@ -125,7 +125,7 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
General.ApplyToEntity();
|
||||
Transform.ApplyToEntity();
|
||||
LayerBrush.ApplyToEntity();
|
||||
LayerBrush.BaseProperties.ApplyToEntity();
|
||||
|
||||
// LEDs
|
||||
LayerEntity.Leds.Clear();
|
||||
@ -187,7 +187,7 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
var properties = new List<BaseLayerProperty>(General.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
|
||||
// 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);
|
||||
Transform.Override(TimeSpan.Zero);
|
||||
LayerBrush.OverrideProperties(TimeSpan.Zero);
|
||||
LayerBrush.BaseProperties.Override(TimeSpan.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
General.Update(deltaTime);
|
||||
Transform.Update(deltaTime);
|
||||
LayerBrush.UpdateProperties(deltaTime);
|
||||
LayerBrush.BaseProperties.Update(deltaTime);
|
||||
}
|
||||
|
||||
LayerBrush.Update(deltaTime);
|
||||
@ -212,7 +212,7 @@ namespace Artemis.Core.Models.Profile
|
||||
{
|
||||
General.Override(timeOverride);
|
||||
Transform.Override(timeOverride);
|
||||
LayerBrush.OverrideProperties(timeOverride);
|
||||
LayerBrush.BaseProperties.Override(timeOverride);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@ -5,7 +5,7 @@ using Artemis.Storage.Entities.Profile;
|
||||
namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
{
|
||||
/// <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>
|
||||
public abstract class BaseLayerProperty
|
||||
{
|
||||
@ -42,11 +42,15 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
/// <summary>
|
||||
/// Used to declare that this property doesn't belong to a plugin and should use the core plugin GUID
|
||||
/// </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 LayerPropertyGroup LayerPropertyGroup { get; set; }
|
||||
internal abstract IReadOnlyList<BaseLayerPropertyKeyframe> BaseKeyframes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Applies the provided property entity to the layer property by deserializing the JSON base value and keyframe values
|
||||
|
||||
@ -70,7 +70,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
/// </summary>
|
||||
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>
|
||||
/// Adds a keyframe to the layer property
|
||||
|
||||
@ -14,29 +14,34 @@ namespace Artemis.Core.Models.Profile
|
||||
public class LayerPropertyGroup
|
||||
{
|
||||
private ReadOnlyCollection<BaseLayerProperty> _allLayerProperties;
|
||||
private readonly List<BaseLayerProperty> _layerProperties;
|
||||
private readonly List<LayerPropertyGroup> _layerPropertyGroups;
|
||||
|
||||
protected LayerPropertyGroup()
|
||||
{
|
||||
LayerProperties = new List<BaseLayerProperty>();
|
||||
LayerPropertyGroups = new List<LayerPropertyGroup>();
|
||||
_layerProperties = new List<BaseLayerProperty>();
|
||||
_layerPropertyGroups = new List<LayerPropertyGroup>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this property group's properties are all initialized
|
||||
/// </summary>
|
||||
public bool PropertiesInitialized { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to declare that this property group doesn't belong to a plugin and should use the core plugin GUID
|
||||
/// </summary>
|
||||
internal bool IsCorePropertyGroup { get; set; }
|
||||
public bool IsCorePropertyGroup { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of all layer properties in this group
|
||||
/// </summary>
|
||||
internal List<BaseLayerProperty> LayerProperties { get; set; }
|
||||
public ReadOnlyCollection<BaseLayerProperty> LayerProperties => _layerProperties.AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// A list of al child groups in this group
|
||||
/// </summary>
|
||||
internal List<LayerPropertyGroup> LayerPropertyGroups { get; set; }
|
||||
public ReadOnlyCollection<LayerPropertyGroup> LayerPropertyGroups => _layerPropertyGroups.AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// 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);
|
||||
InitializeProperty(layer, path, instance);
|
||||
propertyInfo.SetValue(this, instance);
|
||||
LayerProperties.Add(instance);
|
||||
_layerProperties.Add(instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -76,7 +81,7 @@ namespace Artemis.Core.Models.Profile
|
||||
var instance = (LayerPropertyGroup) Activator.CreateInstance(propertyInfo.PropertyType);
|
||||
instance.InitializeProperties(layerService, layer, $"{path}{propertyInfo.Name}.");
|
||||
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
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties()
|
||||
public IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties()
|
||||
{
|
||||
if (!PropertiesInitialized)
|
||||
return new List<BaseLayerProperty>();
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Models.Profile.LayerProperties;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using SkiaSharp;
|
||||
@ -29,7 +27,7 @@ namespace Artemis.Core.Plugins.LayerBrush
|
||||
/// </summary>
|
||||
public PluginInfo PluginInfo => Descriptor.LayerBrushProvider.PluginInfo;
|
||||
|
||||
internal virtual LayerPropertyGroup BaseProperties => null;
|
||||
public virtual LayerPropertyGroup BaseProperties => null;
|
||||
|
||||
/// <summary>
|
||||
/// 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 ApplyToEntity()
|
||||
{
|
||||
}
|
||||
|
||||
internal virtual void UpdateProperties(double deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
internal virtual void OverrideProperties(TimeSpan overrideTime)
|
||||
{
|
||||
}
|
||||
|
||||
internal virtual IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties()
|
||||
{
|
||||
return new List<BaseLayerProperty>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -47,7 +47,7 @@ namespace Artemis.Core.Plugins.LayerBrush
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
internal override LayerPropertyGroup BaseProperties => Properties;
|
||||
public override LayerPropertyGroup BaseProperties => Properties;
|
||||
|
||||
internal override void InitializeProperties(ILayerService layerService, string path)
|
||||
{
|
||||
@ -56,22 +56,17 @@ namespace Artemis.Core.Plugins.LayerBrush
|
||||
PropertiesInitialized = true;
|
||||
}
|
||||
|
||||
internal override void ApplyToEntity()
|
||||
internal virtual void ApplyToEntity()
|
||||
{
|
||||
Properties.ApplyToEntity();
|
||||
}
|
||||
|
||||
internal override void UpdateProperties(double deltaTime)
|
||||
{
|
||||
Properties.Update(deltaTime);
|
||||
}
|
||||
|
||||
internal override void OverrideProperties(TimeSpan overrideTime)
|
||||
internal virtual void OverrideProperties(TimeSpan overrideTime)
|
||||
{
|
||||
Properties.Override(overrideTime);
|
||||
}
|
||||
|
||||
internal override IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties()
|
||||
internal virtual IReadOnlyCollection<BaseLayerProperty> GetAllLayerProperties()
|
||||
{
|
||||
return Properties.GetAllLayerProperties();
|
||||
}
|
||||
|
||||
@ -76,10 +76,5 @@ namespace Artemis.Core.Services
|
||||
|
||||
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};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ using System.Windows.Media;
|
||||
using Artemis.Core.Events;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Models.Profile.LayerProperties;
|
||||
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Artemis.UI.Events;
|
||||
@ -21,28 +22,22 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
||||
public class LayerPropertiesViewModel : ProfileEditorPanelViewModel
|
||||
{
|
||||
private readonly ICoreService _coreService;
|
||||
private readonly List<LayerPropertyViewModel> _layerPropertyViewModels;
|
||||
private readonly ILayerPropertyVmFactory _layerPropertyVmFactory;
|
||||
private readonly IPropertyTreeVmFactory _propertyTreeVmFactory;
|
||||
private readonly IPropertyTimelineVmFactory _propertyTimelineVmFactory;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private Layer _lastSelectedLayer;
|
||||
|
||||
public LayerPropertiesViewModel(IProfileEditorService profileEditorService,
|
||||
ICoreService coreService,
|
||||
ISettingsService settingsService,
|
||||
ILayerPropertyVmFactory layerPropertyVmFactory,
|
||||
IPropertyTreeVmFactory propertyTreeVmFactory,
|
||||
IPropertyTimelineVmFactory propertyTimelineVmFactory)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_coreService = coreService;
|
||||
_settingsService = settingsService;
|
||||
_layerPropertyVmFactory = layerPropertyVmFactory;
|
||||
_propertyTreeVmFactory = propertyTreeVmFactory;
|
||||
_propertyTimelineVmFactory = propertyTimelineVmFactory;
|
||||
_layerPropertyViewModels = new List<LayerPropertyViewModel>();
|
||||
|
||||
PixelsPerSecond = 31;
|
||||
}
|
||||
@ -67,6 +62,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
||||
set => _profileEditorService.CurrentTime = TimeSpan.FromSeconds(value.Left / PixelsPerSecond);
|
||||
}
|
||||
|
||||
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; set; }
|
||||
public PropertyTreeViewModel PropertyTree { get; set; }
|
||||
public PropertyTimelineViewModel PropertyTimeline { get; set; }
|
||||
|
||||
@ -88,12 +84,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
||||
_profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
|
||||
_profileEditorService.CurrentTimeChanged -= ProfileEditorServiceOnCurrentTimeChanged;
|
||||
|
||||
if (_lastSelectedLayer != null)
|
||||
{
|
||||
_lastSelectedLayer.Properties.LayerPropertyRegistered -= LayerOnPropertyRegistered;
|
||||
_lastSelectedLayer.Properties.LayerPropertyRemoved -= LayerOnPropertyRemoved;
|
||||
}
|
||||
|
||||
PropertyTree?.Dispose();
|
||||
PropertyTimeline?.Dispose();
|
||||
PropertyTree = null;
|
||||
@ -122,78 +112,30 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
||||
|
||||
private void PopulateProperties(ProfileElement profileElement)
|
||||
{
|
||||
if (_lastSelectedLayer != null)
|
||||
{
|
||||
_lastSelectedLayer.Properties.LayerPropertyRegistered -= LayerOnPropertyRegistered;
|
||||
_lastSelectedLayer.Properties.LayerPropertyRemoved -= LayerOnPropertyRemoved;
|
||||
}
|
||||
|
||||
LayerPropertyGroups.Clear();
|
||||
if (profileElement is Layer layer)
|
||||
{
|
||||
// Create VMs for missing properties
|
||||
foreach (var baseLayerProperty in layer.Properties)
|
||||
// Add the built-in root groups of the layer
|
||||
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))
|
||||
CreatePropertyViewModel(baseLayerProperty);
|
||||
}
|
||||
|
||||
// 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;
|
||||
Name = layer.LayerBrush.Descriptor.DisplayName,
|
||||
Description = layer.LayerBrush.Descriptor.Description
|
||||
};
|
||||
LayerPropertyGroups.Add(new LayerPropertyGroupViewModel(layer.LayerBrush.BaseProperties, brushDescription));
|
||||
}
|
||||
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
|
||||
@ -259,9 +201,16 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
||||
|
||||
private TimeSpan CalculateEndTime()
|
||||
{
|
||||
// End time is the last keyframe + 10 sec
|
||||
var lastKeyFrame = PropertyTimeline.PropertyTrackViewModels.SelectMany(r => r.KeyframeViewModels).OrderByDescending(t => t.Keyframe.Position).FirstOrDefault();
|
||||
return lastKeyFrame?.Keyframe.Position.Add(new TimeSpan(0, 0, 0, 10)) ?? TimeSpan.MaxValue;
|
||||
if (!(_profileEditorService.SelectedProfileElement is Layer layer))
|
||||
return 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)
|
||||
@ -323,19 +272,24 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
||||
return;
|
||||
}
|
||||
|
||||
// If shift is held, snap to closest keyframe
|
||||
var visibleKeyframes = PropertyTimeline.PropertyTrackViewModels
|
||||
.Where(t => t.LayerPropertyViewModel.Parent != null && t.LayerPropertyViewModel.Parent.IsExpanded)
|
||||
.SelectMany(t => t.KeyframeViewModels);
|
||||
var visibleKeyframes = GetKeyframes(true);
|
||||
|
||||
// Take a tolerance of 5 pixels (half a keyframe width)
|
||||
var tolerance = 1000f / PixelsPerSecond * 5;
|
||||
var closeKeyframe = visibleKeyframes.FirstOrDefault(
|
||||
kf => Math.Abs(kf.Keyframe.Position.TotalMilliseconds - newTime.TotalMilliseconds) < tolerance
|
||||
);
|
||||
_profileEditorService.CurrentTime = closeKeyframe?.Keyframe.Position ?? newTime;
|
||||
var closeKeyframe = visibleKeyframes.FirstOrDefault(k => Math.Abs(k.Position.TotalMilliseconds - newTime.TotalMilliseconds) < tolerance);
|
||||
_profileEditorService.CurrentTime = closeKeyframe?.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
|
||||
|
||||
#region Events
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,108 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Models.Profile.LayerProperties;
|
||||
using Artemis.Core.Utilities;
|
||||
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput;
|
||||
using Artemis.UI.Services.Interfaces;
|
||||
using Ninject;
|
||||
using Stylet;
|
||||
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
|
||||
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
|
||||
|
||||
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
||||
{
|
||||
public class LayerPropertyViewModel<T> : LayerPropertyViewModel
|
||||
public class LayerPropertyViewModel<T> : LayerPropertyBaseViewModel
|
||||
{
|
||||
private readonly IKernel _kernel;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private bool _keyframesEnabled;
|
||||
private bool _isExpanded;
|
||||
|
||||
public LayerPropertyViewModel(LayerProperty<T> layerProperty, LayerPropertyViewModel parent, IKernel kernel, IProfileEditorService profileEditorService)
|
||||
public LayerPropertyViewModel(LayerProperty<T> layerProperty, PropertyDescriptionAttribute propertyDescription)
|
||||
{
|
||||
_kernel = kernel;
|
||||
_profileEditorService = profileEditorService;
|
||||
_keyframesEnabled = layerProperty.KeyframesEnabled;
|
||||
|
||||
LayerProperty = layerProperty;
|
||||
Parent = parent;
|
||||
Children = new List<LayerPropertyViewModel>();
|
||||
|
||||
// TODO: Get from attribute
|
||||
IsExpanded = false;
|
||||
|
||||
Parent?.Children.Add(this);
|
||||
PropertyDescription = propertyDescription;
|
||||
}
|
||||
|
||||
public LayerProperty<T> LayerProperty { get; }
|
||||
public PropertyDescriptionAttribute PropertyDescription { get; }
|
||||
|
||||
public bool IsExpanded
|
||||
public override List<BaseLayerPropertyKeyframe> GetKeyframes(bool visibleOnly)
|
||||
{
|
||||
get => _isExpanded;
|
||||
set
|
||||
{
|
||||
_isExpanded = value;
|
||||
OnExpandedStateChanged();
|
||||
}
|
||||
return LayerProperty.BaseKeyframes.ToList();
|
||||
}
|
||||
|
||||
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; }
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user