diff --git a/src/Artemis.Core/Models/IUpdateModel.cs b/src/Artemis.Core/Models/IUpdateModel.cs
index 870079a7f..24c480c73 100644
--- a/src/Artemis.Core/Models/IUpdateModel.cs
+++ b/src/Artemis.Core/Models/IUpdateModel.cs
@@ -8,7 +8,7 @@
///
/// Performs an update on the model
///
- /// The delta time in seconds
- void Update(double deltaTime);
+ /// The timeline to apply during update
+ void Update(Timeline timeline);
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs
index c1e86d9cf..6d473ac1b 100644
--- a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs
+++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs
@@ -137,16 +137,18 @@ namespace Artemis.Core
///
/// Updates the smoothing progress of the data binding
///
- /// The time in seconds that passed since the last update
- public void Update(double deltaTime)
+ /// The timeline to apply during update
+ public void Update(Timeline timeline)
{
if (_disposed)
throw new ObjectDisposedException("DataBinding");
// Data bindings cannot go back in time like brushes
- deltaTime = Math.Max(0, deltaTime);
+ TimeSpan deltaTime = timeline.LastDelta;
+ if (deltaTime < TimeSpan.Zero)
+ deltaTime = TimeSpan.Zero;
- _easingProgress = _easingProgress.Add(TimeSpan.FromSeconds(deltaTime));
+ _easingProgress = _easingProgress.Add(deltaTime);
if (_easingProgress > EasingTime)
_easingProgress = EasingTime;
}
diff --git a/src/Artemis.Core/Models/Profile/Folder.cs b/src/Artemis.Core/Models/Profile/Folder.cs
index 5e489b190..d904606cc 100644
--- a/src/Artemis.Core/Models/Profile/Folder.cs
+++ b/src/Artemis.Core/Models/Profile/Folder.cs
@@ -34,14 +34,12 @@ namespace Artemis.Core
_layerEffects = new List();
_expandedPropertyGroups = new List();
- ApplyRenderElementDefaults();
Parent.AddChild(this);
}
internal Folder(Profile profile, ProfileElement parent, FolderEntity folderEntity)
{
FolderEntity = folderEntity;
-
EntityId = folderEntity.Id;
Profile = profile;
@@ -52,11 +50,21 @@ namespace Artemis.Core
_layerEffects = new List();
_expandedPropertyGroups = new List();
+
Load();
+ UpdateChildrenTimelineLength();
}
+ ///
+ /// Gets a boolean indicating whether this folder is at the root of the profile tree
+ ///
public bool IsRootFolder => Parent == Profile;
+ ///
+ /// Gets the longest timeline of all this folders children
+ ///
+ public Timeline LongestChildTimeline { get; private set; }
+
internal FolderEntity FolderEntity { get; set; }
internal override RenderElementEntity RenderElementEntity => FolderEntity;
@@ -80,11 +88,8 @@ namespace Artemis.Core
if (!Enabled)
return;
- // Ensure the layer must still be displayed
UpdateDisplayCondition();
-
- // Update the layer timeline
- UpdateTimeLines(deltaTime);
+ UpdateTimeline(deltaTime);
foreach (ProfileElement child in Children)
child.Update(deltaTime);
@@ -94,8 +99,7 @@ namespace Artemis.Core
public override void Reset()
{
DisplayConditionMet = false;
- TimeLine = TimelineLength;
- ExtraTimeLines.Clear();
+ Timeline.JumpToStart();
foreach (ProfileElement child in Children)
child.Reset();
@@ -108,7 +112,7 @@ namespace Artemis.Core
throw new ObjectDisposedException("Folder");
base.AddChild(child, order);
- UpdateTimeLineLength();
+ UpdateChildrenTimelineLength();
CalculateRenderProperties();
}
@@ -119,7 +123,7 @@ namespace Artemis.Core
throw new ObjectDisposedException("Folder");
base.RemoveChild(child);
- UpdateTimeLineLength();
+ UpdateChildrenTimelineLength();
CalculateRenderProperties();
}
@@ -147,14 +151,21 @@ namespace Artemis.Core
OnRenderPropertiesUpdated();
}
- protected internal override void UpdateTimeLineLength()
+ private void UpdateChildrenTimelineLength()
{
- TimelineLength = !Children.Any() ? TimeSpan.Zero : Children.OfType().Max(c => c.TimelineLength);
- if (StartSegmentLength + MainSegmentLength + EndSegmentLength > TimelineLength)
- TimelineLength = StartSegmentLength + MainSegmentLength + EndSegmentLength;
+ Timeline longest = new Timeline() {MainSegmentLength = TimeSpan.Zero};
+ foreach (ProfileElement profileElement in Children)
+ {
+ if (profileElement is Folder folder && folder.LongestChildTimeline.Length > longest.Length)
+ longest = folder.LongestChildTimeline;
+ else if (profileElement is Layer layer &&
+ layer.Timeline.PlayMode == TimelinePlayMode.Once &&
+ layer.Timeline.StopMode == TimelineStopMode.Finish &&
+ layer.Timeline.Length > longest.Length)
+ longest = layer.Timeline;
+ }
- if (Parent is RenderProfileElement parent)
- parent.UpdateTimeLineLength();
+ LongestChildTimeline = longest;
}
protected override void Dispose(bool disposing)
@@ -208,8 +219,6 @@ namespace Artemis.Core
#region Rendering
- private TimeSpan _lastRenderTime;
-
public override void Render(SKCanvas canvas, SKImageInfo canvasInfo)
{
if (Disposed)
@@ -222,28 +231,24 @@ namespace Artemis.Core
if (Path == null)
return;
- RenderFolder(TimeLine, canvas, canvasInfo);
+ RenderFolder(Timeline, canvas, canvasInfo);
}
- private void PrepareForRender(TimeSpan timeLine)
+ private void PrepareForRender(Timeline timeline)
{
- double renderDelta = (timeLine - _lastRenderTime).TotalSeconds;
-
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled))
{
- baseLayerEffect.BaseProperties?.Update(timeLine, renderDelta);
- baseLayerEffect.Update(renderDelta);
+ baseLayerEffect.BaseProperties?.Update(timeline);
+ baseLayerEffect.Update(timeline.LastDelta.TotalSeconds);
}
-
- _lastRenderTime = timeLine;
}
- private void RenderFolder(TimeSpan timeLine, SKCanvas canvas, SKImageInfo canvasInfo)
+ private void RenderFolder(Timeline timeline, SKCanvas canvas, SKImageInfo canvasInfo)
{
- if (timeLine > TimelineLength)
+ if (Timeline.IsFinished && LongestChildTimeline.IsFinished)
return;
- PrepareForRender(timeLine);
+ PrepareForRender(timeline);
if (_folderBitmap == null)
{
diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs
index f767ba514..85d12fd9d 100644
--- a/src/Artemis.Core/Models/Profile/Layer.cs
+++ b/src/Artemis.Core/Models/Profile/Layer.cs
@@ -45,14 +45,14 @@ namespace Artemis.Core
_expandedPropertyGroups = new List();
Initialize();
- ApplyRenderElementDefaults();
-
Parent.AddChild(this);
}
internal Layer(Profile profile, ProfileElement parent, LayerEntity layerEntity)
{
LayerEntity = layerEntity;
+ EntityId = layerEntity.Id;
+
Profile = profile;
Parent = parent;
General = new LayerGeneralProperties();
@@ -176,14 +176,6 @@ namespace Artemis.Core
ActivateLayerBrush();
}
- ///
- public override void Reset()
- {
- DisplayConditionMet = false;
- TimeLine = TimelineLength;
- ExtraTimeLines.Clear();
- }
-
#region Storage
internal override void Load()
@@ -258,9 +250,7 @@ namespace Artemis.Core
#endregion
#region Rendering
-
- private TimeSpan _lastRenderTime;
-
+
///
public override void Update(double deltaTime)
{
@@ -270,16 +260,15 @@ namespace Artemis.Core
if (!Enabled)
return;
- // Ensure the layer must still be displayed
UpdateDisplayCondition();
-
- // Update the layer timeline
- UpdateTimeLines(deltaTime);
+ UpdateTimeline(deltaTime);
}
- protected internal override void UpdateTimeLineLength()
+ ///
+ public override void Reset()
{
- TimelineLength = StartSegmentLength + MainSegmentLength + EndSegmentLength;
+ DisplayConditionMet = false;
+ Timeline.JumpToStart();
}
///
@@ -298,35 +287,31 @@ namespace Artemis.Core
if (LayerBrush?.BaseProperties?.PropertiesInitialized == false || LayerBrush?.BrushType != LayerBrushType.Regular)
return;
- RenderLayer(TimeLine, canvas);
- foreach (TimeSpan extraTimeLine in ExtraTimeLines)
- RenderLayer(extraTimeLine, canvas);
+ RenderLayer(Timeline, canvas);
+ foreach (Timeline extraTimeline in Timeline.ExtraTimelines)
+ RenderLayer(extraTimeline, canvas);
}
- private void PrepareForRender(TimeSpan renderTime)
+ private void PrepareForRender(Timeline timeline)
{
- double renderDelta = (renderTime - _lastRenderTime).TotalSeconds;
-
- General.Update(renderTime, renderDelta);
- Transform.Update(renderTime, renderDelta);
- LayerBrush.BaseProperties?.Update(renderTime, renderDelta);
- LayerBrush.Update(renderDelta);
+ General.Update(timeline);
+ Transform.Update(timeline);
+ LayerBrush.BaseProperties?.Update(timeline);
+ LayerBrush.Update(timeline.LastDelta.TotalSeconds);
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled))
{
- baseLayerEffect.BaseProperties?.Update(renderTime, renderDelta);
- baseLayerEffect.Update(renderDelta);
+ baseLayerEffect.BaseProperties?.Update(timeline);
+ baseLayerEffect.Update(timeline.LastDelta.TotalSeconds);
}
-
- _lastRenderTime = renderTime;
}
- private void RenderLayer(TimeSpan timeLine, SKCanvas canvas)
+ private void RenderLayer(Timeline timeline, SKCanvas canvas)
{
- if (timeLine > TimelineLength)
+ if (timeline.IsFinished)
return;
- PrepareForRender(timeLine);
+ PrepareForRender(timeline);
if (_layerBitmap == null)
{
diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs
index 9c5f381db..512b63213 100644
--- a/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs
+++ b/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs
@@ -40,8 +40,7 @@ namespace Artemis.Core
///
/// Updates the layer properties internal state
///
- /// The current position in the timeline
- /// The position difference since last update
- void Update(TimeSpan renderTime, double deltaTime);
+ /// The timeline to apply to the property
+ void Update(Timeline timeline);
}
}
\ 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 ca08aa337..cdc7f9aa4 100644
--- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs
+++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs
@@ -34,20 +34,18 @@ namespace Artemis.Core
///
public string Path { get; private set; }
- ///
- /// Updates the property, applying keyframes and data bindings to the current value
- ///
- public void Update(TimeSpan time, double deltaTime)
+ ///
+ public void Update(Timeline timeline)
{
if (_disposed)
throw new ObjectDisposedException("LayerProperty");
CurrentValue = BaseValue;
-
+
if (ProfileElement.ApplyKeyframesEnabled)
- UpdateKeyframes(time);
+ UpdateKeyframes(timeline);
if (ProfileElement.ApplyDataBindingsEnabled)
- UpdateDataBindings(deltaTime);
+ UpdateDataBindings(timeline);
OnUpdated();
}
@@ -125,8 +123,7 @@ namespace Artemis.Core
return;
_baseValue = value;
- Update(ProfileElement.TimeLine, 0);
- OnCurrentValueSet();
+ ReapplyUpdate();
}
}
@@ -169,8 +166,7 @@ namespace Artemis.Core
// Force an update so that the base value is applied to the current value and
// keyframes/data bindings are applied using the new base value
- Update(ProfileElement.TimeLine, 0);
- OnCurrentValueSet();
+ ReapplyUpdate();
}
///
@@ -185,6 +181,13 @@ namespace Artemis.Core
CurrentValue = DefaultValue;
}
+ private void ReapplyUpdate()
+ {
+ ProfileElement.Timeline.ClearDelta();
+ Update(ProfileElement.Timeline);
+ OnCurrentValueSet();
+ }
+
#endregion
#region Keyframes
@@ -294,13 +297,13 @@ namespace Artemis.Core
_keyframes = _keyframes.OrderBy(k => k.Position).ToList();
}
- private void UpdateKeyframes(TimeSpan time)
+ private void UpdateKeyframes(Timeline timeline)
{
if (!KeyframesSupported || !KeyframesEnabled)
return;
-
+
// The current keyframe is the last keyframe before the current time
- CurrentKeyframe = _keyframes.LastOrDefault(k => k.Position <= time);
+ CurrentKeyframe = _keyframes.LastOrDefault(k => k.Position <= timeline.Position);
// Keyframes are sorted by position so we can safely assume the next keyframe's position is after the current
int nextIndex = _keyframes.IndexOf(CurrentKeyframe) + 1;
NextKeyframe = _keyframes.Count > nextIndex ? _keyframes[nextIndex] : null;
@@ -314,7 +317,7 @@ namespace Artemis.Core
else
{
TimeSpan timeDiff = NextKeyframe.Position - CurrentKeyframe.Position;
- float keyframeProgress = (float) ((time - CurrentKeyframe.Position).TotalMilliseconds / timeDiff.TotalMilliseconds);
+ float keyframeProgress = (float) ((timeline.Position - CurrentKeyframe.Position).TotalMilliseconds / timeDiff.TotalMilliseconds);
float keyframeProgressEased = (float) Easings.Interpolate(keyframeProgress, CurrentKeyframe.EasingFunction);
UpdateCurrentValue(keyframeProgress, keyframeProgressEased);
}
@@ -361,7 +364,7 @@ namespace Artemis.Core
{
return _dataBindingRegistrations;
}
-
+
public void RegisterDataBindingProperty(Expression> propertyExpression, DataBindingConverter converter)
{
if (_disposed)
@@ -416,11 +419,11 @@ namespace Artemis.Core
OnDataBindingDisabled(new LayerPropertyEventArgs(dataBinding.LayerProperty));
}
- private void UpdateDataBindings(double deltaTime)
+ private void UpdateDataBindings(Timeline timeline)
{
foreach (IDataBinding dataBinding in _dataBindings)
{
- dataBinding.Update(deltaTime);
+ dataBinding.Update(timeline);
dataBinding.Apply();
}
}
@@ -484,12 +487,10 @@ namespace Artemis.Core
_keyframes.Clear();
try
{
- _keyframes.AddRange(Entity.KeyframeEntities.Select(k => new LayerPropertyKeyframe(
- JsonConvert.DeserializeObject(k.Value),
- k.Position,
- (Easings.Functions) k.EasingFunction,
- this
- )));
+ _keyframes.AddRange(
+ Entity.KeyframeEntities.Where(k => k.Position <= ProfileElement.Timeline.Length)
+ .Select(k => new LayerPropertyKeyframe(JsonConvert.DeserializeObject(k.Value), k.Position, (Easings.Functions) k.EasingFunction, this))
+ );
}
catch (JsonException e)
{
diff --git a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs
index a9cb08a99..48afecab9 100644
--- a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs
+++ b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs
@@ -198,12 +198,12 @@ namespace Artemis.Core
layerPropertyGroup.ApplyToEntity();
}
- internal void Update(TimeSpan renderTime, double deltaTime)
+ internal void Update(Timeline timeline)
{
foreach (ILayerProperty layerProperty in LayerProperties)
- layerProperty.Update(renderTime, deltaTime);
+ layerProperty.Update(timeline);
foreach (LayerPropertyGroup layerPropertyGroup in LayerPropertyGroups)
- layerPropertyGroup.Update(renderTime, deltaTime);
+ layerPropertyGroup.Update(timeline);
}
private void InitializeProperty(PropertyInfo propertyInfo, PropertyDescriptionAttribute propertyDescription)
diff --git a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs
index dd530719f..9cea2b10e 100644
--- a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs
+++ b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs
@@ -17,6 +17,7 @@ namespace Artemis.Core
{
ApplyDataBindingsEnabled = true;
ApplyKeyframesEnabled = true;
+ Timeline = new Timeline();
LayerEffectStore.LayerEffectAdded += LayerEffectStoreOnLayerEffectAdded;
LayerEffectStore.LayerEffectRemoved += LayerEffectStoreOnLayerEffectRemoved;
@@ -30,8 +31,8 @@ namespace Artemis.Core
? new DataModelConditionGroup(null, RenderElementEntity.DisplayCondition)
: new DataModelConditionGroup(null);
- Timeline = RenderElementEntity.Timeline != null
- ? new Timeline(RenderElementEntity.Timeline)
+ Timeline = RenderElementEntity.Timeline != null
+ ? new Timeline(RenderElementEntity.Timeline)
: new Timeline();
ActivateEffects();
@@ -70,7 +71,17 @@ namespace Artemis.Core
///
/// Gets the timeline associated with this render element
///
- public Timeline? Timeline { get; private set; }
+ public Timeline Timeline { get; private set; }
+
+ ///
+ /// Updates the according to the provided and current display condition status
+ ///
+ public void UpdateTimeline(double deltaTime)
+ {
+ // The play mode dictates whether to stick to the main segment unless the display conditions contains events
+ bool stickToMainSegment = Timeline.PlayMode == TimelinePlayMode.Repeat && (DisplayConditionMet || DisplayCondition != null && DisplayCondition.ContainsEvents);
+ Timeline.Update(TimeSpan.FromSeconds(deltaTime), stickToMainSegment);
+ }
#endregion
@@ -297,6 +308,9 @@ namespace Artemis.Core
///
public bool ApplyDataBindingsEnabled { get; set; }
+ ///
+ /// Evaluates the display conditions on this element and applies any required changes to the
+ ///
public void UpdateDisplayCondition()
{
if (DisplayCondition == null)
@@ -306,26 +320,30 @@ namespace Artemis.Core
}
bool conditionMet = DisplayCondition.Evaluate();
-
- // Regular conditions reset the timeline whenever their condition is met and was not met before that
if (!DisplayCondition.ContainsEvents)
{
+ // Regular conditions reset the timeline whenever their condition is met and was not met before that
if (conditionMet && !DisplayConditionMet && Timeline.IsFinished)
Timeline.JumpToStart();
+ // If regular conditions are no longer met, jump to the end segment if stop mode requires it
+ if (!conditionMet && DisplayConditionMet && Timeline.StopMode == TimelineStopMode.SkipToEnd)
+ Timeline.JumpToEndSegment();
}
- // Event conditions reset if the timeline finished and otherwise apply their overlap mode
else if (conditionMet)
{
+ // Event conditions reset if the timeline finished
if (Timeline.IsFinished)
- {
Timeline.JumpToStart();
- }
+ // and otherwise apply their overlap mode
else
{
if (Timeline.EventOverlapMode == TimeLineEventOverlapMode.Restart)
Timeline.JumpToStart();
else if (Timeline.EventOverlapMode == TimeLineEventOverlapMode.Copy)
Timeline.AddExtraTimeline();
+ // The third option is ignore which is handled below:
+
+ // done
}
}
diff --git a/src/Artemis.Core/Models/Profile/Timeline.cs b/src/Artemis.Core/Models/Profile/Timeline.cs
index dec48c34c..a7e5b50e6 100644
--- a/src/Artemis.Core/Models/Profile/Timeline.cs
+++ b/src/Artemis.Core/Models/Profile/Timeline.cs
@@ -64,11 +64,14 @@ namespace Artemis.Core
private TimelinePlayMode _playMode;
private TimelineStopMode _stopMode;
private readonly List _extraTimelines;
+ private TimeSpan _startSegmentLength;
+ private TimeSpan _mainSegmentLength;
+ private TimeSpan _endSegmentLength;
///
/// Gets the parent this timeline is an extra timeline of
///
- public Timeline Parent { get; }
+ public Timeline? Parent { get; }
///
/// Gets the current position of the timeline
@@ -81,13 +84,21 @@ namespace Artemis.Core
///
/// Gets the delta that was applied during the last call to
+ ///
+ /// Note: If this is an extra timeline is always equal to
+ ///
///
public TimeSpan LastDelta
{
- get => _lastDelta;
+ get => Parent == null ? _lastDelta : DeltaToParent;
private set => SetAndNotify(ref _lastDelta, value);
}
+ ///
+ /// Gets the delta to this timeline's
+ ///
+ public TimeSpan DeltaToParent => Parent != null ? Position - Parent.Position : TimeSpan.Zero;
+
///
/// Gets or sets the mode in which the render element starts its timeline when display conditions are met
///
@@ -124,7 +135,7 @@ namespace Artemis.Core
///
/// Gets a boolean indicating whether the timeline has finished its run
///
- public bool IsFinished => Position > Length;
+ public bool IsFinished => Position > Length || Length == TimeSpan.Zero;
#region Segments
@@ -136,17 +147,41 @@ namespace Artemis.Core
///
/// Gets or sets the length of the start segment
///
- public TimeSpan StartSegmentLength { get; set; }
+ public TimeSpan StartSegmentLength
+ {
+ get => _startSegmentLength;
+ set
+ {
+ if (SetAndNotify(ref _startSegmentLength, value))
+ NotifySegmentShiftAt(TimelineSegment.Start, false);
+ }
+ }
///
/// Gets or sets the length of the main segment
///
- public TimeSpan MainSegmentLength { get; set; }
+ public TimeSpan MainSegmentLength
+ {
+ get => _mainSegmentLength;
+ set
+ {
+ if (SetAndNotify(ref _mainSegmentLength, value))
+ NotifySegmentShiftAt(TimelineSegment.Main, false);
+ }
+ }
///
/// Gets or sets the length of the end segment
///
- public TimeSpan EndSegmentLength { get; set; }
+ public TimeSpan EndSegmentLength
+ {
+ get => _endSegmentLength;
+ set
+ {
+ if (SetAndNotify(ref _endSegmentLength, value))
+ NotifySegmentShiftAt(TimelineSegment.End, false);
+ }
+ }
///
/// Gets or sets the start position of the main segment
@@ -154,7 +189,11 @@ namespace Artemis.Core
public TimeSpan MainSegmentStartPosition
{
get => StartSegmentEndPosition;
- set => StartSegmentEndPosition = value;
+ set
+ {
+ StartSegmentEndPosition = value;
+ NotifySegmentShiftAt(TimelineSegment.Main, true);
+ }
}
///
@@ -163,7 +202,11 @@ namespace Artemis.Core
public TimeSpan EndSegmentStartPosition
{
get => MainSegmentEndPosition;
- set => MainSegmentEndPosition = value;
+ set
+ {
+ MainSegmentEndPosition = value;
+ NotifySegmentShiftAt(TimelineSegment.End, true);
+ }
}
///
@@ -172,7 +215,11 @@ namespace Artemis.Core
public TimeSpan StartSegmentEndPosition
{
get => StartSegmentLength;
- set => StartSegmentLength = value;
+ set
+ {
+ StartSegmentLength = value;
+ NotifySegmentShiftAt(TimelineSegment.Start, false);
+ }
}
///
@@ -181,7 +228,11 @@ namespace Artemis.Core
public TimeSpan MainSegmentEndPosition
{
get => StartSegmentEndPosition + MainSegmentLength;
- set => MainSegmentLength = value - StartSegmentEndPosition >= TimeSpan.Zero ? value - StartSegmentEndPosition : TimeSpan.Zero;
+ set
+ {
+ MainSegmentLength = value - StartSegmentEndPosition >= TimeSpan.Zero ? value - StartSegmentEndPosition : TimeSpan.Zero;
+ NotifySegmentShiftAt(TimelineSegment.Main, false);
+ }
}
///
@@ -190,11 +241,41 @@ namespace Artemis.Core
public TimeSpan EndSegmentEndPosition
{
get => MainSegmentEndPosition + EndSegmentLength;
- set => EndSegmentLength = value - MainSegmentEndPosition >= TimeSpan.Zero ? value - MainSegmentEndPosition : TimeSpan.Zero;
+ set
+ {
+ EndSegmentLength = value - MainSegmentEndPosition >= TimeSpan.Zero ? value - MainSegmentEndPosition : TimeSpan.Zero;
+ NotifySegmentShiftAt(TimelineSegment.End, false);
+ }
}
internal TimelineEntity Entity { get; set; }
+ ///
+ /// Notifies the right segments in a way that I don't have to think about it
+ ///
+ /// The segment that was updated
+ /// Whether the start point of the was updated
+ private void NotifySegmentShiftAt(TimelineSegment segment, bool startUpdated)
+ {
+ if (segment <= TimelineSegment.End)
+ {
+ if (startUpdated || segment < TimelineSegment.End)
+ NotifyOfPropertyChange(nameof(EndSegmentStartPosition));
+ NotifyOfPropertyChange(nameof(EndSegmentEndPosition));
+ }
+
+ if (segment <= TimelineSegment.Main)
+ {
+ if (startUpdated || segment < TimelineSegment.Main)
+ NotifyOfPropertyChange(nameof(MainSegmentStartPosition));
+ NotifyOfPropertyChange(nameof(MainSegmentEndPosition));
+ }
+
+ if (segment <= TimelineSegment.Start) NotifyOfPropertyChange(nameof(StartSegmentEndPosition));
+
+ NotifyOfPropertyChange(nameof(Length));
+ }
+
#endregion
#endregion
@@ -213,6 +294,9 @@ namespace Artemis.Core
if (stickToMainSegment && Position >= MainSegmentStartPosition)
Position = MainSegmentStartPosition + TimeSpan.FromMilliseconds(Position.TotalMilliseconds % MainSegmentLength.TotalMilliseconds);
+
+ foreach (Timeline extraTimeline in _extraTimelines)
+ extraTimeline.Update(delta, false);
}
///
@@ -225,6 +309,8 @@ namespace Artemis.Core
LastDelta = TimeSpan.Zero - Position;
Position = TimeSpan.Zero;
+
+ _extraTimelines.Clear();
}
///
@@ -237,6 +323,8 @@ namespace Artemis.Core
LastDelta = EndSegmentStartPosition - Position;
Position = EndSegmentStartPosition;
+
+ _extraTimelines.Clear();
}
///
@@ -249,6 +337,8 @@ namespace Artemis.Core
LastDelta = EndSegmentEndPosition - Position;
Position = EndSegmentEndPosition;
+
+ _extraTimelines.Clear();
}
///
@@ -258,12 +348,20 @@ namespace Artemis.Core
/// Whether to stick to the main segment, wrapping around if needed
public void Override(TimeSpan position, bool stickToMainSegment)
{
- _extraTimelines.Clear();
-
LastDelta = position - Position;
Position = position;
if (stickToMainSegment && Position >= MainSegmentStartPosition)
Position = MainSegmentStartPosition + TimeSpan.FromMilliseconds(Position.TotalMilliseconds % MainSegmentLength.TotalMilliseconds);
+
+ _extraTimelines.Clear();
+ }
+
+ ///
+ /// Sets the to
+ ///
+ public void ClearDelta()
+ {
+ LastDelta = TimeSpan.Zero;
}
#endregion
@@ -295,6 +393,13 @@ namespace Artemis.Core
#endregion
}
+ internal enum TimelineSegment
+ {
+ Start,
+ Main,
+ End
+ }
+
///
/// Represents a mode for render elements to start their timeline when display conditions are met
///
diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs
index 824649181..9098b1556 100644
--- a/src/Artemis.Core/Services/CoreService.cs
+++ b/src/Artemis.Core/Services/CoreService.cs
@@ -123,7 +123,7 @@ namespace Artemis.Core.Services
_introAnimation.Render(args.DeltaTime, args.Canvas, _rgbService.BitmapBrush.Bitmap.Info);
}
- TimeSpan introLength = _introAnimation.AnimationProfile.GetAllLayers().Max(l => l.TimelineLength);
+ TimeSpan introLength = _introAnimation.AnimationProfile.GetAllLayers().Max(l => l.Timeline.Length);
// Stop rendering after the profile finishes (take 1 second extra in case of slow updates)
Task.Run(async () =>
diff --git a/src/Artemis.Storage/Migrations/M4ProfileSegments.cs b/src/Artemis.Storage/Migrations/M4ProfileSegments.cs
index e9a92bdfb..c54e3dc0f 100644
--- a/src/Artemis.Storage/Migrations/M4ProfileSegments.cs
+++ b/src/Artemis.Storage/Migrations/M4ProfileSegments.cs
@@ -13,31 +13,32 @@ namespace Artemis.Storage.Migrations
public void Apply(LiteRepository repository)
{
- List profiles = repository.Query().ToList();
- foreach (ProfileEntity profileEntity in profiles)
- {
- foreach (FolderEntity folder in profileEntity.Folders.Where(f => f.MainSegmentLength == TimeSpan.Zero))
- {
- if (folder.PropertyEntities.Any(p => p.KeyframeEntities.Any()))
- folder.MainSegmentLength = folder.PropertyEntities.Where(p => p.KeyframeEntities.Any()).Max(p => p.KeyframeEntities.Max(k => k.Position));
- if (folder.MainSegmentLength == TimeSpan.Zero)
- folder.MainSegmentLength = TimeSpan.FromSeconds(5);
-
- folder.PlayMode = 0;
- }
-
- foreach (LayerEntity layer in profileEntity.Layers.Where(l => l.MainSegmentLength == TimeSpan.Zero))
- {
- if (layer.PropertyEntities.Any(p => p.KeyframeEntities.Any()))
- layer.MainSegmentLength = layer.PropertyEntities.Where(p => p.KeyframeEntities.Any()).Max(p => p.KeyframeEntities.Max(k => k.Position));
- if (layer.MainSegmentLength == TimeSpan.Zero)
- layer.MainSegmentLength = TimeSpan.FromSeconds(5);
-
- layer.PlayMode = 0;
- }
-
- repository.Update(profileEntity);
- }
+ // Lesson for next time: Use BsonDocuments in migrations
+ // List profiles = repository.Query().ToList();
+ // foreach (ProfileEntity profileEntity in profiles)
+ // {
+ // foreach (FolderEntity folder in profileEntity.Folders.Where(f => f.MainSegmentLength == TimeSpan.Zero))
+ // {
+ // if (folder.PropertyEntities.Any(p => p.KeyframeEntities.Any()))
+ // folder.MainSegmentLength = folder.PropertyEntities.Where(p => p.KeyframeEntities.Any()).Max(p => p.KeyframeEntities.Max(k => k.Position));
+ // if (folder.MainSegmentLength == TimeSpan.Zero)
+ // folder.MainSegmentLength = TimeSpan.FromSeconds(5);
+ //
+ // folder.PlayMode = 0;
+ // }
+ //
+ // foreach (LayerEntity layer in profileEntity.Layers.Where(l => l.MainSegmentLength == TimeSpan.Zero))
+ // {
+ // if (layer.PropertyEntities.Any(p => p.KeyframeEntities.Any()))
+ // layer.MainSegmentLength = layer.PropertyEntities.Where(p => p.KeyframeEntities.Any()).Max(p => p.KeyframeEntities.Max(k => k.Position));
+ // if (layer.MainSegmentLength == TimeSpan.Zero)
+ // layer.MainSegmentLength = TimeSpan.FromSeconds(5);
+ //
+ // layer.PlayMode = 0;
+ // }
+ //
+ // repository.Update(profileEntity);
+ // }
}
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs
index 6b7b8d719..72bcb7b7b 100644
--- a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs
+++ b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs
@@ -52,8 +52,8 @@ namespace Artemis.UI.Shared.Services
set
{
if (_currentTime.Equals(value)) return;
- if (SelectedProfileElement != null && value > SelectedProfileElement.TimelineLength)
- _currentTime = SelectedProfileElement.TimelineLength;
+ if (SelectedProfileElement != null && value > SelectedProfileElement.Timeline.Length)
+ _currentTime = SelectedProfileElement.Timeline.Length;
else
_currentTime = value;
UpdateProfilePreview();
@@ -150,9 +150,9 @@ namespace Artemis.UI.Shared.Services
// Stick to the main segment for any element that is not currently selected
foreach (Folder folder in SelectedProfile.GetAllFolders())
- folder.OverrideTimeLines(CurrentTime, folder != SelectedProfileElement);
+ folder.Timeline.Override(CurrentTime, folder != SelectedProfileElement);
foreach (Layer layer in SelectedProfile.GetAllLayers())
- layer.OverrideTimeLines(CurrentTime, layer != SelectedProfileElement);
+ layer.Timeline.Override(CurrentTime, layer != SelectedProfileElement);
_coreService.FrameRendered += CoreServiceOnFrameRendered;
}
@@ -232,24 +232,23 @@ namespace Artemis.UI.Shared.Services
if (snapToSegments)
{
// Snap to the end of the start segment
- if (Math.Abs(time.TotalMilliseconds - SelectedProfileElement.StartSegmentLength.TotalMilliseconds) < tolerance.TotalMilliseconds)
- return SelectedProfileElement.StartSegmentLength;
+ if (Math.Abs(time.TotalMilliseconds - SelectedProfileElement.Timeline.StartSegmentEndPosition.TotalMilliseconds) < tolerance.TotalMilliseconds)
+ return SelectedProfileElement.Timeline.StartSegmentEndPosition;
// Snap to the end of the main segment
- TimeSpan mainSegmentEnd = SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength;
- if (Math.Abs(time.TotalMilliseconds - mainSegmentEnd.TotalMilliseconds) < tolerance.TotalMilliseconds)
- return mainSegmentEnd;
+ if (Math.Abs(time.TotalMilliseconds - SelectedProfileElement.Timeline.MainSegmentEndPosition.TotalMilliseconds) < tolerance.TotalMilliseconds)
+ return SelectedProfileElement.Timeline.MainSegmentEndPosition;
// Snap to the end of the end segment (end of the timeline)
- if (Math.Abs(time.TotalMilliseconds - SelectedProfileElement.TimelineLength.TotalMilliseconds) < tolerance.TotalMilliseconds)
- return SelectedProfileElement.TimelineLength;
+ if (Math.Abs(time.TotalMilliseconds - SelectedProfileElement.Timeline.EndSegmentEndPosition.TotalMilliseconds) < tolerance.TotalMilliseconds)
+ return SelectedProfileElement.Timeline.EndSegmentEndPosition;
}
if (snapToCurrentTime)
{
// Snap to the current time
if (Math.Abs(time.TotalMilliseconds - CurrentTime.TotalMilliseconds) < tolerance.TotalMilliseconds)
- return SelectedProfileElement.StartSegmentLength;
+ return CurrentTime;
}
if (snapTimes != null)
diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml
index 38d8331c0..cc49f3d59 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml
+++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml
@@ -200,7 +200,7 @@
+ IsChecked="{Binding Path=RenderProfileElement.Timeline.EventOverlapMode, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Restart}}">
RESTART
@@ -215,7 +215,7 @@
+ IsChecked="{Binding Path=RenderProfileElement.Timeline.EventOverlapMode, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Ignore}}">
IGNORE
@@ -230,7 +230,7 @@
+ IsChecked="{Binding Path=RenderProfileElement.Timeline.EventOverlapMode, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static core:TimeLineEventOverlapMode.Copy}}">
COPY
diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs
index 9f2dd89a6..c4646dd37 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs
@@ -43,24 +43,24 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
public bool DisplayContinuously
{
- get => RenderProfileElement?.PlayMode == TimelinePlayMode.Repeat;
+ get => RenderProfileElement?.Timeline.PlayMode == TimelinePlayMode.Repeat;
set
{
TimelinePlayMode playMode = value ? TimelinePlayMode.Repeat : TimelinePlayMode.Once;
- if (RenderProfileElement == null || RenderProfileElement?.PlayMode == playMode) return;
- RenderProfileElement.PlayMode = playMode;
+ if (RenderProfileElement == null || RenderProfileElement?.Timeline.PlayMode == playMode) return;
+ RenderProfileElement.Timeline.PlayMode = playMode;
_profileEditorService.UpdateSelectedProfileElement();
}
}
public bool AlwaysFinishTimeline
{
- get => RenderProfileElement?.StopMode == TimelineStopMode.Finish;
+ get => RenderProfileElement?.Timeline.StopMode == TimelineStopMode.Finish;
set
{
TimelineStopMode stopMode = value ? TimelineStopMode.Finish : TimelineStopMode.SkipToEnd;
- if (RenderProfileElement == null || RenderProfileElement?.StopMode == stopMode) return;
- RenderProfileElement.StopMode = stopMode;
+ if (RenderProfileElement == null || RenderProfileElement?.Timeline.StopMode == stopMode) return;
+ RenderProfileElement.Timeline.StopMode = stopMode;
_profileEditorService.UpdateSelectedProfileElement();
}
}
diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingViewModel.cs
index 153e9ca40..9c7d0a4cd 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DataBindingViewModel.cs
@@ -237,7 +237,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
}
// While playing in preview data bindings aren't updated
- Registration.DataBinding.Update(0.04);
+ Registration.DataBinding.Update(Registration.LayerProperty.ProfileElement.Timeline);
if (ActiveItem.SupportsTestValue)
{
diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs
index 3ed17124f..41401ab7e 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs
@@ -567,7 +567,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
{
if (Repeating && RepeatTimeline)
{
- if (newTime > SelectedProfileElement.TimelineLength)
+ if (newTime > SelectedProfileElement.Timeline.Length)
newTime = TimeSpan.Zero;
}
else if (Repeating && RepeatSegment)
@@ -575,9 +575,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
if (newTime > GetCurrentSegmentEnd())
newTime = GetCurrentSegmentStart();
}
- else if (newTime > SelectedProfileElement.TimelineLength)
+ else if (newTime > SelectedProfileElement.Timeline.Length)
{
- newTime = SelectedProfileElement.TimelineLength;
+ newTime = SelectedProfileElement.Timeline.Length;
Pause();
}
}
diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineKeyframeViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineKeyframeViewModel.cs
index 92e96040b..6c9b8e7d5 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineKeyframeViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineKeyframeViewModel.cs
@@ -148,8 +148,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
{
if (position < TimeSpan.Zero)
LayerPropertyKeyframe.Position = TimeSpan.Zero;
- else if (position > _profileEditorService.SelectedProfileElement.TimelineLength)
- LayerPropertyKeyframe.Position = _profileEditorService.SelectedProfileElement.TimelineLength;
+ else if (position > _profileEditorService.SelectedProfileElement.Timeline.Length)
+ LayerPropertyKeyframe.Position = _profileEditorService.SelectedProfileElement.Timeline.Length;
else
LayerPropertyKeyframe.Position = position;
@@ -170,7 +170,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
);
// If possible, shift the keyframe to the right by 11 pixels
TimeSpan desiredPosition = newKeyframe.Position + TimeSpan.FromMilliseconds(1000f / _profileEditorService.PixelsPerSecond * 11);
- if (desiredPosition <= newKeyframe.LayerProperty.ProfileElement.TimelineLength)
+ if (desiredPosition <= newKeyframe.LayerProperty.ProfileElement.Timeline.Length)
newKeyframe.Position = desiredPosition;
// Otherwise if possible shift it to the left by 11 pixels
else
diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs
index 888d0db50..066b66cdb 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs
@@ -56,10 +56,10 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
start ??= TimeSpan.Zero;
end ??= TimeSpan.MaxValue;
- List> toShift = LayerProperty.Keyframes.Where(k => k.Position >= start && k.Position < end).ToList();
+ List> toShift = LayerProperty.Keyframes.Where(k => k.Position > start && k.Position < end).ToList();
foreach (LayerPropertyKeyframe keyframe in toShift)
keyframe.Position += amount;
-
+
UpdateKeyframes();
}
diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineSegmentViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineSegmentViewModel.cs
index 4c9b4ab4d..974a64b66 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineSegmentViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineSegmentViewModel.cs
@@ -48,7 +48,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
ProfileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
ProfileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
if (ProfileEditorService.SelectedProfileElement != null)
- ProfileEditorService.SelectedProfileElement.PropertyChanged += SelectedProfileElementOnPropertyChanged;
+ ProfileEditorService.SelectedProfileElement.Timeline.PropertyChanged += TimelineOnPropertyChanged;
Update();
}
@@ -104,13 +104,13 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
{
if (Segment != SegmentViewModelType.Main)
return false;
- return SelectedProfileElement?.PlayMode == TimelinePlayMode.Repeat;
+ return SelectedProfileElement?.Timeline.PlayMode == TimelinePlayMode.Repeat;
}
set
{
- if (Segment != SegmentViewModelType.Main)
+ if (Segment != SegmentViewModelType.Main || SelectedProfileElement == null)
return;
- SelectedProfileElement.PlayMode = value ? TimelinePlayMode.Repeat : TimelinePlayMode.Once;
+ SelectedProfileElement.Timeline.PlayMode = value ? TimelinePlayMode.Repeat : TimelinePlayMode.Once;
ProfileEditorService.UpdateSelectedProfileElement();
NotifyOfPropertyChange(nameof(RepeatSegment));
}
@@ -156,32 +156,35 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
{
if (SelectedProfileElement == null)
{
- SegmentLength = TimeSpan.Zero;
SegmentStart = TimeSpan.Zero;
SegmentEnd = TimeSpan.Zero;
+ SegmentLength = TimeSpan.Zero;
SegmentStartPosition = 0;
SegmentWidth = 0;
SegmentEnabled = false;
return;
}
+ // It would be nice to do this differently if this patterns end up appearing in more places
if (Segment == SegmentViewModelType.Start)
{
- SegmentLength = SelectedProfileElement.StartSegmentLength;
SegmentStart = TimeSpan.Zero;
+ SegmentEnd = SelectedProfileElement.Timeline.StartSegmentEndPosition;
+ SegmentLength = SelectedProfileElement.Timeline.StartSegmentLength;
}
else if (Segment == SegmentViewModelType.Main)
{
- SegmentLength = SelectedProfileElement.MainSegmentLength;
- SegmentStart = SelectedProfileElement.StartSegmentLength;
+ SegmentStart = SelectedProfileElement.Timeline.MainSegmentStartPosition;
+ SegmentEnd = SelectedProfileElement.Timeline.MainSegmentEndPosition;
+ SegmentLength = SelectedProfileElement.Timeline.MainSegmentLength;
}
else if (Segment == SegmentViewModelType.End)
{
- SegmentLength = SelectedProfileElement.EndSegmentLength;
- SegmentStart = SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength;
+ SegmentStart = SelectedProfileElement.Timeline.EndSegmentStartPosition;
+ SegmentEnd = SelectedProfileElement.Timeline.EndSegmentEndPosition;
+ SegmentLength = SelectedProfileElement.Timeline.EndSegmentLength;
}
- SegmentEnd = SegmentStart + SegmentLength;
SegmentStartPosition = SegmentStart.TotalSeconds * ProfileEditorService.PixelsPerSecond;
SegmentWidth = SegmentLength.TotalSeconds * ProfileEditorService.PixelsPerSecond;
SegmentEnabled = SegmentLength != TimeSpan.Zero;
@@ -195,28 +198,25 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
public void DisableSegment()
{
- TimeSpan startSegmentEnd = SelectedProfileElement.StartSegmentLength;
- TimeSpan mainSegmentEnd = SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength;
-
TimeSpan oldSegmentLength = SegmentLength;
if (Segment == SegmentViewModelType.Start)
{
// Remove keyframes that fall in this segment
- WipeKeyframes(null, startSegmentEnd);
- SelectedProfileElement.StartSegmentLength = TimeSpan.Zero;
+ WipeKeyframes(null, SelectedProfileElement.Timeline.StartSegmentEndPosition);
+ SelectedProfileElement.Timeline.StartSegmentLength = TimeSpan.Zero;
}
else if (Segment == SegmentViewModelType.Main)
{
// Remove keyframes that fall in this segment
- WipeKeyframes(startSegmentEnd, startSegmentEnd);
- SelectedProfileElement.MainSegmentLength = TimeSpan.Zero;
+ WipeKeyframes(SelectedProfileElement.Timeline.MainSegmentStartPosition, SelectedProfileElement.Timeline.MainSegmentEndPosition);
+ SelectedProfileElement.Timeline.MainSegmentLength = TimeSpan.Zero;
}
else if (Segment == SegmentViewModelType.End)
{
// Remove keyframes that fall in this segment
- WipeKeyframes(mainSegmentEnd, null);
- SelectedProfileElement.EndSegmentLength = TimeSpan.Zero;
+ WipeKeyframes(SelectedProfileElement.Timeline.EndSegmentStartPosition, SelectedProfileElement.Timeline.EndSegmentEndPosition);
+ SelectedProfileElement.Timeline.EndSegmentLength = TimeSpan.Zero;
}
ShiftNextSegment(SegmentLength - oldSegmentLength);
@@ -228,11 +228,11 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
{
ShiftNextSegment(TimeSpan.FromSeconds(1));
if (Segment == SegmentViewModelType.Start)
- SelectedProfileElement.StartSegmentLength = TimeSpan.FromSeconds(1);
+ SelectedProfileElement.Timeline.StartSegmentLength = TimeSpan.FromSeconds(1);
else if (Segment == SegmentViewModelType.Main)
- SelectedProfileElement.MainSegmentLength = TimeSpan.FromSeconds(1);
+ SelectedProfileElement.Timeline.MainSegmentLength = TimeSpan.FromSeconds(1);
else if (Segment == SegmentViewModelType.End)
- SelectedProfileElement.EndSegmentLength = TimeSpan.FromSeconds(1);
+ SelectedProfileElement.Timeline.EndSegmentLength = TimeSpan.FromSeconds(1);
ProfileEditorService.UpdateSelectedProfileElement();
Update();
@@ -290,27 +290,24 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
public void UpdateLength(TimeSpan newTime)
{
- TimeSpan oldSegmentLength = SegmentLength;
- if (Segment == SegmentViewModelType.Start)
- {
- if (newTime < TimeSpan.FromMilliseconds(100))
- newTime = TimeSpan.FromMilliseconds(100);
- SelectedProfileElement.StartSegmentLength = newTime;
- }
- else if (Segment == SegmentViewModelType.Main)
- {
- if (newTime < SelectedProfileElement.StartSegmentLength + TimeSpan.FromMilliseconds(100))
- newTime = SelectedProfileElement.StartSegmentLength + TimeSpan.FromMilliseconds(100);
- SelectedProfileElement.MainSegmentLength = newTime - SelectedProfileElement.StartSegmentLength;
- }
- else if (Segment == SegmentViewModelType.End)
- {
- if (newTime < SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength + TimeSpan.FromMilliseconds(100))
- newTime = SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength + TimeSpan.FromMilliseconds(100);
- SelectedProfileElement.EndSegmentLength = newTime - SelectedProfileElement.StartSegmentLength - SelectedProfileElement.MainSegmentLength;
- }
+ if (newTime < TimeSpan.FromMilliseconds(100))
+ newTime = TimeSpan.FromMilliseconds(100);
+
+ TimeSpan difference = newTime - SegmentEnd;
+
+ if (difference > TimeSpan.Zero)
+ ShiftNextSegment(difference);
+
+ if (Segment == SegmentViewModelType.Start)
+ SelectedProfileElement.Timeline.StartSegmentEndPosition = newTime;
+ else if (Segment == SegmentViewModelType.Main)
+ SelectedProfileElement.Timeline.MainSegmentEndPosition = newTime;
+ else if (Segment == SegmentViewModelType.End)
+ SelectedProfileElement.Timeline.EndSegmentEndPosition = newTime;
+
+ if (difference < TimeSpan.Zero)
+ ShiftNextSegment(difference);
- ShiftNextSegment(SegmentLength - oldSegmentLength);
Update();
}
@@ -323,7 +320,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
ProfileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
ProfileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
if (SelectedProfileElement != null)
- SelectedProfileElement.PropertyChanged -= SelectedProfileElementOnPropertyChanged;
+ SelectedProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
}
#endregion
@@ -333,20 +330,20 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
private void ProfileEditorServiceOnProfileElementSelected(object? sender, RenderProfileElementEventArgs e)
{
if (e.PreviousRenderProfileElement != null)
- e.PreviousRenderProfileElement.PropertyChanged -= SelectedProfileElementOnPropertyChanged;
+ e.PreviousRenderProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
if (e.RenderProfileElement != null)
- e.RenderProfileElement.PropertyChanged += SelectedProfileElementOnPropertyChanged;
+ e.RenderProfileElement.Timeline.PropertyChanged += TimelineOnPropertyChanged;
Update();
}
- private void SelectedProfileElementOnPropertyChanged(object sender, PropertyChangedEventArgs e)
+ private void TimelineOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
- if (e.PropertyName == nameof(RenderProfileElement.StartSegmentLength) ||
- e.PropertyName == nameof(RenderProfileElement.MainSegmentLength) ||
- e.PropertyName == nameof(RenderProfileElement.EndSegmentLength))
+ if (e.PropertyName == nameof(Core.Timeline.StartSegmentLength) ||
+ e.PropertyName == nameof(Core.Timeline.MainSegmentLength) ||
+ e.PropertyName == nameof(Core.Timeline.EndSegmentLength))
Update();
- else if (e.PropertyName == nameof(RenderProfileElement.PlayMode))
+ else if (e.PropertyName == nameof(Core.Timeline.PlayMode))
NotifyOfPropertyChange(nameof(RepeatSegment));
}
@@ -359,15 +356,12 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
public void ShiftNextSegment(TimeSpan amount)
{
- TimeSpan segmentEnd = TimeSpan.Zero;
if (Segment == SegmentViewModelType.Start)
- segmentEnd = SelectedProfileElement.StartSegmentLength;
+ ShiftKeyframes(SelectedProfileElement.Timeline.StartSegmentEndPosition, null, amount);
else if (Segment == SegmentViewModelType.Main)
- segmentEnd = SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength;
+ ShiftKeyframes(SelectedProfileElement.Timeline.MainSegmentEndPosition, null, amount);
else if (Segment == SegmentViewModelType.End)
- segmentEnd = SelectedProfileElement.TimelineLength;
-
- ShiftKeyframes(segmentEnd, null, amount);
+ ShiftKeyframes(SelectedProfileElement.Timeline.EndSegmentEndPosition, null, amount);
}
private void WipeKeyframes(TimeSpan? start, TimeSpan? end)
diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineViewModel.cs
index 83c271cb4..5dd9a62b9 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineViewModel.cs
@@ -29,7 +29,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
_profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
_profileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
if (_profileEditorService.SelectedProfileElement != null)
- _profileEditorService.SelectedProfileElement.PropertyChanged += SelectedProfileElementOnPropertyChanged;
+ _profileEditorService.SelectedProfileElement.Timeline.PropertyChanged += TimelineOnPropertyChanged;
Update();
}
@@ -75,9 +75,12 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
TotalTimelineWidth = EndSegmentEndPosition;
}
- private void SelectedProfileElementOnPropertyChanged(object sender, PropertyChangedEventArgs e)
+ private void TimelineOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
- Update();
+ if (e.PropertyName == nameof(Core.Timeline.StartSegmentLength) ||
+ e.PropertyName == nameof(Core.Timeline.MainSegmentLength) ||
+ e.PropertyName == nameof(Core.Timeline.EndSegmentLength))
+ Update();
}
private void ProfileEditorServiceOnPixelsPerSecondChanged(object sender, EventArgs e)
@@ -88,9 +91,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
private void ProfileEditorServiceOnProfileElementSelected(object? sender, RenderProfileElementEventArgs e)
{
if (e.PreviousRenderProfileElement != null)
- e.PreviousRenderProfileElement.PropertyChanged -= SelectedProfileElementOnPropertyChanged;
+ e.PreviousRenderProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
if (e.RenderProfileElement != null)
- e.RenderProfileElement.PropertyChanged += SelectedProfileElementOnPropertyChanged;
+ e.RenderProfileElement.Timeline.PropertyChanged += TimelineOnPropertyChanged;
Update();
}
@@ -184,13 +187,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
// If shift is held, snap to the current time
// Take a tolerance of 5 pixels (half a keyframe width)
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
- {
- float tolerance = 1000f / _profileEditorService.PixelsPerSecond * 5;
- if (Math.Abs(_profileEditorService.CurrentTime.TotalMilliseconds - time.TotalMilliseconds) < tolerance)
- time = _profileEditorService.CurrentTime;
- else if (Math.Abs(_profileEditorService.SelectedProfileElement.StartSegmentLength.TotalMilliseconds - time.TotalMilliseconds) < tolerance)
- time = _profileEditorService.SelectedProfileElement.StartSegmentLength;
- }
+ time = _profileEditorService.SnapToTimeline(time, TimeSpan.FromMilliseconds(1000f / _profileEditorService.PixelsPerSecond * 5), false, true);
return time;
}
@@ -351,7 +348,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
_profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
_profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
if (_profileEditorService.SelectedProfileElement != null)
- _profileEditorService.SelectedProfileElement.PropertyChanged -= SelectedProfileElementOnPropertyChanged;
+ _profileEditorService.SelectedProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
}
#endregion