mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Refactored shape brushes to use the properties system
This commit is contained in:
1 parent
022e14e98d
commit
9b1d28840c
40 files changed
+650
-686
No files matched your search
@@ -152,8 +152,10 @@
|
||||
<Compile Include="Models\Profile\KeyframeEngines\FloatKeyframeEngine.cs" />
|
||||
<Compile Include="Models\Profile\KeyframeEngines\IntKeyframeEngine.cs" />
|
||||
<Compile Include="Models\Profile\KeyframeEngines\KeyframeEngine.cs" />
|
||||
<Compile Include="Models\Profile\KeyframeEngines\SKColorKeyframeEngine.cs" />
|
||||
<Compile Include="Models\Profile\KeyframeEngines\SKPointKeyframeEngine.cs" />
|
||||
<Compile Include="Models\Profile\KeyframeEngines\SKSizeKeyframeEngine.cs" />
|
||||
<Compile Include="Models\Profile\LayerBrushReference.cs" />
|
||||
<Compile Include="Models\Profile\LayerProperties\BaseKeyframe.cs" />
|
||||
<Compile Include="Models\Profile\LayerProperties\Keyframe.cs" />
|
||||
<Compile Include="Models\Profile\LayerProperties\BaseLayerProperty.cs" />
|
||||
@@ -178,8 +180,6 @@
|
||||
<Compile Include="Plugins\LayerBrush\LayerBrush.cs" />
|
||||
<Compile Include="Plugins\LayerBrush\LayerBrushDescriptor.cs" />
|
||||
<Compile Include="Plugins\LayerBrush\LayerBrushProvider.cs" />
|
||||
<Compile Include="Plugins\LayerBrush\LayerBrushSettings.cs" />
|
||||
<Compile Include="Plugins\LayerBrush\LayerBrushViewModel.cs" />
|
||||
<Compile Include="Plugins\Models\PluginInfo.cs" />
|
||||
<Compile Include="Plugins\Models\PluginSetting.cs" />
|
||||
<Compile Include="Plugins\Models\PluginSettings.cs" />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
@@ -6,5 +7,6 @@ namespace Artemis.Core
|
||||
{
|
||||
public static readonly string DataFolder = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\Artemis\\";
|
||||
public static readonly string ConnectionString = $"FileName={DataFolder}\\database.db;Mode=Exclusive";
|
||||
public static readonly PluginInfo CorePluginInfo = new PluginInfo {Guid = Guid.Parse("ffffffff-ffff-ffff-ffff-ffffffffffff"), Name = "Artemis Core"};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Core.Models.Profile.LayerProperties;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core.Models.Profile.KeyframeEngines
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class SKColorKeyframeEngine : KeyframeEngine
|
||||
{
|
||||
public sealed override List<Type> CompatibleTypes { get; } = new List<Type> {typeof(SKColor)};
|
||||
|
||||
protected override object GetInterpolatedValue()
|
||||
{
|
||||
var currentKeyframe = (Keyframe<SKColor>) CurrentKeyframe;
|
||||
var nextKeyframe = (Keyframe<SKColor>) NextKeyframe;
|
||||
|
||||
var redDiff = nextKeyframe.Value.Red - currentKeyframe.Value.Red;
|
||||
var greenDiff = nextKeyframe.Value.Green - currentKeyframe.Value.Green;
|
||||
var blueDiff = nextKeyframe.Value.Blue - currentKeyframe.Value.Blue;
|
||||
var alphaDiff = nextKeyframe.Value.Alpha - currentKeyframe.Value.Alpha;
|
||||
|
||||
return new SKColor(
|
||||
(byte) (currentKeyframe.Value.Red + redDiff * KeyframeProgressEased),
|
||||
(byte) (currentKeyframe.Value.Green + greenDiff * KeyframeProgressEased),
|
||||
(byte) (currentKeyframe.Value.Blue + blueDiff * KeyframeProgressEased),
|
||||
(byte)(currentKeyframe.Value.Alpha + alphaDiff * KeyframeProgressEased)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,15 +8,18 @@ using Artemis.Core.Models.Profile.LayerProperties;
|
||||
using Artemis.Core.Models.Profile.LayerShapes;
|
||||
using Artemis.Core.Models.Surface;
|
||||
using Artemis.Core.Plugins.LayerBrush;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Newtonsoft.Json;
|
||||
using Ninject;
|
||||
using Ninject.Parameters;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core.Models.Profile
|
||||
{
|
||||
public sealed class Layer : ProfileElement
|
||||
{
|
||||
private readonly Dictionary<string, BaseLayerProperty> _properties;
|
||||
private readonly Dictionary<(Guid, string), BaseLayerProperty> _properties;
|
||||
private LayerShape _layerShape;
|
||||
private List<ArtemisLed> _leds;
|
||||
private SKPath _path;
|
||||
@@ -31,12 +34,12 @@ namespace Artemis.Core.Models.Profile
|
||||
Name = name;
|
||||
|
||||
_leds = new List<ArtemisLed>();
|
||||
_properties = new Dictionary<string, BaseLayerProperty>();
|
||||
_properties = new Dictionary<(Guid, string), BaseLayerProperty>();
|
||||
|
||||
CreateDefaultProperties();
|
||||
CreateShapeType();
|
||||
ApplyShapeType();
|
||||
|
||||
ShapeTypeProperty.ValueChanged += (sender, args) => CreateShapeType();
|
||||
ShapeTypeProperty.ValueChanged += (sender, args) => ApplyShapeType();
|
||||
}
|
||||
|
||||
internal Layer(Profile profile, ProfileElement parent, LayerEntity layerEntity)
|
||||
@@ -50,27 +53,12 @@ namespace Artemis.Core.Models.Profile
|
||||
Order = layerEntity.Order;
|
||||
|
||||
_leds = new List<ArtemisLed>();
|
||||
_properties = new Dictionary<string, BaseLayerProperty>();
|
||||
_properties = new Dictionary<(Guid, string), BaseLayerProperty>();
|
||||
|
||||
CreateDefaultProperties();
|
||||
CreateShapeType();
|
||||
ApplyShapeType();
|
||||
|
||||
ShapeTypeProperty.ValueChanged += (sender, args) => CreateShapeType();
|
||||
}
|
||||
|
||||
private void CreateShapeType()
|
||||
{
|
||||
switch (ShapeTypeProperty.CurrentValue)
|
||||
{
|
||||
case LayerShapeType.Ellipse:
|
||||
LayerShape = new Ellipse(this);
|
||||
break;
|
||||
case LayerShapeType.Rectangle:
|
||||
LayerShape = new Rectangle(this);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
ShapeTypeProperty.ValueChanged += (sender, args) => ApplyShapeType();
|
||||
}
|
||||
|
||||
internal LayerEntity LayerEntity { get; set; }
|
||||
@@ -126,6 +114,8 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
public LayerProperty<SKBlendMode> BlendModeProperty { get; set; }
|
||||
|
||||
public LayerProperty<LayerBrushReference> BrushReferenceProperty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The anchor point property of this layer, also found in <see cref="Properties" />
|
||||
/// </summary>
|
||||
@@ -156,6 +146,39 @@ namespace Artemis.Core.Models.Profile
|
||||
/// </summary>
|
||||
public LayerBrush LayerBrush { get; internal set; }
|
||||
|
||||
#region Storage
|
||||
|
||||
internal override void ApplyToEntity()
|
||||
{
|
||||
// Properties
|
||||
LayerEntity.Id = EntityId;
|
||||
LayerEntity.ParentId = Parent?.EntityId ?? new Guid();
|
||||
LayerEntity.Order = Order;
|
||||
LayerEntity.Name = Name;
|
||||
LayerEntity.ProfileId = Profile.EntityId;
|
||||
foreach (var layerProperty in Properties)
|
||||
layerProperty.ApplyToEntity();
|
||||
|
||||
// LEDs
|
||||
LayerEntity.Leds.Clear();
|
||||
foreach (var artemisLed in Leds)
|
||||
{
|
||||
var ledEntity = new LedEntity
|
||||
{
|
||||
DeviceHash = artemisLed.Device.RgbDevice.GetDeviceHashCode(),
|
||||
LedName = artemisLed.RgbLed.Id.ToString()
|
||||
};
|
||||
LayerEntity.Leds.Add(ledEntity);
|
||||
}
|
||||
|
||||
// Conditions TODO
|
||||
LayerEntity.Condition.Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rendering
|
||||
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
foreach (var property in Properties)
|
||||
@@ -276,6 +299,29 @@ namespace Artemis.Core.Models.Profile
|
||||
LayerBrush?.Render(canvas, LayerShape.Path, paint);
|
||||
}
|
||||
|
||||
internal void CalculateRenderProperties()
|
||||
{
|
||||
if (!Leds.Any())
|
||||
{
|
||||
Path = new SKPath();
|
||||
|
||||
LayerShape?.CalculateRenderProperties();
|
||||
OnRenderPropertiesUpdated();
|
||||
return;
|
||||
}
|
||||
|
||||
var path = new SKPath {FillType = SKPathFillType.Winding};
|
||||
foreach (var artemisLed in Leds)
|
||||
path.AddRect(artemisLed.AbsoluteRenderRectangle);
|
||||
|
||||
Path = path;
|
||||
|
||||
// This is called here so that the shape's render properties are up to date when other code
|
||||
// responds to OnRenderPropertiesUpdated
|
||||
LayerShape?.CalculateRenderProperties();
|
||||
OnRenderPropertiesUpdated();
|
||||
}
|
||||
|
||||
private SKPoint GetLayerAnchorPosition()
|
||||
{
|
||||
var positionProperty = PositionProperty.CurrentValue;
|
||||
@@ -290,43 +336,9 @@ namespace Artemis.Core.Models.Profile
|
||||
return position;
|
||||
}
|
||||
|
||||
internal override void ApplyToEntity()
|
||||
{
|
||||
// Properties
|
||||
LayerEntity.Id = EntityId;
|
||||
LayerEntity.ParentId = Parent?.EntityId ?? new Guid();
|
||||
LayerEntity.Order = Order;
|
||||
LayerEntity.Name = Name;
|
||||
LayerEntity.ProfileId = Profile.EntityId;
|
||||
foreach (var layerProperty in Properties)
|
||||
layerProperty.ApplyToEntity();
|
||||
#endregion
|
||||
|
||||
// LEDs
|
||||
LayerEntity.Leds.Clear();
|
||||
foreach (var artemisLed in Leds)
|
||||
{
|
||||
var ledEntity = new LedEntity
|
||||
{
|
||||
DeviceHash = artemisLed.Device.RgbDevice.GetDeviceHashCode(),
|
||||
LedName = artemisLed.RgbLed.Id.ToString()
|
||||
};
|
||||
LayerEntity.Leds.Add(ledEntity);
|
||||
}
|
||||
|
||||
// Conditions TODO
|
||||
LayerEntity.Condition.Clear();
|
||||
|
||||
// Brush
|
||||
if (LayerBrush != null)
|
||||
{
|
||||
LayerEntity.BrushEntity = new BrushEntity
|
||||
{
|
||||
BrushPluginGuid = LayerBrush.Descriptor.LayerBrushProvider.PluginInfo.Guid,
|
||||
BrushType = LayerBrush.GetType().Name,
|
||||
Configuration = JsonConvert.SerializeObject(LayerBrush.Settings)
|
||||
};
|
||||
}
|
||||
}
|
||||
#region LED management
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new <see cref="ArtemisLed" /> to the layer and updates the render properties.
|
||||
@@ -385,47 +397,39 @@ namespace Artemis.Core.Models.Profile
|
||||
CalculateRenderProperties();
|
||||
}
|
||||
|
||||
internal void CalculateRenderProperties()
|
||||
#endregion
|
||||
|
||||
#region Shape management
|
||||
|
||||
private void ApplyShapeType()
|
||||
{
|
||||
if (!Leds.Any())
|
||||
switch (ShapeTypeProperty.CurrentValue)
|
||||
{
|
||||
Path = new SKPath();
|
||||
|
||||
LayerShape?.CalculateRenderProperties();
|
||||
OnRenderPropertiesUpdated();
|
||||
return;
|
||||
case LayerShapeType.Ellipse:
|
||||
LayerShape = new Ellipse(this);
|
||||
break;
|
||||
case LayerShapeType.Rectangle:
|
||||
LayerShape = new Rectangle(this);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
var path = new SKPath {FillType = SKPathFillType.Winding};
|
||||
foreach (var artemisLed in Leds)
|
||||
path.AddRect(artemisLed.AbsoluteRenderRectangle);
|
||||
|
||||
Path = path;
|
||||
|
||||
// This is called here so that the shape's render properties are up to date when other code
|
||||
// responds to OnRenderPropertiesUpdated
|
||||
LayerShape?.CalculateRenderProperties();
|
||||
OnRenderPropertiesUpdated();
|
||||
}
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[Layer] {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Adds the provided layer property to the layer.
|
||||
/// Adds the provided layer property and its children to the layer.
|
||||
/// If found, the last stored base value and keyframes will be applied to the provided property.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of value of the layer property</typeparam>
|
||||
/// <param name="layerProperty">The property to apply to the layer</param>
|
||||
/// <returns>True if an existing value was found and applied, otherwise false.</returns>
|
||||
public bool AddLayerProperty<T>(LayerProperty<T> layerProperty)
|
||||
public bool RegisterLayerProperty<T>(LayerProperty<T> layerProperty)
|
||||
{
|
||||
return AddLayerProperty((BaseLayerProperty) layerProperty);
|
||||
return RegisterLayerProperty((BaseLayerProperty) layerProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -434,9 +438,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// </summary>
|
||||
/// <param name="layerProperty">The property to apply to the layer</param>
|
||||
/// <returns>True if an existing value was found and applied, otherwise false.</returns>
|
||||
public bool AddLayerProperty(BaseLayerProperty layerProperty)
|
||||
public bool RegisterLayerProperty(BaseLayerProperty layerProperty)
|
||||
{
|
||||
if (_properties.ContainsKey(layerProperty.Id))
|
||||
if (_properties.ContainsKey((layerProperty.PluginInfo.Guid, layerProperty.Id)))
|
||||
throw new ArtemisCoreException($"Duplicate property ID detected. Layer already contains a property with ID {layerProperty.Id}.");
|
||||
|
||||
var propertyEntity = LayerEntity.PropertyEntities.FirstOrDefault(p => p.Id == layerProperty.Id && p.ValueType == layerProperty.Type.Name);
|
||||
@@ -444,66 +448,91 @@ namespace Artemis.Core.Models.Profile
|
||||
if (propertyEntity != null)
|
||||
layerProperty.ApplyToProperty(propertyEntity);
|
||||
|
||||
_properties.Add(layerProperty.Id, layerProperty);
|
||||
_properties.Add((layerProperty.PluginInfo.Guid, layerProperty.Id), layerProperty);
|
||||
OnLayerPropertyRegistered();
|
||||
return propertyEntity != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the provided layer property from the layer.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of value of the layer property</typeparam>
|
||||
/// <param name="layerProperty">The property to remove from the layer</param>
|
||||
public void RemoveLayerProperty<T>(LayerProperty<T> layerProperty)
|
||||
{
|
||||
RemoveLayerProperty((BaseLayerProperty) layerProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the provided layer property from the layer.
|
||||
/// </summary>
|
||||
/// <param name="layerProperty">The property to remove from the layer</param>
|
||||
public void RemoveLayerProperty(BaseLayerProperty layerProperty)
|
||||
{
|
||||
if (!_properties.ContainsKey((layerProperty.PluginInfo.Guid, layerProperty.Id)))
|
||||
throw new ArtemisCoreException($"Could not find a property with ID {layerProperty.Id}.");
|
||||
|
||||
var property = _properties[(layerProperty.PluginInfo.Guid, layerProperty.Id)];
|
||||
property.Parent?.Children.Remove(property);
|
||||
_properties.Remove((layerProperty.PluginInfo.Guid, layerProperty.Id));
|
||||
|
||||
OnLayerPropertyRemoved();
|
||||
}
|
||||
|
||||
/// <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="pluginInfo">The plugin this property belongs to</param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public LayerProperty<T> GetLayerPropertyById<T>(string id)
|
||||
public LayerProperty<T> GetLayerPropertyById<T>(PluginInfo pluginInfo, string id)
|
||||
{
|
||||
if (!_properties.ContainsKey(id))
|
||||
if (!_properties.ContainsKey((pluginInfo.Guid, id)))
|
||||
return null;
|
||||
|
||||
var property = _properties[id];
|
||||
var property = _properties[(pluginInfo.Guid, 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];
|
||||
return (LayerProperty<T>) _properties[(pluginInfo.Guid, id)];
|
||||
}
|
||||
|
||||
private void CreateDefaultProperties()
|
||||
{
|
||||
var shape = new LayerProperty<object>(this, null, "Core.Shape", "Shape", "A collection of basic shape properties.");
|
||||
// Shape
|
||||
var shape = new LayerProperty<object>(this, "Core.Shape", "Shape", "A collection of basic shape properties.");
|
||||
ShapeTypeProperty = new LayerProperty<LayerShapeType>(this, shape, "Core.ShapeType", "Shape type", "The type of shape to draw in this layer.") {CanUseKeyframes = false};
|
||||
FillTypeProperty = new LayerProperty<LayerFillType>(this, shape, "Core.FillType", "Fill type", "How to make the shape adjust to scale changes.") {CanUseKeyframes = false};
|
||||
BlendModeProperty = new LayerProperty<SKBlendMode>(this, shape, "Core.BlendMode", "Blend mode", "How to blend this layer into the resulting image.") {CanUseKeyframes = false};
|
||||
shape.Children.Add(ShapeTypeProperty);
|
||||
shape.Children.Add(FillTypeProperty);
|
||||
shape.Children.Add(BlendModeProperty);
|
||||
ShapeTypeProperty.Value = LayerShapeType.Rectangle;
|
||||
FillTypeProperty.Value = LayerFillType.Stretch;
|
||||
BlendModeProperty.Value = SKBlendMode.SrcOver;
|
||||
|
||||
var transform = new LayerProperty<object>(this, null, "Core.Transform", "Transform", "A collection of transformation properties.") {ExpandByDefault = true};
|
||||
RegisterLayerProperty(shape);
|
||||
foreach (var shapeProperty in shape.Children)
|
||||
RegisterLayerProperty(shapeProperty);
|
||||
|
||||
// Brush
|
||||
var brush = new LayerProperty<object>(this, "Core.Brush", "Brush", "A collection of properties that configure the selected brush.");
|
||||
BrushReferenceProperty = new LayerProperty<LayerBrushReference>(this, brush, "Core.BrushReference", "Brush type", "The type of brush to use for this layer.") {CanUseKeyframes = false};
|
||||
|
||||
RegisterLayerProperty(brush);
|
||||
foreach (var brushProperty in brush.Children)
|
||||
RegisterLayerProperty(brushProperty);
|
||||
|
||||
// Transform
|
||||
var transform = new LayerProperty<object>(this, "Core.Transform", "Transform", "A collection of transformation properties.") {ExpandByDefault = true};
|
||||
AnchorPointProperty = new LayerProperty<SKPoint>(this, transform, "Core.AnchorPoint", "Anchor Point", "The point at which the shape is attached to its position.");
|
||||
PositionProperty = new LayerProperty<SKPoint>(this, transform, "Core.Position", "Position", "The position of the shape.");
|
||||
ScaleProperty = new LayerProperty<SKSize>(this, transform, "Core.Scale", "Scale", "The scale of the shape.") {InputAffix = "%"};
|
||||
RotationProperty = new LayerProperty<float>(this, transform, "Core.Rotation", "Rotation", "The rotation of the shape in degrees.") {InputAffix = "°"};
|
||||
OpacityProperty = new LayerProperty<float>(this, transform, "Core.Opacity", "Opacity", "The opacity of the shape.") {InputAffix = "%"};
|
||||
transform.Children.Add(AnchorPointProperty);
|
||||
transform.Children.Add(PositionProperty);
|
||||
transform.Children.Add(ScaleProperty);
|
||||
transform.Children.Add(RotationProperty);
|
||||
|
||||
// Set default values
|
||||
ShapeTypeProperty.Value = LayerShapeType.Rectangle;
|
||||
FillTypeProperty.Value = LayerFillType.Stretch;
|
||||
BlendModeProperty.Value = SKBlendMode.SrcOver;
|
||||
|
||||
ScaleProperty.Value = new SKSize(100, 100);
|
||||
OpacityProperty.Value = 100;
|
||||
|
||||
|
||||
transform.Children.Add(OpacityProperty);
|
||||
|
||||
AddLayerProperty(shape);
|
||||
foreach (var shapeProperty in shape.Children)
|
||||
AddLayerProperty(shapeProperty);
|
||||
|
||||
AddLayerProperty(transform);
|
||||
RegisterLayerProperty(transform);
|
||||
foreach (var transformProperty in transform.Children)
|
||||
AddLayerProperty(transformProperty);
|
||||
RegisterLayerProperty(transformProperty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -512,6 +541,8 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
public event EventHandler RenderPropertiesUpdated;
|
||||
public event EventHandler ShapePropertiesUpdated;
|
||||
public event EventHandler LayerPropertyRegistered;
|
||||
public event EventHandler LayerPropertyRemoved;
|
||||
|
||||
private void OnRenderPropertiesUpdated()
|
||||
{
|
||||
@@ -524,6 +555,21 @@ namespace Artemis.Core.Models.Profile
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[Layer] {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
|
||||
}
|
||||
|
||||
private void OnLayerPropertyRegistered()
|
||||
{
|
||||
LayerPropertyRegistered?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void OnLayerPropertyRemoved()
|
||||
{
|
||||
LayerPropertyRemoved?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public enum LayerShapeType
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using Artemis.Core.Plugins.LayerBrush;
|
||||
|
||||
namespace Artemis.Core.Models.Profile
|
||||
{
|
||||
/// <summary>
|
||||
/// A reference to a <see cref="LayerBrushDescriptor" />
|
||||
/// </summary>
|
||||
public class LayerBrushReference
|
||||
{
|
||||
/// <summary>
|
||||
/// The GUID of the plugin the brush descriptor resides in
|
||||
/// </summary>
|
||||
public Guid BrushPluginGuid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The full type name of the brush descriptor
|
||||
/// </summary>
|
||||
public string BrushType { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Exceptions;
|
||||
using Artemis.Core.Models.Profile.KeyframeEngines;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
using Artemis.Core.Utilities;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Newtonsoft.Json;
|
||||
@@ -13,9 +14,10 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
{
|
||||
private object _baseValue;
|
||||
|
||||
protected BaseLayerProperty(Layer layer, BaseLayerProperty parent, string id, string name, string description, Type type)
|
||||
protected BaseLayerProperty(Layer layer, PluginInfo pluginInfo, BaseLayerProperty parent, string id, string name, string description, Type type)
|
||||
{
|
||||
Layer = layer;
|
||||
PluginInfo = pluginInfo;
|
||||
Parent = parent;
|
||||
Id = id;
|
||||
Name = name;
|
||||
@@ -23,8 +25,14 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
Type = type;
|
||||
CanUseKeyframes = true;
|
||||
|
||||
// This can only be null if accessed internally
|
||||
if (PluginInfo == null)
|
||||
PluginInfo = Constants.CorePluginInfo;
|
||||
|
||||
Children = new List<BaseLayerProperty>();
|
||||
BaseKeyframes = new List<BaseKeyframe>();
|
||||
|
||||
parent?.Children.Add(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -32,6 +40,11 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
/// </summary>
|
||||
public Layer Layer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Info of the plugin associated with this property
|
||||
/// </summary>
|
||||
public PluginInfo PluginInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent property of this property.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,14 +1,73 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
|
||||
namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a property on the layer. This property is visible in the profile editor and can be key-framed (unless
|
||||
/// opted out)
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
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))
|
||||
internal LayerProperty(Layer layer, BaseLayerProperty parent, string id, string name, string description) : base(layer, null, parent, id, name, description, typeof(T))
|
||||
{
|
||||
}
|
||||
|
||||
internal LayerProperty(Layer layer, string id, string name, string description) : base(layer, null, null, id, name, description, typeof(T))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a property on the layer. This property is visible in the profile editor and can be key-framed (unless
|
||||
/// opted out)
|
||||
/// <para>
|
||||
/// Note: The value and keyframes of the property are stored using the ID, after adding the property to the layer
|
||||
/// these are restored.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="layer">The layer the property is applied to</param>
|
||||
/// <param name="pluginInfo">The plugin to create this property for</param>
|
||||
/// <param name="parent">The parent of this property, use this to create a tree-hierarchy in the editor</param>
|
||||
/// <param name="id">A and ID identifying your property, must be unique within your plugin</param>
|
||||
/// <param name="name">A name for your property, this is visible in the editor</param>
|
||||
/// <param name="description">A description for your property, this is visible in the editor</param>
|
||||
public LayerProperty(Layer layer, PluginInfo pluginInfo, BaseLayerProperty parent, string id, string name, string description) : base(layer, pluginInfo, parent, id, name, description,
|
||||
typeof(T))
|
||||
{
|
||||
if (layer == null)
|
||||
throw new ArgumentNullException(nameof(layer));
|
||||
if (pluginInfo == null)
|
||||
throw new ArgumentNullException(nameof(pluginInfo));
|
||||
if (id == null)
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a property on the layer. This property is visible in the profile editor and can be key-framed (unless
|
||||
/// opted out)
|
||||
/// <para>
|
||||
/// Note: The value and keyframes of the property are stored using the ID, after adding the property to the layer
|
||||
/// these are restored.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="layer">The layer the property is applied to</param>
|
||||
/// <param name="pluginInfo">The plugin to create this property for</param>
|
||||
/// <param name="id">A and ID identifying your property, must be unique within your plugin</param>
|
||||
/// <param name="name">A name for your property, this is visible in the editor</param>
|
||||
/// <param name="description">A description for your property, this is visible in the editor</param>
|
||||
public LayerProperty(Layer layer, PluginInfo pluginInfo, string id, string name, string description) : base(layer, pluginInfo, null, id, name, description, typeof(T))
|
||||
{
|
||||
if (layer == null)
|
||||
throw new ArgumentNullException(nameof(layer));
|
||||
if (pluginInfo == null)
|
||||
throw new ArgumentNullException(nameof(pluginInfo));
|
||||
if (id == null)
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the property without any keyframes applied
|
||||
/// </summary>
|
||||
|
||||
@@ -1,32 +1,25 @@
|
||||
using System;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Models.Profile.LayerProperties;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core.Plugins.LayerBrush
|
||||
{
|
||||
public abstract class LayerBrush : IDisposable
|
||||
{
|
||||
protected LayerBrush(Layer layer, LayerBrushSettings settings, LayerBrushDescriptor descriptor)
|
||||
protected LayerBrush(Layer layer, LayerBrushDescriptor descriptor)
|
||||
{
|
||||
Layer = layer;
|
||||
Settings = settings;
|
||||
Descriptor = descriptor;
|
||||
}
|
||||
|
||||
public Layer Layer { get; }
|
||||
public LayerBrushSettings Settings { get; }
|
||||
public LayerBrushDescriptor Descriptor { get; }
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the profile editor to populate the brush properties panel
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract LayerBrushViewModel GetViewModel();
|
||||
|
||||
/// <summary>
|
||||
/// Called before rendering every frame, write your update logic here
|
||||
/// </summary>
|
||||
@@ -46,5 +39,38 @@ namespace Artemis.Core.Plugins.LayerBrush
|
||||
public virtual void Render(SKCanvas canvas, SKPath path, SKPaint paint)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides an easy way to add your own properties to the layer, for more info see <see cref="LayerProperty{T}" />.
|
||||
/// <para>Note: If found, the last value and keyframes are loaded and set when calling this method.</para>
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="parent">The parent of this property, use this to create a tree-hierarchy in the editor</param>
|
||||
/// <param name="id">A and ID identifying your property, must be unique within your plugin</param>
|
||||
/// <param name="name">A name for your property, this is visible in the editor</param>
|
||||
/// <param name="description">A description for your property, this is visible in the editor</param>
|
||||
/// <returns>The layer property</returns>
|
||||
protected LayerProperty<T> RegisterLayerProperty<T>(BaseLayerProperty parent, string id, string name, string description)
|
||||
{
|
||||
var property = new LayerProperty<T>(Layer, Descriptor.LayerBrushProvider.PluginInfo, parent, id, name, description);
|
||||
Layer.RegisterLayerProperty(property);
|
||||
return property;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides an easy way to add your own properties to the layer, for more info see <see cref="LayerProperty{T}" />.
|
||||
/// <para>Note: If found, the last value and keyframes are loaded and set when calling this method.</para>
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="id">A and ID identifying your property, must be unique within your plugin</param>
|
||||
/// <param name="name">A name for your property, this is visible in the editor</param>
|
||||
/// <param name="description">A description for your property, this is visible in the editor</param>
|
||||
/// <returns>The layer property</returns>
|
||||
protected LayerProperty<T> RegisterLayerProperty<T>(string id, string name, string description)
|
||||
{
|
||||
var property = new LayerProperty<T>(Layer, Descriptor.LayerBrushProvider.PluginInfo, Layer.BrushReferenceProperty.Parent, id, name, description);
|
||||
Layer.RegisterLayerProperty(property);
|
||||
return property;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.Core.Plugins.LayerBrush
|
||||
{
|
||||
public abstract class LayerBrushSettings : PropertyChangedBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the dispatcher to use to dispatch PropertyChanged events. Defaults to
|
||||
/// Execute.DefaultPropertyChangedDispatcher
|
||||
/// </summary>
|
||||
[XmlIgnore]
|
||||
[JsonIgnore]
|
||||
public override Action<Action> PropertyChangedDispatcher { get; set; } = Execute.DefaultPropertyChangedDispatcher;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.Core.Plugins.LayerBrush
|
||||
{
|
||||
public abstract class LayerBrushViewModel : PropertyChangedBase
|
||||
{
|
||||
protected LayerBrushViewModel(LayerBrush brush)
|
||||
{
|
||||
Brush = brush;
|
||||
}
|
||||
|
||||
public LayerBrush Brush { get; }
|
||||
}
|
||||
}
|
||||
@@ -75,14 +75,9 @@ namespace Artemis.Core.RGB.NET
|
||||
{
|
||||
foreach (var renderTarget in renderTargets)
|
||||
{
|
||||
if (renderTarget.Led.Id == LedId.Keyboard_W)
|
||||
Console.WriteLine();
|
||||
var scaledLocation = renderTarget.Point * Scale;
|
||||
if (scaledLocation.X < Bitmap.Width && scaledLocation.Y < Bitmap.Height)
|
||||
{
|
||||
var test = Bitmap.GetPixel(scaledLocation.X.RoundToInt(), scaledLocation.Y.RoundToInt());
|
||||
RenderedTargets[renderTarget] = Bitmap.GetPixel(scaledLocation.X.RoundToInt(), scaledLocation.Y.RoundToInt()).ToRgbColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,8 @@ namespace Artemis.Core.Services.Interfaces
|
||||
/// <see cref="LayerBrushDescriptor" /> to the provided <see cref="Layer" />.
|
||||
/// </summary>
|
||||
/// <param name="layer">The layer to add the new layer element to</param>
|
||||
/// <param name="brushDescriptor">The descriptor of the new layer brush</param>
|
||||
/// <param name="settings">JSON settings to be deserialized and injected into the layer brush</param>
|
||||
/// <returns></returns>
|
||||
LayerBrush InstantiateLayerBrush(Layer layer, LayerBrushDescriptor brushDescriptor, string settings = null);
|
||||
LayerBrush InstantiateLayerBrush(Layer layer);
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates and adds a compatible <see cref="KeyframeEngine" /> to the provided <see cref="LayerProperty{T}" />
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Models.Profile.KeyframeEngines;
|
||||
using Artemis.Core.Models.Profile.LayerProperties;
|
||||
using Artemis.Core.Plugins.Exceptions;
|
||||
using Artemis.Core.Plugins.LayerBrush;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Newtonsoft.Json;
|
||||
using Ninject;
|
||||
using Ninject.Parameters;
|
||||
using Serilog;
|
||||
@@ -18,57 +15,38 @@ namespace Artemis.Core.Services
|
||||
{
|
||||
private readonly IKernel _kernel;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IPluginService _pluginService;
|
||||
|
||||
public LayerService(IKernel kernel, ILogger logger)
|
||||
public LayerService(IKernel kernel, ILogger logger, IPluginService pluginService)
|
||||
{
|
||||
_kernel = kernel;
|
||||
_logger = logger;
|
||||
_pluginService = pluginService;
|
||||
}
|
||||
|
||||
public LayerBrush InstantiateLayerBrush(Layer layer, LayerBrushDescriptor brushDescriptor, string settings)
|
||||
public LayerBrush InstantiateLayerBrush(Layer layer)
|
||||
{
|
||||
// Determine the settings type declared by the layer element
|
||||
object settingsInstance = null;
|
||||
var properties = brushDescriptor.LayerBrushType.GetProperties();
|
||||
var settingsType = properties.FirstOrDefault(p => p.Name == "Settings" &&
|
||||
p.DeclaringType == brushDescriptor.LayerBrushType)?.PropertyType;
|
||||
RemoveLayerBrush(layer);
|
||||
|
||||
// Deserialize the settings if provided, check for null in JSON as well
|
||||
if (settings != null && settings != "null")
|
||||
{
|
||||
// Setting where provided but no settings type was found, something is wrong
|
||||
if (settingsType == null)
|
||||
{
|
||||
throw new ArtemisPluginException(
|
||||
brushDescriptor.LayerBrushProvider.PluginInfo,
|
||||
$"Settings where provided but layer element of type {brushDescriptor.LayerBrushType.Name} has no Settings property."
|
||||
);
|
||||
}
|
||||
var descriptorReference = layer.BrushReferenceProperty.CurrentValue;
|
||||
if (descriptorReference == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
settingsInstance = JsonConvert.DeserializeObject(settings, settingsType);
|
||||
}
|
||||
catch (JsonSerializationException e)
|
||||
{
|
||||
_logger.Warning(e, "Failed to deserialize settings for layer type {type}, resetting element settings - Plugin info: {pluginInfo}",
|
||||
brushDescriptor.LayerBrushType.Name,
|
||||
brushDescriptor.LayerBrushProvider.PluginInfo);
|
||||
// Get a matching descriptor
|
||||
var layerBrushProviders = _pluginService.GetPluginsOfType<LayerBrushProvider>();
|
||||
var descriptors = layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors).ToList();
|
||||
var descriptor = descriptors.FirstOrDefault(d => d.LayerBrushProvider.PluginInfo.Guid == descriptorReference.BrushPluginGuid &&
|
||||
d.LayerBrushType.Name == descriptorReference.BrushType);
|
||||
|
||||
settingsInstance = Activator.CreateInstance(settingsType);
|
||||
}
|
||||
}
|
||||
// If no settings found, provide a fresh instance of the settings type
|
||||
else if (settingsType != null)
|
||||
settingsInstance = Activator.CreateInstance(settingsType);
|
||||
if (descriptor == null)
|
||||
return null;
|
||||
|
||||
var arguments = new IParameter[]
|
||||
{
|
||||
new ConstructorArgument("layer", layer),
|
||||
new ConstructorArgument("settings", settingsInstance),
|
||||
new ConstructorArgument("descriptor", brushDescriptor)
|
||||
new ConstructorArgument("descriptor", descriptor)
|
||||
};
|
||||
var layerElement = (LayerBrush) _kernel.Get(brushDescriptor.LayerBrushType, arguments);
|
||||
var layerElement = (LayerBrush) _kernel.Get(descriptor.LayerBrushType, arguments);
|
||||
layer.LayerBrush = layerElement;
|
||||
|
||||
return layerElement;
|
||||
@@ -92,10 +70,17 @@ namespace Artemis.Core.Services
|
||||
return keyframeEngine;
|
||||
}
|
||||
|
||||
public void RemoveLayerBrush(Layer layer, LayerBrush layerElement)
|
||||
public void RemoveLayerBrush(Layer layer)
|
||||
{
|
||||
if (layer.LayerBrush == null)
|
||||
return;
|
||||
|
||||
var brush = layer.LayerBrush;
|
||||
layer.LayerBrush = null;
|
||||
|
||||
var propertiesToRemove = layer.Properties.Where(l => l.PluginInfo == brush.Descriptor.LayerBrushProvider.PluginInfo).ToList();
|
||||
foreach (var layerProperty in propertiesToRemove)
|
||||
layer.RemoveLayerProperty(layerProperty);
|
||||
brush.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,7 @@ namespace Artemis.Core.Services
|
||||
|
||||
internal SettingsService(IPluginSettingRepository pluginSettingRepository)
|
||||
{
|
||||
var pluginInfo = new PluginInfo {Guid = Guid.Parse("ffffffff-ffff-ffff-ffff-ffffffffffff"), Name = "Artemis Core"};
|
||||
_pluginSettings = new PluginSettings(pluginInfo, pluginSettingRepository);
|
||||
_pluginSettings = new PluginSettings(Constants.CorePluginInfo, pluginSettingRepository);
|
||||
}
|
||||
|
||||
public PluginSetting<T> GetSetting<T>(string name, T defaultValue = default)
|
||||
|
||||
@@ -148,20 +148,9 @@ namespace Artemis.Core.Services.Storage
|
||||
|
||||
private void InstantiateProfileLayerBrushes(Profile profile)
|
||||
{
|
||||
var layerBrushProviders = _pluginService.GetPluginsOfType<LayerBrushProvider>();
|
||||
var descriptors = layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors).ToList();
|
||||
|
||||
// Only instantiate brushes for layers without an existing brush instance
|
||||
foreach (var layer in profile.GetAllLayers().Where(l => l.LayerBrush == null && l.LayerEntity.BrushEntity != null))
|
||||
{
|
||||
// Get a matching descriptor
|
||||
var descriptor = descriptors.FirstOrDefault(d => d.LayerBrushProvider.PluginInfo.Guid == layer.LayerEntity.BrushEntity.BrushPluginGuid &&
|
||||
d.LayerBrushType.Name == layer.LayerEntity.BrushEntity.BrushType);
|
||||
|
||||
// If a descriptor that matches if found, instantiate it with the GUID of the element entity
|
||||
if (descriptor != null)
|
||||
_layerService.InstantiateLayerBrush(layer, descriptor, layer.LayerEntity.BrushEntity.Configuration);
|
||||
}
|
||||
foreach (var layer in profile.GetAllLayers().Where(l => l.LayerBrush == null))
|
||||
_layerService.InstantiateLayerBrush(layer);
|
||||
}
|
||||
|
||||
private void InstantiateProfileKeyframeEngines(Profile profile)
|
||||
|
||||
Reference in new issue
Block a user