mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Profiles - Removed the technical concept of extra timelines for events
Profiles - Properly separated out update and render logic Profile editor - Implemented layer visualization
This commit is contained in:
1 parent
ff4ec16690
commit
89beb92935
18 files changed
+431
-292
No files matched your search
@@ -158,8 +158,8 @@ namespace Artemis.Core
|
||||
// If the timeline was already running, look at the event overlap mode
|
||||
if (EventOverlapMode == TimeLineEventOverlapMode.Restart)
|
||||
timeline.JumpToStart();
|
||||
else if (EventOverlapMode == TimeLineEventOverlapMode.Copy)
|
||||
timeline.AddExtraTimeline();
|
||||
else if (EventOverlapMode == TimeLineEventOverlapMode.Copy && ProfileElement is Layer layer)
|
||||
layer.CreateCopyAsChild();
|
||||
else if (EventOverlapMode == TimeLineEventOverlapMode.Toggle && !wasMet)
|
||||
timeline.JumpToStart();
|
||||
|
||||
|
||||
@@ -102,6 +102,9 @@ namespace Artemis.Core
|
||||
else if (Timeline.IsFinished)
|
||||
Disable();
|
||||
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
||||
baseLayerEffect.InternalUpdate(Timeline);
|
||||
|
||||
foreach (ProfileElement child in Children)
|
||||
child.Update(deltaTime);
|
||||
}
|
||||
@@ -176,41 +179,35 @@ namespace Artemis.Core
|
||||
// No point rendering if all children are disabled
|
||||
if (!Children.Any(c => c is RenderProfileElement {Enabled: true}))
|
||||
return;
|
||||
|
||||
lock (Timeline)
|
||||
|
||||
SKPaint layerPaint = new() {FilterQuality = SKFilterQuality.Low};
|
||||
try
|
||||
{
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
||||
baseLayerEffect.InternalUpdate(Timeline);
|
||||
SKRectI rendererBounds = SKRectI.Create(0, 0, Bounds.Width, Bounds.Height);
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
||||
baseLayerEffect.InternalPreProcess(canvas, rendererBounds, layerPaint);
|
||||
|
||||
SKPaint layerPaint = new() {FilterQuality = SKFilterQuality.Low};
|
||||
try
|
||||
{
|
||||
SKRectI rendererBounds = SKRectI.Create(0, 0, Bounds.Width, Bounds.Height);
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
||||
baseLayerEffect.InternalPreProcess(canvas, rendererBounds, layerPaint);
|
||||
// No point rendering if the alpha was set to zero by one of the effects
|
||||
if (layerPaint.Color.Alpha == 0)
|
||||
return;
|
||||
|
||||
// No point rendering if the alpha was set to zero by one of the effects
|
||||
if (layerPaint.Color.Alpha == 0)
|
||||
return;
|
||||
canvas.SaveLayer(layerPaint);
|
||||
canvas.Translate(Bounds.Left - basePosition.X, Bounds.Top - basePosition.Y);
|
||||
|
||||
canvas.SaveLayer(layerPaint);
|
||||
canvas.Translate(Bounds.Left - basePosition.X, Bounds.Top - basePosition.Y);
|
||||
// Iterate the children in reverse because the first layer must be rendered last to end up on top
|
||||
for (int index = Children.Count - 1; index > -1; index--)
|
||||
Children[index].Render(canvas, new SKPointI(Bounds.Left, Bounds.Top));
|
||||
|
||||
// Iterate the children in reverse because the first layer must be rendered last to end up on top
|
||||
for (int index = Children.Count - 1; index > -1; index--)
|
||||
Children[index].Render(canvas, new SKPointI(Bounds.Left, Bounds.Top));
|
||||
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
||||
baseLayerEffect.InternalPostProcess(canvas, rendererBounds, layerPaint);
|
||||
}
|
||||
finally
|
||||
{
|
||||
canvas.Restore();
|
||||
layerPaint.DisposeSelfAndProperties();
|
||||
}
|
||||
|
||||
Timeline.ClearDelta();
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
||||
baseLayerEffect.InternalPostProcess(canvas, rendererBounds, layerPaint);
|
||||
}
|
||||
finally
|
||||
{
|
||||
canvas.Restore();
|
||||
layerPaint.DisposeSelfAndProperties();
|
||||
}
|
||||
|
||||
Timeline.ClearDelta();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -233,6 +230,14 @@ namespace Artemis.Core
|
||||
Enabled = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OverrideTimelineAndApply(TimeSpan position, bool stickToMainSegment)
|
||||
{
|
||||
Timeline.Override(position, stickToMainSegment);
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
||||
baseLayerEffect.InternalUpdate(Timeline);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Disable()
|
||||
{
|
||||
@@ -314,7 +319,7 @@ namespace Artemis.Core
|
||||
ChildrenList.Add(new Layer(Profile, this, childLayer));
|
||||
|
||||
// Ensure order integrity, should be unnecessary but no one is perfect specially me
|
||||
ChildrenList.Sort((a,b) => a.Order.CompareTo(b.Order));
|
||||
ChildrenList.Sort((a, b) => a.Order.CompareTo(b.Order));
|
||||
for (int index = 0; index < ChildrenList.Count; index++)
|
||||
ChildrenList[index].Order = index + 1;
|
||||
|
||||
|
||||
@@ -345,17 +345,30 @@ namespace Artemis.Core
|
||||
Enable();
|
||||
else if (Timeline.IsFinished)
|
||||
Disable();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Reset()
|
||||
{
|
||||
UpdateDisplayCondition();
|
||||
if (Timeline.Delta == TimeSpan.Zero)
|
||||
return;
|
||||
|
||||
if (DisplayConditionMet)
|
||||
Timeline.JumpToStart();
|
||||
else
|
||||
Timeline.JumpToEnd();
|
||||
General.Update(Timeline);
|
||||
Transform.Update(Timeline);
|
||||
LayerBrush?.InternalUpdate(Timeline);
|
||||
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
||||
baseLayerEffect.InternalUpdate(Timeline);
|
||||
|
||||
// Remove children that finished their timeline and update the rest
|
||||
for (int index = 0; index < Children.Count; index++)
|
||||
{
|
||||
ProfileElement profileElement = Children[index];
|
||||
if (((Layer) profileElement).Timeline.IsFinished)
|
||||
{
|
||||
RemoveChild(profileElement);
|
||||
profileElement.Dispose();
|
||||
index--;
|
||||
}
|
||||
else
|
||||
profileElement.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -365,88 +378,18 @@ namespace Artemis.Core
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
// Ensure the layer is ready
|
||||
if (!Enabled || Path == null || LayerShape?.Path == null || !General.PropertiesInitialized || !Transform.PropertiesInitialized)
|
||||
if (!Enabled || Path == null || LayerShape?.Path == null || !General.PropertiesInitialized || !Transform.PropertiesInitialized || !Leds.Any())
|
||||
return;
|
||||
|
||||
// Render children first so they go below
|
||||
for (int i = Children.Count - 1; i >= 0; i--)
|
||||
Children[i].Render(canvas, basePosition);
|
||||
|
||||
// Ensure the brush is ready
|
||||
if (LayerBrush == null || LayerBrush?.BaseProperties?.PropertiesInitialized == false)
|
||||
return;
|
||||
|
||||
RenderTimeline(Timeline, canvas, basePosition);
|
||||
foreach (Timeline extraTimeline in Timeline.ExtraTimelines.ToList())
|
||||
RenderTimeline(extraTimeline, canvas, basePosition);
|
||||
Timeline.ClearDelta();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Enable()
|
||||
{
|
||||
if (Enabled)
|
||||
return;
|
||||
|
||||
bool tryOrBreak = TryOrBreak(() => LayerBrush?.InternalEnable(), "Failed to enable layer brush");
|
||||
if (!tryOrBreak)
|
||||
return;
|
||||
|
||||
tryOrBreak = TryOrBreak(() =>
|
||||
{
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects)
|
||||
baseLayerEffect.InternalEnable();
|
||||
}, "Failed to enable one or more effects");
|
||||
if (!tryOrBreak)
|
||||
return;
|
||||
|
||||
Enabled = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Activate()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Deactivate()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Disable()
|
||||
{
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
LayerBrush?.InternalDisable();
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects)
|
||||
baseLayerEffect.InternalDisable();
|
||||
|
||||
Enabled = false;
|
||||
}
|
||||
|
||||
private void ApplyTimeline(Timeline timeline)
|
||||
{
|
||||
if (timeline.Delta == TimeSpan.Zero)
|
||||
return;
|
||||
|
||||
General.Update(timeline);
|
||||
Transform.Update(timeline);
|
||||
LayerBrush?.InternalUpdate(timeline);
|
||||
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
||||
baseLayerEffect.InternalUpdate(timeline);
|
||||
}
|
||||
|
||||
private void RenderTimeline(Timeline timeline, SKCanvas canvas, SKPointI basePosition)
|
||||
{
|
||||
if (Path == null || LayerBrush == null)
|
||||
throw new ArtemisCoreException("The layer is not yet ready for rendering");
|
||||
|
||||
if (!Leds.Any() || timeline.IsFinished)
|
||||
return;
|
||||
|
||||
ApplyTimeline(timeline);
|
||||
|
||||
if (LayerBrush?.BrushType != LayerBrushType.Regular)
|
||||
if (Timeline.IsFinished || LayerBrush?.BrushType != LayerBrushType.Regular)
|
||||
return;
|
||||
|
||||
SKPaint layerPaint = new() {FilterQuality = SKFilterQuality.Low};
|
||||
@@ -501,34 +444,96 @@ namespace Artemis.Core
|
||||
canvas.Restore();
|
||||
layerPaint.DisposeSelfAndProperties();
|
||||
}
|
||||
|
||||
Timeline.ClearDelta();
|
||||
}
|
||||
|
||||
private void DelegateRendering(SKCanvas canvas, SKPath renderPath, SKRect bounds, SKPaint layerPaint)
|
||||
/// <inheritdoc />
|
||||
public override void Enable()
|
||||
{
|
||||
if (LayerBrush == null)
|
||||
throw new ArtemisCoreException("The layer is not yet ready for rendering");
|
||||
if (Enabled)
|
||||
return;
|
||||
|
||||
bool tryOrBreak = TryOrBreak(() => LayerBrush?.InternalEnable(), "Failed to enable layer brush");
|
||||
if (!tryOrBreak)
|
||||
return;
|
||||
|
||||
tryOrBreak = TryOrBreak(() =>
|
||||
{
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects)
|
||||
baseLayerEffect.InternalEnable();
|
||||
}, "Failed to enable one or more effects");
|
||||
if (!tryOrBreak)
|
||||
return;
|
||||
|
||||
Enabled = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OverrideTimelineAndApply(TimeSpan position, bool stickToMainSegment)
|
||||
{
|
||||
Timeline.Override(position, stickToMainSegment);
|
||||
|
||||
General.Update(Timeline);
|
||||
Transform.Update(Timeline);
|
||||
LayerBrush?.InternalUpdate(Timeline);
|
||||
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
||||
baseLayerEffect.InternalPreProcess(canvas, bounds, layerPaint);
|
||||
baseLayerEffect.InternalUpdate(Timeline);
|
||||
}
|
||||
|
||||
try
|
||||
/// <inheritdoc />
|
||||
public override void Activate()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Deactivate()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Disable()
|
||||
{
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
LayerBrush?.InternalDisable();
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects)
|
||||
baseLayerEffect.InternalDisable();
|
||||
|
||||
Enabled = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Reset()
|
||||
{
|
||||
UpdateDisplayCondition();
|
||||
|
||||
if (DisplayConditionMet)
|
||||
Timeline.JumpToStart();
|
||||
else
|
||||
Timeline.JumpToEnd();
|
||||
|
||||
while (Children.Any())
|
||||
{
|
||||
canvas.SaveLayer(layerPaint);
|
||||
canvas.ClipPath(renderPath);
|
||||
|
||||
// Restore the blend mode before doing the actual render
|
||||
layerPaint.BlendMode = SKBlendMode.SrcOver;
|
||||
|
||||
LayerBrush.InternalRender(canvas, bounds, layerPaint);
|
||||
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
||||
baseLayerEffect.InternalPostProcess(canvas, bounds, layerPaint);
|
||||
Children[0].Dispose();
|
||||
RemoveChild(Children[0]);
|
||||
}
|
||||
}
|
||||
|
||||
finally
|
||||
{
|
||||
canvas.Restore();
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a copy of this layer as a child and plays it once
|
||||
/// </summary>
|
||||
public void CreateCopyAsChild()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
// Create a copy of the layer and it's properties
|
||||
|
||||
// Add to children
|
||||
}
|
||||
|
||||
internal void CalculateRenderProperties()
|
||||
@@ -582,6 +587,34 @@ namespace Artemis.Core
|
||||
return position;
|
||||
}
|
||||
|
||||
private void DelegateRendering(SKCanvas canvas, SKPath renderPath, SKRect bounds, SKPaint layerPaint)
|
||||
{
|
||||
if (LayerBrush == null)
|
||||
throw new ArtemisCoreException("The layer is not yet ready for rendering");
|
||||
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
||||
baseLayerEffect.InternalPreProcess(canvas, bounds, layerPaint);
|
||||
|
||||
try
|
||||
{
|
||||
canvas.SaveLayer(layerPaint);
|
||||
canvas.ClipPath(renderPath);
|
||||
|
||||
// Restore the blend mode before doing the actual render
|
||||
layerPaint.BlendMode = SKBlendMode.SrcOver;
|
||||
|
||||
LayerBrush.InternalRender(canvas, bounds, layerPaint);
|
||||
|
||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => !e.Suspended))
|
||||
baseLayerEffect.InternalPostProcess(canvas, bounds, layerPaint);
|
||||
}
|
||||
|
||||
finally
|
||||
{
|
||||
canvas.Restore();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a transformation matrix that applies the current transformation settings
|
||||
/// </summary>
|
||||
|
||||
@@ -49,6 +49,12 @@ namespace Artemis.Core
|
||||
Keyframes = new ReadOnlyCollection<LayerPropertyKeyframe<T>>(_keyframes);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Path} - {CurrentValue} ({PropertyType})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
|
||||
/// </summary>
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace Artemis.Core
|
||||
/// Updates the <see cref="Timeline" /> according to the provided <paramref name="deltaTime" /> and current display
|
||||
/// condition status
|
||||
/// </summary>
|
||||
public void UpdateTimeline(double deltaTime)
|
||||
protected void UpdateTimeline(double deltaTime)
|
||||
{
|
||||
// TODO: Move to conditions
|
||||
|
||||
@@ -327,7 +327,7 @@ namespace Artemis.Core
|
||||
|
||||
OrderEffects();
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal void ActivateLayerEffect(BaseLayerEffect layerEffect)
|
||||
{
|
||||
@@ -406,5 +406,12 @@ namespace Artemis.Core
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the main timeline to the specified time and clears any extra time lines
|
||||
/// </summary>
|
||||
/// <param name="position">The position to set the timeline to</param>
|
||||
/// <param name="stickToMainSegment">Whether to stick to the main segment, wrapping around if needed</param>
|
||||
public abstract void OverrideTimelineAndApply(TimeSpan position, bool stickToMainSegment);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ namespace Artemis.Core;
|
||||
/// </summary>
|
||||
public class Timeline : CorePropertyChanged, IStorageModel
|
||||
{
|
||||
private const int MaxExtraTimelines = 15;
|
||||
private readonly object _lock = new();
|
||||
|
||||
/// <summary>
|
||||
@@ -21,78 +20,33 @@ public class Timeline : CorePropertyChanged, IStorageModel
|
||||
{
|
||||
Entity = new TimelineEntity();
|
||||
MainSegmentLength = TimeSpan.FromSeconds(5);
|
||||
|
||||
_extraTimelines = new List<Timeline>();
|
||||
ExtraTimelines = new ReadOnlyCollection<Timeline>(_extraTimelines);
|
||||
|
||||
|
||||
Save();
|
||||
}
|
||||
|
||||
internal Timeline(TimelineEntity entity)
|
||||
{
|
||||
Entity = entity;
|
||||
_extraTimelines = new List<Timeline>();
|
||||
ExtraTimelines = new ReadOnlyCollection<Timeline>(_extraTimelines);
|
||||
|
||||
Load();
|
||||
}
|
||||
|
||||
private Timeline(Timeline parent)
|
||||
{
|
||||
Entity = new TimelineEntity();
|
||||
Parent = parent;
|
||||
StartSegmentLength = Parent.StartSegmentLength;
|
||||
MainSegmentLength = Parent.MainSegmentLength;
|
||||
EndSegmentLength = Parent.EndSegmentLength;
|
||||
|
||||
_extraTimelines = new List<Timeline>();
|
||||
ExtraTimelines = new ReadOnlyCollection<Timeline>(_extraTimelines);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Progress: {Position}/{Length} - delta: {Delta}";
|
||||
}
|
||||
|
||||
#region Extra timelines
|
||||
|
||||
/// <summary>
|
||||
/// Adds an extra timeline to this timeline
|
||||
/// </summary>
|
||||
public void AddExtraTimeline()
|
||||
{
|
||||
_extraTimelines.Add(new Timeline(this));
|
||||
if (_extraTimelines.Count > MaxExtraTimelines)
|
||||
_extraTimelines.RemoveAt(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all extra timelines from this timeline
|
||||
/// </summary>
|
||||
public void ClearExtraTimelines()
|
||||
{
|
||||
_extraTimelines.Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Properties
|
||||
|
||||
private TimeSpan _position;
|
||||
private TimeSpan _lastDelta;
|
||||
private TimelinePlayMode _playMode;
|
||||
private TimelineStopMode _stopMode;
|
||||
private readonly List<Timeline> _extraTimelines;
|
||||
private TimeSpan _startSegmentLength;
|
||||
private TimeSpan _mainSegmentLength;
|
||||
private TimeSpan _endSegmentLength;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent this timeline is an extra timeline of
|
||||
/// </summary>
|
||||
public Timeline? Parent { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current position of the timeline
|
||||
/// </summary>
|
||||
@@ -105,21 +59,13 @@ public class Timeline : CorePropertyChanged, IStorageModel
|
||||
/// <summary>
|
||||
/// Gets the cumulative delta of all calls to <see cref="Update" /> that took place after the last call to
|
||||
/// <see cref="ClearDelta" />
|
||||
/// <para>
|
||||
/// Note: If this is an extra timeline <see cref="Delta" /> is always equal to <see cref="DeltaToParent" />
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public TimeSpan Delta
|
||||
{
|
||||
get => Parent == null ? _lastDelta : DeltaToParent;
|
||||
get => _lastDelta;
|
||||
private set => SetAndNotify(ref _lastDelta, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the delta to this timeline's <see cref="Parent" />
|
||||
/// </summary>
|
||||
public TimeSpan DeltaToParent => Parent != null ? Position - Parent.Position : TimeSpan.Zero;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the mode in which the render element starts its timeline when display conditions are met
|
||||
/// </summary>
|
||||
@@ -138,15 +84,10 @@ public class Timeline : CorePropertyChanged, IStorageModel
|
||||
set => SetAndNotify(ref _stopMode, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of extra copies of the timeline applied to this timeline
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<Timeline> ExtraTimelines { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether the timeline has finished its run
|
||||
/// </summary>
|
||||
public bool IsFinished => Position > Length && !ExtraTimelines.Any();
|
||||
public bool IsFinished => Position > Length;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether the timeline progress has been overridden
|
||||
@@ -327,19 +268,15 @@ public class Timeline : CorePropertyChanged, IStorageModel
|
||||
IsOverridden = false;
|
||||
_lastOverridePosition = Position;
|
||||
|
||||
if (stickToMainSegment && Position > MainSegmentEndPosition)
|
||||
{
|
||||
// If the main segment has no length, simply stick to the start of the segment
|
||||
if (MainSegmentLength == TimeSpan.Zero)
|
||||
Position = MainSegmentStartPosition;
|
||||
// Ensure wrapping back around retains the delta time
|
||||
else
|
||||
Position = MainSegmentStartPosition + TimeSpan.FromMilliseconds(delta.TotalMilliseconds % MainSegmentLength.TotalMilliseconds);
|
||||
}
|
||||
if (!stickToMainSegment || Position <= MainSegmentEndPosition)
|
||||
return;
|
||||
|
||||
_extraTimelines.RemoveAll(t => t.IsFinished);
|
||||
foreach (Timeline extraTimeline in _extraTimelines)
|
||||
extraTimeline.Update(delta, false);
|
||||
// If the main segment has no length, simply stick to the start of the segment
|
||||
if (MainSegmentLength == TimeSpan.Zero)
|
||||
Position = MainSegmentStartPosition;
|
||||
// Ensure wrapping back around retains the delta time
|
||||
else
|
||||
Position = MainSegmentStartPosition + TimeSpan.FromMilliseconds(delta.TotalMilliseconds % MainSegmentLength.TotalMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,11 +326,11 @@ public class Timeline : CorePropertyChanged, IStorageModel
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the <see cref="Position" /> to the specified time and clears any extra time lines
|
||||
/// Overrides the <see cref="Position" /> to the specified time
|
||||
/// </summary>
|
||||
/// <param name="position">The position to set the timeline to</param>
|
||||
/// <param name="stickToMainSegment">Whether to stick to the main segment, wrapping around if needed</param>
|
||||
public void Override(TimeSpan position, bool stickToMainSegment)
|
||||
internal void Override(TimeSpan position, bool stickToMainSegment)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
@@ -403,24 +340,22 @@ public class Timeline : CorePropertyChanged, IStorageModel
|
||||
IsOverridden = true;
|
||||
_lastOverridePosition = position;
|
||||
|
||||
if (stickToMainSegment && Position >= MainSegmentStartPosition)
|
||||
{
|
||||
bool atSegmentStart = Position == MainSegmentStartPosition;
|
||||
if (MainSegmentLength > TimeSpan.Zero)
|
||||
{
|
||||
Position = MainSegmentStartPosition + TimeSpan.FromMilliseconds(Position.TotalMilliseconds % MainSegmentLength.TotalMilliseconds);
|
||||
// If the cursor is at the end of the timeline we don't want to wrap back around yet so only allow going to the start if the cursor
|
||||
// is actually at the start of the segment
|
||||
if (Position == MainSegmentStartPosition && !atSegmentStart)
|
||||
Position = MainSegmentEndPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
Position = MainSegmentStartPosition;
|
||||
}
|
||||
}
|
||||
if (!stickToMainSegment || Position < MainSegmentStartPosition)
|
||||
return;
|
||||
|
||||
_extraTimelines.Clear();
|
||||
bool atSegmentStart = Position == MainSegmentStartPosition;
|
||||
if (MainSegmentLength > TimeSpan.Zero)
|
||||
{
|
||||
Position = MainSegmentStartPosition + TimeSpan.FromMilliseconds(Position.TotalMilliseconds % MainSegmentLength.TotalMilliseconds);
|
||||
// If the cursor is at the end of the timeline we don't want to wrap back around yet so only allow going to the start if the cursor
|
||||
// is actually at the start of the segment
|
||||
if (Position == MainSegmentStartPosition && !atSegmentStart)
|
||||
Position = MainSegmentEndPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
Position = MainSegmentStartPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user