Added keyframe creation outside the timeline

Added existing shape moving
This commit is contained in:
SpoinkyNL committed 2020-01-13 22:11:25 +01:00
1 parent a138ec916d
commit 7ddf816ca5
22 files changed
+178 -148

No files matched your search

@@ -40,25 +40,25 @@
<!-- Misc controls & time display -->
<DockPanel Grid.Row="0" VerticalAlignment="Center">
<StackPanel Orientation="Horizontal">
<Button Style="{StaticResource MaterialDesignIconForegroundButton}" ToolTip="Play from start (Shift+Space)" Command="{s:Action PlayFromStart}">
<Button Style="{StaticResource MaterialDesignIconForegroundButton}" ToolTip="Play from start (Shift+Space)" Command="{s:Action PlayFromStart}" Focusable="False">
<materialDesign:PackIcon Kind="StepForward" />
</Button>
<Button Style="{StaticResource MaterialDesignIconForegroundButton}" ToolTip="Toggle play/pause (Space)" Command="{s:Action Play}">
<Button Style="{StaticResource MaterialDesignIconForegroundButton}" ToolTip="Toggle play/pause (Space)" Command="{s:Action Play}" Focusable="False">
<StackPanel>
<materialDesign:PackIcon Kind="Play" Visibility="{Binding Playing, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}" />
<materialDesign:PackIcon Kind="Pause" Visibility="{Binding Playing, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}" />
</StackPanel>
</Button>
<Button Style="{StaticResource MaterialDesignIconForegroundButton}" ToolTip="Go to start" Command="{s:Action GoToStart}">
<Button Style="{StaticResource MaterialDesignIconForegroundButton}" ToolTip="Go to start" Command="{s:Action GoToStart}" Focusable="False">
<materialDesign:PackIcon Kind="SkipBackward" />
</Button>
<Button Style="{StaticResource MaterialDesignIconForegroundButton}" ToolTip="Go to end" Command="{s:Action GoToEnd}">
<Button Style="{StaticResource MaterialDesignIconForegroundButton}" ToolTip="Go to end" Command="{s:Action GoToEnd}" Focusable="False">
<materialDesign:PackIcon Kind="SkipForward" />
</Button>
<Button Style="{StaticResource MaterialDesignIconForegroundButton}" ToolTip="Previous frame" Command="{s:Action GoToPreviousFrame}">
<Button Style="{StaticResource MaterialDesignIconForegroundButton}" ToolTip="Previous frame" Command="{s:Action GoToPreviousFrame}" Focusable="False">
<materialDesign:PackIcon Kind="SkipPrevious" />
</Button>
<Button Style="{StaticResource MaterialDesignIconForegroundButton}" ToolTip="Next frame" Command="{s:Action GoToNextFrame}">
<Button Style="{StaticResource MaterialDesignIconForegroundButton}" ToolTip="Next frame" Command="{s:Action GoToNextFrame}" Focusable="False">
<materialDesign:PackIcon Kind="SkipNext" />
</Button>
</StackPanel>
@@ -19,7 +19,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
{
_kernel = kernel;
_profileEditorService = profileEditorService;
_keyframesEnabled = layerProperty.UntypedKeyframes.Any();
_keyframesEnabled = layerProperty.IsUsingKeyframes;
LayerProperty = layerProperty;
Parent = parent;
@@ -56,6 +56,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
LayerProperty.ClearKeyframes();
// Force the keyframe engine to update, the new keyframe is the current keyframe
LayerProperty.IsUsingKeyframes = _keyframesEnabled;
LayerProperty.KeyframeEngine.Update(0);
_profileEditorService.UpdateSelectedProfileElement();
@@ -15,7 +15,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
public float FloatInputValue
{
get => (float) InputValue;
get => (float?) InputValue ?? 0f;
set => InputValue = value;
}
@@ -23,17 +23,5 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
{
NotifyOfPropertyChange(() => FloatInputValue);
}
protected override void UpdateBaseValue(object value)
{
var layerProperty = (LayerProperty<float>) LayerPropertyViewModel.LayerProperty;
layerProperty.Value = (float) value;
}
protected override void UpdateKeyframeValue(BaseKeyframe baseKeyframe, object value)
{
var keyframe = (Keyframe<float>) baseKeyframe;
keyframe.Value = (float) value;
}
}
}
@@ -15,7 +15,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
public int IntInputValue
{
get => (int) InputValue;
get => (int?) InputValue ?? 0;
set => InputValue = value;
}
@@ -23,17 +23,5 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
{
NotifyOfPropertyChange(() => IntInputValue);
}
protected override void UpdateBaseValue(object value)
{
var layerProperty = (LayerProperty<int>) LayerPropertyViewModel.LayerProperty;
layerProperty.Value = (int) value;
}
protected override void UpdateKeyframeValue(BaseKeyframe baseKeyframe, object value)
{
var keyframe = (Keyframe<int>) baseKeyframe;
keyframe.Value = (int) value;
}
}
}
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.UI.Exceptions;
using Artemis.UI.Services.Interfaces;
using Stylet;
@@ -43,29 +42,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
private void UpdateInputValue(object value)
{
// If keyframes are disabled, update the base value
if (!LayerPropertyViewModel.KeyframesEnabled)
{
UpdateBaseValue(value);
return;
}
// If on a keyframe, update the keyframe
var currentKeyframe = LayerPropertyViewModel.LayerProperty.UntypedKeyframes.FirstOrDefault(k => k.Position == ProfileEditorService.CurrentTime);
// Create a new keyframe if none found
if (currentKeyframe == null)
currentKeyframe = LayerPropertyViewModel.LayerProperty.CreateNewKeyframe(ProfileEditorService.CurrentTime);
UpdateKeyframeValue(currentKeyframe, value);
LayerPropertyViewModel.LayerProperty.SetCurrentValue(value, ProfileEditorService.CurrentTime);
// Force the keyframe engine to update, the edited keyframe might affect the current keyframe progress
LayerPropertyViewModel.LayerProperty.KeyframeEngine.Update(0);
ProfileEditorService.UpdateSelectedProfileElement();
}
public abstract void Update();
protected abstract void UpdateBaseValue(object value);
protected abstract void UpdateKeyframeValue(BaseKeyframe baseKeyframe, object value);
}
}
@@ -19,14 +19,14 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
[DependsOn(nameof(InputValue))]
public float X
{
get => ((SKPoint) InputValue).X;
get => ((SKPoint?) InputValue)?.X ?? 0;
set => InputValue = new SKPoint(value, Y);
}
[DependsOn(nameof(InputValue))]
public float Y
{
get => ((SKPoint) InputValue).Y;
get => ((SKPoint?)InputValue)?.Y ?? 0;
set => InputValue = new SKPoint(X, value);
}
@@ -35,17 +35,5 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
NotifyOfPropertyChange(() => X);
NotifyOfPropertyChange(() => Y);
}
protected override void UpdateBaseValue(object value)
{
var layerProperty = (LayerProperty<SKPoint>) LayerPropertyViewModel.LayerProperty;
layerProperty.Value = (SKPoint) value;
}
protected override void UpdateKeyframeValue(BaseKeyframe baseKeyframe, object value)
{
var keyframe = (Keyframe<SKPoint>) baseKeyframe;
keyframe.Value = (SKPoint) value;
}
}
}
@@ -19,14 +19,14 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
[DependsOn(nameof(InputValue))]
public float Width
{
get => ((SKSize) InputValue).Width;
get => ((SKSize?) InputValue)?.Width ?? 0;
set => InputValue = new SKSize(value, Height);
}
[DependsOn(nameof(InputValue))]
public float Height
{
get => ((SKSize) InputValue).Height;
get => ((SKSize?)InputValue)?.Height ?? 0;
set => InputValue = new SKSize(Width, value);
}
@@ -35,17 +35,5 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
NotifyOfPropertyChange(() => Width);
NotifyOfPropertyChange(() => Height);
}
protected override void UpdateBaseValue(object value)
{
var layerProperty = (LayerProperty<SKSize>) LayerPropertyViewModel.LayerProperty;
layerProperty.Value = (SKSize) value;
}
protected override void UpdateKeyframeValue(BaseKeyframe baseKeyframe, object value)
{
var keyframe = (Keyframe<SKSize>) baseKeyframe;
keyframe.Value = (SKSize) value;
}
}
}
@@ -1,4 +1,5 @@
using Artemis.Core.Models.Profile;
using Artemis.Core.Services.Interfaces;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Services.Interfaces;
@@ -10,9 +11,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem
public FolderViewModel(ProfileElement folder,
IProfileEditorService profileEditorService,
IDialogService dialogService,
ILayerService layerService,
IFolderViewModelFactory folderViewModelFactory,
ILayerViewModelFactory layerViewModelFactory) :
base(null, folder, profileEditorService, dialogService, folderViewModelFactory, layerViewModelFactory)
base(null, folder, profileEditorService, dialogService, layerService, folderViewModelFactory, layerViewModelFactory)
{
}
@@ -20,9 +22,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem
ProfileElement folder,
IProfileEditorService profileEditorService,
IDialogService dialogService,
ILayerService layerService,
IFolderViewModelFactory folderViewModelFactory,
ILayerViewModelFactory layerViewModelFactory) :
base(parent, folder, profileEditorService, dialogService, folderViewModelFactory, layerViewModelFactory)
base(parent, folder, profileEditorService, dialogService, layerService, folderViewModelFactory, layerViewModelFactory)
{
}
@@ -1,4 +1,5 @@
using Artemis.Core.Models.Profile;
using Artemis.Core.Services.Interfaces;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Services.Interfaces;
@@ -10,9 +11,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem
ProfileElement folder,
IProfileEditorService profileEditorService,
IDialogService dialogService,
ILayerService layerService,
IFolderViewModelFactory folderViewModelFactory,
ILayerViewModelFactory layerViewModelFactory) :
base(parent, folder, profileEditorService, dialogService, folderViewModelFactory, layerViewModelFactory)
base(parent, folder, profileEditorService, dialogService, layerService, folderViewModelFactory, layerViewModelFactory)
{
}
@@ -2,6 +2,7 @@
using System.Linq;
using System.Threading.Tasks;
using Artemis.Core.Models.Profile;
using Artemis.Core.Services.Interfaces;
using Artemis.UI.Exceptions;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.Module.ProfileEditor.Dialogs;
@@ -13,6 +14,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem
public abstract class TreeItemViewModel : PropertyChangedBase
{
private readonly IDialogService _dialogService;
private readonly ILayerService _layerService;
private readonly IFolderViewModelFactory _folderViewModelFactory;
private readonly ILayerViewModelFactory _layerViewModelFactory;
private readonly IProfileEditorService _profileEditorService;
@@ -21,11 +23,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem
ProfileElement profileElement,
IProfileEditorService profileEditorService,
IDialogService dialogService,
ILayerService layerService,
IFolderViewModelFactory folderViewModelFactory,
ILayerViewModelFactory layerViewModelFactory)
{
_profileEditorService = profileEditorService;
_dialogService = dialogService;
_layerService = layerService;
_folderViewModelFactory = folderViewModelFactory;
_layerViewModelFactory = layerViewModelFactory;
@@ -117,7 +121,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem
if (!SupportsChildren)
throw new ArtemisUIException("Cannot add a layer to a profile element of type " + ProfileElement.GetType().Name);
ProfileElement.AddChild(new Layer(ProfileElement.Profile, ProfileElement, "New layer"));
var layer = new Layer(ProfileElement.Profile, ProfileElement, "New layer");
foreach (var baseLayerProperty in layer.Properties)
_layerService.InstantiateKeyframeEngine(baseLayerProperty);
ProfileElement.AddChild(layer);
UpdateProfileElements();
_profileEditorService.UpdateSelectedProfile();
}
@@ -28,9 +28,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
Layer.RenderPropertiesUpdated += LayerOnRenderPropertiesUpdated;
_profileEditorService.SelectedProfileElementChanged += OnSelectedProfileElementChanged;
_profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated;
_profileEditorService.CurrentTimeChanged += ProfileEditorServiceOnCurrentTimeChanged;
_profileEditorService.ProfilePreviewUpdated += ProfileEditorServiceOnProfilePreviewUpdated;
}
public Layer Layer { get; }
public Geometry LayerGeometry { get; set; }
@@ -102,8 +103,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
}
var skRect = Layer.LayerShape.GetUnscaledRectangle();
var rect = new Rect(skRect.Left, skRect.Top, Math.Max(0, skRect.Width), Math.Max(0,skRect.Height));
var rect = new Rect(skRect.Left, skRect.Top, Math.Max(0, skRect.Width), Math.Max(0, skRect.Height));
var shapeGeometry = Geometry.Empty;
switch (Layer.LayerShape)
{
@@ -189,7 +190,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
{
Layer.RenderPropertiesUpdated -= LayerOnRenderPropertiesUpdated;
}
#region Event handlers
private void LayerOnRenderPropertiesUpdated(object sender, EventArgs e)
@@ -208,7 +209,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
Update();
}
private void ProfileEditorServiceOnCurrentTimeChanged(object sender, EventArgs e)
private void ProfileEditorServiceOnProfilePreviewUpdated(object sender, EventArgs e)
{
if (!IsSelected)
return;
@@ -9,15 +9,20 @@
d:DesignHeight="450"
d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type local:EditToolViewModel}}">
<Canvas>
<Canvas UseLayoutRounding="False">
<!-- The rectangle around the shape that allows modification -->
<Rectangle Width="{Binding ShapeSkRect.Width}"
Height="{Binding ShapeSkRect.Height}"
Canvas.Left="{Binding ShapeSkRect.Left}"
Canvas.Top="{Binding ShapeSkRect.Top}"
Fill="Transparent"
Stroke="{DynamicResource PrimaryHueMidBrush}"
StrokeThickness="1"
StrokeDashArray="2 2" />
StrokeDashArray="2 2"
Cursor="Hand"
MouseDown="{s:Action ShapeEditMouseDown}"
MouseUp="{s:Action ShapeEditMouseUp}"
MouseMove="{s:Action Move}"/>
<!-- Top left display -->
<Rectangle Width="4" Height="4" Canvas.Left="{Binding ShapeSkRect.Left}" Canvas.Top="{Binding ShapeSkRect.Top}" Fill="{DynamicResource SecondaryAccentBrush}" Margin="-2,-2,0,0" />
@@ -10,7 +10,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
{
public class EditToolViewModel : VisualizationToolViewModel
{
private bool _mouseDown;
private bool _isDragging;
private double _dragOffsetY;
private double _dragOffsetX;
public EditToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService) : base(profileViewModel, profileEditorService)
{
@@ -19,7 +21,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
profileEditorService.SelectedProfileChanged += (sender, args) => Update();
profileEditorService.SelectedProfileElementUpdated += (sender, args) => Update();
profileEditorService.CurrentTimeChanged += (sender, args) => Update();
profileEditorService.ProfilePreviewUpdated += (sender, args) => Update();
}
private void Update()
@@ -34,41 +36,64 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
public void ShapeEditMouseDown(object sender, MouseButtonEventArgs e)
{
if (_isDragging)
return;
((IInputElement) sender).CaptureMouse();
_mouseDown = true;
if (ProfileEditorService.SelectedProfileElement is Layer layer)
{
var dragStartPosition = GetRelativePosition(sender, e);
var skRect = layer.LayerShape.GetUnscaledRectangle();
_dragOffsetX = skRect.Left - dragStartPosition.X;
_dragOffsetY = skRect.Top - dragStartPosition.Y;
}
_isDragging = true;
e.Handled = true;
}
public void ShapeEditMouseUp(object sender, MouseButtonEventArgs e)
{
((IInputElement) sender).ReleaseMouseCapture();
_mouseDown = false;
ProfileEditorService.UpdateSelectedProfileElement();
_isDragging = false;
e.Handled = true;
}
public void Move(object sender, MouseEventArgs e)
{
if (!_isDragging || !(ProfileEditorService.SelectedProfileElement is Layer layer))
return;
var position = GetRelativePosition(sender, e);
var skRect = layer.LayerShape.GetUnscaledRectangle();
layer.LayerShape.SetFromUnscaledRectangle(
SKRect.Create((float) (position.X + _dragOffsetX), (float) (position.Y + _dragOffsetY), skRect.Width, skRect.Height),
ProfileEditorService.CurrentTime
);
ProfileEditorService.UpdateProfilePreview();
}
public void TopLeftRotate(object sender, MouseEventArgs e)
{
}
public void TopLeftResize(object sender, MouseEventArgs e)
{
}
public void TopCenterResize(object sender, MouseEventArgs e)
{
if (!_mouseDown)
return;
if (!(ProfileEditorService.SelectedProfileElement is Layer layer))
if (!_isDragging || !(ProfileEditorService.SelectedProfileElement is Layer layer))
return;
var position = GetRelativePosition(sender, e);
var skRect = layer.LayerShape.GetUnscaledRectangle();
skRect.Top = (float) Math.Min(position.Y, skRect.Bottom);
layer.LayerShape.SetFromUnscaledRectangle(skRect);
ProfileEditorService.UpdateSelectedProfileElement();
layer.LayerShape.SetFromUnscaledRectangle(skRect, ProfileEditorService.CurrentTime);
ProfileEditorService.UpdateProfilePreview();
}
public void TopRightRotate(object sender, MouseEventArgs e)
@@ -81,18 +106,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
public void CenterRightResize(object sender, MouseEventArgs e)
{
if (!_mouseDown)
return;
if (!(ProfileEditorService.SelectedProfileElement is Layer layer))
if (!_isDragging || !(ProfileEditorService.SelectedProfileElement is Layer layer))
return;
var position = GetRelativePosition(sender, e);
var skRect = layer.LayerShape.GetUnscaledRectangle();
skRect.Right = (float) Math.Max(position.X, skRect.Left);
layer.LayerShape.SetFromUnscaledRectangle(skRect);
ProfileEditorService.UpdateSelectedProfileElement();
layer.LayerShape.SetFromUnscaledRectangle(skRect, ProfileEditorService.CurrentTime);
ProfileEditorService.UpdateProfilePreview();
}
private Point GetRelativePosition(object sender, MouseEventArgs mouseEventArgs)
@@ -111,18 +133,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
public void BottomCenterResize(object sender, MouseEventArgs e)
{
if (!_mouseDown)
return;
if (!(ProfileEditorService.SelectedProfileElement is Layer layer))
if (!_isDragging || !(ProfileEditorService.SelectedProfileElement is Layer layer))
return;
var position = GetRelativePosition(sender, e);
var skRect = layer.LayerShape.GetUnscaledRectangle();
skRect.Bottom = (float) Math.Max(position.Y, skRect.Top);
layer.LayerShape.SetFromUnscaledRectangle(skRect);
ProfileEditorService.UpdateSelectedProfileElement();
layer.LayerShape.SetFromUnscaledRectangle(skRect, ProfileEditorService.CurrentTime);
ProfileEditorService.UpdateProfilePreview();
}
public void BottomLeftRotate(object sender, MouseEventArgs e)
@@ -135,18 +154,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
public void CenterLeftResize(object sender, MouseEventArgs e)
{
if (!_mouseDown)
return;
if (!(ProfileEditorService.SelectedProfileElement is Layer layer))
if (!_isDragging || !(ProfileEditorService.SelectedProfileElement is Layer layer))
return;
var position = GetRelativePosition(sender, e);
var skRect = layer.LayerShape.GetUnscaledRectangle();
skRect.Left = (float) Math.Min(position.X, skRect.Right);
layer.LayerShape.SetFromUnscaledRectangle(skRect);
ProfileEditorService.UpdateSelectedProfileElement();
layer.LayerShape.SetFromUnscaledRectangle(skRect, ProfileEditorService.CurrentTime);
ProfileEditorService.UpdateProfilePreview();
}
}
}
@@ -48,7 +48,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
layer.LayerShape = new Ellipse(layer);
// Apply the drag rectangle
layer.LayerShape.SetFromUnscaledRectangle(DragRectangle.ToSKRect());
layer.LayerShape.SetFromUnscaledRectangle(DragRectangle.ToSKRect(), ProfileEditorService.CurrentTime);
ProfileEditorService.UpdateSelectedProfileElement();
}
}
@@ -48,7 +48,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
layer.LayerShape = new Rectangle(layer);
// Apply the drag rectangle
layer.LayerShape.SetFromUnscaledRectangle(DragRectangle.ToSKRect());
layer.LayerShape.SetFromUnscaledRectangle(DragRectangle.ToSKRect(), ProfileEditorService.CurrentTime);
ProfileEditorService.UpdateSelectedProfileElement();
}
}
@@ -55,7 +55,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
layer.AddLeds(selectedLeds);
// Restore the saved size
if (layer.LayerShape != null)
layer.LayerShape.SetFromUnscaledRectangle(shapeSize);
layer.LayerShape.SetFromUnscaledRectangle(shapeSize, ProfileEditorService.CurrentTime);
ProfileEditorService.UpdateSelectedProfileElement();
}