1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Added generic typing to layer properties and keyframes

Restructured the way property input VMs are created
This commit is contained in:
Robert 2020-01-08 19:54:27 +01:00
parent e1a4a155b6
commit 139e1879c1
21 changed files with 342 additions and 155 deletions

View File

@ -149,7 +149,9 @@
<Compile Include="Extensions\TypeExtensions.cs" /> <Compile Include="Extensions\TypeExtensions.cs" />
<Compile Include="JsonConverters\SKColorConverter.cs" /> <Compile Include="JsonConverters\SKColorConverter.cs" />
<Compile Include="Models\DataModelDescription.cs" /> <Compile Include="Models\DataModelDescription.cs" />
<Compile Include="Models\Profile\Keyframe.cs" /> <Compile Include="Models\Profile\LayerProperties\BaseKeyframe.cs" />
<Compile Include="Models\Profile\LayerProperties\Keyframe.cs" />
<Compile Include="Models\Profile\LayerProperties\BaseLayerProperty.cs" />
<Compile Include="Models\Profile\LayerShapes\Ellipse.cs" /> <Compile Include="Models\Profile\LayerShapes\Ellipse.cs" />
<Compile Include="Models\Profile\LayerShapes\Fill.cs" /> <Compile Include="Models\Profile\LayerShapes\Fill.cs" />
<Compile Include="Models\Profile\LayerShapes\Polygon.cs" /> <Compile Include="Models\Profile\LayerShapes\Polygon.cs" />
@ -161,7 +163,7 @@
<Compile Include="Ninject\LoggerProvider.cs" /> <Compile Include="Ninject\LoggerProvider.cs" />
<Compile Include="Ninject\PluginSettingsProvider.cs" /> <Compile Include="Ninject\PluginSettingsProvider.cs" />
<Compile Include="Ninject\SettingsServiceProvider.cs" /> <Compile Include="Ninject\SettingsServiceProvider.cs" />
<Compile Include="Models\Profile\LayerProperty.cs" /> <Compile Include="Models\Profile\LayerProperties\LayerProperty.cs" />
<Compile Include="Plugins\Abstract\ModuleDataModel.cs" /> <Compile Include="Plugins\Abstract\ModuleDataModel.cs" />
<Compile Include="Plugins\Abstract\ModuleViewModel.cs" /> <Compile Include="Plugins\Abstract\ModuleViewModel.cs" />
<Compile Include="Plugins\Abstract\ProfileModule.cs" /> <Compile Include="Plugins\Abstract\ProfileModule.cs" />

View File

@ -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; }
}
}

View File

