Profile editor - Reimplemented more of the timeline

This commit is contained in:
SpoinkyNL committed 2020-09-11 22:30:57 +02:00
1 parent 56ba44dbce
commit a28b2fe2ea
24 files changed
+294 -296

No files matched your search

@@ -41,8 +41,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
{
KeyframePositions.Clear();
KeyframePositions.AddRange(LayerPropertyGroupViewModel
.GetAllKeyframePositions(false)
.Select(p => p.TotalSeconds * _profileEditorService.PixelsPerSecond));
.GetAllKeyframeViewModels(false)
.Select(p => p.Position.TotalSeconds * _profileEditorService.PixelsPerSecond));
}
}
}
@@ -7,7 +7,7 @@ using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
{
public class TimelineKeyframeViewModel<T> : Screen, IDisposable
public class TimelineKeyframeViewModel<T> : Screen, ITimelineKeyframeViewModel
{
private readonly IProfileEditorService _profileEditorService;
@@ -31,12 +31,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
set => SetAndNotify(ref _easingViewModels, value);
}
public bool IsSelected
{
get => _isSelected;
set => SetAndNotify(ref _isSelected, value);
}
public double X
{
get => _x;
@@ -49,6 +43,14 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
set => SetAndNotify(ref _timestamp, value);
}
public bool IsSelected
{
get => _isSelected;
set => SetAndNotify(ref _isSelected, value);
}
public TimeSpan Position => LayerPropertyKeyframe.Position;
public void Dispose()
{
LayerPropertyKeyframe.PropertyChanged -= LayerPropertyKeyframeOnPropertyChanged;
@@ -110,9 +112,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
_offset = null;
}
public void SaveOffsetToKeyframe(TimelineKeyframeViewModel<T> keyframeViewModel)
public void SaveOffsetToKeyframe(ITimelineKeyframeViewModel source)
{
if (keyframeViewModel == this)
if (source == this)
{
_offset = null;
return;
@@ -121,15 +123,15 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
if (_offset != null)
return;
_offset = LayerPropertyKeyframe.Position - keyframeViewModel.LayerPropertyKeyframe.Position;
_offset = LayerPropertyKeyframe.Position - source.Position;
}
public void ApplyOffsetToKeyframe(TimelineKeyframeViewModel<T> keyframeViewModel)
public void ApplyOffsetToKeyframe(ITimelineKeyframeViewModel source)
{
if (keyframeViewModel == this || _offset == null)
if (source == this || _offset == null)
return;
UpdatePosition(keyframeViewModel.LayerPropertyKeyframe.Position + _offset.Value);
UpdatePosition(source.Position + _offset.Value);
}
public void UpdatePosition(TimeSpan position)
@@ -148,6 +150,18 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
#region Context menu actions
public void ContextMenuOpening()
{
CreateEasingViewModels();
}
public void ContextMenuClosing()
{
foreach (var timelineEasingViewModel in EasingViewModels)
timelineEasingViewModel.EasingModeSelected -= TimelineEasingViewModelOnEasingModeSelected;
EasingViewModels.Clear();
}
public void Copy()
{
var newKeyframe = new LayerPropertyKeyframe<T>(
@@ -180,4 +194,26 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
#endregion
}
public interface ITimelineKeyframeViewModel : IScreen, IDisposable
{
bool IsSelected { get; set; }
TimeSpan Position { get; }
#region Movement
void SaveOffsetToKeyframe(ITimelineKeyframeViewModel source);
void ApplyOffsetToKeyframe(ITimelineKeyframeViewModel source);
void UpdatePosition(TimeSpan position);
void ReleaseMovement();
#endregion
#region Context menu actions
void Copy();
void Delete();
#endregion
}
}
@@ -21,9 +21,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
LayerPropertyViewModel = layerPropertyViewModel;
}
public List<TimeSpan> GetAllKeyframePositions()
public List<ITimelineKeyframeViewModel> GetAllKeyframeViewModels()
{
return LayerProperty.Keyframes.Select(k => k.Position).ToList();
return Items.Cast<ITimelineKeyframeViewModel>().ToList();
}
private void UpdateKeyframes()
@@ -49,6 +49,30 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
timelineKeyframeViewModel.Update();
}
public void WipeKeyframes(TimeSpan? start, TimeSpan? end)
{
start ??= TimeSpan.Zero;
end ??= TimeSpan.MaxValue;
var toShift = LayerProperty.Keyframes.Where(k => k.Position >= start && k.Position <= end).ToList();
foreach (var keyframe in toShift)
LayerProperty.RemoveKeyframe(keyframe);
UpdateKeyframes();
}
public void ShiftKeyframes(TimeSpan? start, TimeSpan? end, TimeSpan amount)
{
start ??= TimeSpan.Zero;
end ??= TimeSpan.MaxValue;
var toShift = LayerProperty.Keyframes.Where(k => k.Position >= start && k.Position <= end).ToList();
foreach (var keyframe in toShift)
keyframe.Position += amount;
UpdateKeyframes();
}
public void Dispose()
{
}
@@ -56,6 +80,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
public interface ITimelinePropertyViewModel : IScreen, IDisposable
{
List<TimeSpan> GetAllKeyframePositions();
List<ITimelineKeyframeViewModel> GetAllKeyframeViewModels();
void WipeKeyframes(TimeSpan? start, TimeSpan? end);
void ShiftKeyframes(TimeSpan? start, TimeSpan? end, TimeSpan amount);
}
}
@@ -18,10 +18,12 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
private bool _showRepeatButton;
private bool _showSegmentName;
public TimelineSegmentViewModel(IProfileEditorService profileEditorService, SegmentViewModelType segment)
public TimelineSegmentViewModel(SegmentViewModelType segment, BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups,
IProfileEditorService profileEditorService)
{
ProfileEditorService = profileEditorService;
Segment = segment;
LayerPropertyGroups = layerPropertyGroups;
SelectedProfileElement = ProfileEditorService.SelectedProfileElement;
switch (Segment)
@@ -47,6 +49,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
public RenderProfileElement SelectedProfileElement { get; }
public SegmentViewModelType Segment { get; }
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; }
public IProfileEditorService ProfileEditorService { get; }
public string ToolTip { get; }
@@ -130,7 +133,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
public void DisableSegment()
{
var keyframes = SelectedProfileElement.GetAllKeyframes();
var startSegmentEnd = SelectedProfileElement.StartSegmentLength;
var mainSegmentEnd = SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength;
@@ -139,22 +141,19 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
if (Segment == SegmentViewModelType.Start)
{
// Remove keyframes that fall in this segment
foreach (var baseLayerPropertyKeyframe in keyframes.Where(k => k.Position <= startSegmentEnd))
baseLayerPropertyKeyframe.Remove();
WipeKeyframes(null, startSegmentEnd);
SelectedProfileElement.StartSegmentLength = TimeSpan.Zero;
}
else if (Segment == SegmentViewModelType.Main)
{
// Remove keyframes that fall in this segment
foreach (var baseLayerPropertyKeyframe in keyframes.Where(k => k.Position > startSegmentEnd && k.Position <= mainSegmentEnd))
baseLayerPropertyKeyframe.Remove();
WipeKeyframes(startSegmentEnd, startSegmentEnd);
SelectedProfileElement.MainSegmentLength = TimeSpan.Zero;
}
else if (Segment == SegmentViewModelType.End)
{
// Remove keyframes that fall in this segment
foreach (var baseLayerPropertyKeyframe in keyframes.Where(k => k.Position > mainSegmentEnd))
baseLayerPropertyKeyframe.Remove();
WipeKeyframes(mainSegmentEnd, null);
SelectedProfileElement.EndSegmentLength = TimeSpan.Zero;
}
@@ -188,8 +187,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
else if (Segment == SegmentViewModelType.End)
segmentEnd = SelectedProfileElement.TimelineLength;
foreach (var baseLayerPropertyKeyframe in SelectedProfileElement.GetAllKeyframes().Where(k => k.Position > segmentEnd))
baseLayerPropertyKeyframe.Position += amount;
ShiftKeyframes(segmentEnd, null, amount);
}
public void SegmentMouseDown(object sender, MouseButtonEventArgs e)
@@ -227,7 +225,10 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
// If holding down shift, snap to the closest element on the timeline
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
newTime = ProfileEditorService.SnapToTimeline(newTime, TimeSpan.FromMilliseconds(1000f / ProfileEditorService.PixelsPerSecond * 5), false, true, true);
{
var keyframeTimes = LayerPropertyGroups.SelectMany(g => g.GetAllKeyframeViewModels(true)).Select(k => k.Position).ToList();
newTime = ProfileEditorService.SnapToTimeline(newTime, TimeSpan.FromMilliseconds(1000f / ProfileEditorService.PixelsPerSecond * 5), false, true, keyframeTimes);
}
// If holding down control, round to the closest 50ms
else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds / 50.0) * 50.0);
@@ -272,7 +273,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
NotifyOfPropertyChange(nameof(RepeatSegment));
}
private void ProfileEditorServiceOnPixelsPerSecondChanged(object? sender, EventArgs e)
{
NotifyOfPropertyChange(nameof(SegmentWidth));
@@ -291,6 +291,18 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
ShowRepeatButton = SegmentWidth > 45 && IsMainSegment;
ShowDisableButton = SegmentWidth > 25;
}
private void WipeKeyframes(TimeSpan? start, TimeSpan? end)
{
foreach (var layerPropertyGroupViewModel in LayerPropertyGroups)
layerPropertyGroupViewModel.WipeKeyframes(start, end);
}
private void ShiftKeyframes(TimeSpan? start, TimeSpan? end, TimeSpan amount)
{
foreach (var layerPropertyGroupViewModel in LayerPropertyGroups)
layerPropertyGroupViewModel.ShiftKeyframes(start, end, amount);
}
}
public enum SegmentViewModelType
@@ -14,7 +14,7 @@ using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
{
public class TimelineViewModel : PropertyChangedBase, IViewAware, IDisposable
public class TimelineViewModel : Screen, IDisposable
{
private readonly LayerPropertiesViewModel _layerPropertiesViewModel;
private readonly IProfileEditorService _profileEditorService;
@@ -105,7 +105,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
// if (e.LeftButton == MouseButtonState.Released)
// return;
var viewModel = (sender as Ellipse)?.DataContext as TimelineKeyframeViewModel;
var viewModel = (sender as Ellipse)?.DataContext as ITimelineKeyframeViewModel;
if (viewModel == null)
return;
@@ -130,7 +130,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
public void KeyframeMouseMove(object sender, MouseEventArgs e)
{
var viewModel = (sender as Ellipse)?.DataContext as TimelineKeyframeViewModel;
var viewModel = (sender as Ellipse)?.DataContext as ITimelineKeyframeViewModel;
if (viewModel == null)
return;
@@ -142,24 +142,12 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
#region Context menu actions
public void ContextMenuOpening(object sender, ContextMenuEventArgs e)
{
var viewModel = (sender as Ellipse)?.DataContext as TimelineKeyframeViewModel;
viewModel?.CreateEasingViewModels();
}
public void ContextMenuClosing(object sender, ContextMenuEventArgs e)
{
var viewModel = (sender as Ellipse)?.DataContext as TimelineKeyframeViewModel;
viewModel?.EasingViewModels.Clear();
}
public void Copy(TimelineKeyframeViewModel viewModel)
public void Copy(ITimelineKeyframeViewModel viewModel)
{
viewModel.Copy();
}
public void Delete(TimelineKeyframeViewModel viewModel)
public void Delete(ITimelineKeyframeViewModel viewModel)
{
viewModel.Delete();
}
@@ -198,7 +186,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
#region Keyframe movement
public void MoveSelectedKeyframes(TimeSpan cursorTime, TimelineKeyframeViewModel sourceKeyframeViewModel)
public void MoveSelectedKeyframes(TimeSpan cursorTime, ITimelineKeyframeViewModel sourceKeyframeViewModel)
{
// Ensure the selection rectangle doesn't show, the view isn't aware of different types of dragging
SelectionRectangle.Rect = new Rect();
@@ -214,8 +202,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
TimeSpan.FromMilliseconds(1000f / _profileEditorService.PixelsPerSecond * 5),
true,
false,
true,
sourceKeyframeViewModel.BaseLayerPropertyKeyframe
keyframeViewModels.Where(k => k != sourceKeyframeViewModel).Select(k => k.Position).ToList()
);
}
@@ -267,7 +254,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
SelectionRectangle.Rect = selectedRect;
var keyframeViewModels = GetAllKeyframeViewModels();
var selectedKeyframes = HitTestUtilities.GetHitViewModels<TimelineKeyframeViewModel>((Visual) sender, SelectionRectangle);
var selectedKeyframes = HitTestUtilities.GetHitViewModels<ITimelineKeyframeViewModel>((Visual) sender, SelectionRectangle);
foreach (var keyframeViewModel in keyframeViewModels)
keyframeViewModel.IsSelected = selectedKeyframes.Contains(keyframeViewModel);
@@ -287,7 +274,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
}
}
public void SelectKeyframe(TimelineKeyframeViewModel clicked, bool selectBetween, bool toggle)
public void SelectKeyframe(ITimelineKeyframeViewModel clicked, bool selectBetween, bool toggle)
{
var keyframeViewModels = GetAllKeyframeViewModels();
if (selectBetween)
@@ -329,33 +316,15 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
}
}
private List<TimelineKeyframeViewModel> GetAllKeyframeViewModels()
private List<ITimelineKeyframeViewModel> GetAllKeyframeViewModels()
{
var viewModels = new List<LayerPropertyBaseViewModel>();
var viewModels = new List<ITimelineKeyframeViewModel>();
foreach (var layerPropertyGroupViewModel in LayerPropertyGroups)
viewModels.AddRange(layerPropertyGroupViewModel.GetAllChildren());
var keyframes = viewModels.Where(vm => vm is LayerPropertyViewModel)
.SelectMany(vm => ((LayerPropertyViewModel) vm).TimelinePropertyBaseViewModel.TimelineKeyframeViewModels)
.ToList();
return keyframes;
viewModels.AddRange(layerPropertyGroupViewModel.GetAllKeyframeViewModels(false));
return viewModels;
}
#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
}
}