improve:图片选中
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
<UserControl x:Class="Ink_Canvas.Controls.ImageSelectionOverlay"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Background="{x:Null}"
|
||||
IsHitTestVisible="True">
|
||||
<Canvas x:Name="OverlayRoot" Background="Transparent" IsHitTestVisible="True" ClipToBounds="False">
|
||||
<Rectangle x:Name="MoveSurface"
|
||||
Fill="Transparent"
|
||||
Cursor="SizeAll"
|
||||
IsHitTestVisible="True" />
|
||||
<Rectangle x:Name="FrameBorder"
|
||||
Stroke="#22D3A9"
|
||||
StrokeThickness="1.5"
|
||||
Fill="Transparent"
|
||||
IsHitTestVisible="False"
|
||||
SnapsToDevicePixels="True" />
|
||||
|
||||
<Line x:Name="RotationLine"
|
||||
Stroke="#22D3A9"
|
||||
StrokeThickness="1.5"
|
||||
IsHitTestVisible="False"
|
||||
SnapsToDevicePixels="True" />
|
||||
|
||||
<Ellipse x:Name="RotationHandle"
|
||||
Width="14" Height="14"
|
||||
Fill="#22D3A9"
|
||||
Stroke="White"
|
||||
StrokeThickness="2"
|
||||
Cursor="Hand" />
|
||||
|
||||
<Ellipse x:Name="TopLeftHandle"
|
||||
Width="12" Height="12"
|
||||
Fill="White"
|
||||
Stroke="#22D3A9"
|
||||
StrokeThickness="1.5"
|
||||
Cursor="SizeNWSE" />
|
||||
<Ellipse x:Name="TopRightHandle"
|
||||
Width="12" Height="12"
|
||||
Fill="White"
|
||||
Stroke="#22D3A9"
|
||||
StrokeThickness="1.5"
|
||||
Cursor="SizeNESW" />
|
||||
<Ellipse x:Name="BottomLeftHandle"
|
||||
Width="12" Height="12"
|
||||
Fill="White"
|
||||
Stroke="#22D3A9"
|
||||
StrokeThickness="1.5"
|
||||
Cursor="SizeNESW" />
|
||||
<Ellipse x:Name="BottomRightHandle"
|
||||
Width="12" Height="12"
|
||||
Fill="White"
|
||||
Stroke="#22D3A9"
|
||||
StrokeThickness="1.5"
|
||||
Cursor="SizeNWSE" />
|
||||
</Canvas>
|
||||
</UserControl>
|
||||
@@ -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<ImageResizeDeltaEventArgs> ResizeDelta;
|
||||
public event EventHandler<ImageMoveDeltaEventArgs> MoveDelta;
|
||||
public event EventHandler<ImageRotateDeltaEventArgs> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -666,86 +666,10 @@
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- 图片缩放选择点 -->
|
||||
<Canvas Name="ImageResizeHandlesCanvas"
|
||||
Visibility="Collapsed"
|
||||
Panel.ZIndex="1000">
|
||||
<!-- 四个角控制点 -->
|
||||
<Ellipse Name="ImageTopLeftHandle"
|
||||
Width="8" Height="8"
|
||||
Fill="White"
|
||||
Stroke="#0078D4"
|
||||
StrokeThickness="1"
|
||||
Cursor="SizeNWSE"
|
||||
MouseLeftButtonDown="ImageResizeHandle_MouseLeftButtonDown"
|
||||
MouseLeftButtonUp="ImageResizeHandle_MouseLeftButtonUp"
|
||||
MouseMove="ImageResizeHandle_MouseMove" />
|
||||
<Ellipse Name="ImageTopRightHandle"
|
||||
Width="8" Height="8"
|
||||
Fill="White"
|
||||
Stroke="#0078D4"
|
||||
StrokeThickness="1"
|
||||
Cursor="SizeNESW"
|
||||
MouseLeftButtonDown="ImageResizeHandle_MouseLeftButtonDown"
|
||||
MouseLeftButtonUp="ImageResizeHandle_MouseLeftButtonUp"
|
||||
MouseMove="ImageResizeHandle_MouseMove" />
|
||||
<Ellipse Name="ImageBottomLeftHandle"
|
||||
Width="8" Height="8"
|
||||
Fill="White"
|
||||
Stroke="#0078D4"
|
||||
StrokeThickness="1"
|
||||
Cursor="SizeNESW"
|
||||
MouseLeftButtonDown="ImageResizeHandle_MouseLeftButtonDown"
|
||||
MouseLeftButtonUp="ImageResizeHandle_MouseLeftButtonUp"
|
||||
MouseMove="ImageResizeHandle_MouseMove" />
|
||||
<Ellipse Name="ImageBottomRightHandle"
|
||||
Width="8" Height="8"
|
||||
Fill="White"
|
||||
Stroke="#0078D4"
|
||||
StrokeThickness="1"
|
||||
Cursor="SizeNWSE"
|
||||
MouseLeftButtonDown="ImageResizeHandle_MouseLeftButtonDown"
|
||||
MouseLeftButtonUp="ImageResizeHandle_MouseLeftButtonUp"
|
||||
MouseMove="ImageResizeHandle_MouseMove" />
|
||||
|
||||
<!-- 四个边控制点 -->
|
||||
<Ellipse Name="ImageTopHandle"
|
||||
Width="8" Height="8"
|
||||
Fill="White"
|
||||
Stroke="#0078D4"
|
||||
StrokeThickness="1"
|
||||
Cursor="SizeNS"
|
||||
MouseLeftButtonDown="ImageResizeHandle_MouseLeftButtonDown"
|
||||
MouseLeftButtonUp="ImageResizeHandle_MouseLeftButtonUp"
|
||||
MouseMove="ImageResizeHandle_MouseMove" />
|
||||
<Ellipse Name="ImageBottomHandle"
|
||||
Width="8" Height="8"
|
||||
Fill="White"
|
||||
Stroke="#0078D4"
|
||||
StrokeThickness="1"
|
||||
Cursor="SizeNS"
|
||||
MouseLeftButtonDown="ImageResizeHandle_MouseLeftButtonDown"
|
||||
MouseLeftButtonUp="ImageResizeHandle_MouseLeftButtonUp"
|
||||
MouseMove="ImageResizeHandle_MouseMove" />
|
||||
<Ellipse Name="ImageLeftHandle"
|
||||
Width="8" Height="8"
|
||||
Fill="White"
|
||||
Stroke="#0078D4"
|
||||
StrokeThickness="1"
|
||||
Cursor="SizeWE"
|
||||
MouseLeftButtonDown="ImageResizeHandle_MouseLeftButtonDown"
|
||||
MouseLeftButtonUp="ImageResizeHandle_MouseLeftButtonUp"
|
||||
MouseMove="ImageResizeHandle_MouseMove" />
|
||||
<Ellipse Name="ImageRightHandle"
|
||||
Width="8" Height="8"
|
||||
Fill="White"
|
||||
Stroke="#0078D4"
|
||||
StrokeThickness="1"
|
||||
Cursor="SizeWE"
|
||||
MouseLeftButtonDown="ImageResizeHandle_MouseLeftButtonDown"
|
||||
MouseLeftButtonUp="ImageResizeHandle_MouseLeftButtonUp"
|
||||
MouseMove="ImageResizeHandle_MouseMove" />
|
||||
</Canvas>
|
||||
<!-- 图片选中框(边框 + 四角自由缩放 + 顶部旋转手柄) -->
|
||||
<localControls:ImageSelectionOverlay x:Name="ImageSelectionOverlay"
|
||||
Visibility="Collapsed"
|
||||
Panel.ZIndex="1000" />
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -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<RotateTransform>().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<ScaleTransform>().FirstOrDefault();
|
||||
var translateTransform = transformGroup.Children.OfType<TranslateTransform>().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<TranslateTransform>().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<ScaleTransform>().FirstOrDefault();
|
||||
var translateTransform = transformGroup.Children.OfType<TranslateTransform>().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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user