@ -2,7 +2,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Artemis.Core.Exceptions;
using Artemis.Core.Extensions; using Artemis.Core.Extensions;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Models.Profile.LayerShapes; using Artemis.Core.Models.Profile.LayerShapes;
using Artemis.Core.Models.Surface; using Artemis.Core.Models.Surface;
using Artemis.Core.Plugins.LayerBrush; using Artemis.Core.Plugins.LayerBrush;
@ -14,7 +16,7 @@ namespace Artemis.Core.Models.Profile
{ {
public sealed class Layer : ProfileElement public sealed class Layer : ProfileElement
{ {
private readonly List<LayerProperty> _properties; private readonly Dictionary<string, BaseLayerProperty> _properties;
private LayerShape _layerShape; private LayerShape _layerShape;
private List<ArtemisLed> _leds; private List<ArtemisLed> _leds;
@ -28,7 +30,7 @@ namespace Artemis.Core.Models.Profile
Name = name; Name = name;
_leds = new List<ArtemisLed>(); _leds = new List<ArtemisLed>();
_properties = new List<LayerProperty>(); _properties = new Dictionary<string, BaseLayerProperty>();
CreateDefaultProperties(); CreateDefaultProperties();
} }
@ -44,7 +46,7 @@ namespace Artemis.Core.Models.Profile
Order = layerEntity.Order; Order = layerEntity.Order;
_leds = new List<ArtemisLed>(); _leds = new List<ArtemisLed>();
_properties = new List<LayerProperty>(); _properties = new Dictionary<string, BaseLayerProperty>();
// TODO: Load properties from entity instead of creating the defaults // TODO: Load properties from entity instead of creating the defaults
CreateDefaultProperties(); CreateDefaultProperties();
@ -113,32 +115,32 @@ namespace Artemis.Core.Models.Profile
/// <summary> /// <summary>
/// A collection of all the properties on this layer /// A collection of all the properties on this layer
/// </summary> /// </summary>
public ReadOnlyCollection<LayerProperty> Properties => _properties.AsReadOnly(); public ReadOnlyCollection<BaseLayerProperty> Properties => _properties.Values.ToList().AsReadOnly();
/// <summary> /// <summary>
/// The anchor point property of this layer, also found in <see cref="Properties" /> /// The anchor point property of this layer, also found in <see cref="Properties" />
/// </summary> /// </summary>
public LayerProperty AnchorPointProperty { get; private set; } public LayerProperty<SKPoint> AnchorPointProperty { get; private set; }
/// <summary> /// <summary>
/// The position of this layer, also found in <see cref="Properties" /> /// The position of this layer, also found in <see cref="Properties" />
/// </summary> /// </summary>
public LayerProperty PositionProperty { get; private set; } public LayerProperty<SKPoint> PositionProperty { get; private set; }
/// <summary> /// <summary>
/// The scale property of this layer, also found in <see cref="Properties" /> /// The scale property of this layer, also found in <see cref="Properties" />
/// </summary> /// </summary>
public LayerProperty ScaleProperty { get; private set; } public LayerProperty<SKSize> ScaleProperty { get; private set; }
/// <summary> /// <summary>
/// The rotation property of this layer, also found in <see cref="Properties" /> /// The rotation property of this layer, also found in <see cref="Properties" />
/// </summary> /// </summary>
public LayerProperty RotationProperty { get; private set; } public LayerProperty<int> RotationProperty { get; private set; }
/// <summary> /// <summary>
/// The opacity property of this layer, also found in <see cref="Properties" /> /// The opacity property of this layer, also found in <see cref="Properties" />
/// </summary> /// </summary>
public LayerProperty OpacityProperty { get; private set; } public LayerProperty<float> OpacityProperty { get; private set; }
/// <summary> /// <summary>
/// The brush that will fill the <see cref="LayerShape" />. /// The brush that will fill the <see cref="LayerShape" />.
@ -262,6 +264,62 @@ namespace Artemis.Core.Models.Profile
CalculateRenderProperties(); CalculateRenderProperties();
} }
#region Properties
public void AddLayerProperty<T>(LayerProperty<T> 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);
}
/// <summary>
/// If found, returns the <see cref="LayerProperty{T}"/> matching the provided ID
/// </summary>
/// <typeparam name="T">The type of the layer property</typeparam>
/// <param name="id"></param>
/// <returns></returns>
public LayerProperty<T> GetLayerPropertyById<T>(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<T>) _properties[id];
}
private void CreateDefaultProperties()
{
var transformProperty = new LayerProperty<object>(this, null, "Core.Transform", "Transform", "The default properties collection every layer has, allows you to transform the shape.");
AnchorPointProperty = new LayerProperty<SKPoint>(this, transformProperty, "Core.AnchorPoint", "Anchor Point", "The point at which the shape is attached to its position.");
PositionProperty = new LayerProperty<SKPoint>(this, transformProperty, "Core.Position", "Position", "The position of the shape.");
ScaleProperty = new LayerProperty<SKSize>(this, transformProperty, "Core.Scale", "Scale", "The scale of the shape.") {InputAffix = "%"};
RotationProperty = new LayerProperty<int>(this, transformProperty, "Core.Rotation", "Rotation", "The rotation of the shape in degrees.") {InputAffix = "°"};
OpacityProperty = new LayerProperty<float>(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() internal void CalculateRenderProperties()
{ {
if (!Leds.Any()) if (!Leds.Any())
@ -291,23 +349,6 @@ namespace Artemis.Core.Models.Profile
OnRenderPropertiesUpdated(); 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() public override string ToString()
{ {

View File

@ -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; }
}
}

View File

@ -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<BaseLayerProperty>();
BaseKeyframes = new List<BaseKeyframe>();
}
/// <summary>
/// The layer this property applies to
/// </summary>
public Layer Layer { get; }
/// <summary>
/// The parent property of this property.
/// </summary>
public BaseLayerProperty Parent { get; }
/// <summary>
/// The child properties of this property.
/// <remarks>If the layer has children it cannot contain a value or keyframes.</remarks>
/// </summary>
public List<BaseLayerProperty> Children { get; set; }
/// <summary>
/// A unique identifier for this property, a layer may not contain two properties with the same ID.
/// </summary>
public string Id { get; set; }
/// <summary>
/// The user-friendly name for this property, shown in the UI.
/// </summary>
public string Name { get; set; }
/// <summary>
/// The user-friendly description for this property, shown in the UI.
/// </summary>
public string Description { get; set; }
/// <summary>
/// An optional input prefix to show before input elements in the UI.
/// </summary>
public string InputPrefix { get; set; }
/// <summary>
/// An optional input affix to show behind input elements in the UI.
/// </summary>
public string InputAffix { get; set; }
/// <summary>
/// The type of value this layer property contains.
/// </summary>
public Type Type { get; set; }
protected List<BaseKeyframe> BaseKeyframes { get; set; }
/// <summary>
/// A list of keyframes defining different values of the property in time, this list contains the untyped <see cref="BaseKeyframe"/>.
/// </summary>
public IReadOnlyCollection<BaseKeyframe> 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}";
}
}
}

