mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Transform tool - Mostly implemented resizing
This commit is contained in:
parent
12e91b8c81
commit
1716eba8ec
@ -45,30 +45,14 @@ public static class LayerExtensions
|
||||
/// <summary>
|
||||
/// Returns an absolute and scaled rectangular path for the given layer in real coordinates.
|
||||
/// </summary>
|
||||
public static SKPath GetLayerPath(this Layer layer, bool includeTranslation, bool includeScale, bool includeRotation, SKPoint? anchorOverride = null)
|
||||
public static SKPath GetLayerPath(this Layer layer, bool includeTranslation, bool includeScale, bool includeRotation)
|
||||
{
|
||||
SKRect layerBounds = GetLayerBounds(layer);
|
||||
|
||||
// Apply transformation like done by the core during layer rendering (same differences apply as in GetLayerTransformGroup)
|
||||
SKPoint anchorPosition = GetLayerAnchorPosition(layer);
|
||||
if (anchorOverride != null)
|
||||
anchorPosition = anchorOverride.Value;
|
||||
|
||||
SKPoint anchorProperty = layer.Transform.AnchorPoint.CurrentValue;
|
||||
|
||||
// Translation originates from the unscaled center of the shape and is tied to the anchor
|
||||
float x = anchorPosition.X - layerBounds.MidX - anchorProperty.X * layerBounds.Width;
|
||||
float y = anchorPosition.Y - layerBounds.MidY - anchorProperty.Y * layerBounds.Height;
|
||||
|
||||
SKMatrix transform = layer.GetTransformMatrix(false, includeTranslation, includeScale, includeRotation, layerBounds);
|
||||
SKPath path = new();
|
||||
path.AddRect(layerBounds);
|
||||
if (includeTranslation)
|
||||
path.Transform(SKMatrix.CreateTranslation(x, y));
|
||||
if (includeScale)
|
||||
path.Transform(SKMatrix.CreateScale(layer.Transform.Scale.CurrentValue.Width / 100f, layer.Transform.Scale.CurrentValue.Height / 100f, anchorPosition.X, anchorPosition.Y));
|
||||
if (includeRotation)
|
||||
path.Transform(SKMatrix.CreateRotationDegrees(layer.Transform.Rotation.CurrentValue, anchorPosition.X, anchorPosition.Y));
|
||||
|
||||
path.Transform(transform);
|
||||
return path;
|
||||
}
|
||||
|
||||
@ -91,19 +75,27 @@ public static class LayerExtensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the offset from the given point to the top-left of the layer
|
||||
/// Returns the offset from the given point to the closest sides of the layer's shape bounds
|
||||
/// </summary>
|
||||
public static SKPoint GetDragOffset(this Layer layer, SKPoint dragStart)
|
||||
{
|
||||
// Figure out what the top left will be if the shape moves to the current cursor position
|
||||
SKPoint scaledDragStart = GetScaledPoint(layer, dragStart, true);
|
||||
SKPoint tempAnchor = GetLayerAnchorPosition(layer, scaledDragStart);
|
||||
SKPoint tempTopLeft = GetLayerPath(layer, true, true, true, tempAnchor)[0];
|
||||
SKRect bounds = layer.GetLayerPath(true, true, false).Bounds;
|
||||
SKPoint anchor = layer.GetLayerAnchorPosition();
|
||||
|
||||
// Get the shape's position
|
||||
SKPoint topLeft = GetLayerPath(layer, true, true, true)[0];
|
||||
float xOffset = 0f, yOffset = 0f;
|
||||
|
||||
// The difference between the two is the offset
|
||||
return topLeft - tempTopLeft;
|
||||
// X offset
|
||||
if (dragStart.X < anchor.X)
|
||||
xOffset = bounds.Left - dragStart.X;
|
||||
else if (dragStart.X > anchor.X)
|
||||
xOffset = bounds.Right - dragStart.X;
|
||||
|
||||
// Y offset
|
||||
if (dragStart.Y < anchor.Y)
|
||||
yOffset = bounds.Top - dragStart.Y;
|
||||
else if (dragStart.Y > anchor.Y)
|
||||
yOffset = bounds.Bottom - dragStart.Y;
|
||||
|
||||
return new SKPoint(xOffset, yOffset);
|
||||
}
|
||||
}
|
||||
@ -1,23 +1,63 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared.Extensions;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.PanAndZoom;
|
||||
using Avalonia.Controls.Shapes;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.LogicalTree;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Avalonia.Skia;
|
||||
using Avalonia.Styling;
|
||||
using ReactiveUI;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Tools;
|
||||
|
||||
public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
||||
{
|
||||
private ZoomBorder? _zoomBorder;
|
||||
private PointerPoint _dragOffset;
|
||||
private SKPoint _dragStart;
|
||||
private SKPoint _dragOffset;
|
||||
|
||||
private readonly Ellipse _rotateTopLeft;
|
||||
private readonly Ellipse _rotateTopRight;
|
||||
private readonly Ellipse _rotateBottomRight;
|
||||
private readonly Ellipse _rotateBottomLeft;
|
||||
|
||||
private readonly Rectangle _resizeTopCenter;
|
||||
private readonly Rectangle _resizeRightCenter;
|
||||
private readonly Rectangle _resizeBottomCenter;
|
||||
private readonly Rectangle _resizeLeftCenter;
|
||||
private readonly Rectangle _resizeTopLeft;
|
||||
private readonly Rectangle _resizeTopRight;
|
||||
private readonly Rectangle _resizeBottomRight;
|
||||
private readonly Rectangle _resizeBottomLeft;
|
||||
|
||||
private readonly Ellipse _anchorPoint;
|
||||
|
||||
public TransformToolView()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_rotateTopLeft = this.Get<Ellipse>("RotateTopLeft");
|
||||
_rotateTopRight = this.Get<Ellipse>("RotateTopRight");
|
||||
_rotateBottomRight = this.Get<Ellipse>("RotateBottomRight");
|
||||
_rotateBottomLeft = this.Get<Ellipse>("RotateBottomLeft");
|
||||
|
||||
_resizeTopCenter = this.Get<Rectangle>("ResizeTopCenter");
|
||||
_resizeRightCenter = this.Get<Rectangle>("ResizeRightCenter");
|
||||
_resizeBottomCenter = this.Get<Rectangle>("ResizeBottomCenter");
|
||||
_resizeLeftCenter = this.Get<Rectangle>("ResizeLeftCenter");
|
||||
_resizeTopLeft = this.Get<Rectangle>("ResizeTopLeft");
|
||||
_resizeTopRight = this.Get<Rectangle>("ResizeTopRight");
|
||||
_resizeBottomRight = this.Get<Rectangle>("ResizeBottomRight");
|
||||
_resizeBottomLeft = this.Get<Rectangle>("ResizeBottomLeft");
|
||||
|
||||
_anchorPoint = this.Get<Ellipse>("AnchorPoint");
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
@ -30,7 +70,7 @@ public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
||||
/// <inheritdoc />
|
||||
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
|
||||
{
|
||||
_zoomBorder = (ZoomBorder?)this.GetLogicalAncestors().FirstOrDefault(l => l is ZoomBorder);
|
||||
_zoomBorder = (ZoomBorder?) this.GetLogicalAncestors().FirstOrDefault(l => l is ZoomBorder);
|
||||
if (_zoomBorder != null)
|
||||
_zoomBorder.PropertyChanged += ZoomBorderOnPropertyChanged;
|
||||
base.OnAttachedToLogicalTree(e);
|
||||
@ -58,11 +98,12 @@ public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
||||
|
||||
private void RotationOnPointerPressed(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
IInputElement? element = (IInputElement?)sender;
|
||||
if (element == null || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
Shape? element = (Shape?) sender;
|
||||
if (element == null || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed || ViewModel?.Layer == null)
|
||||
return;
|
||||
|
||||
_dragOffset = e.GetCurrentPoint(_zoomBorder);
|
||||
_dragStart = e.GetCurrentPoint(_zoomBorder).Position.ToSKPoint();
|
||||
_dragOffset = ViewModel.Layer.GetDragOffset(_dragStart);
|
||||
|
||||
e.Pointer.Capture(element);
|
||||
e.Handled = true;
|
||||
@ -70,8 +111,8 @@ public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
||||
|
||||
private void RotationOnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
IInputElement? element = (IInputElement?)sender;
|
||||
if (element == null || e.Pointer.Captured != element || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
Shape? element = (Shape?) sender;
|
||||
if (element == null || !ReferenceEquals(e.Pointer.Captured, element) || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
return;
|
||||
|
||||
e.Pointer.Capture(null);
|
||||
@ -80,8 +121,8 @@ public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
||||
|
||||
private void RotationOnPointerMoved(object? sender, PointerEventArgs e)
|
||||
{
|
||||
IInputElement? element = (IInputElement?) sender;
|
||||
if (element == null || e.Pointer.Captured != element || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
Shape? element = (Shape?) sender;
|
||||
if (element == null || !ReferenceEquals(e.Pointer.Captured, element) || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
return;
|
||||
|
||||
e.Handled = true;
|
||||
@ -93,11 +134,12 @@ public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
||||
|
||||
private void MoveOnPointerPressed(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
IInputElement? element = (IInputElement?)sender;
|
||||
if (element == null || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
Shape? element = (Shape?) sender;
|
||||
if (element == null || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed || ViewModel?.Layer == null)
|
||||
return;
|
||||
|
||||
_dragOffset = e.GetCurrentPoint(_zoomBorder);
|
||||
_dragStart = e.GetCurrentPoint(_zoomBorder).Position.ToSKPoint();
|
||||
_dragOffset = ViewModel.Layer.GetDragOffset(_dragStart);
|
||||
|
||||
e.Pointer.Capture(element);
|
||||
e.Handled = true;
|
||||
@ -105,8 +147,8 @@ public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
||||
|
||||
private void MoveOnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
IInputElement? element = (IInputElement?)sender;
|
||||
if (element == null || e.Pointer.Captured != element || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
Shape? element = (Shape?) sender;
|
||||
if (element == null || !ReferenceEquals(e.Pointer.Captured, element) || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
return;
|
||||
|
||||
e.Pointer.Capture(null);
|
||||
@ -115,8 +157,8 @@ public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
||||
|
||||
private void MoveOnPointerMoved(object? sender, PointerEventArgs e)
|
||||
{
|
||||
IInputElement? element = (IInputElement?)sender;
|
||||
if (element == null || e.Pointer.Captured != element || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
Shape? element = (Shape?) sender;
|
||||
if (element == null || !ReferenceEquals(e.Pointer.Captured, element) || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
return;
|
||||
|
||||
e.Handled = true;
|
||||
@ -128,11 +170,15 @@ public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
||||
|
||||
private void ResizeOnPointerPressed(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
IInputElement? element = (IInputElement?)sender;
|
||||
if (element == null || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
Shape? element = (Shape?) sender;
|
||||
if (element == null || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed || ViewModel?.Layer == null)
|
||||
return;
|
||||
|
||||
_dragOffset = e.GetCurrentPoint(_zoomBorder);
|
||||
_dragStart = CounteractLayerRotation(e.GetCurrentPoint(this).Position.ToSKPoint(), ViewModel.Layer);
|
||||
_dragOffset = ViewModel.Layer.GetDragOffset(_dragStart);
|
||||
|
||||
SKPoint position = GetPositionForViewModel(e);
|
||||
ViewModel.StartResize(position);
|
||||
|
||||
e.Pointer.Capture(element);
|
||||
e.Handled = true;
|
||||
@ -140,22 +186,70 @@ public class TransformToolView : ReactiveUserControl<TransformToolViewModel>
|
||||
|
||||
private void ResizeOnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
IInputElement? element = (IInputElement?)sender;
|
||||
if (element == null || e.Pointer.Captured != element || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
Shape? element = (Shape?) sender;
|
||||
if (element == null || !ReferenceEquals(e.Pointer.Captured, element) || e.InitialPressMouseButton != MouseButton.Left || ViewModel?.Layer == null)
|
||||
return;
|
||||
|
||||
SKPoint position = GetPositionForViewModel(e);
|
||||
ViewModel.FinishResize(position, GetResizeDirection(element), e.KeyModifiers.HasFlag(KeyModifiers.Shift));
|
||||
|
||||
e.Pointer.Capture(null);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void ResizeOnPointerMoved(object? sender, PointerEventArgs e)
|
||||
{
|
||||
IInputElement? element = (IInputElement?)sender;
|
||||
if (element == null || e.Pointer.Captured != element || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
Shape? element = (Shape?) sender;
|
||||
if (element == null || !ReferenceEquals(e.Pointer.Captured, element) || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed || ViewModel?.Layer == null)
|
||||
return;
|
||||
|
||||
SKPoint position = GetPositionForViewModel(e);
|
||||
ViewModel.UpdateResize(position, GetResizeDirection(element), e.KeyModifiers.HasFlag(KeyModifiers.Shift));
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private SKPoint GetPositionForViewModel(PointerEventArgs e)
|
||||
{
|
||||
if (ViewModel?.Layer == null)
|
||||
return SKPoint.Empty;
|
||||
|
||||
SKPoint point = CounteractLayerRotation(e.GetCurrentPoint(this).Position.ToSKPoint(), ViewModel.Layer);
|
||||
return point + _dragOffset;
|
||||
}
|
||||
|
||||
private static SKPoint CounteractLayerRotation(SKPoint point, Layer layer)
|
||||
{
|
||||
SKPoint pivot = layer.GetLayerAnchorPosition();
|
||||
|
||||
using SKPath counterRotatePath = new();
|
||||
counterRotatePath.AddPoly(new[] {SKPoint.Empty, point}, false);
|
||||
counterRotatePath.Transform(SKMatrix.CreateRotationDegrees(layer.Transform.Rotation.CurrentValue * -1, pivot.X, pivot.Y));
|
||||
|
||||
return counterRotatePath.Points[1];
|
||||
}
|
||||
|
||||
private TransformToolViewModel.ResizeSide GetResizeDirection(Shape shape)
|
||||
{
|
||||
if (ReferenceEquals(shape, _resizeTopLeft))
|
||||
return TransformToolViewModel.ResizeSide.Top | TransformToolViewModel.ResizeSide.Left;
|
||||
if (ReferenceEquals(shape, _resizeTopRight))
|
||||
return TransformToolViewModel.ResizeSide.Top | TransformToolViewModel.ResizeSide.Right;
|
||||
if (ReferenceEquals(shape, _resizeBottomRight))
|
||||
return TransformToolViewModel.ResizeSide.Bottom | TransformToolViewModel.ResizeSide.Right;
|
||||
if (ReferenceEquals(shape, _resizeBottomLeft))
|
||||
return TransformToolViewModel.ResizeSide.Bottom | TransformToolViewModel.ResizeSide.Left;
|
||||
if (ReferenceEquals(shape, _resizeTopCenter))
|
||||
return TransformToolViewModel.ResizeSide.Top;
|
||||
if (ReferenceEquals(shape, _resizeRightCenter))
|
||||
return TransformToolViewModel.ResizeSide.Right;
|
||||
if (ReferenceEquals(shape, _resizeBottomCenter))
|
||||
return TransformToolViewModel.ResizeSide.Bottom;
|
||||
if (ReferenceEquals(shape, _resizeLeftCenter))
|
||||
return TransformToolViewModel.ResizeSide.Left;
|
||||
|
||||
throw new ArgumentException("Given shape isn't a resize shape");
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared.Extensions;
|
||||
using Artemis.UI.Shared.Services.ProfileEditor;
|
||||
using Artemis.UI.Shared.Services.ProfileEditor.Commands;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.Mixins;
|
||||
using Material.Icons;
|
||||
@ -14,6 +17,7 @@ namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Tools;
|
||||
|
||||
public class TransformToolViewModel : ToolViewModel
|
||||
{
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private readonly ObservableAsPropertyHelper<bool> _isEnabled;
|
||||
private RelativePoint _relativeAnchor;
|
||||
private double _inverseRotation;
|
||||
@ -21,10 +25,13 @@ public class TransformToolViewModel : ToolViewModel
|
||||
private double _rotation;
|
||||
private Rect _shapeBounds;
|
||||
private Point _anchor;
|
||||
private TimeSpan _time;
|
||||
|
||||
/// <inheritdoc />
|
||||
public TransformToolViewModel(IProfileEditorService profileEditorService)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
|
||||
// Not disposed when deactivated but when really disposed
|
||||
_isEnabled = profileEditorService.ProfileElement.Select(p => p is Layer).ToProperty(this, vm => vm.IsEnabled);
|
||||
|
||||
@ -69,7 +76,11 @@ public class TransformToolViewModel : ToolViewModel
|
||||
.DisposeWith(d);
|
||||
|
||||
this.WhenAnyValue(vm => vm.Layer).Subscribe(_ => Update()).DisposeWith(d);
|
||||
profileEditorService.Time.Subscribe(_ => Update()).DisposeWith(d);
|
||||
profileEditorService.Time.Subscribe(t =>
|
||||
{
|
||||
_time = t;
|
||||
Update();
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
@ -151,17 +162,159 @@ public class TransformToolViewModel : ToolViewModel
|
||||
Anchor = new Point(ShapeBounds.Width * RelativeAnchor.Point.X, ShapeBounds.Height * RelativeAnchor.Point.Y);
|
||||
}
|
||||
|
||||
public enum ShapeControlPoint
|
||||
#region Resizing
|
||||
|
||||
private SKSize _resizeStartScale;
|
||||
private bool _hadKeyframe;
|
||||
|
||||
public void StartResize(SKPoint position)
|
||||
{
|
||||
TopLeft,
|
||||
TopRight,
|
||||
BottomRight,
|
||||
BottomLeft,
|
||||
TopCenter,
|
||||
RightCenter,
|
||||
BottomCenter,
|
||||
LeftCenter,
|
||||
LayerShape,
|
||||
Anchor
|
||||
if (Layer == null)
|
||||
return;
|
||||
|
||||
_resizeStartScale = Layer.Transform.Scale.CurrentValue;
|
||||
_hadKeyframe = Layer.Transform.Scale.Keyframes.Any(k => k.Position == _time);
|
||||
}
|
||||
|
||||
public void FinishResize(SKPoint position, ResizeSide side, bool evenSides)
|
||||
{
|
||||
if (Layer == null)
|
||||
return;
|
||||
|
||||
// Grab the size one last time
|
||||
SKSize size = UpdateResize(position, side, evenSides);
|
||||
|
||||
// If the layer has keyframes, new keyframes may have been added while the user was dragging
|
||||
if (Layer.Transform.Scale.KeyframesEnabled)
|
||||
{
|
||||
// If there was already a keyframe at the old spot, edit that keyframe
|
||||
if (_hadKeyframe)
|
||||
_profileEditorService.ExecuteCommand(new UpdateLayerProperty<SKSize>(Layer.Transform.Scale, size, _resizeStartScale, _time));
|
||||
// If there was no keyframe yet, remove the keyframe that was created while dragging and create a permanent one
|
||||
else
|
||||
{
|
||||
Layer.Transform.Scale.RemoveKeyframe(Layer.Transform.Scale.Keyframes.First(k => k.Position == _time));
|
||||
_profileEditorService.ExecuteCommand(new UpdateLayerProperty<SKSize>(Layer.Transform.Scale, size, _time));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_profileEditorService.ExecuteCommand(new UpdateLayerProperty<SKSize>(Layer.Transform.Scale, size, _resizeStartScale, _time));
|
||||
}
|
||||
}
|
||||
|
||||
public SKSize UpdateResize(SKPoint position, ResizeSide side, bool evenSides)
|
||||
{
|
||||
if (Layer == null)
|
||||
return SKSize.Empty;
|
||||
|
||||
SKPoint normalizedAnchor = Layer.Transform.AnchorPoint;
|
||||
// TODO Remove when anchor is centralized at 0.5,0.5
|
||||
normalizedAnchor = new SKPoint(normalizedAnchor.X + 0.5f, normalizedAnchor.Y + 0.5f);
|
||||
|
||||
// The anchor is used to ensure a side can't shrink past the anchor
|
||||
SKPoint anchor = Layer.GetLayerAnchorPosition();
|
||||
// The bounds are used to determine whether to shrink or grow
|
||||
SKRect shapeBounds = Layer.GetLayerPath(true, true, false).Bounds;
|
||||
|
||||
float width = shapeBounds.Width;
|
||||
float height = shapeBounds.Height;
|
||||
|
||||
// Resize each side as requested, the sides of each axis are mutually exclusive
|
||||
if (side.HasFlag(ResizeSide.Left))
|
||||
{
|
||||
if (position.X > anchor.X)
|
||||
position.X = anchor.X;
|
||||
|
||||
float anchorOffset = 1f - normalizedAnchor.X;
|
||||
float difference = MathF.Abs(shapeBounds.Left - position.X);
|
||||
if (position.X < shapeBounds.Left)
|
||||
width += difference / anchorOffset;
|
||||
else
|
||||
width -= difference / anchorOffset;
|
||||
}
|
||||
else if (side.HasFlag(ResizeSide.Right))
|
||||
{
|
||||
if (position.X < anchor.X)
|
||||
position.X = anchor.X;
|
||||
|
||||
float anchorOffset = normalizedAnchor.X;
|
||||
float difference = MathF.Abs(shapeBounds.Right - position.X);
|
||||
if (position.X > shapeBounds.Right)
|
||||
width += difference / anchorOffset;
|
||||
else
|
||||
width -= difference / anchorOffset;
|
||||
}
|
||||
|
||||
if (side.HasFlag(ResizeSide.Top))
|
||||
{
|
||||
if (position.Y > anchor.Y)
|
||||
position.Y = anchor.Y;
|
||||
|
||||
float anchorOffset = 1f - normalizedAnchor.Y;
|
||||
float difference = MathF.Abs(shapeBounds.Top - position.Y);
|
||||
if (position.Y < shapeBounds.Top)
|
||||
height += difference / anchorOffset;
|
||||
else
|
||||
height -= difference / anchorOffset;
|
||||
}
|
||||
else if (side.HasFlag(ResizeSide.Bottom))
|
||||
{
|
||||
if (position.Y < anchor.Y)
|
||||
position.Y = anchor.Y;
|
||||
|
||||
float anchorOffset = normalizedAnchor.Y;
|
||||
float difference = MathF.Abs(shapeBounds.Bottom - position.Y);
|
||||
if (position.Y > shapeBounds.Bottom)
|
||||
height += difference / anchorOffset;
|
||||
else
|
||||
height -= difference / anchorOffset;
|
||||
}
|
||||
|
||||
// Even out the sides to the size of the longest side
|
||||
if (evenSides)
|
||||
{
|
||||
if (width > height)
|
||||
width = height;
|
||||
else
|
||||
height = width;
|
||||
}
|
||||
|
||||
// Normalize the scale to a percentage
|
||||
SKRect bounds = Layer.GetLayerBounds();
|
||||
width = width / bounds.Width * 100f;
|
||||
height = height / bounds.Height * 100f;
|
||||
|
||||
Layer.Transform.Scale.SetCurrentValue(new SKSize(width, height), _time);
|
||||
return new SKSize(width, height);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rotating
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Movement
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Anchor movement
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
[Flags]
|
||||
public enum ResizeSide
|
||||
{
|
||||
Top = 1,
|
||||
Right = 2,
|
||||
Bottom = 4,
|
||||
Left = 8,
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user