diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index ea172f092..b57dbfde5 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -149,7 +149,9 @@ - + + + @@ -161,7 +163,7 @@ - + diff --git a/src/Artemis.Core/Models/Profile/Keyframe.cs b/src/Artemis.Core/Models/Profile/Keyframe.cs deleted file mode 100644 index f89ace002..000000000 --- a/src/Artemis.Core/Models/Profile/Keyframe.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace Artemis.Core.Models.Profile -{ - public class Keyframe - { - public Layer Layer { get; set; } - public LayerProperty Property { get; set; } - - public TimeSpan Position { get; set; } - public object Value { get; set; } - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index b1113a996..019148c7e 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -2,7 +2,9 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using Artemis.Core.Exceptions; using Artemis.Core.Extensions; +using Artemis.Core.Models.Profile.LayerProperties; using Artemis.Core.Models.Profile.LayerShapes; using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.LayerBrush; @@ -14,7 +16,7 @@ namespace Artemis.Core.Models.Profile { public sealed class Layer : ProfileElement { - private readonly List _properties; + private readonly Dictionary _properties; private LayerShape _layerShape; private List _leds; @@ -28,7 +30,7 @@ namespace Artemis.Core.Models.Profile Name = name; _leds = new List(); - _properties = new List(); + _properties = new Dictionary(); CreateDefaultProperties(); } @@ -44,7 +46,7 @@ namespace Artemis.Core.Models.Profile Order = layerEntity.Order; _leds = new List(); - _properties = new List(); + _properties = new Dictionary(); // TODO: Load properties from entity instead of creating the defaults CreateDefaultProperties(); @@ -113,32 +115,32 @@ namespace Artemis.Core.Models.Profile /// /// A collection of all the properties on this layer /// - public ReadOnlyCollection Properties => _properties.AsReadOnly(); + public ReadOnlyCollection Properties => _properties.Values.ToList().AsReadOnly(); /// /// The anchor point property of this layer, also found in /// - public LayerProperty AnchorPointProperty { get; private set; } + public LayerProperty AnchorPointProperty { get; private set; } /// /// The position of this layer, also found in /// - public LayerProperty PositionProperty { get; private set; } + public LayerProperty PositionProperty { get; private set; } /// /// The scale property of this layer, also found in /// - public LayerProperty ScaleProperty { get; private set; } + public LayerProperty ScaleProperty { get; private set; } /// /// The rotation property of this layer, also found in /// - public LayerProperty RotationProperty { get; private set; } + public LayerProperty RotationProperty { get; private set; } /// /// The opacity property of this layer, also found in /// - public LayerProperty OpacityProperty { get; private set; } + public LayerProperty OpacityProperty { get; private set; } /// /// The brush that will fill the . @@ -262,6 +264,62 @@ namespace Artemis.Core.Models.Profile CalculateRenderProperties(); } + #region Properties + + public void AddLayerProperty(LayerProperty layerProperty) + { + if (_properties.ContainsKey(layerProperty.Id)) + throw new ArtemisCoreException($"Duplicate property ID detected. Layer already contains a property with ID {layerProperty.Id}."); + + _properties.Add(layerProperty.Id, layerProperty); + } + + public void AddLayerProperty(BaseLayerProperty layerProperty) + { + if (_properties.ContainsKey(layerProperty.Id)) + throw new ArtemisCoreException($"Duplicate property ID detected. Layer already contains a property with ID {layerProperty.Id}."); + + _properties.Add(layerProperty.Id, layerProperty); + } + + /// + /// If found, returns the matching the provided ID + /// + /// The type of the layer property + /// + /// + public LayerProperty GetLayerPropertyById(string id) + { + if (!_properties.ContainsKey(id)) + return null; + + var property = _properties[id]; + if (property.Type != typeof(T)) + throw new ArtemisCoreException($"Property type mismatch. Expected property {property} to have type {typeof(T)} but it has {property.Type} instead."); + return (LayerProperty) _properties[id]; + } + + private void CreateDefaultProperties() + { + var transformProperty = new LayerProperty(this, null, "Core.Transform", "Transform", "The default properties collection every layer has, allows you to transform the shape."); + AnchorPointProperty = new LayerProperty(this, transformProperty, "Core.AnchorPoint", "Anchor Point", "The point at which the shape is attached to its position."); + PositionProperty = new LayerProperty(this, transformProperty, "Core.Position", "Position", "The position of the shape."); + ScaleProperty = new LayerProperty(this, transformProperty, "Core.Scale", "Scale", "The scale of the shape.") {InputAffix = "%"}; + RotationProperty = new LayerProperty(this, transformProperty, "Core.Rotation", "Rotation", "The rotation of the shape in degrees.") {InputAffix = "°"}; + OpacityProperty = new LayerProperty(this, transformProperty, "Core.Opacity", "Opacity", "The opacity of the shape.") {InputAffix = "%"}; + transformProperty.Children.Add(AnchorPointProperty); + transformProperty.Children.Add(PositionProperty); + transformProperty.Children.Add(ScaleProperty); + transformProperty.Children.Add(RotationProperty); + transformProperty.Children.Add(OpacityProperty); + + AddLayerProperty(transformProperty); + foreach (var transformPropertyChild in transformProperty.Children) + AddLayerProperty(transformPropertyChild); + } + + #endregion + internal void CalculateRenderProperties() { if (!Leds.Any()) @@ -291,23 +349,6 @@ namespace Artemis.Core.Models.Profile OnRenderPropertiesUpdated(); } - private void CreateDefaultProperties() - { - var transformProperty = new LayerProperty(this, null, "Transform", "The default properties collection every layer has, allows you to transform the shape.", null); - AnchorPointProperty = new LayerProperty(this, transformProperty, "Anchor Point", "The point at which the shape is attached to its position.", typeof(SKPoint)); - PositionProperty = new LayerProperty(this, transformProperty, "Position", "The position of the shape.", typeof(SKPoint)); - ScaleProperty = new LayerProperty(this, transformProperty, "Scale", "The scale of the shape.", typeof(SKSize)) { InputAffix = "%" }; - RotationProperty = new LayerProperty(this, transformProperty, "Rotation", "The rotation of the shape in degrees.", typeof(int)) {InputAffix = "°" }; - OpacityProperty = new LayerProperty(this, transformProperty, "Opacity", "The opacity of the shape.", typeof(float)) {InputAffix = "%"}; - transformProperty.Children.Add(AnchorPointProperty); - transformProperty.Children.Add(PositionProperty); - transformProperty.Children.Add(ScaleProperty); - transformProperty.Children.Add(RotationProperty); - transformProperty.Children.Add(OpacityProperty); - - _properties.Add(transformProperty); - _properties.AddRange(transformProperty.Children); - } public override string ToString() { diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/BaseKeyframe.cs b/src/Artemis.Core/Models/Profile/LayerProperties/BaseKeyframe.cs new file mode 100644 index 000000000..59639f372 --- /dev/null +++ b/src/Artemis.Core/Models/Profile/LayerProperties/BaseKeyframe.cs @@ -0,0 +1,19 @@ +using System; + +namespace Artemis.Core.Models.Profile.LayerProperties +{ + public class BaseKeyframe + { + protected BaseKeyframe(Layer layer, BaseLayerProperty property) + { + Layer = layer; + BaseProperty = property; + } + + public Layer Layer { get; set; } + public TimeSpan Position { get; set; } + + protected BaseLayerProperty BaseProperty { get; } + protected object BaseValue { get; set; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs new file mode 100644 index 000000000..b65a6f1a7 --- /dev/null +++ b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using Artemis.Core.Exceptions; + +namespace Artemis.Core.Models.Profile.LayerProperties +{ + public abstract class BaseLayerProperty + { + private object _baseValue; + + protected BaseLayerProperty(Layer layer, BaseLayerProperty parent, string id, string name, string description, Type type) + { + Layer = layer; + Parent = parent; + Id = id; + Name = name; + Description = description; + Type = type; + + Children = new List(); + BaseKeyframes = new List(); + } + + /// + /// The layer this property applies to + /// + public Layer Layer { get; } + + /// + /// The parent property of this property. + /// + public BaseLayerProperty Parent { get; } + + /// + /// The child properties of this property. + /// If the layer has children it cannot contain a value or keyframes. + /// + public List Children { get; set; } + + /// + /// A unique identifier for this property, a layer may not contain two properties with the same ID. + /// + public string Id { get; set; } + + /// + /// The user-friendly name for this property, shown in the UI. + /// + public string Name { get; set; } + + /// + /// The user-friendly description for this property, shown in the UI. + /// + public string Description { get; set; } + + /// + /// An optional input prefix to show before input elements in the UI. + /// + public string InputPrefix { get; set; } + + /// + /// An optional input affix to show behind input elements in the UI. + /// + public string InputAffix { get; set; } + + /// + /// The type of value this layer property contains. + /// + public Type Type { get; set; } + + protected List BaseKeyframes { get; set; } + /// + /// A list of keyframes defining different values of the property in time, this list contains the untyped . + /// + public IReadOnlyCollection UntypedKeyframes => BaseKeyframes.AsReadOnly(); + + protected object BaseValue + { + get => _baseValue; + set + { + if (value != null && value.GetType() != Type) + throw new ArtemisCoreException($"Cannot set value of type {value.GetType()} on property {this}, expected type is {Type}."); + _baseValue = value; + } + } + + + public void ApplyToEntity() + { + // Big o' TODO + } + + public override string ToString() + { + return $"{nameof(Id)}: {Id}, {nameof(Name)}: {Name}, {nameof(Description)}: {Description}"; + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/Keyframe.cs b/src/Artemis.Core/Models/Profile/LayerProperties/Keyframe.cs new file mode 100644 index 000000000..63af5027b --- /dev/null +++ b/src/Artemis.Core/Models/Profile/LayerProperties/Keyframe.cs @@ -0,0 +1,18 @@ +namespace Artemis.Core.Models.Profile.LayerProperties +{ + /// + public class Keyframe : BaseKeyframe + { + public Keyframe(Layer layer, LayerProperty propertyBase) : base(layer, propertyBase) + { + } + + public LayerProperty Property => (LayerProperty) BaseProperty; + + public T Value + { + get => (T) BaseValue; + set => BaseValue = value; + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs new file mode 100644 index 000000000..4141deac3 --- /dev/null +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs @@ -0,0 +1,49 @@ +using System.Collections.ObjectModel; +using System.Linq; + +namespace Artemis.Core.Models.Profile.LayerProperties +{ + public class LayerProperty : BaseLayerProperty + { + public LayerProperty(Layer layer, BaseLayerProperty parent, string id, string name, string description) : base(layer, parent, id, name, description, typeof(T)) + { + } + + public T Value + { + get => (T) BaseValue; + set => BaseValue = value; + } + + /// + /// A list of keyframes defining different values of the property in time, this list contains the strongly typed + /// + public ReadOnlyCollection> Keyframes => BaseKeyframes.Cast>().ToList().AsReadOnly(); + + /// + /// Adds a keyframe to the property. + /// + /// The keyframe to remove + public void AddKeyframe(Keyframe keyframe) + { + BaseKeyframes.Add(keyframe); + } + + /// + /// Removes a keyframe from the property. + /// + /// The keyframe to remove + public void RemoveKeyframe(Keyframe keyframe) + { + BaseKeyframes.Remove(keyframe); + } + + /// + /// Removes all keyframes from the property. + /// + public void ClearKeyframes() + { + BaseKeyframes.Clear(); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperty.cs deleted file mode 100644 index a18d78351..000000000 --- a/src/Artemis.Core/Models/Profile/LayerProperty.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Collections.Generic; -using Artemis.Core.Exceptions; - -namespace Artemis.Core.Models.Profile -{ - public class LayerProperty - { - private object _baseValue; - - internal LayerProperty(Layer layer, LayerProperty parent, string name, string description, Type type) - { - Layer = layer; - Parent = parent; - Name = name; - Description = description; - Type = type; - - Children = new List(); - Keyframes = new List(); - } - - public Layer Layer { get; } - public LayerProperty Parent { get; } - public List Children { get; set; } - - public string Name { get; set; } - public string Description { get; set; } - public string InputPrefix { get; set; } - public string InputAffix { get; set; } - public Type Type { get; set; } - - public object BaseValue - { - get => _baseValue; - set - { - if (value != null && value.GetType() != Type) - throw new ArtemisCoreException($"Cannot set value of type {value.GetType()} on property {Name}, expected type is {Type}."); - _baseValue = value; - } - } - - public List Keyframes { get; set; } - - public void ApplyToEntity() - { - // Big o' TODO - } - } -} \ No newline at end of file diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index 914cd321b..878cf7b41 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -559,6 +559,9 @@ + + + diff --git a/src/Artemis.UI/Ninject/Factories/IViewModelFactory.cs b/src/Artemis.UI/Ninject/Factories/IViewModelFactory.cs index b1e9a2d43..7ef5d016b 100644 --- a/src/Artemis.UI/Ninject/Factories/IViewModelFactory.cs +++ b/src/Artemis.UI/Ninject/Factories/IViewModelFactory.cs @@ -1,8 +1,10 @@ using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Profile.LayerProperties; using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Abstract; using Artemis.UI.Screens.Module; using Artemis.UI.Screens.Module.ProfileEditor; +using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties; using Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem; using Artemis.UI.Screens.Module.ProfileEditor.Visualization; using Artemis.UI.Screens.Settings.Tabs.Devices; @@ -43,4 +45,9 @@ namespace Artemis.UI.Ninject.Factories { ProfileLayerViewModel Create(Layer layer); } + + public interface ILayerPropertyViewModelFactory : IViewModelFactory + { + LayerPropertyViewModel Create(BaseLayerProperty layerProperty, LayerPropertyViewModel parent); + } } \ No newline at end of file diff --git a/src/Artemis.UI/Ninject/UiModule.cs b/src/Artemis.UI/Ninject/UiModule.cs index 0d7773c65..5d2bbc32d 100644 --- a/src/Artemis.UI/Ninject/UiModule.cs +++ b/src/Artemis.UI/Ninject/UiModule.cs @@ -2,6 +2,7 @@ using Artemis.UI.Ninject.Factories; using Artemis.UI.Screens; using Artemis.UI.Screens.Module.ProfileEditor; +using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput; using Artemis.UI.Services.Interfaces; using Artemis.UI.Stylet; using Artemis.UI.ViewModels.Dialogs; @@ -57,6 +58,15 @@ namespace Artemis.UI.Ninject .BindAllBaseClasses(); }); + // Bind property input VMs + Kernel.Bind(x => + { + x.FromThisAssembly() + .SelectAllClasses() + .InheritedFrom() + .BindAllBaseClasses(); + }); + // Bind all UI services as singletons Kernel.Bind(x => { diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs index c8d8c98ec..2684abcd5 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Windows; using System.Windows.Input; using Artemis.Core.Models.Profile; +using Artemis.UI.Ninject.Factories; using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree; using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline; using Artemis.UI.Services.Interfaces; @@ -12,10 +13,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties public class LayerPropertiesViewModel : ProfileEditorPanelViewModel { private readonly IProfileEditorService _profileEditorService; + private readonly ILayerPropertyViewModelFactory _layerPropertyViewModelFactory; - public LayerPropertiesViewModel(IProfileEditorService profileEditorService) + public LayerPropertiesViewModel(IProfileEditorService profileEditorService, ILayerPropertyViewModelFactory layerPropertyViewModelFactory) { _profileEditorService = profileEditorService; + _layerPropertyViewModelFactory = layerPropertyViewModelFactory; CurrentTime = TimeSpan.Zero; PixelsPerSecond = 1; @@ -75,7 +78,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties // Only create VMs for top-level parents, let parents populate their own children recursively var propertyViewModels = selectedLayer.Properties .Where(p => p.Children.Any()) - .Select(p => new LayerPropertyViewModel(p, null)) + .Select(p => _layerPropertyViewModelFactory.Create(p, null)) .ToList(); PropertyTree.PopulateProperties(propertyViewModels); diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs index b96bac1fc..9b46aed45 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs @@ -1,26 +1,46 @@ using System.Collections.Generic; -using Artemis.Core.Models.Profile; +using System.Linq; +using Artemis.Core.Models.Profile.LayerProperties; +using Artemis.UI.Ninject.Factories; +using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput; +using Ninject; using Stylet; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties { public class LayerPropertyViewModel : PropertyChangedBase { - public LayerPropertyViewModel(LayerProperty layerProperty, LayerPropertyViewModel parent) + private readonly IKernel _kernel; + + public LayerPropertyViewModel(BaseLayerProperty layerProperty, + LayerPropertyViewModel parent, + ILayerPropertyViewModelFactory layerPropertyViewModelFactory, IKernel kernel) { + _kernel = kernel; + LayerProperty = layerProperty; Parent = parent; Children = new List(); foreach (var child in layerProperty.Children) - Children.Add(new LayerPropertyViewModel(child, this)); + Children.Add(layerPropertyViewModelFactory.Create(child, this)); } - public LayerProperty LayerProperty { get; } + public BaseLayerProperty LayerProperty { get; } public LayerPropertyViewModel Parent { get; } public List Children { get; set; } public bool IsExpanded { get; set; } + + public PropertyInputViewModel GetPropertyInputViewModel() + { + var match = _kernel.Get>().FirstOrDefault(p => p.CompatibleTypes.Contains(LayerProperty.Type)); + if (match == null) + return null; + + match.Initialize(this); + return match; + } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/FloatPropertyInputViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/FloatPropertyInputViewModel.cs index 256820991..e2a9bbdfa 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/FloatPropertyInputViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/FloatPropertyInputViewModel.cs @@ -1,16 +1,10 @@ -using Artemis.UI.Exceptions; +using System; +using System.Collections.Generic; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput { public class FloatPropertyInputViewModel : PropertyInputViewModel { - public FloatPropertyInputViewModel(LayerPropertyViewModel layerPropertyViewModel) : base(layerPropertyViewModel) - { - if (layerPropertyViewModel.LayerProperty.Type != typeof(float)) - { - throw new ArtemisUIException("This input VM expects a layer property of type float, " + - $"not the provided type {layerPropertyViewModel.LayerProperty.Type.Name}"); - } - } + public sealed override List CompatibleTypes { get; } = new List {typeof(float)}; } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/IntPropertyInputViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/IntPropertyInputViewModel.cs index 46b58cd47..b1a2df52c 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/IntPropertyInputViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/IntPropertyInputViewModel.cs @@ -1,16 +1,10 @@ -using Artemis.UI.Exceptions; +using System; +using System.Collections.Generic; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput { public class IntPropertyInputViewModel : PropertyInputViewModel { - public IntPropertyInputViewModel(LayerPropertyViewModel layerPropertyViewModel) : base(layerPropertyViewModel) - { - if (layerPropertyViewModel.LayerProperty.Type != typeof(int)) - { - throw new ArtemisUIException("This input VM expects a layer property of type int, " + - $"not the provided type {layerPropertyViewModel.LayerProperty.Type.Name}"); - } - } + public sealed override List CompatibleTypes { get; } = new List {typeof(int)}; } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/PropertyInputViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/PropertyInputViewModel.cs index 6f8b6babe..1b0ab7268 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/PropertyInputViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/PropertyInputViewModel.cs @@ -1,14 +1,26 @@ -using Stylet; +using System; +using System.Collections.Generic; +using Artemis.UI.Exceptions; +using Stylet; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput { public abstract class PropertyInputViewModel : PropertyChangedBase { - protected PropertyInputViewModel(LayerPropertyViewModel layerPropertyViewModel) - { - LayerPropertyViewModel = layerPropertyViewModel; - } + public bool Initialized { get; private set; } - public LayerPropertyViewModel LayerPropertyViewModel { get; } + public abstract List CompatibleTypes { get; } + public LayerPropertyViewModel LayerPropertyViewModel { get; private set; } + + public void Initialize(LayerPropertyViewModel layerPropertyViewModel) + { + if (Initialized) + throw new ArtemisUIException("Cannot initialize the same property input VM twice"); + if (!CompatibleTypes.Contains(layerPropertyViewModel.LayerProperty.Type)) + throw new ArtemisUIException($"This input VM does not support the provided type {layerPropertyViewModel.LayerProperty.Type.Name}"); + + LayerPropertyViewModel = layerPropertyViewModel; + Initialized = true; + } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKPointPropertyInputViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKPointPropertyInputViewModel.cs index 7dd58c2f0..189d21481 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKPointPropertyInputViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKPointPropertyInputViewModel.cs @@ -1,17 +1,11 @@ -using Artemis.UI.Exceptions; +using System; +using System.Collections.Generic; using SkiaSharp; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput { public class SKPointPropertyInputViewModel : PropertyInputViewModel { - public SKPointPropertyInputViewModel(LayerPropertyViewModel layerPropertyViewModel) : base(layerPropertyViewModel) - { - if (layerPropertyViewModel.LayerProperty.Type != typeof(SKPoint)) - { - throw new ArtemisUIException($"This input VM expects a layer property of type {nameof(SKPoint)}, " + - $"not the provided type {layerPropertyViewModel.LayerProperty.Type.Name}"); - } - } + public sealed override List CompatibleTypes { get; } = new List {typeof(SKPoint)}; } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKSizePropertyInputViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKSizePropertyInputViewModel.cs index 00dcb43da..ae184a64f 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKSizePropertyInputViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/SKSizePropertyInputViewModel.cs @@ -1,17 +1,11 @@ -using Artemis.UI.Exceptions; +using System; +using System.Collections.Generic; using SkiaSharp; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput { public class SKSizePropertyInputViewModel : PropertyInputViewModel { - public SKSizePropertyInputViewModel(LayerPropertyViewModel layerPropertyViewModel) : base(layerPropertyViewModel) - { - if (layerPropertyViewModel.LayerProperty.Type != typeof(SKSize)) - { - throw new ArtemisUIException($"This input VM expects a layer property of type {nameof(SKSize)}, " + - $"not the provided type {layerPropertyViewModel.LayerProperty.Type.Name}"); - } - } + public sealed override List CompatibleTypes { get; } = new List {typeof(SKSize)}; } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyTreeChildViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyTreeChildViewModel.cs index 132e9f1e4..99cdebf1e 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyTreeChildViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyTreeChildViewModel.cs @@ -1,5 +1,6 @@ -using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput; -using SkiaSharp; +using System.Collections.Generic; +using System.Linq; +using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree { @@ -10,16 +11,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree public PropertyTreeChildViewModel(LayerPropertyViewModel layerPropertyViewModel) { LayerPropertyViewModel = layerPropertyViewModel; - - // TODO: Leverage DI for this and make it less shitty :)) - if (LayerPropertyViewModel.LayerProperty.Type == typeof(SKPoint)) - PropertyInputViewModel = new SKPointPropertyInputViewModel(LayerPropertyViewModel); - else if (LayerPropertyViewModel.LayerProperty.Type == typeof(SKSize)) - PropertyInputViewModel = new SKSizePropertyInputViewModel(LayerPropertyViewModel); - else if (LayerPropertyViewModel.LayerProperty.Type == typeof(int)) - PropertyInputViewModel = new IntPropertyInputViewModel(LayerPropertyViewModel); - else if (LayerPropertyViewModel.LayerProperty.Type == typeof(float)) - PropertyInputViewModel = new FloatPropertyInputViewModel(LayerPropertyViewModel); + PropertyInputViewModel = layerPropertyViewModel.GetPropertyInputViewModel(); } public LayerPropertyViewModel LayerPropertyViewModel { get; } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackKeyframeViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackKeyframeViewModel.cs index 3c6f1574e..821ddddf4 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackKeyframeViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackKeyframeViewModel.cs @@ -1,17 +1,18 @@ using System; using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Profile.LayerProperties; using Stylet; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline { public class PropertyTrackKeyframeViewModel : PropertyChangedBase { - public PropertyTrackKeyframeViewModel(Keyframe keyframe) + public PropertyTrackKeyframeViewModel(BaseKeyframe keyframe) { Keyframe = keyframe; } - public Keyframe Keyframe { get; } + public BaseKeyframe Keyframe { get; } public double X { get; set; } public string Timestamp { get; set; } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackViewModel.cs index 0e64f6bc6..b998f1512 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackViewModel.cs @@ -21,7 +21,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline public void PopulateKeyframes() { - foreach (var keyframe in LayerPropertyViewModel.LayerProperty.Keyframes) + foreach (var keyframe in LayerPropertyViewModel.LayerProperty.UntypedKeyframes) { if (KeyframeViewModels.Any(k => k.Keyframe == keyframe)) continue;