View File

@ -0,0 +1,18 @@
namespace Artemis.Core.Models.Profile.LayerProperties
{
/// <inheritdoc />
public class Keyframe<T> : BaseKeyframe
{
public Keyframe(Layer layer, LayerProperty<T> propertyBase) : base(layer, propertyBase)
{
}
public LayerProperty<T> Property => (LayerProperty<T>) BaseProperty;
public T Value
{
get => (T) BaseValue;
set => BaseValue = value;
}
}
}

View File

@ -0,0 +1,49 @@
using System.Collections.ObjectModel;
using System.Linq;
namespace Artemis.Core.Models.Profile.LayerProperties
{
public class LayerProperty<T> : 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;
}
/// <summary>
/// A list of keyframes defining different values of the property in time, this list contains the strongly typed <see cref="Keyframe{T}"/>
/// </summary>
public ReadOnlyCollection<Keyframe<T>> Keyframes => BaseKeyframes.Cast<Keyframe<T>>().ToList().AsReadOnly();
/// <summary>
/// Adds a keyframe to the property.
/// </summary>
/// <param name="keyframe">The keyframe to remove</param>
public void AddKeyframe(Keyframe<T> keyframe)
{
BaseKeyframes.Add(keyframe);
}
/// <summary>
/// Removes a keyframe from the property.
/// </summary>
/// <param name="keyframe">The keyframe to remove</param>
public void RemoveKeyframe(Keyframe<T> keyframe)
{
BaseKeyframes.Remove(keyframe);
}
/// <summary>
/// Removes all keyframes from the property.
/// </summary>
public void ClearKeyframes()
{
BaseKeyframes.Clear();
}
}
}

View File

@ -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<LayerProperty>();
Keyframes = new List<Keyframe>();
}
public Layer Layer { get; }
public LayerProperty Parent { get; }
public List<LayerProperty> 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<Keyframe> Keyframes { get; set; }
public void ApplyToEntity()
{
// Big o' TODO
}
}
}

View File

@ -559,6 +559,9 @@
<ItemGroup> <ItemGroup>
<Resource Include="Resources\aero_drag_ew.cur" /> <Resource Include="Resources\aero_drag_ew.cur" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Ninject\Providers\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>
<PostBuildEvent> <PostBuildEvent>

View File

@ -1,8 +1,10 @@
using Artemis.Core.Models.Profile; using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Models.Surface; using Artemis.Core.Models.Surface;
using Artemis.Core.Plugins.Abstract; using Artemis.Core.Plugins.Abstract;
using Artemis.UI.Screens.Module; using Artemis.UI.Screens.Module;
using Artemis.UI.Screens.Module.ProfileEditor; 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.ProfileTree.TreeItem;
using Artemis.UI.Screens.Module.ProfileEditor.Visualization; using Artemis.UI.Screens.Module.ProfileEditor.Visualization;
using Artemis.UI.Screens.Settings.Tabs.Devices; using Artemis.UI.Screens.Settings.Tabs.Devices;
@ -43,4 +45,9 @@ namespace Artemis.UI.Ninject.Factories
{ {
ProfileLayerViewModel Create(Layer layer); ProfileLayerViewModel Create(Layer layer);
} }
public interface ILayerPropertyViewModelFactory : IViewModelFactory
{
LayerPropertyViewModel Create(BaseLayerProperty layerProperty, LayerPropertyViewModel parent);
}
} }

