diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index 19a20ab39..45b6bc8b3 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -122,6 +122,7 @@ namespace Artemis.Core.Models.Profile LayerEntity.Order = Order; LayerEntity.Name = Name; LayerEntity.ProfileId = Profile.EntityId; + General.ApplyToEntity(); Transform.ApplyToEntity(); LayerBrush.ApplyToEntity(); @@ -184,27 +185,36 @@ namespace Artemis.Core.Models.Profile if (LayerBrush == null) return; - General.Update(deltaTime); - Transform.Update(deltaTime); - LayerBrush.UpdateProperties(deltaTime); - var properties = new List(General.GetAllLayerProperties()); properties.AddRange(Transform.GetAllLayerProperties()); properties.AddRange(LayerBrush.GetAllLayerProperties()); // 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 - var timeLineEnd = properties.Max(p => p.GetLastKeyframePosition()); + var timeLineEnd = properties.Max(p => p.BaseKeyframes.Max(k => k.Position)); if (properties.Any(p => p.TimelineProgress >= timeLineEnd)) { General.Override(TimeSpan.Zero); Transform.Override(TimeSpan.Zero); LayerBrush.OverrideProperties(TimeSpan.Zero); } + else + { + General.Update(deltaTime); + Transform.Update(deltaTime); + LayerBrush.UpdateProperties(deltaTime); + } LayerBrush.Update(deltaTime); } + public void OverrideProgress(TimeSpan timeOverride) + { + General.Override(timeOverride); + Transform.Override(timeOverride); + LayerBrush.OverrideProperties(timeOverride); + } + /// public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo) { diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs index e27f82c6c..9863661da 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs @@ -9,12 +9,9 @@ namespace Artemis.Core.Models.Profile.LayerProperties /// public abstract class BaseLayerProperty { - /// - /// Used to declare that this property doesn't belong to a plugin and should use the core plugin GUID - /// - internal bool IsCoreProperty { get; set; } - internal PropertyEntity PropertyEntity { get; set; } - internal LayerPropertyGroup LayerPropertyGroup { get; set; } + internal BaseLayerProperty() + { + } /// /// Gets whether keyframes are supported on this property @@ -42,6 +39,15 @@ namespace Artemis.Core.Models.Profile.LayerProperties /// public TimeSpan TimelineProgress { get; internal set; } + /// + /// Used to declare that this property doesn't belong to a plugin and should use the core plugin GUID + /// + internal bool IsCoreProperty { get; set; } + + internal PropertyEntity PropertyEntity { get; set; } + internal LayerPropertyGroup LayerPropertyGroup { get; set; } + internal abstract IReadOnlyList BaseKeyframes { get; } + /// /// Applies the provided property entity to the layer property by deserializing the JSON base value and keyframe values /// @@ -54,8 +60,5 @@ namespace Artemis.Core.Models.Profile.LayerProperties /// /// internal abstract void ApplyToEntity(); - - internal abstract List GetKeyframePositions(); - internal abstract TimeSpan GetLastKeyframePosition(); } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerPropertyKeyframe.cs b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerPropertyKeyframe.cs new file mode 100644 index 000000000..b4adf932f --- /dev/null +++ b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerPropertyKeyframe.cs @@ -0,0 +1,27 @@ +using System; +using Artemis.Core.Utilities; + +namespace Artemis.Core.Models.Profile.LayerProperties +{ + /// + /// For internal use only, use instead. + /// + public abstract class BaseLayerPropertyKeyframe + { + internal BaseLayerPropertyKeyframe() + { + } + + /// + /// The position of this keyframe in the timeline + /// + public abstract TimeSpan Position { get; set; } + + /// + /// The easing function applied on the value of the keyframe + /// + public abstract Easings.Functions EasingFunction { get; set; } + + internal abstract BaseLayerProperty BaseLayerProperty { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs index 1ce9a5ec3..a9b0a397a 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs @@ -12,7 +12,8 @@ namespace Artemis.Core.Models.Profile.LayerProperties /// /// Represents a property on a layer. Properties are saved in storage and can optionally be modified from the UI. /// - /// Note: You cannot initialize layer properties yourself. If properly placed and annotated, the Artemis core will initialize + /// Note: You cannot initialize layer properties yourself. If properly placed and annotated, the Artemis core will + /// initialize /// these for you. /// /// @@ -53,12 +54,12 @@ namespace Artemis.Core.Models.Profile.LayerProperties get => !KeyframesEnabled || !KeyframesSupported ? BaseValue : _currentValue; internal set => _currentValue = value; } - + /// /// Gets a read-only list of all the keyframes on this layer property /// public IReadOnlyList> Keyframes => _keyframes.AsReadOnly(); - + /// /// Gets the current keyframe in the timeline according to the current progress /// @@ -68,7 +69,9 @@ namespace Artemis.Core.Models.Profile.LayerProperties /// Gets the next keyframe in the timeline according to the current progress /// public LayerPropertyKeyframe NextKeyframe { get; protected set; } - + + internal override IReadOnlyList BaseKeyframes => _keyframes.Cast().ToList().AsReadOnly(); + /// /// Adds a keyframe to the layer property /// @@ -93,6 +96,16 @@ namespace Artemis.Core.Models.Profile.LayerProperties OnKeyframeRemoved(); } + /// + /// Removes all keyframes from the layer property + /// + public void ClearKeyframes() + { + var keyframes = new List>(_keyframes); + foreach (var layerPropertyKeyframe in keyframes) + RemoveKeyframe(layerPropertyKeyframe); + } + /// /// Called every update (if keyframes are both supported and enabled) to determine the new /// based on the provided progress @@ -167,6 +180,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties IsLoadedFromStorage = true; BaseValue = JsonConvert.DeserializeObject(entity.Value); CurrentValue = BaseValue; + KeyframesEnabled = entity.KeyframesEnabled; _keyframes.Clear(); _keyframes.AddRange(entity.KeyframeEntities.Select(k => new LayerPropertyKeyframe( @@ -194,6 +208,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties throw new ArtemisCoreException("Layer property is not yet initialized"); PropertyEntity.Value = JsonConvert.SerializeObject(BaseValue); + PropertyEntity.KeyframesEnabled = KeyframesEnabled; PropertyEntity.KeyframeEntities.Clear(); PropertyEntity.KeyframeEntities.AddRange(Keyframes.Select(k => new KeyframeEntity { @@ -203,16 +218,6 @@ namespace Artemis.Core.Models.Profile.LayerProperties })); } - internal override List GetKeyframePositions() - { - return Keyframes.Select(k => k.Position).ToList(); - } - - internal override TimeSpan GetLastKeyframePosition() - { - return Keyframes.LastOrDefault()?.Position ?? TimeSpan.Zero; - } - #region Events public event EventHandler Updated; diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs index b89b9fbaa..7cb1ffcb0 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs @@ -3,7 +3,7 @@ using Artemis.Core.Utilities; namespace Artemis.Core.Models.Profile.LayerProperties { - public class LayerPropertyKeyframe + public class LayerPropertyKeyframe : BaseLayerPropertyKeyframe { private TimeSpan _position; @@ -14,10 +14,18 @@ namespace Artemis.Core.Models.Profile.LayerProperties EasingFunction = easingFunction; } + /// + /// The layer property this keyframe is applied to + /// public LayerProperty LayerProperty { get; internal set; } + + /// + /// The value of this keyframe + /// public T Value { get; set; } - public TimeSpan Position + /// + public override TimeSpan Position { get => _position; set @@ -27,6 +35,9 @@ namespace Artemis.Core.Models.Profile.LayerProperties } } - public Easings.Functions EasingFunction { get; set; } + /// + public sealed override Easings.Functions EasingFunction { get; set; } + + internal override BaseLayerProperty BaseLayerProperty => LayerProperty; } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/LayerBrush/BaseLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrush/BaseLayerBrush.cs index 8e36e0ab3..beecad9b4 100644 --- a/src/Artemis.Core/Plugins/LayerBrush/BaseLayerBrush.cs +++ b/src/Artemis.Core/Plugins/LayerBrush/BaseLayerBrush.cs @@ -29,6 +29,8 @@ namespace Artemis.Core.Plugins.LayerBrush /// public PluginInfo PluginInfo => Descriptor.LayerBrushProvider.PluginInfo; + internal virtual LayerPropertyGroup BaseProperties => null; + /// /// Called when the brush is being removed from the layer /// diff --git a/src/Artemis.Core/Plugins/LayerBrush/LayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrush/LayerBrush.cs index 517322571..b3807f239 100644 --- a/src/Artemis.Core/Plugins/LayerBrush/LayerBrush.cs +++ b/src/Artemis.Core/Plugins/LayerBrush/LayerBrush.cs @@ -46,6 +46,9 @@ namespace Artemis.Core.Plugins.LayerBrush { } + /// + internal override LayerPropertyGroup BaseProperties => Properties; + internal override void InitializeProperties(ILayerService layerService, string path) { Properties.InitializeProperties(layerService, Layer, path); diff --git a/src/Artemis.Core/Services/LayerService.cs b/src/Artemis.Core/Services/LayerService.cs index 4ef8c7981..a1cd47f46 100644 --- a/src/Artemis.Core/Services/LayerService.cs +++ b/src/Artemis.Core/Services/LayerService.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using Artemis.Core.Models.Profile; using Artemis.Core.Plugins.LayerBrush; using Artemis.Core.Services.Interfaces; @@ -75,5 +76,10 @@ namespace Artemis.Core.Services layer.LayerEntity.PropertyEntities.RemoveAll(p => p.PluginGuid == brush.PluginInfo.Guid); } + + public void GetLayerPropertyGroups(Layer layer) + { + var groups = new List {layer.General, layer.Transform, layer.LayerBrush.BrushProperties}; + } } } \ No newline at end of file diff --git a/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs b/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs index 4c339e22e..de95b56b8 100644 --- a/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs @@ -14,7 +14,7 @@ namespace Artemis.Storage.Entities.Profile public string Path { get; set; } public string Value { get; set; } - public bool IsUsingKeyframes { get; set; } + public bool KeyframesEnabled { get; set; } public List KeyframeEntities { get; set; } } diff --git a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs index 34986e68d..a783c2876 100644 --- a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs +++ b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs @@ -70,6 +70,6 @@ namespace Artemis.UI.Ninject.Factories public interface IPropertyTrackKeyframeVmFactory : IVmFactory { - PropertyTrackKeyframeViewModel Create(PropertyTrackViewModel propertyTrackViewModel, BaseKeyframe keyframe); + PropertyTrackKeyframeViewModel Create(PropertyTrackViewModel propertyTrackViewModel, LayerPropertyKeyframe keyframe); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs index 497e6f379..2c3572a5f 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Artemis.Core.Models.Profile.LayerProperties; +using Artemis.Core.Utilities; using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput; using Artemis.UI.Services.Interfaces; using Ninject; @@ -9,31 +10,30 @@ using Stylet; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties { - public class LayerPropertyViewModel : PropertyChangedBase + public class LayerPropertyViewModel : LayerPropertyViewModel { private readonly IKernel _kernel; private readonly IProfileEditorService _profileEditorService; private bool _keyframesEnabled; private bool _isExpanded; - public LayerPropertyViewModel(BaseLayerProperty layerProperty, LayerPropertyViewModel parent, IKernel kernel, IProfileEditorService profileEditorService) + public LayerPropertyViewModel(LayerProperty layerProperty, LayerPropertyViewModel parent, IKernel kernel, IProfileEditorService profileEditorService) { _kernel = kernel; _profileEditorService = profileEditorService; - _keyframesEnabled = layerProperty.IsUsingKeyframes; + _keyframesEnabled = layerProperty.KeyframesEnabled; LayerProperty = layerProperty; Parent = parent; Children = new List(); - IsExpanded = layerProperty.ExpandByDefault; + + // TODO: Get from attribute + IsExpanded = false; Parent?.Children.Add(this); } - public BaseLayerProperty LayerProperty { get; } - - public LayerPropertyViewModel Parent { get; } - public List Children { get; } + public LayerProperty LayerProperty { get; } public bool IsExpanded { @@ -58,7 +58,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties public PropertyInputViewModel GetPropertyInputViewModel() { // If the type is an enum type, search for Enum instead. - var type = LayerProperty.Type; + var type = typeof(T); if (type.IsEnum) type = typeof(Enum); @@ -72,15 +72,16 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties private void UpdateKeyframes() { + // Either create a new first keyframe or clear all the keyframes if (_keyframesEnabled) - LayerProperty.CreateNewKeyframe(_profileEditorService.CurrentTime, LayerProperty.GetCurrentValue()); + LayerProperty.AddKeyframe(new LayerPropertyKeyframe(LayerProperty.CurrentValue, _profileEditorService.CurrentTime, Easings.Functions.Linear)); else LayerProperty.ClearKeyframes(); // Force the keyframe engine to update, the new keyframe is the current keyframe - LayerProperty.IsUsingKeyframes = _keyframesEnabled; - LayerProperty.KeyframeEngine?.Update(0); + LayerProperty.KeyframesEnabled = _keyframesEnabled; + LayerProperty.Update(0); _profileEditorService.UpdateSelectedProfileElement(); } @@ -88,6 +89,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties #region Events public event EventHandler ExpandedStateChanged; + protected virtual void OnExpandedStateChanged() { ExpandedStateChanged?.Invoke(this, EventArgs.Empty); @@ -97,4 +99,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties #endregion } + + public class LayerPropertyViewModel : PropertyChangedBase + { + public LayerPropertyViewModel Parent { get; protected set; } + public List Children { get; protected set; } + } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackKeyframeViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackKeyframeViewModel.cs index 30876cdbe..a4f0d692c 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackKeyframeViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackKeyframeViewModel.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Input; @@ -10,12 +9,12 @@ using Stylet; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline { - public class PropertyTrackKeyframeViewModel : PropertyChangedBase + public class PropertyTrackKeyframeViewModel : PropertyTrackKeyframeViewModel { private readonly IProfileEditorService _profileEditorService; private int _pixelsPerSecond; - public PropertyTrackKeyframeViewModel(PropertyTrackViewModel propertyTrackViewModel, BaseKeyframe keyframe, IProfileEditorService profileEditorService) + public PropertyTrackKeyframeViewModel(PropertyTrackViewModel propertyTrackViewModel, LayerPropertyKeyframe keyframe, IProfileEditorService profileEditorService) { _profileEditorService = profileEditorService; @@ -27,7 +26,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline public bool IsSelected { get; set; } public PropertyTrackViewModel PropertyTrackViewModel { get; } - public BaseKeyframe Keyframe { get; } + public LayerPropertyKeyframe Keyframe { get; } public BindableCollection EasingViewModels { get; set; } public double X { get; set; } public string Timestamp { get; set; } @@ -170,4 +169,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline #endregion } + + public abstract class PropertyTrackKeyframeViewModel : PropertyChangedBase + { + } } \ No newline at end of file diff --git a/src/Artemis.UI/Services/ProfileEditorService.cs b/src/Artemis.UI/Services/ProfileEditorService.cs index f552f8ac2..19c497b38 100644 --- a/src/Artemis.UI/Services/ProfileEditorService.cs +++ b/src/Artemis.UI/Services/ProfileEditorService.cs @@ -74,18 +74,11 @@ namespace Artemis.UI.Services { if (SelectedProfile == null) return; + var delta = CurrentTime - _lastUpdateTime; foreach (var layer in SelectedProfile.GetAllLayers()) { - // Override keyframe progress - foreach (var baseLayerProperty in layer.Properties) - baseLayerProperty.KeyframeEngine?.OverrideProgress(CurrentTime); - - // Force layer shape to redraw - layer.LayerShape?.CalculateRenderProperties(); - // Manually update the layer's engine and brush - foreach (var property in layer.Properties) - property.KeyframeEngine?.Update(delta.TotalSeconds); + layer.OverrideProgress(CurrentTime); layer.LayerBrush?.Update(delta.TotalSeconds); }