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:
parent
e1a4a155b6
commit
139e1879c1
@ -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" />
|
||||||
|
|||||||
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/Artemis.Core/Models/Profile/LayerProperties/Keyframe.cs
Normal file
18
src/Artemis.Core/Models/Profile/LayerProperties/Keyframe.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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>
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -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 =>
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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; }
|
||||||
|
|||||||
@ -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; }
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user