View File

@ -2,6 +2,7 @@
using Artemis.UI.Ninject.Factories; using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens; using Artemis.UI.Screens;
using Artemis.UI.Screens.Module.ProfileEditor; using Artemis.UI.Screens.Module.ProfileEditor;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput;
using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Interfaces;
using Artemis.UI.Stylet; using Artemis.UI.Stylet;
using Artemis.UI.ViewModels.Dialogs; using Artemis.UI.ViewModels.Dialogs;
@ -57,6 +58,15 @@ namespace Artemis.UI.Ninject
.BindAllBaseClasses(); .BindAllBaseClasses();
}); });
// Bind property input VMs
Kernel.Bind(x =>
{
x.FromThisAssembly()
.SelectAllClasses()
.InheritedFrom<PropertyInputViewModel>()
.BindAllBaseClasses();
});
// Bind all UI services as singletons // Bind all UI services as singletons
Kernel.Bind(x => Kernel.Bind(x =>
{ {

View File

@ -3,6 +3,7 @@ using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using Artemis.Core.Models.Profile; 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.PropertyTree;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline; using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline;
using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Interfaces;
@ -12,10 +13,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
public class LayerPropertiesViewModel : ProfileEditorPanelViewModel public class LayerPropertiesViewModel : ProfileEditorPanelViewModel
{ {
private readonly IProfileEditorService _profileEditorService; private readonly IProfileEditorService _profileEditorService;
private readonly ILayerPropertyViewModelFactory _layerPropertyViewModelFactory;
public LayerPropertiesViewModel(IProfileEditorService profileEditorService) public LayerPropertiesViewModel(IProfileEditorService profileEditorService, ILayerPropertyViewModelFactory layerPropertyViewModelFactory)
{ {
_profileEditorService = profileEditorService; _profileEditorService = profileEditorService;
_layerPropertyViewModelFactory = layerPropertyViewModelFactory;
CurrentTime = TimeSpan.Zero; CurrentTime = TimeSpan.Zero;
PixelsPerSecond = 1; 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 // Only create VMs for top-level parents, let parents populate their own children recursively
var propertyViewModels = selectedLayer.Properties var propertyViewModels = selectedLayer.Properties
.Where(p => p.Children.Any()) .Where(p => p.Children.Any())
.Select(p => new LayerPropertyViewModel(p, null)) .Select(p => _layerPropertyViewModelFactory.Create(p, null))
.ToList(); .ToList();
PropertyTree.PopulateProperties(propertyViewModels); PropertyTree.PopulateProperties(propertyViewModels);

View File

@ -1,26 +1,46 @@
using System.Collections.Generic; 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; using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
{ {
public class LayerPropertyViewModel : PropertyChangedBase 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; LayerProperty = layerProperty;
Parent = parent; Parent = parent;
Children = new List<LayerPropertyViewModel>(); Children = new List<LayerPropertyViewModel>();
foreach (var child in layerProperty.Children) 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 LayerPropertyViewModel Parent { get; }
public List<LayerPropertyViewModel> Children { get; set; } public List<LayerPropertyViewModel> Children { get; set; }
public bool IsExpanded { get; set; } public bool IsExpanded { get; set; }
public PropertyInputViewModel GetPropertyInputViewModel()
{
var match = _kernel.Get<List<PropertyInputViewModel>>().FirstOrDefault(p => p.CompatibleTypes.Contains(LayerProperty.Type));
if (match == null)
return null;
match.Initialize(this);
return match;
}
} }
} }

View File

@ -1,16 +1,10 @@
using Artemis.UI.Exceptions; using System;
using System.Collections.Generic;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput
{ {
public class FloatPropertyInputViewModel : PropertyInputViewModel public class FloatPropertyInputViewModel : PropertyInputViewModel
{ {
public FloatPropertyInputViewModel(LayerPropertyViewModel layerPropertyViewModel) : base(layerPropertyViewModel) public sealed override List<Type> CompatibleTypes { get; } = new List<Type> {typeof(float)};
{
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}");
}
}
} }
} }

View File

@ -1,16 +1,10 @@
using Artemis.UI.Exceptions; using System;
using System.Collections.Generic;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput
{ {
public class IntPropertyInputViewModel : PropertyInputViewModel public class IntPropertyInputViewModel : PropertyInputViewModel
{ {
public IntPropertyInputViewModel(LayerPropertyViewModel layerPropertyViewModel) : base(layerPropertyViewModel) public sealed override List<Type> CompatibleTypes { get; } = new List<Type> {typeof(int)};
{
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}");
}
}
} }
} }

View File

@ -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 namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput
{ {
public abstract class PropertyInputViewModel : PropertyChangedBase public abstract class PropertyInputViewModel : PropertyChangedBase
{ {
protected PropertyInputViewModel(LayerPropertyViewModel layerPropertyViewModel) public bool Initialized { get; private set; }
{
LayerPropertyViewModel = layerPropertyViewModel;
}
public LayerPropertyViewModel LayerPropertyViewModel { get; } public abstract List<Type> 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;
}
} }
} }

View File

@ -1,17 +1,11 @@
using Artemis.UI.Exceptions; using System;
using System.Collections.Generic;
using SkiaSharp; using SkiaSharp;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput
{ {
public class SKPointPropertyInputViewModel : PropertyInputViewModel public class SKPointPropertyInputViewModel : PropertyInputViewModel
{ {
public SKPointPropertyInputViewModel(LayerPropertyViewModel layerPropertyViewModel) : base(layerPropertyViewModel) public sealed override List<Type> CompatibleTypes { get; } = new List<Type> {typeof(SKPoint)};
{
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}");
}
}
} }
} }

