diff --git a/Ink Canvas/Controls/ImageSelectionOverlay.xaml b/Ink Canvas/Controls/ImageSelectionOverlay.xaml new file mode 100644 index 00000000..f3fe739c --- /dev/null +++ b/Ink Canvas/Controls/ImageSelectionOverlay.xaml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Ink Canvas/Controls/ImageSelectionOverlay.xaml.cs b/Ink Canvas/Controls/ImageSelectionOverlay.xaml.cs new file mode 100644 index 00000000..2572e1b3 --- /dev/null +++ b/Ink Canvas/Controls/ImageSelectionOverlay.xaml.cs @@ -0,0 +1,248 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Shapes; + +namespace Ink_Canvas.Controls +{ + public enum ImageResizeCorner + { + TopLeft, + TopRight, + BottomLeft, + BottomRight + } + + public class ImageResizeDeltaEventArgs : EventArgs + { + public ImageResizeCorner Corner { get; } + public Point CurrentCanvasPoint { get; } + public Point StartCanvasPoint { get; } + public bool LockAspectRatio { get; } + + public ImageResizeDeltaEventArgs(ImageResizeCorner corner, Point start, Point current, bool lockAspect) + { + Corner = corner; + StartCanvasPoint = start; + CurrentCanvasPoint = current; + LockAspectRatio = lockAspect; + } + } + + public class ImageMoveDeltaEventArgs : EventArgs + { + public Vector Delta { get; } + public ImageMoveDeltaEventArgs(Vector delta) { Delta = delta; } + } + + public class ImageRotateDeltaEventArgs : EventArgs + { + public double AngleDelta { get; } + public ImageRotateDeltaEventArgs(double angleDelta) { AngleDelta = angleDelta; } + } + + public partial class ImageSelectionOverlay : UserControl + { + private const double HandleSize = 12; + private const double RotationHandleSize = 14; + private const double RotationHandleOffset = 28; + + public event EventHandler ResizeDelta; + public event EventHandler MoveDelta; + public event EventHandler RotateDelta; + public event EventHandler InteractionStarted; + public event EventHandler InteractionEnded; + + public IInputElement CoordinateSource { get; set; } + + private Point _rotationCenter; + + private bool _isResizing; + private bool _isRotating; + private bool _isMoving; + private ImageResizeCorner _activeCorner; + private Point _lastPoint; + private double _lastRotationAngle; + + public ImageSelectionOverlay() + { + InitializeComponent(); + + TopLeftHandle.MouseLeftButtonDown += (s, e) => BeginResize(ImageResizeCorner.TopLeft, e, TopLeftHandle); + TopRightHandle.MouseLeftButtonDown += (s, e) => BeginResize(ImageResizeCorner.TopRight, e, TopRightHandle); + BottomLeftHandle.MouseLeftButtonDown += (s, e) => BeginResize(ImageResizeCorner.BottomLeft, e, BottomLeftHandle); + BottomRightHandle.MouseLeftButtonDown += (s, e) => BeginResize(ImageResizeCorner.BottomRight, e, BottomRightHandle); + + TopLeftHandle.MouseMove += ResizeMove; + TopRightHandle.MouseMove += ResizeMove; + BottomLeftHandle.MouseMove += ResizeMove; + BottomRightHandle.MouseMove += ResizeMove; + + TopLeftHandle.MouseLeftButtonUp += EndResize; + TopRightHandle.MouseLeftButtonUp += EndResize; + BottomLeftHandle.MouseLeftButtonUp += EndResize; + BottomRightHandle.MouseLeftButtonUp += EndResize; + + RotationHandle.MouseLeftButtonDown += BeginRotate; + RotationHandle.MouseMove += RotateMove; + RotationHandle.MouseLeftButtonUp += EndRotate; + + MoveSurface.MouseLeftButtonDown += BeginMove; + MoveSurface.MouseMove += MoveMove; + MoveSurface.MouseLeftButtonUp += EndMove; + } + + public void UpdateFrame(Rect canvasBounds, double rotationAngleDegrees) + { + if (canvasBounds.Width <= 0 || canvasBounds.Height <= 0) return; + + _rotationCenter = new Point(canvasBounds.Left + canvasBounds.Width / 2, + canvasBounds.Top + canvasBounds.Height / 2); + + Margin = new Thickness(canvasBounds.Left, canvasBounds.Top, 0, 0); + Width = canvasBounds.Width; + Height = canvasBounds.Height; + + FrameBorder.Width = canvasBounds.Width; + FrameBorder.Height = canvasBounds.Height; + System.Windows.Controls.Canvas.SetLeft(FrameBorder, 0); + System.Windows.Controls.Canvas.SetTop(FrameBorder, 0); + + MoveSurface.Width = canvasBounds.Width; + MoveSurface.Height = canvasBounds.Height; + System.Windows.Controls.Canvas.SetLeft(MoveSurface, 0); + System.Windows.Controls.Canvas.SetTop(MoveSurface, 0); + + double h = HandleSize / 2; + System.Windows.Controls.Canvas.SetLeft(TopLeftHandle, -h); + System.Windows.Controls.Canvas.SetTop(TopLeftHandle, -h); + System.Windows.Controls.Canvas.SetLeft(TopRightHandle, canvasBounds.Width - h); + System.Windows.Controls.Canvas.SetTop(TopRightHandle, -h); + System.Windows.Controls.Canvas.SetLeft(BottomLeftHandle, -h); + System.Windows.Controls.Canvas.SetTop(BottomLeftHandle, canvasBounds.Height - h); + System.Windows.Controls.Canvas.SetLeft(BottomRightHandle, canvasBounds.Width - h); + System.Windows.Controls.Canvas.SetTop(BottomRightHandle, canvasBounds.Height - h); + + double rh = RotationHandleSize / 2; + double midX = canvasBounds.Width / 2; + System.Windows.Controls.Canvas.SetLeft(RotationHandle, midX - rh); + System.Windows.Controls.Canvas.SetTop(RotationHandle, -RotationHandleOffset - rh); + + RotationLine.X1 = midX; + RotationLine.Y1 = 0; + RotationLine.X2 = midX; + RotationLine.Y2 = -RotationHandleOffset; + } + + private IInputElement GetSource() => CoordinateSource ?? (IInputElement)Parent; + + private void BeginResize(ImageResizeCorner corner, MouseButtonEventArgs e, Ellipse handle) + { + var source = GetSource(); + if (source == null) return; + _isResizing = true; + _activeCorner = corner; + _lastPoint = e.GetPosition(source); + handle.CaptureMouse(); + InteractionStarted?.Invoke(this, EventArgs.Empty); + e.Handled = true; + } + + private void ResizeMove(object sender, MouseEventArgs e) + { + if (!_isResizing || !(sender is Ellipse handle) || !handle.IsMouseCaptured) return; + var source = GetSource(); + if (source == null) return; + var current = e.GetPosition(source); + bool lockAspect = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift; + ResizeDelta?.Invoke(this, new ImageResizeDeltaEventArgs(_activeCorner, _lastPoint, current, lockAspect)); + _lastPoint = current; + e.Handled = true; + } + + private void EndResize(object sender, MouseButtonEventArgs e) + { + if (!_isResizing) return; + if (sender is Ellipse handle) handle.ReleaseMouseCapture(); + _isResizing = false; + InteractionEnded?.Invoke(this, EventArgs.Empty); + e.Handled = true; + } + + private void BeginRotate(object sender, MouseButtonEventArgs e) + { + var source = GetSource(); + if (source == null) return; + _isRotating = true; + var p = e.GetPosition(source); + _lastRotationAngle = AngleFromCenter(p); + RotationHandle.CaptureMouse(); + InteractionStarted?.Invoke(this, EventArgs.Empty); + e.Handled = true; + } + + private void RotateMove(object sender, MouseEventArgs e) + { + if (!_isRotating || !RotationHandle.IsMouseCaptured) return; + var source = GetSource(); + if (source == null) return; + var p = e.GetPosition(source); + double angle = AngleFromCenter(p); + double delta = angle - _lastRotationAngle; + if (delta > 180) delta -= 360; + else if (delta < -180) delta += 360; + _lastRotationAngle = angle; + RotateDelta?.Invoke(this, new ImageRotateDeltaEventArgs(delta)); + e.Handled = true; + } + + private void EndRotate(object sender, MouseButtonEventArgs e) + { + if (!_isRotating) return; + RotationHandle.ReleaseMouseCapture(); + _isRotating = false; + InteractionEnded?.Invoke(this, EventArgs.Empty); + e.Handled = true; + } + + private void BeginMove(object sender, MouseButtonEventArgs e) + { + var source = GetSource(); + if (source == null) return; + _isMoving = true; + _lastPoint = e.GetPosition(source); + MoveSurface.CaptureMouse(); + InteractionStarted?.Invoke(this, EventArgs.Empty); + e.Handled = true; + } + + private void MoveMove(object sender, MouseEventArgs e) + { + if (!_isMoving || !MoveSurface.IsMouseCaptured) return; + var source = GetSource(); + if (source == null) return; + var current = e.GetPosition(source); + var delta = current - _lastPoint; + _lastPoint = current; + MoveDelta?.Invoke(this, new ImageMoveDeltaEventArgs(delta)); + e.Handled = true; + } + + private void EndMove(object sender, MouseButtonEventArgs e) + { + if (!_isMoving) return; + MoveSurface.ReleaseMouseCapture(); + _isMoving = false; + InteractionEnded?.Invoke(this, EventArgs.Empty); + e.Handled = true; + } + + private double AngleFromCenter(Point p) + { + double dx = p.X - _rotationCenter.X; + double dy = p.Y - _rotationCenter.Y; + return Math.Atan2(dy, dx) * 180.0 / Math.PI; + } + } +} \ No newline at end of file diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml index 81f2b99a..0f2ce824 100644 --- a/Ink Canvas/MainWindow.xaml +++ b/Ink Canvas/MainWindow.xaml @@ -666,86 +666,10 @@ - - - - - - - - - - - - - - + + diff --git a/Ink Canvas/MainWindow_cs/MW_ElementsControls.cs b/Ink Canvas/MainWindow_cs/MW_ElementsControls.cs index e91bcb73..9027e594 100644 --- a/Ink Canvas/MainWindow_cs/MW_ElementsControls.cs +++ b/Ink Canvas/MainWindow_cs/MW_ElementsControls.cs @@ -289,7 +289,7 @@ namespace Ink_Canvas } // 如果是图片元素,更新选择点位置 - if (IsBitmapLikeCanvasElement(element) && ImageResizeHandlesCanvas?.Visibility == Visibility.Visible) + if (IsBitmapLikeCanvasElement(element) && ImageSelectionOverlay?.Visibility == Visibility.Visible) { UpdateImageResizeHandlesPosition(GetElementActualBounds(element)); } @@ -325,7 +325,7 @@ namespace Ink_Canvas } // 如果是图片元素,更新选择点位置 - if (IsBitmapLikeCanvasElement(element) && ImageResizeHandlesCanvas?.Visibility == Visibility.Visible) + if (IsBitmapLikeCanvasElement(element) && ImageSelectionOverlay?.Visibility == Visibility.Visible) { UpdateImageResizeHandlesPosition(GetElementActualBounds(element)); } @@ -415,7 +415,7 @@ namespace Ink_Canvas } // 如果是图片元素,更新选择点位置 - if (IsBitmapLikeCanvasElement(element) && ImageResizeHandlesCanvas?.Visibility == Visibility.Visible) + if (IsBitmapLikeCanvasElement(element) && ImageSelectionOverlay?.Visibility == Visibility.Visible) { UpdateImageResizeHandlesPosition(GetElementActualBounds(element)); } @@ -2176,7 +2176,7 @@ namespace Ink_Canvas if (currentSelectedElement != null && IsBitmapLikeCanvasElement(currentSelectedElement)) { UpdateImageSelectionToolbarPosition(currentSelectedElement); - if (ImageResizeHandlesCanvas?.Visibility == Visibility.Visible) + if (ImageSelectionOverlay?.Visibility == Visibility.Visible) UpdateImageResizeHandlesPosition(GetElementActualBounds(currentSelectedElement)); } }), DispatcherPriority.Loaded); @@ -2379,240 +2379,204 @@ namespace Ink_Canvas #endregion - #region Image Resize Handles + #region Image Selection Overlay - // 图片缩放选择点相关变量 - private bool isResizingImage = false; - private Point imageResizeStartPoint; - private string activeResizeHandle = ""; + private bool _imageOverlayHooked; + + private void EnsureImageOverlayHooks() + { + if (_imageOverlayHooked || ImageSelectionOverlay == null) return; + ImageSelectionOverlay.CoordinateSource = inkCanvas; + ImageSelectionOverlay.ResizeDelta += ImageSelectionOverlay_ResizeDelta; + ImageSelectionOverlay.MoveDelta += ImageSelectionOverlay_MoveDelta; + ImageSelectionOverlay.RotateDelta += ImageSelectionOverlay_RotateDelta; + _imageOverlayHooked = true; + } - // 显示图片缩放选择点 private void ShowImageResizeHandles(FrameworkElement element) { try { - if (ImageResizeHandlesCanvas == null || element == null) return; - - // 获取元素的实际边界 - Rect elementBounds = GetElementActualBounds(element); - - // 设置选择点位置 - UpdateImageResizeHandlesPosition(elementBounds); - - // 显示选择点 - ImageResizeHandlesCanvas.Visibility = Visibility.Visible; + if (ImageSelectionOverlay == null || element == null) return; + EnsureImageOverlayHooks(); + Rect bounds = GetElementActualBounds(element); + ImageSelectionOverlay.UpdateFrame(bounds, GetElementRotationAngle(element)); + ImageSelectionOverlay.Visibility = Visibility.Visible; } catch (Exception ex) { - LogHelper.WriteLogToFile($"显示图片缩放选择点失败: {ex.Message}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"显示图片选中框失败: {ex.Message}", LogHelper.LogType.Error); } } - // 隐藏图片缩放选择点 private void HideImageResizeHandles() { try { - if (ImageResizeHandlesCanvas != null) - { - ImageResizeHandlesCanvas.Visibility = Visibility.Collapsed; - } + if (ImageSelectionOverlay != null) + ImageSelectionOverlay.Visibility = Visibility.Collapsed; } catch (Exception ex) { - LogHelper.WriteLogToFile($"隐藏图片缩放选择点失败: {ex.Message}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"隐藏图片选中框失败: {ex.Message}", LogHelper.LogType.Error); } } - // 更新图片缩放选择点位置 private void UpdateImageResizeHandlesPosition(Rect elementBounds) { try { - if (ImageResizeHandlesCanvas == null) return; - - ImageResizeHandlesCanvas.Margin = new Thickness(elementBounds.Left, elementBounds.Top, 0, 0); - - // 四个角控制点 - System.Windows.Controls.Canvas.SetLeft(ImageTopLeftHandle, -4); - System.Windows.Controls.Canvas.SetTop(ImageTopLeftHandle, -4); - - System.Windows.Controls.Canvas.SetLeft(ImageTopRightHandle, elementBounds.Width - 4); - System.Windows.Controls.Canvas.SetTop(ImageTopRightHandle, -4); - - System.Windows.Controls.Canvas.SetLeft(ImageBottomLeftHandle, -4); - System.Windows.Controls.Canvas.SetTop(ImageBottomLeftHandle, elementBounds.Height - 4); - - System.Windows.Controls.Canvas.SetLeft(ImageBottomRightHandle, elementBounds.Width - 4); - System.Windows.Controls.Canvas.SetTop(ImageBottomRightHandle, elementBounds.Height - 4); - - // 四个边控制点 - System.Windows.Controls.Canvas.SetLeft(ImageTopHandle, elementBounds.Width / 2 - 4); - System.Windows.Controls.Canvas.SetTop(ImageTopHandle, -4); - - System.Windows.Controls.Canvas.SetLeft(ImageBottomHandle, elementBounds.Width / 2 - 4); - System.Windows.Controls.Canvas.SetTop(ImageBottomHandle, elementBounds.Height - 4); - - System.Windows.Controls.Canvas.SetLeft(ImageLeftHandle, -4); - System.Windows.Controls.Canvas.SetTop(ImageLeftHandle, elementBounds.Height / 2 - 4); - - System.Windows.Controls.Canvas.SetLeft(ImageRightHandle, elementBounds.Width - 4); - System.Windows.Controls.Canvas.SetTop(ImageRightHandle, elementBounds.Height / 2 - 4); + if (ImageSelectionOverlay == null) return; + double angle = currentSelectedElement != null ? GetElementRotationAngle(currentSelectedElement) : 0; + ImageSelectionOverlay.UpdateFrame(elementBounds, angle); } catch (Exception ex) { - LogHelper.WriteLogToFile($"更新图片缩放选择点位置失败: {ex.Message}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"更新图片选中框位置失败: {ex.Message}", LogHelper.LogType.Error); } } - // 图片缩放选择点鼠标按下事件 - private void ImageResizeHandle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + private double GetElementRotationAngle(FrameworkElement element) + { + if (element?.RenderTransform is TransformGroup tg) + { + var rt = tg.Children.OfType().FirstOrDefault(); + if (rt != null) return rt.Angle; + } + return 0; + } + + private void ImageSelectionOverlay_ResizeDelta(object sender, ImageResizeDeltaEventArgs e) { try { - if (IsBitmapLikeCanvasElement(currentSelectedElement) && sender is Ellipse ellipse) - { - isResizingImage = true; - imageResizeStartPoint = e.GetPosition(inkCanvas); - - // 确定是哪个控制点 - activeResizeHandle = ellipse.Name; - - // 捕获鼠标 - ellipse.CaptureMouse(); - e.Handled = true; - } + if (!IsBitmapLikeCanvasElement(currentSelectedElement)) return; + ResizeImageByCorner(currentSelectedElement, e.StartCanvasPoint, e.CurrentCanvasPoint, e.Corner, e.LockAspectRatio); } catch (Exception ex) { - LogHelper.WriteLogToFile($"图片缩放选择点鼠标按下事件失败: {ex.Message}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"图片缩放失败: {ex.Message}", LogHelper.LogType.Error); } } - // 图片缩放选择点鼠标释放事件 - private void ImageResizeHandle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + private void ImageSelectionOverlay_MoveDelta(object sender, ImageMoveDeltaEventArgs e) { try { - if (isResizingImage && sender is Ellipse ellipse) + if (currentSelectedElement == null) return; + if (currentSelectedElement.RenderTransform is TransformGroup tg) { - isResizingImage = false; - ellipse.ReleaseMouseCapture(); - activeResizeHandle = ""; - e.Handled = true; - } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"图片缩放选择点鼠标释放事件失败: {ex.Message}", LogHelper.LogType.Error); - } - } - - // 图片缩放选择点鼠标移动事件 - private void ImageResizeHandle_MouseMove(object sender, MouseEventArgs e) - { - try - { - if (isResizingImage && IsBitmapLikeCanvasElement(currentSelectedElement) && sender is Ellipse ellipse) - { - var currentPoint = e.GetPosition(inkCanvas); - ResizeImageByHandle(currentSelectedElement, imageResizeStartPoint, currentPoint, activeResizeHandle); - imageResizeStartPoint = currentPoint; - e.Handled = true; - } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"图片缩放选择点鼠标移动事件失败: {ex.Message}", LogHelper.LogType.Error); - } - } - - // 根据控制点缩放图片 - private void ResizeImageByHandle(FrameworkElement element, Point startPoint, Point currentPoint, string handleName) - { - try - { - if (element.RenderTransform is TransformGroup transformGroup) - { - var scaleTransform = transformGroup.Children.OfType().FirstOrDefault(); - var translateTransform = transformGroup.Children.OfType().FirstOrDefault(); - - if (scaleTransform == null || translateTransform == null) return; - - // 获取图片的当前边界 - Rect currentBounds = GetElementActualBounds(element); - double deltaX = currentPoint.X - startPoint.X; - double deltaY = currentPoint.Y - startPoint.Y; - - // 计算缩放比例 - double scaleX = 1.0; - double scaleY = 1.0; - double translateX = 0; - double translateY = 0; - - switch (handleName) + var tt = tg.Children.OfType().FirstOrDefault(); + if (tt != null) { - case "ImageTopLeftHandle": - scaleX = (currentBounds.Width - deltaX) / currentBounds.Width; - scaleY = (currentBounds.Height - deltaY) / currentBounds.Height; - translateX = deltaX; - translateY = deltaY; - break; - case "ImageTopRightHandle": - scaleX = (currentBounds.Width + deltaX) / currentBounds.Width; - scaleY = (currentBounds.Height - deltaY) / currentBounds.Height; - translateY = deltaY; - break; - case "ImageBottomLeftHandle": - scaleX = (currentBounds.Width - deltaX) / currentBounds.Width; - scaleY = (currentBounds.Height + deltaY) / currentBounds.Height; - translateX = deltaX; - break; - case "ImageBottomRightHandle": - scaleX = (currentBounds.Width + deltaX) / currentBounds.Width; - scaleY = (currentBounds.Height + deltaY) / currentBounds.Height; - break; - case "ImageTopHandle": - scaleY = (currentBounds.Height - deltaY) / currentBounds.Height; - translateY = deltaY; - break; - case "ImageBottomHandle": - scaleY = (currentBounds.Height + deltaY) / currentBounds.Height; - break; - case "ImageLeftHandle": - scaleX = (currentBounds.Width - deltaX) / currentBounds.Width; - translateX = deltaX; - break; - case "ImageRightHandle": - scaleX = (currentBounds.Width + deltaX) / currentBounds.Width; - break; + tt.X += e.Delta.X; + tt.Y += e.Delta.Y; } - - // 限制缩放范围 - scaleX = Math.Max(0.1, Math.Min(scaleX, 5.0)); - scaleY = Math.Max(0.1, Math.Min(scaleY, 5.0)); - - // 应用缩放 - scaleTransform.ScaleX *= scaleX; - scaleTransform.ScaleY *= scaleY; - - // 应用平移 - translateTransform.X += translateX; - translateTransform.Y += translateY; - - // 更新选择点位置 - UpdateImageResizeHandlesPosition(GetElementActualBounds(element)); - - if (BorderImageSelectionControl?.Visibility == Visibility.Visible) - UpdateImageSelectionToolbarPosition(element); } + UpdateImageResizeHandlesPosition(GetElementActualBounds(currentSelectedElement)); + if (BorderImageSelectionControl?.Visibility == Visibility.Visible) + UpdateImageSelectionToolbarPosition(currentSelectedElement); } catch (Exception ex) { - LogHelper.WriteLogToFile($"根据控制点缩放图片失败: {ex.Message}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"图片拖动失败: {ex.Message}", LogHelper.LogType.Error); } } + private void ImageSelectionOverlay_RotateDelta(object sender, ImageRotateDeltaEventArgs e) + { + try + { + if (currentSelectedElement == null) return; + ApplyRotateTransform(currentSelectedElement, e.AngleDelta); + UpdateImageResizeHandlesPosition(GetElementActualBounds(currentSelectedElement)); + if (BorderImageSelectionControl?.Visibility == Visibility.Visible) + UpdateImageSelectionToolbarPosition(currentSelectedElement); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"图片旋转失败: {ex.Message}", LogHelper.LogType.Error); + } + } + + private void ResizeImageByCorner(FrameworkElement element, Point startPoint, Point currentPoint, + ImageResizeCorner corner, bool lockAspect) + { + if (!(element.RenderTransform is TransformGroup transformGroup)) return; + var scaleTransform = transformGroup.Children.OfType().FirstOrDefault(); + var translateTransform = transformGroup.Children.OfType().FirstOrDefault(); + if (scaleTransform == null || translateTransform == null) return; + + Rect currentBounds = GetElementActualBounds(element); + if (currentBounds.Width <= 0 || currentBounds.Height <= 0) return; + + double deltaX = currentPoint.X - startPoint.X; + double deltaY = currentPoint.Y - startPoint.Y; + + double scaleX = 1.0, scaleY = 1.0, translateX = 0, translateY = 0; + + switch (corner) + { + case ImageResizeCorner.TopLeft: + scaleX = (currentBounds.Width - deltaX) / currentBounds.Width; + scaleY = (currentBounds.Height - deltaY) / currentBounds.Height; + translateX = deltaX; + translateY = deltaY; + break; + case ImageResizeCorner.TopRight: + scaleX = (currentBounds.Width + deltaX) / currentBounds.Width; + scaleY = (currentBounds.Height - deltaY) / currentBounds.Height; + translateY = deltaY; + break; + case ImageResizeCorner.BottomLeft: + scaleX = (currentBounds.Width - deltaX) / currentBounds.Width; + scaleY = (currentBounds.Height + deltaY) / currentBounds.Height; + translateX = deltaX; + break; + case ImageResizeCorner.BottomRight: + scaleX = (currentBounds.Width + deltaX) / currentBounds.Width; + scaleY = (currentBounds.Height + deltaY) / currentBounds.Height; + break; + } + + if (lockAspect) + { + double uniform = Math.Min(scaleX, scaleY); + scaleX = uniform; + scaleY = uniform; + // recompute translate so opposite corner stays put + double wNew = currentBounds.Width * uniform; + double hNew = currentBounds.Height * uniform; + switch (corner) + { + case ImageResizeCorner.TopLeft: + translateX = currentBounds.Width - wNew; + translateY = currentBounds.Height - hNew; + break; + case ImageResizeCorner.TopRight: + translateX = 0; + translateY = currentBounds.Height - hNew; + break; + case ImageResizeCorner.BottomLeft: + translateX = currentBounds.Width - wNew; + translateY = 0; + break; + } + } + + scaleX = Math.Max(0.1, Math.Min(scaleX, 5.0)); + scaleY = Math.Max(0.1, Math.Min(scaleY, 5.0)); + + scaleTransform.ScaleX *= scaleX; + scaleTransform.ScaleY *= scaleY; + translateTransform.X += translateX; + translateTransform.Y += translateY; + + UpdateImageResizeHandlesPosition(GetElementActualBounds(element)); + if (BorderImageSelectionControl?.Visibility == Visibility.Visible) + UpdateImageSelectionToolbarPosition(element); + } + #endregion } }