diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerPropertyKeyframe.cs b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerPropertyKeyframe.cs index d54a254a4..d0537d8b1 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerPropertyKeyframe.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerPropertyKeyframe.cs @@ -18,11 +18,6 @@ namespace Artemis.Core.Models.Profile.LayerProperties /// public BaseLayerProperty BaseLayerProperty { get; internal set; } - /// - /// The timeline this keyframe is contained in - /// - public abstract Timeline Timeline { get; set; } - /// /// The position of this keyframe in the timeline /// @@ -33,11 +28,4 @@ namespace Artemis.Core.Models.Profile.LayerProperties /// public Easings.Functions EasingFunction { get; set; } } - - public enum Timeline - { - Start, - Main, - End - } } \ 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 e3f255975..8595a084a 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs @@ -23,16 +23,10 @@ namespace Artemis.Core.Models.Profile.LayerProperties private T _currentValue; private bool _isInitialized; private List> _keyframes; - private List> _startKeyframes; - private List> _mainKeyframes; - private List> _endKeyframes; protected LayerProperty() { _keyframes = new List>(); - _startKeyframes = new List>(); - _mainKeyframes = new List>(); - _endKeyframes = new List>(); } /// @@ -90,7 +84,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties /// The value to set. /// /// An optional time to set the value add, if provided and property is using keyframes the value will be set to an new - /// or existing keyframe in the currently active timeline. + /// or existing keyframe. /// public void SetCurrentValue(T value, TimeSpan? time) { @@ -99,10 +93,10 @@ namespace Artemis.Core.Models.Profile.LayerProperties else { // If on a keyframe, update the keyframe - var currentKeyframe = Keyframes.FirstOrDefault(k => k.Position == time.Value && k.Timeline == ProfileElement.CurrentTimeline); + var currentKeyframe = Keyframes.FirstOrDefault(k => k.Position == time.Value); // Create a new keyframe if none found if (currentKeyframe == null) - AddKeyframe(new LayerPropertyKeyframe(value, time.Value, ProfileElement.CurrentTimeline, Easings.Functions.Linear, this)); + AddKeyframe(new LayerPropertyKeyframe(value, time.Value, Easings.Functions.Linear, this)); else currentKeyframe.Value = value; @@ -138,7 +132,6 @@ namespace Artemis.Core.Models.Profile.LayerProperties var newKeyframe = new LayerPropertyKeyframe( keyframe.Value, keyframe.Position, - keyframe.Timeline, keyframe.EasingFunction, keyframe.LayerProperty ); @@ -200,43 +193,23 @@ namespace Artemis.Core.Models.Profile.LayerProperties if (!KeyframesSupported || !KeyframesEnabled) return; - var keyframeSet = _keyframes; - if (ProfileElement.CurrentTimeline == Timeline.Start) - keyframeSet = _startKeyframes; - else if (ProfileElement.CurrentTimeline == Timeline.Main) - keyframeSet = _mainKeyframes; - else if (ProfileElement.CurrentTimeline == Timeline.End) - keyframeSet = _endKeyframes; - // The current keyframe is the last keyframe before the current time - CurrentKeyframe = keyframeSet.LastOrDefault(k => k.Position <= TimelineProgress); - - // If the current keyframe is null, try to find it in previous timelines - if (CurrentKeyframe == null && ProfileElement.CurrentTimeline == Timeline.Main) - CurrentKeyframe = _startKeyframes.LastOrDefault(); - else if (CurrentKeyframe == null && ProfileElement.CurrentTimeline == Timeline.End) - CurrentKeyframe = _mainKeyframes.LastOrDefault() ?? _startKeyframes.LastOrDefault(); - + CurrentKeyframe = _keyframes.LastOrDefault(k => k.Position <= TimelineProgress); // Keyframes are sorted by position so we can safely assume the next keyframe's position is after the current - var nextIndex = keyframeSet.IndexOf(CurrentKeyframe) + 1; - NextKeyframe = keyframeSet.Count > nextIndex ? keyframeSet[nextIndex] : null; + var nextIndex = _keyframes.IndexOf(CurrentKeyframe) + 1; + NextKeyframe = _keyframes.Count > nextIndex ? _keyframes[nextIndex] : null; // No need to update the current value if either of the keyframes are null if (CurrentKeyframe == null) - CurrentValue = keyframeSet.Any() ? keyframeSet[0].Value : BaseValue; + CurrentValue = _keyframes.Any() ? _keyframes[0].Value : BaseValue; else if (NextKeyframe == null) CurrentValue = CurrentKeyframe.Value; // Only determine progress and current value if both keyframes are present else { - // If the current keyframe belongs to a previous timeline, consider it starting at 0 - var currentKeyframePosition = CurrentKeyframe.Position; - if (CurrentKeyframe.Timeline != ProfileElement.CurrentTimeline) - currentKeyframePosition = TimeSpan.Zero; - - var timeDiff = NextKeyframe.Position - currentKeyframePosition; - var keyframeProgress = (float) ((TimelineProgress - currentKeyframePosition).TotalMilliseconds / timeDiff.TotalMilliseconds); - var keyframeProgressEased = (float) Easings.Interpolate(keyframeProgress, CurrentKeyframe.EasingFunction); + var timeDiff = NextKeyframe.Position - CurrentKeyframe.Position; + var keyframeProgress = (float)((TimelineProgress - CurrentKeyframe.Position).TotalMilliseconds / timeDiff.TotalMilliseconds); + var keyframeProgressEased = (float)Easings.Interpolate(keyframeProgress, CurrentKeyframe.EasingFunction); UpdateCurrentValue(keyframeProgress, keyframeProgressEased); } @@ -254,15 +227,11 @@ namespace Artemis.Core.Models.Profile.LayerProperties } /// - /// Sorts the keyframes in ascending order by position and divides the keyframes into different timelines + /// Sorts the keyframes in ascending order by position /// internal void SortKeyframes() { _keyframes = _keyframes.OrderBy(k => k.Position).ToList(); - - _startKeyframes = _keyframes.Where(k => k.Timeline == Timeline.Start).ToList(); - _mainKeyframes = _keyframes.Where(k => k.Timeline == Timeline.Main).ToList(); - _endKeyframes = _keyframes.Where(k => k.Timeline == Timeline.End).ToList(); } internal override void ApplyToLayerProperty(PropertyEntity entity, LayerPropertyGroup layerPropertyGroup, bool fromStorage) @@ -289,8 +258,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties _keyframes.AddRange(entity.KeyframeEntities.Select(k => new LayerPropertyKeyframe( JsonConvert.DeserializeObject(k.Value), k.Position, - (Timeline) k.Timeline, - (Easings.Functions) k.EasingFunction, + (Easings.Functions)k.EasingFunction, this ))); } @@ -319,8 +287,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties { Value = JsonConvert.SerializeObject(k.Value), Position = k.Position, - Timeline = (int) k.Timeline, - EasingFunction = (int) k.EasingFunction + EasingFunction = (int)k.EasingFunction })); } } diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs index 9f6791a80..af37209aa 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs @@ -6,12 +6,10 @@ namespace Artemis.Core.Models.Profile.LayerProperties public class LayerPropertyKeyframe : BaseLayerPropertyKeyframe { private TimeSpan _position; - private Timeline _timeline; - public LayerPropertyKeyframe(T value, TimeSpan position, Timeline timeline, Easings.Functions easingFunction, LayerProperty layerProperty) : base(layerProperty) + public LayerPropertyKeyframe(T value, TimeSpan position, Easings.Functions easingFunction, LayerProperty layerProperty) : base(layerProperty) { _position = position; - _timeline = timeline; Value = value; LayerProperty = layerProperty; EasingFunction = easingFunction; @@ -27,17 +25,6 @@ namespace Artemis.Core.Models.Profile.LayerProperties /// public T Value { get; set; } - /// - public override Timeline Timeline - { - get => _timeline; - set - { - _timeline = value; - LayerProperty.SortKeyframes(); - } - } - /// public override TimeSpan Position { diff --git a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs index a8aa76848..bbc5206ad 100644 --- a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs @@ -19,11 +19,6 @@ namespace Artemis.Core.Models.Profile private SKPath _path; internal abstract RenderElementEntity RenderElementEntity { get; } - /// - /// Gets or sets the currently active timeline - /// - public Timeline CurrentTimeline { get; set; } - /// /// Gets the path containing all the LEDs this entity is applied to, any rendering outside the entity Path is /// clipped. @@ -71,6 +66,66 @@ namespace Artemis.Core.Models.Profile #endregion + #region Timeline + + private TimeSpan _startSegmentLength; + private TimeSpan _mainSegmentLength; + private TimeSpan _endSegmentLength; + private bool _repeatMainSegment; + private bool _alwaysFinishTimeline; + + /// + /// Gets or sets the length of the start segment + /// + public TimeSpan StartSegmentLength + { + get => _startSegmentLength; + set => SetAndNotify(ref _startSegmentLength, value); + } + + /// + /// Gets or sets the length of the main segment + /// + public TimeSpan MainSegmentLength + { + get => _mainSegmentLength; + set => SetAndNotify(ref _mainSegmentLength, value); + } + + /// + /// Gets or sets the length of the end segment + /// + public TimeSpan EndSegmentLength + { + get => _endSegmentLength; + set => SetAndNotify(ref _endSegmentLength, value); + } + + /// + /// Gets the total combined length of all three segments + /// + public TimeSpan TimelineLength => StartSegmentLength + MainSegmentLength + EndSegmentLength; + + /// + /// Gets or sets whether main timeline should repeat itself as long as display conditions are met + /// + public bool RepeatMainSegment + { + get => _repeatMainSegment; + set => SetAndNotify(ref _repeatMainSegment, value); + } + + /// + /// Gets or sets whether the timeline should finish when conditions are no longer met + /// + public bool AlwaysFinishTimeline + { + get => _alwaysFinishTimeline; + set => SetAndNotify(ref _alwaysFinishTimeline, value); + } + + #endregion + #region Effects protected List _layerEffects; @@ -138,7 +193,7 @@ namespace Artemis.Core.Models.Profile #region Conditions private DisplayConditionGroup _displayConditionGroup; - + /// /// Gets or sets the root display condition group /// diff --git a/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs b/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs index 9f627d4ea..c1fa98e4e 100644 --- a/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using Artemis.Core.Models.Profile; -using Artemis.Core.Models.Profile.LayerProperties; using Artemis.Core.Plugins.Abstract; using Artemis.Core.Plugins.Models; using Artemis.UI.Shared.Events; @@ -15,7 +14,6 @@ namespace Artemis.UI.Shared.Services.Interfaces Profile SelectedProfile { get; } RenderProfileElement SelectedProfileElement { get; } TimeSpan CurrentTime { get; set; } - Timeline CurrentTimeline { get; set; } int PixelsPerSecond { get; set; } IReadOnlyList RegisteredPropertyEditors { get; } IKernel Kernel { get; } @@ -55,12 +53,7 @@ namespace Artemis.UI.Shared.Services.Interfaces /// Occurs when the current editor time is changed /// event EventHandler CurrentTimeChanged; - - /// - /// Occurs when the current editor timeline is changed - /// - event EventHandler CurrentTimelineChanged; - + /// /// Occurs when the pixels per second (zoom level) is changed /// diff --git a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs index ad64bc88b..a7a80f022 100644 --- a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs @@ -25,7 +25,6 @@ namespace Artemis.UI.Shared.Services private TimeSpan _currentTime; private TimeSpan _lastUpdateTime; private int _pixelsPerSecond; - private Timeline _currentTimeline; public ProfileEditorService(ICoreService coreService, IProfileService profileService, IKernel kernel, ILogger logger) { @@ -49,24 +48,15 @@ namespace Artemis.UI.Shared.Services set { if (_currentTime.Equals(value)) return; - _currentTime = value; + if (value > SelectedProfileElement.TimelineLength) + _currentTime = SelectedProfileElement.TimelineLength; + else + _currentTime = value; UpdateProfilePreview(); OnCurrentTimeChanged(); } } - public Timeline CurrentTimeline - { - get => _currentTimeline; - set - { - if (_currentTimeline.Equals(value)) return; - _currentTimeline = value; - UpdateProfilePreview(); - OnCurrentTimelineChanged(); - } - } - public int PixelsPerSecond { get => _pixelsPerSecond; @@ -126,14 +116,12 @@ namespace Artemis.UI.Shared.Services var delta = CurrentTime - _lastUpdateTime; foreach (var folder in SelectedProfile.GetAllFolders()) { - folder.CurrentTimeline = CurrentTimeline; foreach (var baseLayerEffect in folder.LayerEffects) baseLayerEffect.Update(delta.TotalSeconds); } foreach (var layer in SelectedProfile.GetAllLayers()) { - layer.CurrentTimeline = CurrentTimeline; layer.OverrideProgress(CurrentTime); layer.LayerBrush?.Update(delta.TotalSeconds); foreach (var baseLayerEffect in layer.LayerEffects) diff --git a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs index 46772a6c6..e9770db83 100644 --- a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs +++ b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs @@ -1,5 +1,6 @@ using Artemis.Core.Models.Profile; using Artemis.Core.Models.Profile.Conditions; +using Artemis.Core.Models.Profile.LayerProperties; using Artemis.Core.Models.Profile.LayerProperties.Attributes; using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Abstract; diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml index 9df02ef19..86b6758ec 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml @@ -30,9 +30,10 @@ - - - Play once + + + Play once + diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesView.xaml index 6b14a0e04..ea35b1e5a 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesView.xaml +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesView.xaml @@ -79,50 +79,49 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + @@ -135,7 +134,6 @@ - @@ -169,28 +167,58 @@ - - + + - + + + + + + - - + + - - + + + + Start + + + + + Main + + + + + End + + + + + @@ -201,17 +229,18 @@ HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" ScrollChanged="TimelineScrollChanged"> - - + - + - + + @@ -291,59 +320,15 @@ - - - - - - Select the enter timeline - Played when the folder/layer starts displaying (condition is met) - - - - - - ENTER - - - - - - - Select the main timeline - Played after the enter timeline finishes, either on repeat or once - - - - - - MAIN - - - - - - - Select the exit timeline - Played when the folder/layer stops displaying (conditon no longer met) - - - - - - - EXIT - - - - diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs index 0013113d6..9fb2daac5 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs @@ -27,14 +27,14 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties { private readonly ILayerPropertyVmFactory _layerPropertyVmFactory; private LayerPropertyGroupViewModel _brushPropertyGroup; - private bool _repeatAfterLastKeyframe; - private int _propertyTreeIndex; - private RenderProfileElement _selectedProfileElement; - private BindableCollection _layerPropertyGroups; - private TreeViewModel _treeViewModel; private EffectsViewModel _effectsViewModel; - private TimelineViewModel _timelineViewModel; + private BindableCollection _layerPropertyGroups; private bool _playing; + private int _propertyTreeIndex; + private bool _repeatAfterLastKeyframe; + private RenderProfileElement _selectedProfileElement; + private TimelineViewModel _timelineViewModel; + private TreeViewModel _treeViewModel; public LayerPropertiesViewModel(IProfileEditorService profileEditorService, ICoreService coreService, ISettingsService settingsService, ILayerPropertyVmFactory layerPropertyVmFactory) @@ -84,16 +84,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties } } - public int CurrentTimelineIndex - { - get => (int) ProfileEditorService.CurrentTimeline; - set - { - ProfileEditorService.CurrentTimeline = (Core.Models.Profile.LayerProperties.Timeline) value; - ProfileEditorService.CurrentTime = TimeSpan.Zero; - } - } - public bool PropertyTreeVisible => PropertyTreeIndex == 0; public RenderProfileElement SelectedProfileElement @@ -133,14 +123,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties get => _timelineViewModel; set => SetAndNotify(ref _timelineViewModel, value); } - + protected override void OnInitialActivate() { PopulateProperties(ProfileEditorService.SelectedProfileElement); ProfileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected; ProfileEditorService.CurrentTimeChanged += ProfileEditorServiceOnCurrentTimeChanged; - ProfileEditorService.CurrentTimelineChanged += ProfileEditorServiceOnCurrentTimelineChanged; ProfileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged; base.OnInitialActivate(); @@ -150,7 +139,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties { ProfileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected; ProfileEditorService.CurrentTimeChanged -= ProfileEditorServiceOnCurrentTimeChanged; - ProfileEditorService.CurrentTimelineChanged -= ProfileEditorServiceOnCurrentTimelineChanged; ProfileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged; PopulateProperties(null); @@ -171,6 +159,14 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e) { + // Placeholder + if (e.RenderProfileElement != null) + { + e.RenderProfileElement.StartSegmentLength = TimeSpan.FromMilliseconds(1000); + e.RenderProfileElement.MainSegmentLength = TimeSpan.FromMilliseconds(5000); + e.RenderProfileElement.EndSegmentLength = TimeSpan.FromMilliseconds(1000); + } + PopulateProperties(e.RenderProfileElement); } @@ -180,11 +176,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties NotifyOfPropertyChange(nameof(TimeCaretPosition)); } - private void ProfileEditorServiceOnCurrentTimelineChanged(object? sender, EventArgs e) - { - NotifyOfPropertyChange(nameof(CurrentTimelineIndex)); - TimelineViewModel.UpdateKeyframes(); - } private void ProfileEditorServiceOnPixelsPerSecondChanged(object sender, EventArgs e) { @@ -239,6 +230,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties } TreeViewModel = _layerPropertyVmFactory.TreeViewModel(this, LayerPropertyGroups); + + TimelineViewModel?.Dispose(); TimelineViewModel = _layerPropertyVmFactory.TimelineViewModel(this, LayerPropertyGroups); ApplyLayerBrush(); @@ -287,7 +280,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties } SortProperties(); - TimelineViewModel.UpdateKeyframes(); + UpdateKeyframes(); } private void ApplyEffects() @@ -322,7 +315,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties } SortProperties(); - TimelineViewModel.UpdateKeyframes(); + UpdateKeyframes(); } private void SortProperties() @@ -347,6 +340,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties } } + private void UpdateKeyframes() + { + TimelineViewModel.Update(); + } + #endregion #region Drag and drop diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/Controls/PropertyTimelineHeader.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/Controls/PropertyTimelineHeader.cs index 84fa4c76c..22490ddce 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/Controls/PropertyTimelineHeader.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/Controls/PropertyTimelineHeader.cs @@ -23,6 +23,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline public static readonly DependencyProperty VisibleWidthProperty = DependencyProperty.Register(nameof(VisibleWidth), typeof(double), typeof(PropertyTimelineHeader), new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsRender)); + public static readonly DependencyProperty OffsetFirstValueProperty = DependencyProperty.Register(nameof(OffsetFirstValue), typeof(bool), typeof(PropertyTimelineHeader), + new FrameworkPropertyMetadata(default(bool), FrameworkPropertyMetadataOptions.AffectsRender)); + private double _subd1; private double _subd2; private double _subd3; @@ -57,6 +60,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline set => SetValue(VisibleWidthProperty, value); } + public bool OffsetFirstValue + { + get => (bool) GetValue(OffsetFirstValueProperty); + set => SetValue(OffsetFirstValueProperty, value); + } + protected override void OnRender(DrawingContext drawingContext) { base.OnRender(drawingContext); @@ -73,7 +82,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline var count = (width + offsetUnits) / units; for (var i = 0; i < count; i++) { - var x = i * units - offsetUnits + 1; + var x = i * units - offsetUnits; // Add a 100px margin to allow the text to partially render when needed if (x < HorizontalOffset - 100 || x > HorizontalOffset + width) continue; @@ -95,8 +104,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline count = (width + offsetUnits) / units; for (var i = 0; i < count; i++) { - var x = i * units - offsetUnits + 1; - if (x > HorizontalOffset && x < HorizontalOffset + width) + var x = i * units - offsetUnits; + if (x == 0 && OffsetFirstValue) + drawingContext.DrawLine(linePen, new Point(1, 20), new Point(1, 30)); + else if (x > HorizontalOffset && x < HorizontalOffset + width) drawingContext.DrawLine(linePen, new Point(x, 20), new Point(x, 30)); } @@ -107,7 +118,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline for (var i = 0; i < count; i++) { if (Math.Abs(i % mul) < 0.001) continue; - var x = i * units - offsetUnits + 1; + var x = i * units - offsetUnits; if (x > HorizontalOffset && x < HorizontalOffset + width) drawingContext.DrawLine(linePen, new Point(x, 25), new Point(x, 30)); } @@ -117,8 +128,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline { var typeFace = new Typeface(FontFamily, new FontStyle(), new FontWeight(), new FontStretch()); var formattedText = new FormattedText(text, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeFace, 9, Fill, null, VisualTreeHelper.GetDpi(this).PixelsPerDip); - if (x == 1) - drawingContext.DrawText(formattedText, new Point(x, 2)); + if (x == 0 && OffsetFirstValue) + drawingContext.DrawText(formattedText, new Point(2, 2)); else drawingContext.DrawText(formattedText, new Point(x - formattedText.Width / 2, 2)); } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelineKeyframeViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelineKeyframeViewModel.cs index 6273574bf..8e320fd77 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelineKeyframeViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelineKeyframeViewModel.cs @@ -27,7 +27,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline var newKeyframe = new LayerPropertyKeyframe( LayerPropertyKeyframe.Value, LayerPropertyKeyframe.Position, - LayerPropertyKeyframe.Timeline, LayerPropertyKeyframe.EasingFunction, LayerPropertyKeyframe.LayerProperty ); diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyGroupViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyGroupViewModel.cs index 7d4dab2f6..881e40045 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyGroupViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyGroupViewModel.cs @@ -35,7 +35,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline { TimelineKeyframeViewModels.Clear(); TimelineKeyframeViewModels.AddRange(LayerPropertyGroupViewModel.GetKeyframes(false) - .Where(k => k.Timeline == _profileEditorService.CurrentTimeline) .Select(k => LayerPropertyGroupViewModel.ProfileEditorService.PixelsPerSecond * k.Position.TotalSeconds)); } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs index cfbb44aaa..2046a9e35 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs @@ -28,9 +28,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline // Only show keyframes if they are enabled if (LayerPropertyViewModel.LayerProperty.KeyframesEnabled) { - var keyframes = LayerPropertyViewModel.LayerProperty.Keyframes - .Where(k => k.Timeline == _profileEditorService.CurrentTimeline) - .ToList(); + var keyframes = LayerPropertyViewModel.LayerProperty.Keyframes.ToList(); var toRemove = TimelineKeyframeViewModels.Where(t => !keyframes.Contains(t.BaseLayerPropertyKeyframe)).ToList(); TimelineKeyframeViewModels.RemoveRange(toRemove); TimelineKeyframeViewModels.AddRange( diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelineView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelineView.xaml index 1e6549ac2..3878820b2 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelineView.xaml +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelineView.xaml @@ -9,11 +9,11 @@ d:DesignHeight="25" d:DesignWidth="800" d:DataContext="{d:DesignInstance local:TimelineViewModel}"> - + MouseMove="{s:Action TimelineCanvasMouseMove}"> @@ -41,6 +41,29 @@ + + + + layerPropertyGroups, - IProfileEditorService profileEditorService) + public TimelineViewModel(LayerPropertiesViewModel layerPropertiesViewModel, BindableCollection layerPropertyGroups, IProfileEditorService profileEditorService) { _layerPropertiesViewModel = layerPropertiesViewModel; _profileEditorService = profileEditorService; + LayerPropertyGroups = layerPropertyGroups; SelectionRectangle = new RectangleGeometry(); - UpdateKeyframes(); + _profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged; + + Update(); } public BindableCollection LayerPropertyGroups { get; } @@ -38,7 +40,19 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline set => SetAndNotify(ref _selectionRectangle, value); } - public void UpdateKeyframes() + public double StartSegmentWidth => _profileEditorService.PixelsPerSecond * _profileEditorService.SelectedProfileElement?.StartSegmentLength.TotalSeconds ?? 0; + public double StartSegmentEndPosition => StartSegmentWidth; + public double MainSegmentWidth => _profileEditorService.PixelsPerSecond * _profileEditorService.SelectedProfileElement?.MainSegmentLength.TotalSeconds ?? 0; + public double MainSegmentEndPosition => StartSegmentWidth + MainSegmentWidth; + public double EndSegmentWidth => _profileEditorService.PixelsPerSecond * _profileEditorService.SelectedProfileElement?.EndSegmentLength.TotalSeconds ?? 0; + public double EndSegmentEndPosition => StartSegmentWidth + MainSegmentWidth + EndSegmentWidth; + + public void Dispose() + { + _profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged; + } + + public void Update() { foreach (var layerPropertyGroupViewModel in LayerPropertyGroups) { @@ -52,6 +66,16 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline } } + private void ProfileEditorServiceOnPixelsPerSecondChanged(object sender, EventArgs e) + { + NotifyOfPropertyChange(nameof(StartSegmentWidth)); + NotifyOfPropertyChange(nameof(StartSegmentEndPosition)); + NotifyOfPropertyChange(nameof(MainSegmentWidth)); + NotifyOfPropertyChange(nameof(MainSegmentEndPosition)); + NotifyOfPropertyChange(nameof(EndSegmentWidth)); + NotifyOfPropertyChange(nameof(EndSegmentEndPosition)); + } + #region Command handlers public void KeyframeMouseDown(object sender, MouseButtonEventArgs e) @@ -274,5 +298,19 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline } #endregion + + #region IViewAware + + public void AttachView(UIElement view) + { + if (View != null) + throw new InvalidOperationException(string.Format("Tried to attach View {0} to ViewModel {1}, but it already has a view attached", view.GetType().Name, GetType().Name)); + + View = view; + } + + public UIElement View { get; set; } + + #endregion } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyViewModel.cs index 6e4017456..c0470e579 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyViewModel.cs @@ -50,7 +50,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree LayerPropertyViewModel.LayerProperty.AddKeyframe(new LayerPropertyKeyframe( LayerPropertyViewModel.LayerProperty.CurrentValue, _profileEditorService.CurrentTime, - _profileEditorService.CurrentTimeline, Easings.Functions.Linear, LayerPropertyViewModel.LayerProperty ));