From dd9c701738fed2731f319153a2035f4f61532fd4 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 6 Feb 2020 20:35:51 +0100 Subject: [PATCH] Show outlines for all layers Rotation fixes Movement fixes --- src/Artemis.Core/Models/Profile/Layer.cs | 18 +++++--- src/Artemis.UI/Artemis.UI.csproj | 2 +- .../Visualization/ProfileLayerView.xaml | 2 +- .../Visualization/ProfileLayerViewModel.cs | 5 +-- .../Visualization/Tools/EditToolViewModel.cs | 44 +++++-------------- .../Interfaces/ILayerEditorService.cs | 8 +++- ...rShapeService.cs => LayerEditorService.cs} | 23 +++++++++- 7 files changed, 53 insertions(+), 49 deletions(-) rename src/Artemis.UI/Services/{LayerShapeService.cs => LayerEditorService.cs} (83%) diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index a34d7a40a..089379fc2 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -1,4 +1,5 @@ -using System; + +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; @@ -156,11 +157,18 @@ namespace Artemis.Core.Models.Profile public override void Update(double deltaTime) { foreach (var property in Properties) - { property.KeyframeEngine?.Update(deltaTime); - // This is a placeholder method of repeating the animation until repeat modes are implemented - if (property.KeyframeEngine != null && property.IsUsingKeyframes && property.KeyframeEngine.NextKeyframe == null) - property.KeyframeEngine.OverrideProgress(TimeSpan.Zero); + + // For now, reset all keyframe engines after the last keyframe was hit + // This is a placeholder method of repeating the animation until repeat modes are implemented + var lastKeyframe = Properties.SelectMany(p => p.UntypedKeyframes).OrderByDescending(t => t.Position).FirstOrDefault(); + if (lastKeyframe != null) + { + if (Properties.Any(p => p.KeyframeEngine?.Progress > lastKeyframe.Position)) + { + foreach (var baseLayerProperty in Properties) + baseLayerProperty.KeyframeEngine?.OverrideProgress(TimeSpan.Zero); + } } LayerBrush?.Update(deltaTime); diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index 4394e7bc9..07ef904df 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -216,7 +216,7 @@ - + diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerView.xaml index 589442a93..7d0d287d0 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerView.xaml +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerView.xaml @@ -16,7 +16,7 @@ - + diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs index a7d931ed4..3a98d529b 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs @@ -190,14 +190,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization private void OnSelectedProfileElementUpdated(object sender, EventArgs e) { - if (IsSelected) - Update(); + Update(); } private void ProfileEditorServiceOnProfilePreviewUpdated(object sender, EventArgs e) { - if (!IsSelected) - return; CreateShapeGeometry(); CreateViewportRectangle(); } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolViewModel.cs index fa01bd363..72b88ddeb 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolViewModel.cs @@ -3,6 +3,7 @@ using System.Windows; using System.Windows.Input; using System.Windows.Media; using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Profile.LayerProperties; using Artemis.UI.Events; using Artemis.UI.Services.Interfaces; using SkiaSharp; @@ -16,7 +17,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools private readonly ILayerEditorService _layerEditorService; private SKPoint _dragOffset; private SKPoint _dragStart; - private SKSize _dragStartScale; private SKPoint _topLeft; public EditToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService, ILayerEditorService layerEditorService) @@ -112,33 +112,24 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools #region Size private bool _isResizing; + private SKSize _dragStartScale; public void ResizeMouseDown(object sender, ShapeControlEventArgs e) { if (_isResizing || !(ProfileEditorService.SelectedProfileElement is Layer layer)) return; - // The path starts at 0,0 so there's no simple way to get the position relative to the top-left of the path - _dragStart = GetRelativePosition(sender, e.MouseEventArgs).ToSKPoint(); + var dragStart = GetRelativePosition(sender, e.MouseEventArgs).ToSKPoint(); + _dragOffset = _layerEditorService.GetDragOffset(layer, dragStart); + _dragStart = dragStart + _dragOffset; _dragStartScale = layer.ScaleProperty.CurrentValue; - // Store the original position and do a test to figure out the mouse offset - var originalPosition = layer.PositionProperty.CurrentValue; - var scaledDragStart = _layerEditorService.GetScaledPoint(layer, _dragStart, true); - layer.PositionProperty.SetCurrentValue(scaledDragStart, ProfileEditorService.CurrentTime); - - // TopLeft is not updated yet and acts as a snapshot of the top-left before changing the position - // GetLayerPath will return the updated position with all transformations applied, the difference is the offset - _dragOffset = _topLeft - _layerEditorService.GetLayerPath(layer, true, true, true).Points[0]; - _dragStart += _dragOffset; - - // Restore the position back to before the test was done - layer.PositionProperty.SetCurrentValue(originalPosition, ProfileEditorService.CurrentTime); _isResizing = true; } public void ResizeMouseUp(object sender, ShapeControlEventArgs e) { + ProfileEditorService.UpdateSelectedProfileElement(); _isResizing = false; } @@ -248,23 +239,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools if (e.ShapeControlPoint == ShapeControlPoint.LayerShape) { - // The path starts at 0,0 so there's no simple way to get the position relative to the top-left of the path - _dragStart = GetRelativePosition(sender, e.MouseEventArgs).ToSKPoint(); - _dragStartScale = layer.ScaleProperty.CurrentValue; - - // Store the original position and do a test to figure out the mouse offset - var originalPosition = layer.PositionProperty.CurrentValue; - var scaledDragStart = _layerEditorService.GetScaledPoint(layer, _dragStart, true); - layer.PositionProperty.SetCurrentValue(scaledDragStart, ProfileEditorService.CurrentTime); - - // TopLeft is not updated yet and acts as a snapshot of the top-left before changing the position - // GetLayerPath will return the updated position with all transformations applied, the difference is the offset - _dragOffset = _topLeft - _layerEditorService.GetLayerPath(layer, true, true, true).Points[0]; - _dragStart += _dragOffset; - - // Restore the position back to before the test was done - layer.PositionProperty.SetCurrentValue(originalPosition, ProfileEditorService.CurrentTime); - + var dragStart = GetRelativePosition(sender, e.MouseEventArgs).ToSKPoint(); + _dragOffset = _layerEditorService.GetDragOffset(layer, dragStart); + _dragStart = dragStart + _dragOffset; _movingShape = true; } else if (e.ShapeControlPoint == ShapeControlPoint.Anchor) @@ -287,6 +264,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools public void MoveMouseUp(object sender, ShapeControlEventArgs e) { + ProfileEditorService.UpdateSelectedProfileElement(); _movingShape = false; _movingAnchor = false; } @@ -393,8 +371,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools { var layerBounds = _layerEditorService.GetLayerBounds(layer); var start = _layerEditorService.GetLayerAnchorPosition(layer); - start.X += layerBounds.Left; - start.Y += layerBounds.Top; var arrival = GetRelativePosition(mouseEventSender, mouseEvent); var radian = (float) Math.Atan2(start.Y - arrival.Y, start.X - arrival.X); diff --git a/src/Artemis.UI/Services/Interfaces/ILayerEditorService.cs b/src/Artemis.UI/Services/Interfaces/ILayerEditorService.cs index f400a5793..7c426925f 100644 --- a/src/Artemis.UI/Services/Interfaces/ILayerEditorService.cs +++ b/src/Artemis.UI/Services/Interfaces/ILayerEditorService.cs @@ -18,8 +18,9 @@ namespace Artemis.UI.Services.Interfaces /// Returns the layer's anchor, corrected for the current render scale. /// /// + /// /// - Point GetLayerAnchorPosition(Layer layer); + Point GetLayerAnchorPosition(Layer layer, SKPoint? positionOverride = null); /// /// Creates a WPF transform group that contains all the transformations required to render the provided layer. @@ -36,8 +37,9 @@ namespace Artemis.UI.Services.Interfaces /// /// /// + /// /// - SKPath GetLayerPath(Layer layer, bool includeTranslation, bool includeScale, bool includeRotation); + SKPath GetLayerPath(Layer layer, bool includeTranslation, bool includeScale, bool includeRotation, SKPoint? anchorOverride = null); /// /// Returns a new point scaled to the layer. @@ -47,5 +49,7 @@ namespace Artemis.UI.Services.Interfaces /// /// SKPoint GetScaledPoint(Layer layer, SKPoint point, bool absolute); + + SKPoint GetDragOffset(Layer layer, SKPoint dragStart); } } \ No newline at end of file diff --git a/src/Artemis.UI/Services/LayerShapeService.cs b/src/Artemis.UI/Services/LayerEditorService.cs similarity index 83% rename from src/Artemis.UI/Services/LayerShapeService.cs rename to src/Artemis.UI/Services/LayerEditorService.cs index 4ab18b804..8efcaeb13 100644 --- a/src/Artemis.UI/Services/LayerShapeService.cs +++ b/src/Artemis.UI/Services/LayerEditorService.cs @@ -32,10 +32,12 @@ namespace Artemis.UI.Services } /// - public Point GetLayerAnchorPosition(Layer layer) + public Point GetLayerAnchorPosition(Layer layer, SKPoint? positionOverride = null) { var layerBounds = GetLayerBounds(layer).ToSKRect(); var positionProperty = layer.PositionProperty.CurrentValue; + if (positionOverride != null) + positionProperty = positionOverride.Value; // Start at the center of the shape var position = new Point(layerBounds.MidX, layerBounds.MidY); @@ -72,12 +74,15 @@ namespace Artemis.UI.Services } /// - public SKPath GetLayerPath(Layer layer, bool includeTranslation, bool includeScale, bool includeRotation) + public SKPath GetLayerPath(Layer layer, bool includeTranslation, bool includeScale, bool includeRotation, SKPoint? anchorOverride = null) { var layerBounds = GetLayerBounds(layer).ToSKRect(); // Apply transformation like done by the core during layer rendering (same differences apply as in GetLayerTransformGroup) var anchorPosition = GetLayerAnchorPosition(layer).ToSKPoint(); + if (anchorOverride != null) + anchorPosition = anchorOverride.Value; + var anchorProperty = layer.AnchorPointProperty.CurrentValue; // Translation originates from the unscaled center of the shape and is tied to the anchor @@ -113,5 +118,19 @@ namespace Artemis.UI.Services 100f / layer.Bounds.Height * (float) (point.Y * renderScale) / 100f ); } + + public SKPoint GetDragOffset(Layer layer, SKPoint dragStart) + { + // Figure out what the top left will be if the shape moves to the current cursor position + var scaledDragStart = GetScaledPoint(layer, dragStart, true); + var tempAnchor = GetLayerAnchorPosition(layer, scaledDragStart).ToSKPoint(); + var tempTopLeft = GetLayerPath(layer, true, true, true, tempAnchor)[0]; + + // Get the shape's position + var topLeft = GetLayerPath(layer, true, true, true)[0]; + + // The difference between the two is the offset + return topLeft - tempTopLeft; + } } } \ No newline at end of file