From b7da73292058220b2e3237ba4ccc96e01926c5cf Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 17 Feb 2020 20:28:13 +0100 Subject: [PATCH] Added keyframe multiselect and group movement --- .../Timeline/PropertyTimelineViewModel.cs | 58 +++++++++++++++++++ .../PropertyTrackKeyframeViewModel.cs | 30 +++++----- .../Timeline/PropertyTrackView.xaml | 24 ++++++++ 3 files changed, 96 insertions(+), 16 deletions(-) diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTimelineViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTimelineViewModel.cs index 9842485a5..5c196db08 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTimelineViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTimelineViewModel.cs @@ -94,5 +94,63 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline foreach (var child in property.Children) CreateViewModels(child); } + + public void SelectKeyframe(PropertyTrackKeyframeViewModel clicked, bool selectBetween, bool toggle) + { + var keyframeViewModels = PropertyTrackViewModels.SelectMany(t => t.KeyframeViewModels.OrderBy(k => k.Keyframe.Position)).ToList(); + if (selectBetween) + { + var selectedIndex = keyframeViewModels.FindIndex(k => k.IsSelected); + // If nothing is selected, select only the clicked + if (selectedIndex == -1) + { + clicked.IsSelected = true; + return; + } + + foreach (var keyframeViewModel in keyframeViewModels) + keyframeViewModel.IsSelected = false; + + var clickedIndex = keyframeViewModels.IndexOf(clicked); + if (clickedIndex < selectedIndex) + { + foreach (var keyframeViewModel in keyframeViewModels.Skip(clickedIndex).Take(selectedIndex - clickedIndex + 1)) + keyframeViewModel.IsSelected = true; + } + else + { + foreach (var keyframeViewModel in keyframeViewModels.Skip(selectedIndex).Take(clickedIndex - selectedIndex + 1)) + keyframeViewModel.IsSelected = true; + } + } + else if (toggle) + { + // Toggle only the clicked keyframe, leave others alone + clicked.IsSelected = !clicked.IsSelected; + } + else + { + // Only select the clicked keyframe + foreach (var keyframeViewModel in keyframeViewModels) + keyframeViewModel.IsSelected = false; + clicked.IsSelected = true; + } + } + + public void MoveSelectedKeyframes(TimeSpan offset) + { + var keyframeViewModels = PropertyTrackViewModels.SelectMany(t => t.KeyframeViewModels.OrderBy(k => k.Keyframe.Position)).ToList(); + foreach (var keyframeViewModel in keyframeViewModels.Where(k => k.IsSelected)) + { + // TODO: Not ideal as this stacks them all if they get to 0, oh well + if (keyframeViewModel.Keyframe.Position + offset > TimeSpan.Zero) + { + keyframeViewModel.Keyframe.Position += offset; + keyframeViewModel.Update(LayerPropertiesViewModel.PixelsPerSecond); + } + } + + _profileEditorService.UpdateProfilePreview(); + } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackKeyframeViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackKeyframeViewModel.cs index 800a34045..811a49e66 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackKeyframeViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackKeyframeViewModel.cs @@ -46,6 +46,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline public void KeyframeMouseDown(object sender, MouseButtonEventArgs e) { + if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift) && !IsSelected) + PropertyTrackViewModel.PropertyTimelineViewModel.SelectKeyframe(this, true, false); + else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) + PropertyTrackViewModel.PropertyTimelineViewModel.SelectKeyframe(this, false, true); + else if (!IsSelected) + PropertyTrackViewModel.PropertyTimelineViewModel.SelectKeyframe(this, false, false); + ((IInputElement) sender).CaptureMouse(); } @@ -71,25 +78,16 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline else newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds)); - if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift)) - { - Keyframe.Position = newTime; - - Update(_pixelsPerSecond); - _profileEditorService.UpdateProfilePreview(); - return; - } - // If shift is held, snap to the current time // Take a tolerance of 5 pixels (half a keyframe width) - var tolerance = 1000f / _pixelsPerSecond * 5; - if (Math.Abs(_profileEditorService.CurrentTime.TotalMilliseconds - newTime.TotalMilliseconds) < tolerance) - Keyframe.Position = _profileEditorService.CurrentTime; - else - Keyframe.Position = newTime; + if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)) + { + var tolerance = 1000f / _pixelsPerSecond * 5; + if (Math.Abs(_profileEditorService.CurrentTime.TotalMilliseconds - newTime.TotalMilliseconds) < tolerance) + newTime = _profileEditorService.CurrentTime; + } - Update(_pixelsPerSecond); - _profileEditorService.UpdateProfilePreview(); + PropertyTrackViewModel.PropertyTimelineViewModel.MoveSelectedKeyframes(newTime - Keyframe.Position); } } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackView.xaml index c86f4cd8e..f50ebdd43 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackView.xaml +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/PropertyTrackView.xaml @@ -29,6 +29,8 @@ + + +