mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Added keyframe multiselect and group movement
This commit is contained in:
parent
4b1b0248f5
commit
b7da732920
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -29,6 +29,8 @@
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Ellipse Fill="{StaticResource PrimaryHueMidBrush}"
|
||||
Stroke="White"
|
||||
StrokeThickness="0"
|
||||
Width="10"
|
||||
Height="10"
|
||||
Margin="-5,6,0,0"
|
||||
@ -37,6 +39,28 @@
|
||||
MouseDown="{s:Action KeyframeMouseDown}"
|
||||
MouseUp="{s:Action KeyframeMouseUp}"
|
||||
MouseMove="{s:Action KeyframeMouseMove}">
|
||||
<Ellipse.Style>
|
||||
<Style TargetType="{x:Type Ellipse}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsSelected}" Value="True">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="StrokeThickness" To="1" Duration="0:0:0.25"></DoubleAnimation>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="StrokeThickness" To="0" Duration="0:0:0.25"></DoubleAnimation>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Ellipse.Style>
|
||||
<Ellipse.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Copy" Command="{s:Action Copy}">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user