mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Profile editor - Implemented timeline segments
Profile editor - Added snapping to multiple elements of the timeline
This commit is contained in:
1 parent
c5219bd224
commit
527fef3dc6
17 files changed
+527
-154
No files matched your search
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Models.Profile.LayerProperties;
|
||||
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Artemis.Storage.Entities.Profile.Abstract;
|
||||
@@ -24,6 +25,7 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
_layerEffects = new List<BaseLayerEffect>();
|
||||
_expandedPropertyGroups = new List<string>();
|
||||
ApplyRenderElementDefaults();
|
||||
}
|
||||
|
||||
internal Folder(Profile profile, ProfileElement parent, FolderEntity folderEntity)
|
||||
@@ -42,8 +44,6 @@ namespace Artemis.Core.Models.Profile
|
||||
_expandedPropertyGroups = new List<string>();
|
||||
_expandedPropertyGroups.AddRange(folderEntity.ExpandedPropertyGroups);
|
||||
|
||||
// TODO: Load conditions
|
||||
|
||||
// Load child folders
|
||||
foreach (var childFolder in Profile.ProfileEntity.Folders.Where(f => f.ParentId == EntityId))
|
||||
ChildrenList.Add(new Folder(profile, this, childFolder));
|
||||
@@ -55,6 +55,8 @@ namespace Artemis.Core.Models.Profile
|
||||
ChildrenList = ChildrenList.OrderBy(c => c.Order).ToList();
|
||||
for (var index = 0; index < ChildrenList.Count; index++)
|
||||
ChildrenList[index].Order = index + 1;
|
||||
|
||||
ApplyRenderElementEntity();
|
||||
}
|
||||
|
||||
internal FolderEntity FolderEntity { get; set; }
|
||||
@@ -187,7 +189,7 @@ namespace Artemis.Core.Models.Profile
|
||||
FolderEntity.ExpandedPropertyGroups.Clear();
|
||||
FolderEntity.ExpandedPropertyGroups.AddRange(_expandedPropertyGroups);
|
||||
|
||||
ApplyLayerEffectsToEntity();
|
||||
ApplyRenderElementToEntity();
|
||||
|
||||
// Conditions
|
||||
RenderElementEntity.RootDisplayCondition = DisplayConditionGroup?.DisplayConditionGroupEntity;
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Extensions;
|
||||
using Artemis.Core.Models.Profile.Conditions;
|
||||
using Artemis.Core.Models.Profile.LayerProperties;
|
||||
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
|
||||
using Artemis.Core.Models.Profile.LayerShapes;
|
||||
@@ -48,6 +47,7 @@ namespace Artemis.Core.Models.Profile
|
||||
_expandedPropertyGroups = new List<string>();
|
||||
|
||||
General.PropertyGroupInitialized += GeneralOnPropertyGroupInitialized;
|
||||
ApplyRenderElementDefaults();
|
||||
}
|
||||
|
||||
internal Layer(Profile profile, ProfileElement parent, LayerEntity layerEntity)
|
||||
@@ -69,6 +69,8 @@ namespace Artemis.Core.Models.Profile
|
||||
_expandedPropertyGroups.AddRange(layerEntity.ExpandedPropertyGroups);
|
||||
|
||||
General.PropertyGroupInitialized += GeneralOnPropertyGroupInitialized;
|
||||
ApplyRenderElementEntity();
|
||||
ApplyRenderElementDefaults();
|
||||
}
|
||||
|
||||
internal LayerEntity LayerEntity { get; set; }
|
||||
@@ -115,14 +117,27 @@ namespace Artemis.Core.Models.Profile
|
||||
get => _layerBrush;
|
||||
internal set => SetAndNotify(ref _layerBrush, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[Layer] {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override List<BaseLayerPropertyKeyframe> GetAllKeyframes()
|
||||
{
|
||||
var keyframes = base.GetAllKeyframes();
|
||||
|
||||
foreach (var baseLayerProperty in General.GetAllLayerProperties())
|
||||
keyframes.AddRange(baseLayerProperty.BaseKeyframes);
|
||||
foreach (var baseLayerProperty in Transform.GetAllLayerProperties())
|
||||
keyframes.AddRange(baseLayerProperty.BaseKeyframes);
|
||||
foreach (var baseLayerProperty in LayerBrush.BaseProperties.GetAllLayerProperties())
|
||||
keyframes.AddRange(baseLayerProperty.BaseKeyframes);
|
||||
|
||||
return keyframes;
|
||||
}
|
||||
|
||||
#region Storage
|
||||
|
||||
internal override void ApplyToEntity()
|
||||
@@ -142,7 +157,7 @@ namespace Artemis.Core.Models.Profile
|
||||
LayerBrush?.BaseProperties.ApplyToEntity();
|
||||
|
||||
// Effects
|
||||
ApplyLayerEffectsToEntity();
|
||||
ApplyRenderElementToEntity();
|
||||
|
||||
// LEDs
|
||||
LayerEntity.Leds.Clear();
|
||||
@@ -206,34 +221,18 @@ namespace Artemis.Core.Models.Profile
|
||||
return;
|
||||
|
||||
UpdateDisplayCondition();
|
||||
deltaTime = UpdateTimeline(deltaTime);
|
||||
|
||||
// TODO: Remove, this is slow and stupid
|
||||
// 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 properties = new List<BaseLayerProperty>(General.GetAllLayerProperties().Where(p => p.BaseKeyframes.Any()));
|
||||
properties.AddRange(Transform.GetAllLayerProperties().Where(p => p.BaseKeyframes.Any()));
|
||||
properties.AddRange(LayerBrush.BaseProperties.GetAllLayerProperties().Where(p => p.BaseKeyframes.Any()));
|
||||
var timeLineEnd = properties.Any() ? properties.Max(p => p.BaseKeyframes.Max(k => k.Position)) : TimeSpan.MaxValue;
|
||||
if (properties.Any(p => p.TimelineProgress >= timeLineEnd))
|
||||
{
|
||||
General.Override(TimeSpan.Zero);
|
||||
Transform.Override(TimeSpan.Zero);
|
||||
LayerBrush.BaseProperties.Override(TimeSpan.Zero);
|
||||
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||
baseLayerEffect.BaseProperties?.Override(TimeSpan.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
General.Update(deltaTime);
|
||||
Transform.Update(deltaTime);
|
||||
LayerBrush.BaseProperties.Update(deltaTime);
|
||||
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||
baseLayerEffect.BaseProperties?.Update(deltaTime);
|
||||
}
|
||||
|
||||
General.Update(deltaTime);
|
||||
Transform.Update(deltaTime);
|
||||
LayerBrush.BaseProperties?.Update(deltaTime);
|
||||
LayerBrush.Update(deltaTime);
|
||||
|
||||
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||
{
|
||||
baseLayerEffect.BaseProperties?.Update(deltaTime);
|
||||
baseLayerEffect.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
public void OverrideProgress(TimeSpan timeOverride)
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using Artemis.Core.Annotations;
|
||||
using Artemis.Core.Models.Profile.Conditions;
|
||||
using Artemis.Core.Models.Profile.LayerProperties;
|
||||
using Artemis.Core.Plugins.LayerBrush.Abstract;
|
||||
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Artemis.Storage.Entities.Profile.Abstract;
|
||||
@@ -14,6 +15,62 @@ namespace Artemis.Core.Models.Profile
|
||||
{
|
||||
public abstract class RenderProfileElement : ProfileElement
|
||||
{
|
||||
protected void ApplyRenderElementDefaults()
|
||||
{
|
||||
if (MainSegmentLength <= TimeSpan.Zero)
|
||||
MainSegmentLength = TimeSpan.FromSeconds(5);
|
||||
}
|
||||
|
||||
protected void ApplyRenderElementEntity()
|
||||
{
|
||||
StartSegmentLength = RenderElementEntity.StartSegmentLength;
|
||||
MainSegmentLength = RenderElementEntity.MainSegmentLength;
|
||||
EndSegmentLength = RenderElementEntity.EndSegmentLength;
|
||||
RepeatMainSegment = RenderElementEntity.RepeatMainSegment;
|
||||
AlwaysFinishTimeline = RenderElementEntity.AlwaysFinishTimeline;
|
||||
}
|
||||
|
||||
protected void ApplyRenderElementToEntity()
|
||||
{
|
||||
RenderElementEntity.StartSegmentLength = StartSegmentLength;
|
||||
RenderElementEntity.MainSegmentLength = MainSegmentLength;
|
||||
RenderElementEntity.EndSegmentLength = EndSegmentLength;
|
||||
RenderElementEntity.RepeatMainSegment = RepeatMainSegment;
|
||||
RenderElementEntity.AlwaysFinishTimeline = AlwaysFinishTimeline;
|
||||
|
||||
RenderElementEntity.LayerEffects.Clear();
|
||||
foreach (var layerEffect in LayerEffects)
|
||||
{
|
||||
var layerEffectEntity = new LayerEffectEntity
|
||||
{
|
||||
Id = layerEffect.EntityId,
|
||||
PluginGuid = layerEffect.PluginInfo.Guid,
|
||||
EffectType = layerEffect.GetType().Name,
|
||||
Name = layerEffect.Name,
|
||||
Enabled = layerEffect.Enabled,
|
||||
HasBeenRenamed = layerEffect.HasBeenRenamed,
|
||||
Order = layerEffect.Order
|
||||
};
|
||||
RenderElementEntity.LayerEffects.Add(layerEffectEntity);
|
||||
layerEffect.BaseProperties.ApplyToEntity();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all keyframes on all properties and effects of this layer
|
||||
/// </summary>
|
||||
public virtual List<BaseLayerPropertyKeyframe> GetAllKeyframes()
|
||||
{
|
||||
var keyframes = new List<BaseLayerPropertyKeyframe>();
|
||||
foreach (var layerEffect in LayerEffects)
|
||||
{
|
||||
foreach (var baseLayerProperty in layerEffect.BaseProperties.GetAllLayerProperties())
|
||||
keyframes.AddRange(baseLayerProperty.BaseKeyframes);
|
||||
}
|
||||
|
||||
return keyframes;
|
||||
}
|
||||
|
||||
#region Properties
|
||||
|
||||
private SKPath _path;
|
||||
@@ -101,6 +158,15 @@ namespace Artemis.Core.Models.Profile
|
||||
set => SetAndNotify(ref _endSegmentLength, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current timeline position
|
||||
/// </summary>
|
||||
public TimeSpan TimelinePosition
|
||||
{
|
||||
get => _timelinePosition;
|
||||
private set => SetAndNotify(ref _timelinePosition, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total combined length of all three segments
|
||||
/// </summary>
|
||||
@@ -124,6 +190,35 @@ namespace Artemis.Core.Models.Profile
|
||||
set => SetAndNotify(ref _alwaysFinishTimeline, value);
|
||||
}
|
||||
|
||||
protected double UpdateTimeline(double deltaTime)
|
||||
{
|
||||
var oldPosition = _timelinePosition;
|
||||
var deltaTimeSpan = TimeSpan.FromSeconds(deltaTime);
|
||||
var mainSegmentEnd = StartSegmentLength + MainSegmentLength;
|
||||
|
||||
TimelinePosition += deltaTimeSpan;
|
||||
|
||||
// Manage segments while the condition is met
|
||||
if (DisplayConditionMet)
|
||||
{
|
||||
// If we are at the end of the main timeline, wrap around back to the beginning
|
||||
if (RepeatMainSegment && TimelinePosition >= mainSegmentEnd)
|
||||
TimelinePosition = StartSegmentLength + (mainSegmentEnd - TimelinePosition);
|
||||
else if (TimelinePosition >= TimelineLength)
|
||||
TimelinePosition = TimelineLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Skip to the last segment if conditions are no longer met
|
||||
if (!AlwaysFinishTimeline && TimelinePosition < mainSegmentEnd)
|
||||
TimelinePosition = mainSegmentEnd;
|
||||
else if (TimelinePosition >= TimelineLength)
|
||||
TimelinePosition = TimelineLength;
|
||||
}
|
||||
|
||||
return (TimelinePosition - oldPosition).TotalSeconds;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Effects
|
||||
@@ -135,26 +230,6 @@ namespace Artemis.Core.Models.Profile
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<BaseLayerEffect> LayerEffects => _layerEffects.AsReadOnly();
|
||||
|
||||
protected void ApplyLayerEffectsToEntity()
|
||||
{
|
||||
RenderElementEntity.LayerEffects.Clear();
|
||||
foreach (var layerEffect in LayerEffects)
|
||||
{
|
||||
var layerEffectEntity = new LayerEffectEntity
|
||||
{
|
||||
Id = layerEffect.EntityId,
|
||||
PluginGuid = layerEffect.PluginInfo.Guid,
|
||||
EffectType = layerEffect.GetType().Name,
|
||||
Name = layerEffect.Name,
|
||||
Enabled = layerEffect.Enabled,
|
||||
HasBeenRenamed = layerEffect.HasBeenRenamed,
|
||||
Order = layerEffect.Order
|
||||
};
|
||||
RenderElementEntity.LayerEffects.Add(layerEffectEntity);
|
||||
layerEffect.BaseProperties.ApplyToEntity();
|
||||
}
|
||||
}
|
||||
|
||||
internal void RemoveLayerEffect([NotNull] BaseLayerEffect effect)
|
||||
{
|
||||
if (effect == null) throw new ArgumentNullException(nameof(effect));
|
||||
@@ -192,8 +267,20 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
#region Conditions
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the display conditions applied to this layer where met or not during last update
|
||||
/// <para>Always true if the layer has no display conditions</para>
|
||||
/// </summary>
|
||||
public bool DisplayConditionMet
|
||||
{
|
||||
get => _displayConditionMet;
|
||||
private set => SetAndNotify(ref _displayConditionMet, value);
|
||||
}
|
||||
|
||||
private DisplayConditionGroup _displayConditionGroup;
|
||||
|
||||
private TimeSpan _timelinePosition;
|
||||
private bool _displayConditionMet;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the root display condition group
|
||||
/// </summary>
|
||||
@@ -205,7 +292,11 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
public void UpdateDisplayCondition()
|
||||
{
|
||||
var rootGroupResult = DisplayConditionGroup.Evaluate();
|
||||
var conditionMet = DisplayConditionGroup == null || DisplayConditionGroup.Evaluate();
|
||||
if (conditionMet && !DisplayConditionMet)
|
||||
TimelinePosition = TimeSpan.Zero;
|
||||
|
||||
DisplayConditionMet = conditionMet;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Reference in new issue
Block a user