mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-31 09:43:46 +00:00
Profiles - Added enter, main and exit timelines
Display conditions - Fleshed out most of the UI
This commit is contained in:
parent
0e873a48cf
commit
7cfe9a46ee
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using Artemis.Core.Services.Interfaces;
|
using Artemis.Core.Services.Interfaces;
|
||||||
using Artemis.Storage.Entities.Profile.Abstract;
|
using Artemis.Storage.Entities.Profile.Abstract;
|
||||||
|
|
||||||
@ -34,9 +35,10 @@ namespace Artemis.Core.Models.Profile.Conditions.Abstract
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract DisplayConditionPartEntity GetEntity();
|
public abstract bool Evaluate();
|
||||||
|
|
||||||
internal abstract void ApplyToEntity();
|
|
||||||
internal abstract void Initialize(IDataModelService dataModelService);
|
internal abstract void Initialize(IDataModelService dataModelService);
|
||||||
|
internal abstract void ApplyToEntity();
|
||||||
|
internal abstract DisplayConditionPartEntity GetEntity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,6 +33,23 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
public BooleanOperator BooleanOperator { get; set; }
|
public BooleanOperator BooleanOperator { get; set; }
|
||||||
public DisplayConditionGroupEntity DisplayConditionGroupEntity { get; set; }
|
public DisplayConditionGroupEntity DisplayConditionGroupEntity { get; set; }
|
||||||
|
|
||||||
|
public override bool Evaluate()
|
||||||
|
{
|
||||||
|
switch (BooleanOperator)
|
||||||
|
{
|
||||||
|
case BooleanOperator.And:
|
||||||
|
return Children.All(c => c.Evaluate());
|
||||||
|
case BooleanOperator.Or:
|
||||||
|
return Children.Any(c => c.Evaluate());
|
||||||
|
case BooleanOperator.AndNot:
|
||||||
|
return Children.All(c => !c.Evaluate());
|
||||||
|
case BooleanOperator.OrNot:
|
||||||
|
return Children.Any(c => !c.Evaluate());
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal override void ApplyToEntity()
|
internal override void ApplyToEntity()
|
||||||
{
|
{
|
||||||
DisplayConditionGroupEntity.BooleanOperator = (int) BooleanOperator;
|
DisplayConditionGroupEntity.BooleanOperator = (int) BooleanOperator;
|
||||||
@ -49,7 +66,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
child.Initialize(dataModelService);
|
child.Initialize(dataModelService);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override DisplayConditionPartEntity GetEntity()
|
internal override DisplayConditionPartEntity GetEntity()
|
||||||
{
|
{
|
||||||
return DisplayConditionGroupEntity;
|
return DisplayConditionGroupEntity;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,18 +8,24 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
{
|
{
|
||||||
public ListOperator ListOperator { get; set; }
|
public ListOperator ListOperator { get; set; }
|
||||||
|
|
||||||
|
public override bool Evaluate()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
internal override void ApplyToEntity()
|
internal override void ApplyToEntity()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Initialize(IDataModelService dataModelService)
|
internal override DisplayConditionPartEntity GetEntity()
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override DisplayConditionPartEntity GetEntity()
|
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void Initialize(IDataModelService dataModelService)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ListOperator
|
public enum ListOperator
|
||||||
|
|||||||
@ -61,6 +61,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
ValidateOperator();
|
ValidateOperator();
|
||||||
ValidateRightSide();
|
ValidateRightSide();
|
||||||
|
|
||||||
CreateExpression();
|
CreateExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,6 +92,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
RightPropertyPath = null;
|
RightPropertyPath = null;
|
||||||
|
|
||||||
SetStaticValue(staticValue);
|
SetStaticValue(staticValue);
|
||||||
|
|
||||||
CreateExpression();
|
CreateExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,14 +113,21 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
var leftType = LeftDataModel.GetTypeAtPath(LeftPropertyPath);
|
var leftType = LeftDataModel.GetTypeAtPath(LeftPropertyPath);
|
||||||
if (displayConditionOperator.SupportsType(leftType))
|
if (displayConditionOperator.SupportsType(leftType))
|
||||||
Operator = displayConditionOperator;
|
Operator = displayConditionOperator;
|
||||||
|
|
||||||
|
CreateExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateExpression()
|
private void CreateExpression()
|
||||||
{
|
{
|
||||||
|
DynamicConditionLambda = null;
|
||||||
|
CompiledDynamicConditionLambda = null;
|
||||||
|
StaticConditionLambda = null;
|
||||||
|
CompiledStaticConditionLambda = null;
|
||||||
|
|
||||||
if (PredicateType == PredicateType.Dynamic)
|
if (PredicateType == PredicateType.Dynamic)
|
||||||
CreateDynamicExpression();
|
CreateDynamicExpression();
|
||||||
else
|
|
||||||
CreateStaticExpression();
|
CreateStaticExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void ApplyToEntity()
|
internal override void ApplyToEntity()
|
||||||
@ -134,6 +143,16 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
DisplayConditionPredicateEntity.OperatorType = Operator?.GetType().Name;
|
DisplayConditionPredicateEntity.OperatorType = Operator?.GetType().Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool Evaluate()
|
||||||
|
{
|
||||||
|
if (CompiledDynamicConditionLambda != null)
|
||||||
|
return CompiledDynamicConditionLambda(LeftDataModel, RightDataModel);
|
||||||
|
if (CompiledStaticConditionLambda != null)
|
||||||
|
return CompiledStaticConditionLambda(LeftDataModel);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
internal override void Initialize(IDataModelService dataModelService)
|
internal override void Initialize(IDataModelService dataModelService)
|
||||||
{
|
{
|
||||||
// Left side
|
// Left side
|
||||||
@ -184,7 +203,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override DisplayConditionPartEntity GetEntity()
|
internal override DisplayConditionPartEntity GetEntity()
|
||||||
{
|
{
|
||||||
return DisplayConditionPredicateEntity;
|
return DisplayConditionPredicateEntity;
|
||||||
}
|
}
|
||||||
@ -199,9 +218,6 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
Operator = null;
|
Operator = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Validates the right side, ensuring it is still compatible with the current left side
|
|
||||||
/// </summary>
|
|
||||||
private void ValidateRightSide()
|
private void ValidateRightSide()
|
||||||
{
|
{
|
||||||
var leftSideType = LeftDataModel.GetTypeAtPath(LeftPropertyPath);
|
var leftSideType = LeftDataModel.GetTypeAtPath(LeftPropertyPath);
|
||||||
@ -223,10 +239,6 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the current static value, ensuring it is a valid type. This assumes the types are compatible if they
|
|
||||||
/// differ.
|
|
||||||
/// </summary>
|
|
||||||
private void SetStaticValue(object staticValue)
|
private void SetStaticValue(object staticValue)
|
||||||
{
|
{
|
||||||
// If the left side is empty simply apply the value, any validation will wait
|
// If the left side is empty simply apply the value, any validation will wait
|
||||||
|
|||||||
@ -65,6 +65,8 @@ namespace Artemis.Core.Models.Profile
|
|||||||
if (!Enabled)
|
if (!Enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
UpdateDisplayCondition();
|
||||||
|
|
||||||
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||||
baseLayerEffect.Update(deltaTime);
|
baseLayerEffect.Update(deltaTime);
|
||||||
|
|
||||||
|
|||||||
@ -205,6 +205,8 @@ namespace Artemis.Core.Models.Profile
|
|||||||
if (LayerBrush?.BaseProperties == null || !LayerBrush.BaseProperties.PropertiesInitialized)
|
if (LayerBrush?.BaseProperties == null || !LayerBrush.BaseProperties.PropertiesInitialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
UpdateDisplayCondition();
|
||||||
|
|
||||||
// TODO: Remove, this is slow and stupid
|
// TODO: Remove, this is slow and stupid
|
||||||
// For now, reset all keyframe engines after the last keyframe was hit
|
// For now, reset all keyframe engines after the last keyframe was hit
|
||||||
// This is a placeholder method of repeating the animation until repeat modes are implemented
|
// This is a placeholder method of repeating the animation until repeat modes are implemented
|
||||||
|
|||||||
@ -18,6 +18,11 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public BaseLayerProperty BaseLayerProperty { get; internal set; }
|
public BaseLayerProperty BaseLayerProperty { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The timeline this keyframe is contained in
|
||||||
|
/// </summary>
|
||||||
|
public abstract Timeline Timeline { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The position of this keyframe in the timeline
|
/// The position of this keyframe in the timeline
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -28,4 +33,11 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Easings.Functions EasingFunction { get; set; }
|
public Easings.Functions EasingFunction { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum Timeline
|
||||||
|
{
|
||||||
|
Start,
|
||||||
|
Main,
|
||||||
|
End
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -23,10 +23,16 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
private T _currentValue;
|
private T _currentValue;
|
||||||
private bool _isInitialized;
|
private bool _isInitialized;
|
||||||
private List<LayerPropertyKeyframe<T>> _keyframes;
|
private List<LayerPropertyKeyframe<T>> _keyframes;
|
||||||
|
private List<LayerPropertyKeyframe<T>> _startKeyframes;
|
||||||
|
private List<LayerPropertyKeyframe<T>> _mainKeyframes;
|
||||||
|
private List<LayerPropertyKeyframe<T>> _endKeyframes;
|
||||||
|
|
||||||
protected LayerProperty()
|
protected LayerProperty()
|
||||||
{
|
{
|
||||||
_keyframes = new List<LayerPropertyKeyframe<T>>();
|
_keyframes = new List<LayerPropertyKeyframe<T>>();
|
||||||
|
_startKeyframes = new List<LayerPropertyKeyframe<T>>();
|
||||||
|
_mainKeyframes = new List<LayerPropertyKeyframe<T>>();
|
||||||
|
_endKeyframes = new List<LayerPropertyKeyframe<T>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -84,7 +90,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
/// <param name="value">The value to set.</param>
|
/// <param name="value">The value to set.</param>
|
||||||
/// <param name="time">
|
/// <param name="time">
|
||||||
/// An optional time to set the value add, if provided and property is using keyframes the value will be set to an new
|
/// An optional time to set the value add, if provided and property is using keyframes the value will be set to an new
|
||||||
/// or existing keyframe.
|
/// or existing keyframe in the currently active timeline.
|
||||||
/// </param>
|
/// </param>
|
||||||
public void SetCurrentValue(T value, TimeSpan? time)
|
public void SetCurrentValue(T value, TimeSpan? time)
|
||||||
{
|
{
|
||||||
@ -93,10 +99,10 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If on a keyframe, update the keyframe
|
// If on a keyframe, update the keyframe
|
||||||
var currentKeyframe = Keyframes.FirstOrDefault(k => k.Position == time.Value);
|
var currentKeyframe = Keyframes.FirstOrDefault(k => k.Position == time.Value && k.Timeline == ProfileElement.CurrentTimeline);
|
||||||
// Create a new keyframe if none found
|
// Create a new keyframe if none found
|
||||||
if (currentKeyframe == null)
|
if (currentKeyframe == null)
|
||||||
AddKeyframe(new LayerPropertyKeyframe<T>(value, time.Value, Easings.Functions.Linear, this));
|
AddKeyframe(new LayerPropertyKeyframe<T>(value, time.Value, ProfileElement.CurrentTimeline, Easings.Functions.Linear, this));
|
||||||
else
|
else
|
||||||
currentKeyframe.Value = value;
|
currentKeyframe.Value = value;
|
||||||
|
|
||||||
@ -132,6 +138,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
var newKeyframe = new LayerPropertyKeyframe<T>(
|
var newKeyframe = new LayerPropertyKeyframe<T>(
|
||||||
keyframe.Value,
|
keyframe.Value,
|
||||||
keyframe.Position,
|
keyframe.Position,
|
||||||
|
keyframe.Timeline,
|
||||||
keyframe.EasingFunction,
|
keyframe.EasingFunction,
|
||||||
keyframe.LayerProperty
|
keyframe.LayerProperty
|
||||||
);
|
);
|
||||||
@ -193,22 +200,42 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
if (!KeyframesSupported || !KeyframesEnabled)
|
if (!KeyframesSupported || !KeyframesEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var keyframeSet = _keyframes;
|
||||||
|
if (ProfileElement.CurrentTimeline == Timeline.Start)
|
||||||
|
keyframeSet = _startKeyframes;
|
||||||
|
else if (ProfileElement.CurrentTimeline == Timeline.Main)
|
||||||
|
keyframeSet = _mainKeyframes;
|
||||||
|
else if (ProfileElement.CurrentTimeline == Timeline.End)
|
||||||
|
keyframeSet = _endKeyframes;
|
||||||
|
|
||||||
// The current keyframe is the last keyframe before the current time
|
// The current keyframe is the last keyframe before the current time
|
||||||
CurrentKeyframe = _keyframes.LastOrDefault(k => k.Position <= TimelineProgress);
|
CurrentKeyframe = keyframeSet.LastOrDefault(k => k.Position <= TimelineProgress);
|
||||||
|
|
||||||
|
// If the current keyframe is null, try to find it in previous timelines
|
||||||
|
if (CurrentKeyframe == null && ProfileElement.CurrentTimeline == Timeline.Main)
|
||||||
|
CurrentKeyframe = _startKeyframes.LastOrDefault();
|
||||||
|
else if (CurrentKeyframe == null && ProfileElement.CurrentTimeline == Timeline.End)
|
||||||
|
CurrentKeyframe = _mainKeyframes.LastOrDefault() ?? _startKeyframes.LastOrDefault();
|
||||||
|
|
||||||
// Keyframes are sorted by position so we can safely assume the next keyframe's position is after the current
|
// Keyframes are sorted by position so we can safely assume the next keyframe's position is after the current
|
||||||
var nextIndex = _keyframes.IndexOf(CurrentKeyframe) + 1;
|
var nextIndex = keyframeSet.IndexOf(CurrentKeyframe) + 1;
|
||||||
NextKeyframe = _keyframes.Count > nextIndex ? _keyframes[nextIndex] : null;
|
NextKeyframe = keyframeSet.Count > nextIndex ? keyframeSet[nextIndex] : null;
|
||||||
|
|
||||||
// No need to update the current value if either of the keyframes are null
|
// No need to update the current value if either of the keyframes are null
|
||||||
if (CurrentKeyframe == null)
|
if (CurrentKeyframe == null)
|
||||||
CurrentValue = _keyframes.Any() ? _keyframes[0].Value : BaseValue;
|
CurrentValue = keyframeSet.Any() ? keyframeSet[0].Value : BaseValue;
|
||||||
else if (NextKeyframe == null)
|
else if (NextKeyframe == null)
|
||||||
CurrentValue = CurrentKeyframe.Value;
|
CurrentValue = CurrentKeyframe.Value;
|
||||||
// Only determine progress and current value if both keyframes are present
|
// Only determine progress and current value if both keyframes are present
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var timeDiff = NextKeyframe.Position - CurrentKeyframe.Position;
|
// If the current keyframe belongs to a previous timeline, consider it starting at 0
|
||||||
var keyframeProgress = (float) ((TimelineProgress - CurrentKeyframe.Position).TotalMilliseconds / timeDiff.TotalMilliseconds);
|
var currentKeyframePosition = CurrentKeyframe.Position;
|
||||||
|
if (CurrentKeyframe.Timeline != ProfileElement.CurrentTimeline)
|
||||||
|
currentKeyframePosition = TimeSpan.Zero;
|
||||||
|
|
||||||
|
var timeDiff = NextKeyframe.Position - currentKeyframePosition;
|
||||||
|
var keyframeProgress = (float) ((TimelineProgress - currentKeyframePosition).TotalMilliseconds / timeDiff.TotalMilliseconds);
|
||||||
var keyframeProgressEased = (float) Easings.Interpolate(keyframeProgress, CurrentKeyframe.EasingFunction);
|
var keyframeProgressEased = (float) Easings.Interpolate(keyframeProgress, CurrentKeyframe.EasingFunction);
|
||||||
UpdateCurrentValue(keyframeProgress, keyframeProgressEased);
|
UpdateCurrentValue(keyframeProgress, keyframeProgressEased);
|
||||||
}
|
}
|
||||||
@ -227,11 +254,15 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sorts the keyframes in ascending order by position
|
/// Sorts the keyframes in ascending order by position and divides the keyframes into different timelines
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal void SortKeyframes()
|
internal void SortKeyframes()
|
||||||
{
|
{
|
||||||
_keyframes = _keyframes.OrderBy(k => k.Position).ToList();
|
_keyframes = _keyframes.OrderBy(k => k.Position).ToList();
|
||||||
|
|
||||||
|
_startKeyframes = _keyframes.Where(k => k.Timeline == Timeline.Start).ToList();
|
||||||
|
_mainKeyframes = _keyframes.Where(k => k.Timeline == Timeline.Main).ToList();
|
||||||
|
_endKeyframes = _keyframes.Where(k => k.Timeline == Timeline.End).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void ApplyToLayerProperty(PropertyEntity entity, LayerPropertyGroup layerPropertyGroup, bool fromStorage)
|
internal override void ApplyToLayerProperty(PropertyEntity entity, LayerPropertyGroup layerPropertyGroup, bool fromStorage)
|
||||||
@ -258,6 +289,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
_keyframes.AddRange(entity.KeyframeEntities.Select(k => new LayerPropertyKeyframe<T>(
|
_keyframes.AddRange(entity.KeyframeEntities.Select(k => new LayerPropertyKeyframe<T>(
|
||||||
JsonConvert.DeserializeObject<T>(k.Value),
|
JsonConvert.DeserializeObject<T>(k.Value),
|
||||||
k.Position,
|
k.Position,
|
||||||
|
(Timeline) k.Timeline,
|
||||||
(Easings.Functions) k.EasingFunction,
|
(Easings.Functions) k.EasingFunction,
|
||||||
this
|
this
|
||||||
)));
|
)));
|
||||||
@ -287,6 +319,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
{
|
{
|
||||||
Value = JsonConvert.SerializeObject(k.Value),
|
Value = JsonConvert.SerializeObject(k.Value),
|
||||||
Position = k.Position,
|
Position = k.Position,
|
||||||
|
Timeline = (int) k.Timeline,
|
||||||
EasingFunction = (int) k.EasingFunction
|
EasingFunction = (int) k.EasingFunction
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,10 +6,12 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
public class LayerPropertyKeyframe<T> : BaseLayerPropertyKeyframe
|
public class LayerPropertyKeyframe<T> : BaseLayerPropertyKeyframe
|
||||||
{
|
{
|
||||||
private TimeSpan _position;
|
private TimeSpan _position;
|
||||||
|
private Timeline _timeline;
|
||||||
|
|
||||||
public LayerPropertyKeyframe(T value, TimeSpan position, Easings.Functions easingFunction, LayerProperty<T> layerProperty) : base(layerProperty)
|
public LayerPropertyKeyframe(T value, TimeSpan position, Timeline timeline, Easings.Functions easingFunction, LayerProperty<T> layerProperty) : base(layerProperty)
|
||||||
{
|
{
|
||||||
_position = position;
|
_position = position;
|
||||||
|
_timeline = timeline;
|
||||||
Value = value;
|
Value = value;
|
||||||
LayerProperty = layerProperty;
|
LayerProperty = layerProperty;
|
||||||
EasingFunction = easingFunction;
|
EasingFunction = easingFunction;
|
||||||
@ -25,6 +27,17 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public T Value { get; set; }
|
public T Value { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Timeline Timeline
|
||||||
|
{
|
||||||
|
get => _timeline;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_timeline = value;
|
||||||
|
LayerProperty.SortKeyframes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override TimeSpan Position
|
public override TimeSpan Position
|
||||||
{
|
{
|
||||||
|
|||||||
@ -4,6 +4,7 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Artemis.Core.Annotations;
|
using Artemis.Core.Annotations;
|
||||||
using Artemis.Core.Models.Profile.Conditions;
|
using Artemis.Core.Models.Profile.Conditions;
|
||||||
|
using Artemis.Core.Models.Profile.LayerProperties;
|
||||||
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
using Artemis.Storage.Entities.Profile.Abstract;
|
using Artemis.Storage.Entities.Profile.Abstract;
|
||||||
@ -18,6 +19,11 @@ namespace Artemis.Core.Models.Profile
|
|||||||
private SKPath _path;
|
private SKPath _path;
|
||||||
internal abstract RenderElementEntity RenderElementEntity { get; }
|
internal abstract RenderElementEntity RenderElementEntity { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the currently active timeline
|
||||||
|
/// </summary>
|
||||||
|
public Timeline CurrentTimeline { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the path containing all the LEDs this entity is applied to, any rendering outside the entity Path is
|
/// Gets the path containing all the LEDs this entity is applied to, any rendering outside the entity Path is
|
||||||
/// clipped.
|
/// clipped.
|
||||||
@ -142,6 +148,11 @@ namespace Artemis.Core.Models.Profile
|
|||||||
set => SetAndNotify(ref _displayConditionGroup, value);
|
set => SetAndNotify(ref _displayConditionGroup, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateDisplayCondition()
|
||||||
|
{
|
||||||
|
var rootGroupResult = DisplayConditionGroup.Evaluate();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Events
|
#region Events
|
||||||
|
|||||||
@ -19,10 +19,10 @@ namespace Artemis.Core.Services.Storage
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ProfileService : IProfileService
|
public class ProfileService : IProfileService
|
||||||
{
|
{
|
||||||
private readonly IRenderElementService _renderElementService;
|
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IPluginService _pluginService;
|
private readonly IPluginService _pluginService;
|
||||||
private readonly IProfileRepository _profileRepository;
|
private readonly IProfileRepository _profileRepository;
|
||||||
|
private readonly IRenderElementService _renderElementService;
|
||||||
private readonly ISurfaceService _surfaceService;
|
private readonly ISurfaceService _surfaceService;
|
||||||
|
|
||||||
internal ProfileService(ILogger logger, IPluginService pluginService, ISurfaceService surfaceService, IRenderElementService renderElementService, IProfileRepository profileRepository)
|
internal ProfileService(ILogger logger, IPluginService pluginService, ISurfaceService surfaceService, IRenderElementService renderElementService, IProfileRepository profileRepository)
|
||||||
@ -39,6 +39,8 @@ namespace Artemis.Core.Services.Storage
|
|||||||
_pluginService.PluginDisabled += OnPluginToggled;
|
_pluginService.PluginDisabled += OnPluginToggled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JsonSerializerSettings MementoSettings { get; set; } = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All};
|
||||||
|
|
||||||
public void ActivateDefaultProfiles()
|
public void ActivateDefaultProfiles()
|
||||||
{
|
{
|
||||||
foreach (var profileModule in _pluginService.GetPluginsOfType<ProfileModule>())
|
foreach (var profileModule in _pluginService.GetPluginsOfType<ProfileModule>())
|
||||||
@ -109,7 +111,7 @@ namespace Artemis.Core.Services.Storage
|
|||||||
public void UpdateProfile(Profile profile, bool includeChildren)
|
public void UpdateProfile(Profile profile, bool includeChildren)
|
||||||
{
|
{
|
||||||
_logger.Debug("Updating profile " + profile);
|
_logger.Debug("Updating profile " + profile);
|
||||||
var memento = JsonConvert.SerializeObject(profile.ProfileEntity);
|
var memento = JsonConvert.SerializeObject(profile.ProfileEntity, MementoSettings);
|
||||||
profile.RedoStack.Clear();
|
profile.RedoStack.Clear();
|
||||||
profile.UndoStack.Push(memento);
|
profile.UndoStack.Push(memento);
|
||||||
|
|
||||||
@ -135,9 +137,9 @@ namespace Artemis.Core.Services.Storage
|
|||||||
|
|
||||||
ActivateProfile(module, null);
|
ActivateProfile(module, null);
|
||||||
var top = profile.UndoStack.Pop();
|
var top = profile.UndoStack.Pop();
|
||||||
var memento = JsonConvert.SerializeObject(profile.ProfileEntity);
|
var memento = JsonConvert.SerializeObject(profile.ProfileEntity, MementoSettings);
|
||||||
profile.RedoStack.Push(memento);
|
profile.RedoStack.Push(memento);
|
||||||
profile.ProfileEntity = JsonConvert.DeserializeObject<ProfileEntity>(top);
|
profile.ProfileEntity = JsonConvert.DeserializeObject<ProfileEntity>(top, MementoSettings);
|
||||||
profile.ApplyToProfile();
|
profile.ApplyToProfile();
|
||||||
ActivateProfile(module, profile);
|
ActivateProfile(module, profile);
|
||||||
|
|
||||||
@ -155,9 +157,9 @@ namespace Artemis.Core.Services.Storage
|
|||||||
|
|
||||||
ActivateProfile(module, null);
|
ActivateProfile(module, null);
|
||||||
var top = profile.RedoStack.Pop();
|
var top = profile.RedoStack.Pop();
|
||||||
var memento = JsonConvert.SerializeObject(profile.ProfileEntity);
|
var memento = JsonConvert.SerializeObject(profile.ProfileEntity, MementoSettings);
|
||||||
profile.UndoStack.Push(memento);
|
profile.UndoStack.Push(memento);
|
||||||
profile.ProfileEntity = JsonConvert.DeserializeObject<ProfileEntity>(top);
|
profile.ProfileEntity = JsonConvert.DeserializeObject<ProfileEntity>(top, MementoSettings);
|
||||||
profile.ApplyToProfile();
|
profile.ApplyToProfile();
|
||||||
ActivateProfile(module, profile);
|
ActivateProfile(module, profile);
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,7 @@ namespace Artemis.Storage.Entities.Profile
|
|||||||
public class KeyframeEntity
|
public class KeyframeEntity
|
||||||
{
|
{
|
||||||
public TimeSpan Position { get; set; }
|
public TimeSpan Position { get; set; }
|
||||||
|
public int Timeline { get; set; }
|
||||||
public string Value { get; set; }
|
public string Value { get; set; }
|
||||||
public int EasingFunction { get; set; }
|
public int EasingFunction { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Artemis.Core.Models.Profile;
|
using Artemis.Core.Models.Profile;
|
||||||
|
using Artemis.Core.Models.Profile.LayerProperties;
|
||||||
using Artemis.Core.Plugins.Abstract;
|
using Artemis.Core.Plugins.Abstract;
|
||||||
using Artemis.Core.Plugins.Models;
|
using Artemis.Core.Plugins.Models;
|
||||||
using Artemis.UI.Shared.Events;
|
using Artemis.UI.Shared.Events;
|
||||||
@ -14,6 +15,7 @@ namespace Artemis.UI.Shared.Services.Interfaces
|
|||||||
Profile SelectedProfile { get; }
|
Profile SelectedProfile { get; }
|
||||||
RenderProfileElement SelectedProfileElement { get; }
|
RenderProfileElement SelectedProfileElement { get; }
|
||||||
TimeSpan CurrentTime { get; set; }
|
TimeSpan CurrentTime { get; set; }
|
||||||
|
Timeline CurrentTimeline { get; set; }
|
||||||
int PixelsPerSecond { get; set; }
|
int PixelsPerSecond { get; set; }
|
||||||
IReadOnlyList<PropertyInputRegistration> RegisteredPropertyEditors { get; }
|
IReadOnlyList<PropertyInputRegistration> RegisteredPropertyEditors { get; }
|
||||||
IKernel Kernel { get; }
|
IKernel Kernel { get; }
|
||||||
@ -54,6 +56,11 @@ namespace Artemis.UI.Shared.Services.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
event EventHandler CurrentTimeChanged;
|
event EventHandler CurrentTimeChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when the current editor timeline is changed
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler CurrentTimelineChanged;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when the pixels per second (zoom level) is changed
|
/// Occurs when the pixels per second (zoom level) is changed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Artemis.Core.Models.Profile;
|
using Artemis.Core.Models.Profile;
|
||||||
|
using Artemis.Core.Models.Profile.LayerProperties;
|
||||||
using Artemis.Core.Plugins.Abstract;
|
using Artemis.Core.Plugins.Abstract;
|
||||||
using Artemis.Core.Plugins.Exceptions;
|
using Artemis.Core.Plugins.Exceptions;
|
||||||
using Artemis.Core.Plugins.Models;
|
using Artemis.Core.Plugins.Models;
|
||||||
@ -24,6 +25,7 @@ namespace Artemis.UI.Shared.Services
|
|||||||
private TimeSpan _currentTime;
|
private TimeSpan _currentTime;
|
||||||
private TimeSpan _lastUpdateTime;
|
private TimeSpan _lastUpdateTime;
|
||||||
private int _pixelsPerSecond;
|
private int _pixelsPerSecond;
|
||||||
|
private Timeline _currentTimeline;
|
||||||
|
|
||||||
public ProfileEditorService(ICoreService coreService, IProfileService profileService, IKernel kernel, ILogger logger)
|
public ProfileEditorService(ICoreService coreService, IProfileService profileService, IKernel kernel, ILogger logger)
|
||||||
{
|
{
|
||||||
@ -46,14 +48,25 @@ namespace Artemis.UI.Shared.Services
|
|||||||
get => _currentTime;
|
get => _currentTime;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_currentTime.Equals(value))
|
if (_currentTime.Equals(value)) return;
|
||||||
return;
|
|
||||||
_currentTime = value;
|
_currentTime = value;
|
||||||
UpdateProfilePreview();
|
UpdateProfilePreview();
|
||||||
OnCurrentTimeChanged();
|
OnCurrentTimeChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Timeline CurrentTimeline
|
||||||
|
{
|
||||||
|
get => _currentTimeline;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_currentTimeline.Equals(value)) return;
|
||||||
|
_currentTimeline = value;
|
||||||
|
UpdateProfilePreview();
|
||||||
|
OnCurrentTimelineChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int PixelsPerSecond
|
public int PixelsPerSecond
|
||||||
{
|
{
|
||||||
get => _pixelsPerSecond;
|
get => _pixelsPerSecond;
|
||||||
@ -113,12 +126,14 @@ namespace Artemis.UI.Shared.Services
|
|||||||
var delta = CurrentTime - _lastUpdateTime;
|
var delta = CurrentTime - _lastUpdateTime;
|
||||||
foreach (var folder in SelectedProfile.GetAllFolders())
|
foreach (var folder in SelectedProfile.GetAllFolders())
|
||||||
{
|
{
|
||||||
|
folder.CurrentTimeline = CurrentTimeline;
|
||||||
foreach (var baseLayerEffect in folder.LayerEffects)
|
foreach (var baseLayerEffect in folder.LayerEffects)
|
||||||
baseLayerEffect.Update(delta.TotalSeconds);
|
baseLayerEffect.Update(delta.TotalSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var layer in SelectedProfile.GetAllLayers())
|
foreach (var layer in SelectedProfile.GetAllLayers())
|
||||||
{
|
{
|
||||||
|
layer.CurrentTimeline = CurrentTimeline;
|
||||||
layer.OverrideProgress(CurrentTime);
|
layer.OverrideProgress(CurrentTime);
|
||||||
layer.LayerBrush?.Update(delta.TotalSeconds);
|
layer.LayerBrush?.Update(delta.TotalSeconds);
|
||||||
foreach (var baseLayerEffect in layer.LayerEffects)
|
foreach (var baseLayerEffect in layer.LayerEffects)
|
||||||
@ -212,6 +227,7 @@ namespace Artemis.UI.Shared.Services
|
|||||||
public event EventHandler<RenderProfileElementEventArgs> ProfileElementSelected;
|
public event EventHandler<RenderProfileElementEventArgs> ProfileElementSelected;
|
||||||
public event EventHandler<RenderProfileElementEventArgs> SelectedProfileElementUpdated;
|
public event EventHandler<RenderProfileElementEventArgs> SelectedProfileElementUpdated;
|
||||||
public event EventHandler CurrentTimeChanged;
|
public event EventHandler CurrentTimeChanged;
|
||||||
|
public event EventHandler CurrentTimelineChanged;
|
||||||
public event EventHandler PixelsPerSecondChanged;
|
public event EventHandler PixelsPerSecondChanged;
|
||||||
public event EventHandler ProfilePreviewUpdated;
|
public event EventHandler ProfilePreviewUpdated;
|
||||||
|
|
||||||
@ -250,6 +266,11 @@ namespace Artemis.UI.Shared.Services
|
|||||||
CurrentTimeChanged?.Invoke(this, EventArgs.Empty);
|
CurrentTimeChanged?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void OnCurrentTimelineChanged()
|
||||||
|
{
|
||||||
|
CurrentTimelineChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void OnPixelsPerSecondChanged()
|
protected virtual void OnPixelsPerSecondChanged()
|
||||||
{
|
{
|
||||||
PixelsPerSecondChanged?.Invoke(this, EventArgs.Empty);
|
PixelsPerSecondChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
|||||||
@ -148,13 +148,11 @@
|
|||||||
HorizontalAlignment="Left">
|
HorizontalAlignment="Left">
|
||||||
<Grid>
|
<Grid>
|
||||||
<StackPanel Visibility="{Binding RightStaticValue, Converter={StaticResource NullToVisibilityConverter}}" Orientation="Horizontal">
|
<StackPanel Visibility="{Binding RightStaticValue, Converter={StaticResource NullToVisibilityConverter}}" Orientation="Horizontal">
|
||||||
<TextBlock Margin="0 0 3 0"
|
<TextBlock FontWeight="Light"
|
||||||
FontWeight="Light"
|
|
||||||
Text="{Binding SelectedLeftSideProperty.PropertyDescription.Prefix}"
|
Text="{Binding SelectedLeftSideProperty.PropertyDescription.Prefix}"
|
||||||
Visibility="{Binding SelectedLeftSideProperty.PropertyDescription.Prefix, Converter={StaticResource NullToVisibilityConverter}}"/>
|
Visibility="{Binding SelectedLeftSideProperty.PropertyDescription.Prefix, Converter={StaticResource NullToVisibilityConverter}}"/>
|
||||||
<TextBlock Text="{Binding RightStaticValue}"/>
|
<TextBlock Text="{Binding RightStaticValue}"/>
|
||||||
<TextBlock Margin="3 0 0 0"
|
<TextBlock FontWeight="Light"
|
||||||
FontWeight="Light"
|
|
||||||
Text="{Binding SelectedLeftSideProperty.PropertyDescription.Affix}"
|
Text="{Binding SelectedLeftSideProperty.PropertyDescription.Affix}"
|
||||||
Visibility="{Binding SelectedLeftSideProperty.PropertyDescription.Affix, Converter={StaticResource NullToVisibilityConverter}}" />
|
Visibility="{Binding SelectedLeftSideProperty.PropertyDescription.Affix, Converter={StaticResource NullToVisibilityConverter}}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@ -9,27 +9,63 @@
|
|||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
<Grid>
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="40" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}" Margin="10 5 0 -4">
|
<TextBlock Grid.ColumnSpan="2" Style="{StaticResource MaterialDesignSubtitle1TextBlock}" Margin="10 5 0 -4">
|
||||||
Display conditions
|
Display conditions
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<Separator Grid.Row="1" Style="{StaticResource MaterialDesignDarkSeparator}" Margin="8 0" />
|
<Separator Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Style="{StaticResource MaterialDesignDarkSeparator}" Margin="8 0" />
|
||||||
|
|
||||||
<Grid Grid.Row="2">
|
<Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2">
|
||||||
<ScrollViewer Margin="8" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
<ScrollViewer Margin="8 0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||||
<ContentControl s:View.Model="{Binding RootGroup}" />
|
<ContentControl s:View.Model="{Binding RootGroup}" />
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<StackPanel Grid.Row="3" VerticalAlignment="Center" HorizontalAlignment="Right" Orientation="Horizontal">
|
<StackPanel Grid.Row="3" Grid.Column="0" Margin="10" Orientation="Horizontal" VerticalAlignment="Bottom" ToolTip="When conditions are met, only go through the entire timeline once.">
|
||||||
<TextBlock Margin="10 0" VerticalAlignment="Center">Disabled</TextBlock>
|
<ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="True" />
|
||||||
<ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}" ToolTip="Default ToggleButton Style" />
|
<TextBlock Margin="5 0 0 0">Play once</TextBlock>
|
||||||
<TextBlock Margin="10 0 15 0" VerticalAlignment="Center">Enabled</TextBlock>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="3" Grid.Column="1" Margin="10" HorizontalAlignment="Right">
|
||||||
|
<TextBlock>When conditions no longer met</TextBlock>
|
||||||
|
<ListBox Style="{StaticResource MaterialDesignToolToggleListBox}" SelectedIndex="{Binding CurrentTimelineIndex}" Height="20" Margin="0 5 0 0">
|
||||||
|
<ListBoxItem Padding="10 0">
|
||||||
|
<ListBoxItem.ToolTip>
|
||||||
|
<ToolTip Placement="Top" VerticalOffset="-5">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock>When conditions are no longer met, finish the timelines and then stop displaying.</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</ToolTip>
|
||||||
|
</ListBoxItem.ToolTip>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="PlayArrow" Width="20" Height="20" Margin="0 -4" />
|
||||||
|
<TextBlock Margin="5 0 0 0" FontSize="11">WAIT FOR FINISH</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</ListBoxItem>
|
||||||
|
<ListBoxItem Padding="10 0">
|
||||||
|
<ListBoxItem.ToolTip>
|
||||||
|
<ToolTip Placement="Top" VerticalOffset="-5">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock>When conditions are no longer met, stop displaying immediately.</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</ToolTip>
|
||||||
|
</ListBoxItem.ToolTip>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="SkipNext" Width="20" Height="20" Margin="0 -4" />
|
||||||
|
<TextBlock Margin="5 0 0 0" FontSize="11">SKIP</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</ListBoxItem>
|
||||||
|
</ListBox>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -291,7 +291,7 @@
|
|||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<ListBox Style="{StaticResource MaterialDesignToolToggleListBox}" SelectedIndex="0" Height="20" Margin="5 0 0 0">
|
<ListBox Style="{StaticResource MaterialDesignToolToggleListBox}" SelectedIndex="{Binding CurrentTimelineIndex}" Height="20" Margin="5 0 0 0">
|
||||||
<ListBoxItem Padding="10 0">
|
<ListBoxItem Padding="10 0">
|
||||||
<ListBoxItem.ToolTip>
|
<ListBoxItem.ToolTip>
|
||||||
<ToolTip Placement="Top" VerticalOffset="-5">
|
<ToolTip Placement="Top" VerticalOffset="-5">
|
||||||
|
|||||||
@ -84,6 +84,16 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int CurrentTimelineIndex
|
||||||
|
{
|
||||||
|
get => (int) ProfileEditorService.CurrentTimeline;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ProfileEditorService.CurrentTimeline = (Core.Models.Profile.LayerProperties.Timeline) value;
|
||||||
|
ProfileEditorService.CurrentTime = TimeSpan.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool PropertyTreeVisible => PropertyTreeIndex == 0;
|
public bool PropertyTreeVisible => PropertyTreeIndex == 0;
|
||||||
|
|
||||||
public RenderProfileElement SelectedProfileElement
|
public RenderProfileElement SelectedProfileElement
|
||||||
@ -130,6 +140,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
|
|
||||||
ProfileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
|
ProfileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
|
||||||
ProfileEditorService.CurrentTimeChanged += ProfileEditorServiceOnCurrentTimeChanged;
|
ProfileEditorService.CurrentTimeChanged += ProfileEditorServiceOnCurrentTimeChanged;
|
||||||
|
ProfileEditorService.CurrentTimelineChanged += ProfileEditorServiceOnCurrentTimelineChanged;
|
||||||
ProfileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
|
ProfileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||||
|
|
||||||
base.OnInitialActivate();
|
base.OnInitialActivate();
|
||||||
@ -139,6 +150,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
{
|
{
|
||||||
ProfileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
|
ProfileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
|
||||||
ProfileEditorService.CurrentTimeChanged -= ProfileEditorServiceOnCurrentTimeChanged;
|
ProfileEditorService.CurrentTimeChanged -= ProfileEditorServiceOnCurrentTimeChanged;
|
||||||
|
ProfileEditorService.CurrentTimelineChanged -= ProfileEditorServiceOnCurrentTimelineChanged;
|
||||||
ProfileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
|
ProfileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||||
|
|
||||||
PopulateProperties(null);
|
PopulateProperties(null);
|
||||||
@ -168,6 +180,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
NotifyOfPropertyChange(nameof(TimeCaretPosition));
|
NotifyOfPropertyChange(nameof(TimeCaretPosition));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ProfileEditorServiceOnCurrentTimelineChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
NotifyOfPropertyChange(nameof(CurrentTimelineIndex));
|
||||||
|
TimelineViewModel.UpdateKeyframes();
|
||||||
|
}
|
||||||
|
|
||||||
private void ProfileEditorServiceOnPixelsPerSecondChanged(object sender, EventArgs e)
|
private void ProfileEditorServiceOnPixelsPerSecondChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
NotifyOfPropertyChange(nameof(TimeCaretPosition));
|
NotifyOfPropertyChange(nameof(TimeCaretPosition));
|
||||||
|
|||||||
@ -27,6 +27,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
|
|||||||
var newKeyframe = new LayerPropertyKeyframe<T>(
|
var newKeyframe = new LayerPropertyKeyframe<T>(
|
||||||
LayerPropertyKeyframe.Value,
|
LayerPropertyKeyframe.Value,
|
||||||
LayerPropertyKeyframe.Position,
|
LayerPropertyKeyframe.Position,
|
||||||
|
LayerPropertyKeyframe.Timeline,
|
||||||
LayerPropertyKeyframe.EasingFunction,
|
LayerPropertyKeyframe.EasingFunction,
|
||||||
LayerPropertyKeyframe.LayerProperty
|
LayerPropertyKeyframe.LayerProperty
|
||||||
);
|
);
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
Visibility="{Binding LayerPropertyGroupViewModel.IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}"
|
Visibility="{Binding LayerPropertyGroupViewModel.IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}"
|
||||||
ItemsSource="{Binding TimelineKeyframeViewModels}"
|
ItemsSource="{Binding TimelineKeyframeViewModels}"
|
||||||
Background="{DynamicResource MaterialDesignToolBarBackground}"
|
Background="{DynamicResource MaterialDesignToolBarBackground}"
|
||||||
HorizontalAlignment="Left">
|
HorizontalAlignment="Stretch">
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsControl.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<Canvas />
|
<Canvas />
|
||||||
@ -49,20 +49,22 @@
|
|||||||
<Rectangle Grid.Row="1" HorizontalAlignment="Stretch" Fill="{DynamicResource MaterialDesignDivider}" Height="1" />
|
<Rectangle Grid.Row="1" HorizontalAlignment="Stretch" Fill="{DynamicResource MaterialDesignDivider}" Height="1" />
|
||||||
|
|
||||||
<ItemsControl Grid.Row="2"
|
<ItemsControl Grid.Row="2"
|
||||||
|
ItemsSource="{Binding LayerPropertyGroupViewModel.Children}"
|
||||||
Visibility="{Binding LayerPropertyGroupViewModel.IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
Visibility="{Binding LayerPropertyGroupViewModel.IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
||||||
ItemsSource="{Binding LayerPropertyGroupViewModel.Children}">
|
HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Stretch">
|
||||||
|
<ItemsControl.ItemContainerStyle>
|
||||||
|
<Style TargetType="ContentPresenter">
|
||||||
|
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||||
|
</Style >
|
||||||
|
</ItemsControl.ItemContainerStyle>
|
||||||
<ItemsControl.Resources>
|
<ItemsControl.Resources>
|
||||||
<DataTemplate DataType="{x:Type layerProperties:LayerPropertyGroupViewModel}">
|
<DataTemplate DataType="{x:Type layerProperties:LayerPropertyGroupViewModel}">
|
||||||
<ContentControl s:View.Model="{Binding TimelinePropertyGroupViewModel}"
|
<ContentControl s:View.Model="{Binding TimelinePropertyGroupViewModel}" IsTabStop="False" HorizontalAlignment="Stretch"/>
|
||||||
VerticalContentAlignment="Stretch"
|
|
||||||
HorizontalContentAlignment="Stretch"
|
|
||||||
IsTabStop="False" />
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
<DataTemplate DataType="{x:Type layerProperties:LayerPropertyViewModel}">
|
<DataTemplate DataType="{x:Type layerProperties:LayerPropertyViewModel}">
|
||||||
<ContentControl s:View.Model="{Binding TimelinePropertyBaseViewModel}"
|
<ContentControl s:View.Model="{Binding TimelinePropertyBaseViewModel}" IsTabStop="False" HorizontalAlignment="Stretch" />
|
||||||
VerticalContentAlignment="Stretch"
|
|
||||||
HorizontalContentAlignment="Stretch"
|
|
||||||
IsTabStop="False" />
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.Resources>
|
</ItemsControl.Resources>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|||||||
@ -2,16 +2,19 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
|
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
|
||||||
|
using Artemis.UI.Shared.Services.Interfaces;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
|
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
|
||||||
{
|
{
|
||||||
public class TimelinePropertyGroupViewModel : PropertyChangedBase
|
public class TimelinePropertyGroupViewModel : PropertyChangedBase
|
||||||
{
|
{
|
||||||
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private BindableCollection<double> _timelineKeyframeViewModels;
|
private BindableCollection<double> _timelineKeyframeViewModels;
|
||||||
|
|
||||||
public TimelinePropertyGroupViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel)
|
public TimelinePropertyGroupViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel, IProfileEditorService profileEditorService)
|
||||||
{
|
{
|
||||||
|
_profileEditorService = profileEditorService;
|
||||||
LayerPropertyGroupViewModel = (LayerPropertyGroupViewModel) layerPropertyBaseViewModel;
|
LayerPropertyGroupViewModel = (LayerPropertyGroupViewModel) layerPropertyBaseViewModel;
|
||||||
TimelineKeyframeViewModels = new BindableCollection<double>();
|
TimelineKeyframeViewModels = new BindableCollection<double>();
|
||||||
|
|
||||||
@ -32,6 +35,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
|
|||||||
{
|
{
|
||||||
TimelineKeyframeViewModels.Clear();
|
TimelineKeyframeViewModels.Clear();
|
||||||
TimelineKeyframeViewModels.AddRange(LayerPropertyGroupViewModel.GetKeyframes(false)
|
TimelineKeyframeViewModels.AddRange(LayerPropertyGroupViewModel.GetKeyframes(false)
|
||||||
|
.Where(k => k.Timeline == _profileEditorService.CurrentTimeline)
|
||||||
.Select(k => LayerPropertyGroupViewModel.ProfileEditorService.PixelsPerSecond * k.Position.TotalSeconds));
|
.Select(k => LayerPropertyGroupViewModel.ProfileEditorService.PixelsPerSecond * k.Position.TotalSeconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,9 @@
|
|||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance local:TimelinePropertyViewModel}"
|
d:DataContext="{d:DesignInstance local:TimelinePropertyViewModel}"
|
||||||
Visibility="{Binding LayerPropertyBaseViewModel.IsVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
Visibility="{Binding LayerPropertyBaseViewModel.IsVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
||||||
|
MinWidth="{Binding Width}"
|
||||||
|
HorizontalAlignment="Stretch">
|
||||||
<Border Height="25" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource MaterialDesignDivider}">
|
<Border Height="25" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource MaterialDesignDivider}">
|
||||||
<ItemsControl ItemsSource="{Binding TimelineKeyframeViewModels}"
|
<ItemsControl ItemsSource="{Binding TimelineKeyframeViewModels}"
|
||||||
Background="{DynamicResource MaterialDesignToolBarBackground}"
|
Background="{DynamicResource MaterialDesignToolBarBackground}"
|
||||||
|
|||||||
@ -28,7 +28,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
|
|||||||
// Only show keyframes if they are enabled
|
// Only show keyframes if they are enabled
|
||||||
if (LayerPropertyViewModel.LayerProperty.KeyframesEnabled)
|
if (LayerPropertyViewModel.LayerProperty.KeyframesEnabled)
|
||||||
{
|
{
|
||||||
var keyframes = LayerPropertyViewModel.LayerProperty.Keyframes.ToList();
|
var keyframes = LayerPropertyViewModel.LayerProperty.Keyframes
|
||||||
|
.Where(k => k.Timeline == _profileEditorService.CurrentTimeline)
|
||||||
|
.ToList();
|
||||||
var toRemove = TimelineKeyframeViewModels.Where(t => !keyframes.Contains(t.BaseLayerPropertyKeyframe)).ToList();
|
var toRemove = TimelineKeyframeViewModels.Where(t => !keyframes.Contains(t.BaseLayerPropertyKeyframe)).ToList();
|
||||||
TimelineKeyframeViewModels.RemoveRange(toRemove);
|
TimelineKeyframeViewModels.RemoveRange(toRemove);
|
||||||
TimelineKeyframeViewModels.AddRange(
|
TimelineKeyframeViewModels.AddRange(
|
||||||
@ -60,12 +62,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
|
|||||||
{
|
{
|
||||||
foreach (var timelineKeyframeViewModel in TimelineKeyframeViewModels)
|
foreach (var timelineKeyframeViewModel in TimelineKeyframeViewModels)
|
||||||
timelineKeyframeViewModel.Update(_profileEditorService.PixelsPerSecond);
|
timelineKeyframeViewModel.Update(_profileEditorService.PixelsPerSecond);
|
||||||
|
|
||||||
|
Width = TimelineKeyframeViewModels.Any() ? TimelineKeyframeViewModels.Max(t => t.X) + 25 : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class TimelinePropertyViewModel : PropertyChangedBase, IDisposable
|
public abstract class TimelinePropertyViewModel : PropertyChangedBase, IDisposable
|
||||||
{
|
{
|
||||||
private BindableCollection<TimelineKeyframeViewModel> _timelineKeyframeViewModels;
|
private BindableCollection<TimelineKeyframeViewModel> _timelineKeyframeViewModels;
|
||||||
|
private double _width;
|
||||||
|
|
||||||
protected TimelinePropertyViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel)
|
protected TimelinePropertyViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel)
|
||||||
{
|
{
|
||||||
@ -81,6 +86,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
|
|||||||
set => SetAndNotify(ref _timelineKeyframeViewModels, value);
|
set => SetAndNotify(ref _timelineKeyframeViewModels, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double Width
|
||||||
|
{
|
||||||
|
get => _width;
|
||||||
|
set => SetAndNotify(ref _width, value);
|
||||||
|
}
|
||||||
|
|
||||||
public abstract void Dispose();
|
public abstract void Dispose();
|
||||||
|
|
||||||
public abstract void UpdateKeyframes();
|
public abstract void UpdateKeyframes();
|
||||||
|
|||||||
@ -12,7 +12,8 @@
|
|||||||
<Grid Background="{DynamicResource MaterialDesignToolBarBackground}"
|
<Grid Background="{DynamicResource MaterialDesignToolBarBackground}"
|
||||||
MouseDown="{s:Action TimelineCanvasMouseDown}"
|
MouseDown="{s:Action TimelineCanvasMouseDown}"
|
||||||
MouseUp="{s:Action TimelineCanvasMouseUp}"
|
MouseUp="{s:Action TimelineCanvasMouseUp}"
|
||||||
MouseMove="{s:Action TimelineCanvasMouseMove}">
|
MouseMove="{s:Action TimelineCanvasMouseMove}"
|
||||||
|
HorizontalAlignment="Stretch">
|
||||||
<Grid.Triggers>
|
<Grid.Triggers>
|
||||||
<EventTrigger RoutedEvent="UIElement.MouseLeftButtonDown">
|
<EventTrigger RoutedEvent="UIElement.MouseLeftButtonDown">
|
||||||
<BeginStoryboard>
|
<BeginStoryboard>
|
||||||
@ -31,12 +32,11 @@
|
|||||||
</Grid.Triggers>
|
</Grid.Triggers>
|
||||||
|
|
||||||
<ItemsControl ItemsSource="{Binding LayerPropertyGroups}"
|
<ItemsControl ItemsSource="{Binding LayerPropertyGroups}"
|
||||||
Width="{Binding Width}"
|
|
||||||
MinWidth="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ScrollViewer}}"
|
MinWidth="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ScrollViewer}}"
|
||||||
HorizontalAlignment="Left">
|
HorizontalAlignment="Left">
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<ContentControl s:View.Model="{Binding TimelinePropertyGroupViewModel}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" />
|
<ContentControl s:View.Model="{Binding TimelinePropertyGroupViewModel}" HorizontalContentAlignment="Left" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|||||||
@ -18,7 +18,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
|
|||||||
private readonly LayerPropertiesViewModel _layerPropertiesViewModel;
|
private readonly LayerPropertiesViewModel _layerPropertiesViewModel;
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private RectangleGeometry _selectionRectangle;
|
private RectangleGeometry _selectionRectangle;
|
||||||
private double _width;
|
|
||||||
|
|
||||||
public TimelineViewModel(LayerPropertiesViewModel layerPropertiesViewModel, BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups,
|
public TimelineViewModel(LayerPropertiesViewModel layerPropertiesViewModel, BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups,
|
||||||
IProfileEditorService profileEditorService)
|
IProfileEditorService profileEditorService)
|
||||||
@ -33,12 +32,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
|
|||||||
|
|
||||||
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; }
|
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; }
|
||||||
|
|
||||||
public double Width
|
|
||||||
{
|
|
||||||
get => _width;
|
|
||||||
set => SetAndNotify(ref _width, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RectangleGeometry SelectionRectangle
|
public RectangleGeometry SelectionRectangle
|
||||||
{
|
{
|
||||||
get => _selectionRectangle;
|
get => _selectionRectangle;
|
||||||
|
|||||||
@ -50,6 +50,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree
|
|||||||
LayerPropertyViewModel.LayerProperty.AddKeyframe(new LayerPropertyKeyframe<T>(
|
LayerPropertyViewModel.LayerProperty.AddKeyframe(new LayerPropertyKeyframe<T>(
|
||||||
LayerPropertyViewModel.LayerProperty.CurrentValue,
|
LayerPropertyViewModel.LayerProperty.CurrentValue,
|
||||||
_profileEditorService.CurrentTime,
|
_profileEditorService.CurrentTime,
|
||||||
|
_profileEditorService.CurrentTimeline,
|
||||||
Easings.Functions.Linear,
|
Easings.Functions.Linear,
|
||||||
LayerPropertyViewModel.LayerProperty
|
LayerPropertyViewModel.LayerProperty
|
||||||
));
|
));
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user