View File

@ -1,17 +1,11 @@
using Artemis.UI.Exceptions; using System;
using System.Collections.Generic;
using SkiaSharp; using SkiaSharp;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput
{ {
public class SKSizePropertyInputViewModel : PropertyInputViewModel public class SKSizePropertyInputViewModel : PropertyInputViewModel
{ {
public SKSizePropertyInputViewModel(LayerPropertyViewModel layerPropertyViewModel) : base(layerPropertyViewModel) public sealed override List<Type> CompatibleTypes { get; } = new List<Type> {typeof(SKSize)};
{
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}");
}
}
} }
} }

View File

@ -1,5 +1,6 @@
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput; using System.Collections.Generic;
using SkiaSharp; using System.Linq;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree
{ {
@ -10,16 +11,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree
public PropertyTreeChildViewModel(LayerPropertyViewModel layerPropertyViewModel) public PropertyTreeChildViewModel(LayerPropertyViewModel layerPropertyViewModel)
{ {
LayerPropertyViewModel = layerPropertyViewModel; LayerPropertyViewModel = layerPropertyViewModel;
PropertyInputViewModel = layerPropertyViewModel.GetPropertyInputViewModel();
// 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);
} }
public LayerPropertyViewModel LayerPropertyViewModel { get; } public LayerPropertyViewModel LayerPropertyViewModel { get; }

View File

@ -1,17 +1,18 @@
using System; using System;
using Artemis.Core.Models.Profile; using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerProperties;
using Stylet; using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
{ {
public class PropertyTrackKeyframeViewModel : PropertyChangedBase public class PropertyTrackKeyframeViewModel : PropertyChangedBase
{ {
public PropertyTrackKeyframeViewModel(Keyframe keyframe) public PropertyTrackKeyframeViewModel(BaseKeyframe keyframe)
{ {
Keyframe = keyframe; Keyframe = keyframe;
} }
public Keyframe Keyframe { get; } public BaseKeyframe Keyframe { get; }
public double X { get; set; } public double X { get; set; }
public string Timestamp { get; set; } public string Timestamp { get; set; }

View File

@ -21,7 +21,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
public void PopulateKeyframes() public void PopulateKeyframes()
{ {
foreach (var keyframe in LayerPropertyViewModel.LayerProperty.Keyframes) foreach (var keyframe in LayerPropertyViewModel.LayerProperty.UntypedKeyframes)
{ {
if (KeyframeViewModels.Any(k => k.Keyframe == keyframe)) if (KeyframeViewModels.Any(k => k.Keyframe == keyframe))
continue; continue;