2025-09-07 13:30:46 +08:00
|
|
|
|
using Ink_Canvas.Helpers;
|
2025-08-31 11:43:52 +08:00
|
|
|
|
using iNKORE.UI.WPF.Modern.Controls;
|
2025-05-25 09:29:48 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
2025-08-31 09:54:13 +08:00
|
|
|
|
using System.Linq;
|
2025-05-25 09:29:48 +08:00
|
|
|
|
using System.Windows;
|
|
|
|
|
|
using System.Windows.Controls;
|
|
|
|
|
|
using System.Windows.Ink;
|
|
|
|
|
|
using System.Windows.Input;
|
|
|
|
|
|
using System.Windows.Media;
|
2025-09-07 01:45:50 +08:00
|
|
|
|
using System.Windows.Shapes;
|
2025-05-25 09:29:48 +08:00
|
|
|
|
using Point = System.Windows.Point;
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
namespace Ink_Canvas
|
|
|
|
|
|
{
|
|
|
|
|
|
public partial class MainWindow : Window
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
#region Floating Control
|
|
|
|
|
|
|
|
|
|
|
|
private object lastBorderMouseDownObject;
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void Border_MouseDown(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2025-06-17 18:21:14 +08:00
|
|
|
|
// 如果发送者是 RandomDrawPanel 或 SingleDrawPanel,且它们被隐藏,则不处理事件
|
2025-08-03 16:46:33 +08:00
|
|
|
|
if (sender is SimpleStackPanel panel)
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((panel == RandomDrawPanel || panel == SingleDrawPanel) &&
|
|
|
|
|
|
panel.Visibility != Visibility.Visible)
|
|
|
|
|
|
{
|
2025-06-17 18:21:14 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-30 21:18:34 +08:00
|
|
|
|
|
2025-05-25 09:29:48 +08:00
|
|
|
|
lastBorderMouseDownObject = sender;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void BorderStrokeSelectionClone_MouseUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (lastBorderMouseDownObject != sender) return;
|
|
|
|
|
|
|
2025-09-20 11:42:33 +08:00
|
|
|
|
try
|
2025-08-03 16:46:33 +08:00
|
|
|
|
{
|
2025-09-20 11:42:33 +08:00
|
|
|
|
var strokes = inkCanvas.GetSelectedStrokes();
|
|
|
|
|
|
if (strokes.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 直接执行克隆操作,与图片克隆保持一致
|
|
|
|
|
|
CloneStrokes(strokes);
|
|
|
|
|
|
LogHelper.WriteLogToFile($"墨迹克隆完成: {strokes.Count} 个墨迹");
|
|
|
|
|
|
}
|
2025-05-25 09:29:48 +08:00
|
|
|
|
}
|
2025-09-20 11:42:33 +08:00
|
|
|
|
catch (Exception ex)
|
2025-08-03 16:46:33 +08:00
|
|
|
|
{
|
2025-09-20 11:42:33 +08:00
|
|
|
|
LogHelper.WriteLogToFile($"墨迹克隆失败: {ex.Message}", LogHelper.LogType.Error);
|
2025-05-25 09:29:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void BorderStrokeSelectionCloneToNewBoard_MouseUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (lastBorderMouseDownObject != sender) return;
|
|
|
|
|
|
|
|
|
|
|
|
var strokes = inkCanvas.GetSelectedStrokes();
|
|
|
|
|
|
inkCanvas.Select(new StrokeCollection());
|
2025-09-20 11:42:33 +08:00
|
|
|
|
CloneStrokesToNewBoard(strokes);
|
2025-05-25 09:29:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void BorderStrokeSelectionDelete_MouseUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (lastBorderMouseDownObject != sender) return;
|
|
|
|
|
|
SymbolIconDelete_MouseUp(sender, e);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void GridPenWidthDecrease_MouseUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (lastBorderMouseDownObject != sender) return;
|
|
|
|
|
|
ChangeStrokeThickness(0.8);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void GridPenWidthIncrease_MouseUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (lastBorderMouseDownObject != sender) return;
|
|
|
|
|
|
ChangeStrokeThickness(1.25);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void ChangeStrokeThickness(double multipler)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var stroke in inkCanvas.GetSelectedStrokes())
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
var newWidth = stroke.DrawingAttributes.Width * multipler;
|
|
|
|
|
|
var newHeight = stroke.DrawingAttributes.Height * multipler;
|
|
|
|
|
|
if (!(newWidth >= DrawingAttributes.MinWidth) || !(newWidth <= DrawingAttributes.MaxWidth)
|
|
|
|
|
|
|| !(newHeight >= DrawingAttributes.MinHeight) ||
|
|
|
|
|
|
!(newHeight <= DrawingAttributes.MaxHeight)) continue;
|
|
|
|
|
|
stroke.DrawingAttributes.Width = newWidth;
|
|
|
|
|
|
stroke.DrawingAttributes.Height = newHeight;
|
|
|
|
|
|
}
|
2025-08-30 21:18:34 +08:00
|
|
|
|
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (DrawingAttributesHistory.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
timeMachine.CommitStrokeDrawingAttributesHistory(DrawingAttributesHistory);
|
|
|
|
|
|
DrawingAttributesHistory = new Dictionary<Stroke, Tuple<DrawingAttributes, DrawingAttributes>>();
|
|
|
|
|
|
foreach (var item in DrawingAttributesHistoryFlag)
|
|
|
|
|
|
{
|
|
|
|
|
|
item.Value.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void GridPenWidthRestore_MouseUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (lastBorderMouseDownObject != sender) return;
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
foreach (var stroke in inkCanvas.GetSelectedStrokes())
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
stroke.DrawingAttributes.Width = inkCanvas.DefaultDrawingAttributes.Width;
|
|
|
|
|
|
stroke.DrawingAttributes.Height = inkCanvas.DefaultDrawingAttributes.Height;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void ImageFlipHorizontal_MouseUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (lastBorderMouseDownObject != sender) return;
|
|
|
|
|
|
|
|
|
|
|
|
var m = new Matrix();
|
|
|
|
|
|
|
|
|
|
|
|
// Find center of element and then transform to get current location of center
|
|
|
|
|
|
var fe = e.Source as FrameworkElement;
|
|
|
|
|
|
var center = new Point(fe.ActualWidth / 2, fe.ActualHeight / 2);
|
|
|
|
|
|
center = new Point(inkCanvas.GetSelectionBounds().Left + inkCanvas.GetSelectionBounds().Width / 2,
|
|
|
|
|
|
inkCanvas.GetSelectionBounds().Top + inkCanvas.GetSelectionBounds().Height / 2);
|
|
|
|
|
|
center = m.Transform(center); // 转换为矩阵缩放和旋转的中心点
|
|
|
|
|
|
|
|
|
|
|
|
// Update matrix to reflect translation/rotation
|
|
|
|
|
|
m.ScaleAt(-1, 1, center.X, center.Y); // 缩放
|
|
|
|
|
|
|
|
|
|
|
|
var targetStrokes = inkCanvas.GetSelectedStrokes();
|
|
|
|
|
|
foreach (var stroke in targetStrokes) stroke.Transform(m, false);
|
|
|
|
|
|
|
|
|
|
|
|
if (DrawingAttributesHistory.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
//var collecion = new StrokeCollection();
|
|
|
|
|
|
//foreach (var item in DrawingAttributesHistory)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// collecion.Add(item.Key);
|
|
|
|
|
|
//}
|
|
|
|
|
|
timeMachine.CommitStrokeDrawingAttributesHistory(DrawingAttributesHistory);
|
|
|
|
|
|
DrawingAttributesHistory = new Dictionary<Stroke, Tuple<DrawingAttributes, DrawingAttributes>>();
|
|
|
|
|
|
foreach (var item in DrawingAttributesHistoryFlag)
|
|
|
|
|
|
{
|
|
|
|
|
|
item.Value.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//updateBorderStrokeSelectionControlLocation();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void ImageFlipVertical_MouseUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (lastBorderMouseDownObject != sender) return;
|
|
|
|
|
|
|
|
|
|
|
|
var m = new Matrix();
|
|
|
|
|
|
|
|
|
|
|
|
// Find center of element and then transform to get current location of center
|
|
|
|
|
|
var fe = e.Source as FrameworkElement;
|
|
|
|
|
|
var center = new Point(fe.ActualWidth / 2, fe.ActualHeight / 2);
|
|
|
|
|
|
center = new Point(inkCanvas.GetSelectionBounds().Left + inkCanvas.GetSelectionBounds().Width / 2,
|
|
|
|
|
|
inkCanvas.GetSelectionBounds().Top + inkCanvas.GetSelectionBounds().Height / 2);
|
|
|
|
|
|
center = m.Transform(center); // 转换为矩阵缩放和旋转的中心点
|
|
|
|
|
|
|
|
|
|
|
|
// Update matrix to reflect translation/rotation
|
|
|
|
|
|
m.ScaleAt(1, -1, center.X, center.Y); // 缩放
|
|
|
|
|
|
|
|
|
|
|
|
var targetStrokes = inkCanvas.GetSelectedStrokes();
|
|
|
|
|
|
foreach (var stroke in targetStrokes) stroke.Transform(m, false);
|
|
|
|
|
|
|
|
|
|
|
|
if (DrawingAttributesHistory.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
timeMachine.CommitStrokeDrawingAttributesHistory(DrawingAttributesHistory);
|
|
|
|
|
|
DrawingAttributesHistory = new Dictionary<Stroke, Tuple<DrawingAttributes, DrawingAttributes>>();
|
|
|
|
|
|
foreach (var item in DrawingAttributesHistoryFlag)
|
|
|
|
|
|
{
|
|
|
|
|
|
item.Value.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
// ... existing code ...
|
|
|
|
|
|
private void ImageRotate45_MouseUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (lastBorderMouseDownObject != sender) return;
|
|
|
|
|
|
|
|
|
|
|
|
var m = new Matrix();
|
|
|
|
|
|
|
|
|
|
|
|
// Find center of element and then transform to get current location of center
|
|
|
|
|
|
var fe = e.Source as FrameworkElement;
|
|
|
|
|
|
var center = new Point(fe.ActualWidth / 2, fe.ActualHeight / 2);
|
|
|
|
|
|
center = new Point(inkCanvas.GetSelectionBounds().Left + inkCanvas.GetSelectionBounds().Width / 2,
|
|
|
|
|
|
inkCanvas.GetSelectionBounds().Top + inkCanvas.GetSelectionBounds().Height / 2);
|
|
|
|
|
|
center = m.Transform(center); // 转换为矩阵缩放和旋转的中心点
|
|
|
|
|
|
|
|
|
|
|
|
// Update matrix to reflect translation/rotation
|
2025-07-31 13:23:33 +08:00
|
|
|
|
m.RotateAt(45, center.X, center.Y); // 顺时针旋转45度
|
2025-05-25 09:29:48 +08:00
|
|
|
|
|
|
|
|
|
|
var targetStrokes = inkCanvas.GetSelectedStrokes();
|
|
|
|
|
|
foreach (var stroke in targetStrokes) stroke.Transform(m, false);
|
|
|
|
|
|
|
|
|
|
|
|
if (DrawingAttributesHistory.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
timeMachine.CommitStrokeDrawingAttributesHistory(DrawingAttributesHistory);
|
|
|
|
|
|
DrawingAttributesHistory = new Dictionary<Stroke, Tuple<DrawingAttributes, DrawingAttributes>>();
|
|
|
|
|
|
foreach (var item in DrawingAttributesHistoryFlag)
|
|
|
|
|
|
{
|
|
|
|
|
|
item.Value.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void ImageRotate90_MouseUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (lastBorderMouseDownObject != sender) return;
|
|
|
|
|
|
|
|
|
|
|
|
var m = new Matrix();
|
|
|
|
|
|
|
|
|
|
|
|
// Find center of element and then transform to get current location of center
|
|
|
|
|
|
var fe = e.Source as FrameworkElement;
|
|
|
|
|
|
var center = new Point(fe.ActualWidth / 2, fe.ActualHeight / 2);
|
|
|
|
|
|
center = new Point(inkCanvas.GetSelectionBounds().Left + inkCanvas.GetSelectionBounds().Width / 2,
|
|
|
|
|
|
inkCanvas.GetSelectionBounds().Top + inkCanvas.GetSelectionBounds().Height / 2);
|
|
|
|
|
|
center = m.Transform(center); // 转换为矩阵缩放和旋转的中心点
|
|
|
|
|
|
|
|
|
|
|
|
// Update matrix to reflect translation/rotation
|
|
|
|
|
|
m.RotateAt(90, center.X, center.Y); // 旋转
|
|
|
|
|
|
|
|
|
|
|
|
var targetStrokes = inkCanvas.GetSelectedStrokes();
|
|
|
|
|
|
foreach (var stroke in targetStrokes) stroke.Transform(m, false);
|
|
|
|
|
|
|
|
|
|
|
|
if (DrawingAttributesHistory.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var collecion = new StrokeCollection();
|
|
|
|
|
|
foreach (var item in DrawingAttributesHistory)
|
|
|
|
|
|
{
|
|
|
|
|
|
collecion.Add(item.Key);
|
|
|
|
|
|
}
|
2025-08-30 21:18:34 +08:00
|
|
|
|
|
2025-05-25 09:29:48 +08:00
|
|
|
|
timeMachine.CommitStrokeDrawingAttributesHistory(DrawingAttributesHistory);
|
|
|
|
|
|
DrawingAttributesHistory = new Dictionary<Stroke, Tuple<DrawingAttributes, DrawingAttributes>>();
|
|
|
|
|
|
foreach (var item in DrawingAttributesHistoryFlag)
|
|
|
|
|
|
{
|
|
|
|
|
|
item.Value.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-07-28 14:40:44 +08:00
|
|
|
|
private bool isGridInkCanvasSelectionCoverMouseDown;
|
2025-10-01 00:53:22 +08:00
|
|
|
|
private bool isStrokeDragging = false;
|
2025-09-07 00:57:48 +08:00
|
|
|
|
private Point strokeDragStartPoint;
|
2025-05-25 09:29:48 +08:00
|
|
|
|
private StrokeCollection StrokesSelectionClone = new StrokeCollection();
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 01:45:50 +08:00
|
|
|
|
// 选择框和选择点相关变量
|
2025-10-01 00:53:22 +08:00
|
|
|
|
private bool isResizing = false;
|
2025-09-07 01:45:50 +08:00
|
|
|
|
private string currentResizeHandle = "";
|
|
|
|
|
|
private Point resizeStartPoint;
|
|
|
|
|
|
private Rect originalSelectionBounds;
|
2025-05-25 09:29:48 +08:00
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void GridInkCanvasSelectionCover_MouseDown(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
isGridInkCanvasSelectionCoverMouseDown = true;
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 01:16:27 +08:00
|
|
|
|
// 检查是否有选中的墨迹
|
2025-09-07 00:57:48 +08:00
|
|
|
|
if (inkCanvas.GetSelectedStrokes().Count > 0)
|
|
|
|
|
|
{
|
2025-09-07 01:16:27 +08:00
|
|
|
|
// 获取鼠标点击位置
|
|
|
|
|
|
var clickPoint = e.GetPosition(inkCanvas);
|
|
|
|
|
|
var selectionBounds = inkCanvas.GetSelectionBounds();
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 01:16:27 +08:00
|
|
|
|
// 检查点击位置是否在选择框边界内
|
2025-09-07 13:30:46 +08:00
|
|
|
|
if (clickPoint.X >= selectionBounds.Left &&
|
|
|
|
|
|
clickPoint.X <= selectionBounds.Right &&
|
|
|
|
|
|
clickPoint.Y >= selectionBounds.Top &&
|
2025-09-07 01:16:27 +08:00
|
|
|
|
clickPoint.Y <= selectionBounds.Bottom)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 只有在选择框边界内才允许拖动
|
|
|
|
|
|
isStrokeDragging = true;
|
|
|
|
|
|
strokeDragStartPoint = clickPoint;
|
|
|
|
|
|
GridInkCanvasSelectionCover.CaptureMouse();
|
|
|
|
|
|
GridInkCanvasSelectionCover.Cursor = Cursors.SizeAll;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 点击在选择框外,取消选择
|
|
|
|
|
|
inkCanvas.Select(new StrokeCollection());
|
|
|
|
|
|
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
|
|
|
|
|
}
|
2025-09-07 00:57:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void GridInkCanvasSelectionCover_MouseMove(object sender, MouseEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!isGridInkCanvasSelectionCoverMouseDown) return;
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 00:57:48 +08:00
|
|
|
|
// 如果正在拖动墨迹,执行拖动操作
|
|
|
|
|
|
if (isStrokeDragging && GridInkCanvasSelectionCover.IsMouseCaptured)
|
|
|
|
|
|
{
|
|
|
|
|
|
var currentPoint = e.GetPosition(inkCanvas);
|
|
|
|
|
|
var delta = currentPoint - strokeDragStartPoint;
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 00:57:48 +08:00
|
|
|
|
// 创建变换矩阵
|
|
|
|
|
|
var matrix = new Matrix();
|
|
|
|
|
|
matrix.Translate(delta.X, delta.Y);
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 00:57:48 +08:00
|
|
|
|
// 对选中的墨迹应用变换
|
|
|
|
|
|
var selectedStrokes = inkCanvas.GetSelectedStrokes();
|
|
|
|
|
|
foreach (var stroke in selectedStrokes)
|
|
|
|
|
|
{
|
|
|
|
|
|
stroke.Transform(matrix, false);
|
|
|
|
|
|
}
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 00:57:48 +08:00
|
|
|
|
// 更新选中栏位置
|
|
|
|
|
|
updateBorderStrokeSelectionControlLocation();
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 00:57:48 +08:00
|
|
|
|
// 更新起始点
|
|
|
|
|
|
strokeDragStartPoint = currentPoint;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (inkCanvas.GetSelectedStrokes().Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 当鼠标在选中区域移动时,更新墨迹选中栏位置
|
|
|
|
|
|
updateBorderStrokeSelectionControlLocation();
|
|
|
|
|
|
}
|
2025-05-25 09:29:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void GridInkCanvasSelectionCover_MouseUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (!isGridInkCanvasSelectionCoverMouseDown) return;
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 00:57:48 +08:00
|
|
|
|
// 结束墨迹拖动
|
|
|
|
|
|
if (isStrokeDragging)
|
|
|
|
|
|
{
|
|
|
|
|
|
isStrokeDragging = false;
|
|
|
|
|
|
GridInkCanvasSelectionCover.ReleaseMouseCapture();
|
|
|
|
|
|
GridInkCanvasSelectionCover.Cursor = Cursors.Arrow;
|
|
|
|
|
|
}
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-05-25 09:29:48 +08:00
|
|
|
|
isGridInkCanvasSelectionCoverMouseDown = false;
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 00:57:48 +08:00
|
|
|
|
// 只有在没有选中墨迹时才隐藏选中栏
|
|
|
|
|
|
if (inkCanvas.GetSelectedStrokes().Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
|
|
|
|
|
}
|
2025-05-25 09:29:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void BtnSelect_Click(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
forceEraser = true;
|
|
|
|
|
|
drawingShapeMode = 0;
|
|
|
|
|
|
inkCanvas.IsManipulationEnabled = false;
|
2025-08-03 16:46:33 +08:00
|
|
|
|
if (inkCanvas.EditingMode == InkCanvasEditingMode.Select)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (inkCanvas.GetSelectedStrokes().Count == inkCanvas.Strokes.Count)
|
|
|
|
|
|
{
|
2025-08-30 11:20:53 +08:00
|
|
|
|
// 使用集中化的工具模式切换方法
|
2025-08-30 21:18:34 +08:00
|
|
|
|
SetCurrentToolMode(InkCanvasEditingMode.Ink,
|
|
|
|
|
|
() => { SetCurrentToolMode(InkCanvasEditingMode.Select); });
|
2025-05-25 09:29:48 +08:00
|
|
|
|
}
|
2025-08-03 16:46:33 +08:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
var selectedStrokes = new StrokeCollection();
|
|
|
|
|
|
foreach (var stroke in inkCanvas.Strokes)
|
|
|
|
|
|
if (stroke.GetBounds().Width > 0 && stroke.GetBounds().Height > 0)
|
|
|
|
|
|
selectedStrokes.Add(stroke);
|
|
|
|
|
|
inkCanvas.Select(selectedStrokes);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-03 16:46:33 +08:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-08-30 11:20:53 +08:00
|
|
|
|
// 使用集中化的工具模式切换方法
|
|
|
|
|
|
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
2025-05-25 09:29:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private double BorderStrokeSelectionControlWidth = 490.0;
|
|
|
|
|
|
private double BorderStrokeSelectionControlHeight = 80.0;
|
2025-07-28 14:40:44 +08:00
|
|
|
|
private bool isProgramChangeStrokeSelection;
|
2025-05-25 09:29:48 +08:00
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void inkCanvas_SelectionChanged(object sender, EventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (isProgramChangeStrokeSelection) return;
|
2025-08-31 11:43:52 +08:00
|
|
|
|
|
2025-09-07 01:22:46 +08:00
|
|
|
|
// 优先检查墨迹选择状态
|
|
|
|
|
|
if (inkCanvas.GetSelectedStrokes().Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 有墨迹被选中,清除图片选择状态
|
|
|
|
|
|
if (currentSelectedElement != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
currentSelectedElement = null;
|
|
|
|
|
|
// 隐藏图片选择工具栏
|
|
|
|
|
|
if (BorderImageSelectionControl != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
BorderImageSelectionControl.Visibility = Visibility.Collapsed;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 01:45:50 +08:00
|
|
|
|
// 显示墨迹选择栏和选择框
|
2025-09-07 01:22:46 +08:00
|
|
|
|
GridInkCanvasSelectionCover.Visibility = Visibility.Visible;
|
|
|
|
|
|
BorderStrokeSelectionClone.Background = Brushes.Transparent;
|
|
|
|
|
|
updateBorderStrokeSelectionControlLocation();
|
2025-09-07 01:45:50 +08:00
|
|
|
|
UpdateSelectionDisplay();
|
2025-09-07 01:22:46 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否有图片元素被选中(通过InkCanvas的选中元素)
|
2025-08-30 22:14:39 +08:00
|
|
|
|
var selectedElements = inkCanvas.GetSelectedElements();
|
2025-08-31 09:54:13 +08:00
|
|
|
|
bool hasImageElement = selectedElements.Any(element => element is Image);
|
2025-08-31 11:43:52 +08:00
|
|
|
|
|
2025-08-30 22:14:39 +08:00
|
|
|
|
// 如果有图片元素被选中,不显示选择框
|
|
|
|
|
|
if (hasImageElement)
|
|
|
|
|
|
{
|
|
|
|
|
|
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
2025-09-07 01:45:50 +08:00
|
|
|
|
HideSelectionDisplay();
|
2025-08-30 22:14:39 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-08-31 11:43:52 +08:00
|
|
|
|
|
2025-09-07 01:22:46 +08:00
|
|
|
|
// 检查是否有图片元素被选中(通过currentSelectedElement)
|
|
|
|
|
|
if (currentSelectedElement != null && currentSelectedElement is Image)
|
2025-08-03 16:46:33 +08:00
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
2025-09-07 01:45:50 +08:00
|
|
|
|
HideSelectionDisplay();
|
2025-09-07 01:22:46 +08:00
|
|
|
|
return;
|
2025-05-25 09:29:48 +08:00
|
|
|
|
}
|
2025-09-07 01:22:46 +08:00
|
|
|
|
|
|
|
|
|
|
// 没有选中任何内容,隐藏选择框
|
|
|
|
|
|
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
2025-09-07 01:45:50 +08:00
|
|
|
|
HideSelectionDisplay();
|
2025-05-25 09:29:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-30 21:18:34 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void updateBorderStrokeSelectionControlLocation()
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
var borderLeft = (inkCanvas.GetSelectionBounds().Left + inkCanvas.GetSelectionBounds().Right -
|
|
|
|
|
|
BorderStrokeSelectionControlWidth) / 2;
|
2025-09-07 00:49:10 +08:00
|
|
|
|
var borderTop = inkCanvas.GetSelectionBounds().Bottom + 10; // 在墨迹下方10像素处显示
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (borderLeft < 0) borderLeft = 0;
|
|
|
|
|
|
if (borderTop < 0) borderTop = 0;
|
|
|
|
|
|
if (Width - borderLeft < BorderStrokeSelectionControlWidth || double.IsNaN(borderLeft))
|
|
|
|
|
|
borderLeft = Width - BorderStrokeSelectionControlWidth;
|
|
|
|
|
|
if (Height - borderTop < BorderStrokeSelectionControlHeight || double.IsNaN(borderTop))
|
|
|
|
|
|
borderTop = Height - BorderStrokeSelectionControlHeight;
|
|
|
|
|
|
|
2025-09-07 00:49:10 +08:00
|
|
|
|
// 确保墨迹选中栏始终显示在墨迹下方
|
|
|
|
|
|
// 如果选中栏会超出屏幕底部,则显示在墨迹上方
|
|
|
|
|
|
if (borderTop + BorderStrokeSelectionControlHeight > Height)
|
|
|
|
|
|
{
|
|
|
|
|
|
borderTop = inkCanvas.GetSelectionBounds().Top - BorderStrokeSelectionControlHeight - 10;
|
|
|
|
|
|
if (borderTop < 0) borderTop = 10; // 如果上方也没有空间,则显示在顶部
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-25 09:29:48 +08:00
|
|
|
|
BorderStrokeSelectionControl.Margin = new Thickness(borderLeft, borderTop, 0, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void GridInkCanvasSelectionCover_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
e.Mode = ManipulationModes.All;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void GridInkCanvasSelectionCover_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (StrokeManipulationHistory?.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
timeMachine.CommitStrokeManipulationHistory(StrokeManipulationHistory);
|
|
|
|
|
|
foreach (var item in StrokeManipulationHistory)
|
|
|
|
|
|
{
|
|
|
|
|
|
StrokeInitialHistory[item.Key] = item.Value.Item2;
|
|
|
|
|
|
}
|
2025-08-30 21:18:34 +08:00
|
|
|
|
|
2025-05-25 09:29:48 +08:00
|
|
|
|
StrokeManipulationHistory = null;
|
|
|
|
|
|
}
|
2025-08-30 21:18:34 +08:00
|
|
|
|
|
2025-05-25 09:29:48 +08:00
|
|
|
|
if (DrawingAttributesHistory.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
timeMachine.CommitStrokeDrawingAttributesHistory(DrawingAttributesHistory);
|
|
|
|
|
|
DrawingAttributesHistory = new Dictionary<Stroke, Tuple<DrawingAttributes, DrawingAttributes>>();
|
|
|
|
|
|
foreach (var item in DrawingAttributesHistoryFlag)
|
|
|
|
|
|
{
|
|
|
|
|
|
item.Value.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void GridInkCanvasSelectionCover_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (dec.Count >= 1)
|
|
|
|
|
|
{
|
2025-07-23 22:57:16 +08:00
|
|
|
|
bool disableScale = dec.Count >= 3;
|
2025-05-25 09:29:48 +08:00
|
|
|
|
var md = e.DeltaManipulation;
|
|
|
|
|
|
var trans = md.Translation; // 获得位移矢量
|
|
|
|
|
|
var rotate = md.Rotation; // 获得旋转角度
|
|
|
|
|
|
var scale = md.Scale; // 获得缩放倍数
|
|
|
|
|
|
|
|
|
|
|
|
var m = new Matrix();
|
|
|
|
|
|
|
|
|
|
|
|
// Find center of element and then transform to get current location of center
|
|
|
|
|
|
var fe = e.Source as FrameworkElement;
|
|
|
|
|
|
var center = new Point(fe.ActualWidth / 2, fe.ActualHeight / 2);
|
|
|
|
|
|
center = new Point(inkCanvas.GetSelectionBounds().Left + inkCanvas.GetSelectionBounds().Width / 2,
|
|
|
|
|
|
inkCanvas.GetSelectionBounds().Top + inkCanvas.GetSelectionBounds().Height / 2);
|
|
|
|
|
|
center = m.Transform(center); // 转换为矩阵缩放和旋转的中心点
|
|
|
|
|
|
|
|
|
|
|
|
// Update matrix to reflect translation/rotation
|
|
|
|
|
|
m.Translate(trans.X, trans.Y); // 移动
|
2025-06-19 22:49:11 +08:00
|
|
|
|
if (!disableScale)
|
|
|
|
|
|
m.ScaleAt(scale.X, scale.Y, center.X, center.Y); // 缩放
|
2025-05-25 09:29:48 +08:00
|
|
|
|
|
|
|
|
|
|
var strokes = inkCanvas.GetSelectedStrokes();
|
|
|
|
|
|
if (StrokesSelectionClone.Count != 0)
|
|
|
|
|
|
strokes = StrokesSelectionClone;
|
|
|
|
|
|
else if (Settings.Gesture.IsEnableTwoFingerRotationOnSelection)
|
|
|
|
|
|
m.RotateAt(rotate, center.X, center.Y); // 旋转
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 01:22:46 +08:00
|
|
|
|
// 应用变换到选中的墨迹
|
2025-08-03 16:46:33 +08:00
|
|
|
|
foreach (var stroke in strokes)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
stroke.Transform(m, false);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
updateBorderStrokeSelectionControlLocation();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-07 07:53:05 +08:00
|
|
|
|
catch (Exception ex)
|
2025-08-30 21:18:34 +08:00
|
|
|
|
{
|
2025-09-07 07:53:05 +08:00
|
|
|
|
LogHelper.WriteLogToFile($"墨迹ManipulationDelta错误: {ex.Message}", LogHelper.LogType.Error);
|
2025-08-30 21:18:34 +08:00
|
|
|
|
}
|
2025-05-25 09:29:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-30 21:18:34 +08:00
|
|
|
|
private void GridInkCanvasSelectionCover_TouchDown(object sender, TouchEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
2025-05-25 09:29:48 +08:00
|
|
|
|
|
2025-08-30 21:18:34 +08:00
|
|
|
|
private void GridInkCanvasSelectionCover_TouchUp(object sender, TouchEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
2025-05-25 09:29:48 +08:00
|
|
|
|
|
2025-09-07 01:22:46 +08:00
|
|
|
|
private void GridInkCanvasSelectionCover_TouchMove(object sender, TouchEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 处理触摸移动事件 - 用于拖动选中的墨迹
|
|
|
|
|
|
if (inkCanvas.GetSelectedStrokes().Count > 0 && dec.Count == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
var currentTouchPoint = e.GetTouchPoint(inkCanvas).Position;
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 07:53:05 +08:00
|
|
|
|
// 检查是否有有效的起始触摸点
|
|
|
|
|
|
if (lastTouchPointOnGridInkCanvasCover != new Point(0, 0))
|
2025-09-07 01:22:46 +08:00
|
|
|
|
{
|
2025-09-07 07:53:05 +08:00
|
|
|
|
var delta = currentTouchPoint - lastTouchPointOnGridInkCanvasCover;
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 07:53:05 +08:00
|
|
|
|
// 只有当移动距离足够大时才进行拖动(避免微小移动造成的抖动)
|
|
|
|
|
|
if (Math.Abs(delta.X) > 1 || Math.Abs(delta.Y) > 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建变换矩阵
|
|
|
|
|
|
var matrix = new Matrix();
|
|
|
|
|
|
matrix.Translate(delta.X, delta.Y);
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 07:53:05 +08:00
|
|
|
|
// 对选中的墨迹应用变换
|
|
|
|
|
|
var selectedStrokes = inkCanvas.GetSelectedStrokes();
|
|
|
|
|
|
foreach (var stroke in selectedStrokes)
|
|
|
|
|
|
{
|
|
|
|
|
|
stroke.Transform(matrix, false);
|
|
|
|
|
|
}
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 07:53:05 +08:00
|
|
|
|
// 更新选中栏位置
|
|
|
|
|
|
updateBorderStrokeSelectionControlLocation();
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 07:53:05 +08:00
|
|
|
|
// 更新最后触摸点
|
|
|
|
|
|
lastTouchPointOnGridInkCanvasCover = currentTouchPoint;
|
|
|
|
|
|
}
|
2025-09-07 01:22:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void GridInkCanvasSelectionCover_PreviewTouchMove(object sender, TouchEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 预览触摸移动事件 - 用于更精确的触摸处理
|
|
|
|
|
|
if (inkCanvas.GetSelectedStrokes().Count > 0 && dec.Count == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
var currentTouchPoint = e.GetTouchPoint(inkCanvas).Position;
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 07:53:05 +08:00
|
|
|
|
// 检查是否有有效的起始触摸点
|
|
|
|
|
|
if (lastTouchPointOnGridInkCanvasCover != new Point(0, 0))
|
2025-09-07 01:22:46 +08:00
|
|
|
|
{
|
2025-09-07 07:53:05 +08:00
|
|
|
|
var delta = currentTouchPoint - lastTouchPointOnGridInkCanvasCover;
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 07:53:05 +08:00
|
|
|
|
// 只有当移动距离足够大时才进行拖动(避免微小移动造成的抖动)
|
|
|
|
|
|
if (Math.Abs(delta.X) > 1 || Math.Abs(delta.Y) > 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建变换矩阵
|
|
|
|
|
|
var matrix = new Matrix();
|
|
|
|
|
|
matrix.Translate(delta.X, delta.Y);
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 07:53:05 +08:00
|
|
|
|
// 对选中的墨迹应用变换
|
|
|
|
|
|
var selectedStrokes = inkCanvas.GetSelectedStrokes();
|
|
|
|
|
|
foreach (var stroke in selectedStrokes)
|
|
|
|
|
|
{
|
|
|
|
|
|
stroke.Transform(matrix, false);
|
|
|
|
|
|
}
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 07:53:05 +08:00
|
|
|
|
// 更新选中栏位置
|
|
|
|
|
|
updateBorderStrokeSelectionControlLocation();
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 07:53:05 +08:00
|
|
|
|
// 更新最后触摸点
|
|
|
|
|
|
lastTouchPointOnGridInkCanvasCover = currentTouchPoint;
|
|
|
|
|
|
}
|
2025-09-07 01:22:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-25 09:29:48 +08:00
|
|
|
|
private Point lastTouchPointOnGridInkCanvasCover = new Point(0, 0);
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void GridInkCanvasSelectionCover_PreviewTouchDown(object sender, TouchEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
dec.Add(e.TouchDevice.Id);
|
|
|
|
|
|
//设备1个的时候,记录中心点
|
2025-08-03 16:46:33 +08:00
|
|
|
|
if (dec.Count == 1)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
var touchPoint = e.GetTouchPoint(null);
|
|
|
|
|
|
centerPoint = touchPoint.Position;
|
2025-09-07 01:22:46 +08:00
|
|
|
|
lastTouchPointOnGridInkCanvasCover = e.GetTouchPoint(inkCanvas).Position;
|
2025-05-25 09:29:48 +08:00
|
|
|
|
|
2025-09-07 01:16:27 +08:00
|
|
|
|
// 检查是否有选中的墨迹
|
|
|
|
|
|
if (inkCanvas.GetSelectedStrokes().Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 获取触摸点位置
|
|
|
|
|
|
var touchPosition = e.GetTouchPoint(inkCanvas).Position;
|
|
|
|
|
|
var selectionBounds = inkCanvas.GetSelectionBounds();
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 01:16:27 +08:00
|
|
|
|
// 检查触摸位置是否在选择框边界内
|
2025-09-07 13:30:46 +08:00
|
|
|
|
if (touchPosition.X >= selectionBounds.Left &&
|
|
|
|
|
|
touchPosition.X <= selectionBounds.Right &&
|
|
|
|
|
|
touchPosition.Y >= selectionBounds.Top &&
|
2025-09-07 01:16:27 +08:00
|
|
|
|
touchPosition.Y <= selectionBounds.Bottom)
|
|
|
|
|
|
{
|
2025-09-07 13:30:46 +08:00
|
|
|
|
// 只有在选择框边界内才允许拖动
|
|
|
|
|
|
// 触摸拖动状态已通过TouchMove事件处理
|
2025-09-07 01:16:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 触摸在选择框外,取消选择
|
|
|
|
|
|
inkCanvas.Select(new StrokeCollection());
|
|
|
|
|
|
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-20 11:42:33 +08:00
|
|
|
|
|
|
|
|
|
|
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
|
|
|
|
|
inkCanvas.Select(new StrokeCollection());
|
2025-05-25 09:29:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void GridInkCanvasSelectionCover_PreviewTouchUp(object sender, TouchEventArgs e)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
dec.Remove(e.TouchDevice.Id);
|
|
|
|
|
|
if (dec.Count >= 1) return;
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 07:53:05 +08:00
|
|
|
|
// 重置触摸状态
|
|
|
|
|
|
lastTouchPointOnGridInkCanvasCover = new Point(0, 0);
|
2025-05-25 09:29:48 +08:00
|
|
|
|
isProgramChangeStrokeSelection = false;
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 07:53:05 +08:00
|
|
|
|
// 检查是否有点击(没有移动)
|
|
|
|
|
|
var currentTouchPoint = e.GetTouchPoint(null).Position;
|
|
|
|
|
|
if (Math.Abs(currentTouchPoint.X - centerPoint.X) < 5 && Math.Abs(currentTouchPoint.Y - centerPoint.Y) < 5)
|
2025-08-03 16:46:33 +08:00
|
|
|
|
{
|
2025-09-07 07:53:05 +08:00
|
|
|
|
// 点击在选择框内,保持选择状态
|
|
|
|
|
|
if (inkCanvas.GetSelectedStrokes().Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var selectionBounds = inkCanvas.GetSelectionBounds();
|
2025-09-07 13:30:46 +08:00
|
|
|
|
if (currentTouchPoint.X >= selectionBounds.Left &&
|
|
|
|
|
|
currentTouchPoint.X <= selectionBounds.Right &&
|
|
|
|
|
|
currentTouchPoint.Y >= selectionBounds.Top &&
|
2025-09-07 07:53:05 +08:00
|
|
|
|
currentTouchPoint.Y <= selectionBounds.Bottom)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 点击在选择框内,保持选择
|
|
|
|
|
|
GridInkCanvasSelectionCover.Visibility = Visibility.Visible;
|
|
|
|
|
|
StrokesSelectionClone = new StrokeCollection();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 07:53:05 +08:00
|
|
|
|
// 点击在选择框外,取消选择
|
2025-05-25 09:29:48 +08:00
|
|
|
|
inkCanvas.Select(new StrokeCollection());
|
|
|
|
|
|
StrokesSelectionClone = new StrokeCollection();
|
|
|
|
|
|
}
|
2025-08-03 16:46:33 +08:00
|
|
|
|
else if (inkCanvas.GetSelectedStrokes().Count == 0)
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
|
|
|
|
|
StrokesSelectionClone = new StrokeCollection();
|
|
|
|
|
|
}
|
2025-08-03 16:46:33 +08:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-05-25 09:29:48 +08:00
|
|
|
|
GridInkCanvasSelectionCover.Visibility = Visibility.Visible;
|
|
|
|
|
|
StrokesSelectionClone = new StrokeCollection();
|
|
|
|
|
|
}
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-05-25 09:29:48 +08:00
|
|
|
|
}
|
2025-07-18 16:12:04 +08:00
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void LassoSelect_Click(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
2025-07-18 16:12:04 +08:00
|
|
|
|
forceEraser = false;
|
|
|
|
|
|
forcePointEraser = false;
|
|
|
|
|
|
drawingShapeMode = 0;
|
2025-08-30 11:20:53 +08:00
|
|
|
|
// 使用集中化的工具模式切换方法
|
|
|
|
|
|
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
2025-07-18 16:12:04 +08:00
|
|
|
|
SetCursorBasedOnEditingMode(inkCanvas);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-03 16:46:33 +08:00
|
|
|
|
private void BtnLassoSelect_Click(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
2025-07-18 16:12:04 +08:00
|
|
|
|
forceEraser = false;
|
|
|
|
|
|
forcePointEraser = false;
|
|
|
|
|
|
drawingShapeMode = 0;
|
2025-08-30 11:20:53 +08:00
|
|
|
|
// 使用集中化的工具模式切换方法
|
|
|
|
|
|
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
2025-07-18 16:12:04 +08:00
|
|
|
|
inkCanvas.IsManipulationEnabled = true;
|
|
|
|
|
|
SetCursorBasedOnEditingMode(inkCanvas);
|
|
|
|
|
|
}
|
2025-07-28 11:15:35 +08:00
|
|
|
|
|
|
|
|
|
|
#region UIElement Selection and Resize
|
2025-08-31 11:43:52 +08:00
|
|
|
|
|
2025-07-28 11:15:35 +08:00
|
|
|
|
private Rect GetUIElementBounds(UIElement element)
|
|
|
|
|
|
{
|
2025-07-30 14:18:45 +08:00
|
|
|
|
if (element is FrameworkElement fe)
|
|
|
|
|
|
{
|
|
|
|
|
|
var left = InkCanvas.GetLeft(element);
|
|
|
|
|
|
var top = InkCanvas.GetTop(element);
|
2025-07-28 11:15:35 +08:00
|
|
|
|
|
2025-07-30 14:18:45 +08:00
|
|
|
|
if (double.IsNaN(left)) left = 0;
|
|
|
|
|
|
if (double.IsNaN(top)) top = 0;
|
2025-07-28 11:15:35 +08:00
|
|
|
|
|
2025-07-30 14:18:45 +08:00
|
|
|
|
var width = fe.ActualWidth > 0 ? fe.ActualWidth : fe.Width;
|
|
|
|
|
|
var height = fe.ActualHeight > 0 ? fe.ActualHeight : fe.Height;
|
2025-07-28 11:15:35 +08:00
|
|
|
|
|
2025-07-30 14:18:45 +08:00
|
|
|
|
// 检查是否有RenderTransform
|
|
|
|
|
|
if (fe.RenderTransform != null && fe.RenderTransform != Transform.Identity)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果有变换,使用变换后的边界
|
|
|
|
|
|
var transform = element.TransformToAncestor(inkCanvas);
|
|
|
|
|
|
var elementBounds = new Rect(0, 0, width, height);
|
|
|
|
|
|
var transformedBounds = transform.TransformBounds(elementBounds);
|
|
|
|
|
|
return transformedBounds;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
// 变换失败时回退到简单计算
|
|
|
|
|
|
return new Rect(left, top, width, height);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-31 09:54:13 +08:00
|
|
|
|
|
|
|
|
|
|
// 没有变换时直接使用位置和大小
|
|
|
|
|
|
return new Rect(left, top, width, height);
|
2025-07-28 11:15:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-30 14:18:45 +08:00
|
|
|
|
return new Rect(0, 0, 0, 0);
|
2025-07-28 11:15:35 +08:00
|
|
|
|
}
|
2025-09-07 01:45:50 +08:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Selection Display and Resize Handles
|
|
|
|
|
|
|
|
|
|
|
|
private void UpdateSelectionDisplay()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (inkCanvas.GetSelectedStrokes().Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
HideSelectionDisplay();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var selectionBounds = inkCanvas.GetSelectionBounds();
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 01:45:50 +08:00
|
|
|
|
// 更新选择框
|
|
|
|
|
|
SelectionRectangle.Visibility = Visibility.Visible;
|
|
|
|
|
|
SelectionRectangle.Margin = new Thickness(selectionBounds.Left, selectionBounds.Top, 0, 0);
|
|
|
|
|
|
SelectionRectangle.Width = selectionBounds.Width;
|
|
|
|
|
|
SelectionRectangle.Height = selectionBounds.Height;
|
|
|
|
|
|
|
|
|
|
|
|
// 更新选择点位置
|
|
|
|
|
|
UpdateSelectionHandles(selectionBounds);
|
|
|
|
|
|
SelectionHandlesCanvas.Visibility = Visibility.Visible;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void HideSelectionDisplay()
|
|
|
|
|
|
{
|
|
|
|
|
|
SelectionRectangle.Visibility = Visibility.Collapsed;
|
|
|
|
|
|
SelectionHandlesCanvas.Visibility = Visibility.Collapsed;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void UpdateSelectionHandles(Rect bounds)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 四个角选择点
|
|
|
|
|
|
TopLeftHandle.Margin = new Thickness(bounds.Left - 4, bounds.Top - 4, 0, 0);
|
|
|
|
|
|
TopRightHandle.Margin = new Thickness(bounds.Right - 4, bounds.Top - 4, 0, 0);
|
|
|
|
|
|
BottomLeftHandle.Margin = new Thickness(bounds.Left - 4, bounds.Bottom - 4, 0, 0);
|
|
|
|
|
|
BottomRightHandle.Margin = new Thickness(bounds.Right - 4, bounds.Bottom - 4, 0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
// 四个边选择点
|
|
|
|
|
|
TopHandle.Margin = new Thickness(bounds.Left + bounds.Width / 2 - 4, bounds.Top - 4, 0, 0);
|
|
|
|
|
|
BottomHandle.Margin = new Thickness(bounds.Left + bounds.Width / 2 - 4, bounds.Bottom - 4, 0, 0);
|
|
|
|
|
|
LeftHandle.Margin = new Thickness(bounds.Left - 4, bounds.Top + bounds.Height / 2 - 4, 0, 0);
|
|
|
|
|
|
RightHandle.Margin = new Thickness(bounds.Right - 4, bounds.Top + bounds.Height / 2 - 4, 0, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SelectionHandle_MouseDown(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (sender is Rectangle handle)
|
|
|
|
|
|
{
|
|
|
|
|
|
isResizing = true;
|
|
|
|
|
|
currentResizeHandle = handle.Name;
|
|
|
|
|
|
resizeStartPoint = e.GetPosition(inkCanvas);
|
|
|
|
|
|
originalSelectionBounds = inkCanvas.GetSelectionBounds();
|
|
|
|
|
|
handle.CaptureMouse();
|
|
|
|
|
|
e.Handled = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SelectionHandle_MouseMove(object sender, MouseEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!isResizing || !(sender is Rectangle handle)) return;
|
|
|
|
|
|
|
|
|
|
|
|
var currentPoint = e.GetPosition(inkCanvas);
|
|
|
|
|
|
var delta = new Point(currentPoint.X - resizeStartPoint.X, currentPoint.Y - resizeStartPoint.Y);
|
|
|
|
|
|
|
|
|
|
|
|
var newBounds = CalculateNewBounds(originalSelectionBounds, delta, currentResizeHandle);
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 01:45:50 +08:00
|
|
|
|
// 应用新的边界到选中的墨迹
|
|
|
|
|
|
ApplyBoundsToStrokes(newBounds);
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 01:45:50 +08:00
|
|
|
|
// 更新选择框显示
|
|
|
|
|
|
UpdateSelectionDisplay();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SelectionHandle_MouseUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (sender is Rectangle handle)
|
|
|
|
|
|
{
|
|
|
|
|
|
isResizing = false;
|
|
|
|
|
|
currentResizeHandle = "";
|
|
|
|
|
|
handle.ReleaseMouseCapture();
|
|
|
|
|
|
e.Handled = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private Rect CalculateNewBounds(Rect originalBounds, Point delta, string handleName)
|
|
|
|
|
|
{
|
|
|
|
|
|
var newBounds = originalBounds;
|
2025-09-07 07:59:21 +08:00
|
|
|
|
double newWidth = originalBounds.Width;
|
|
|
|
|
|
double newHeight = originalBounds.Height;
|
|
|
|
|
|
double newX = originalBounds.X;
|
|
|
|
|
|
double newY = originalBounds.Y;
|
2025-09-07 01:45:50 +08:00
|
|
|
|
|
|
|
|
|
|
switch (handleName)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "TopLeftHandle":
|
2025-09-07 07:59:21 +08:00
|
|
|
|
newX = originalBounds.X + delta.X;
|
|
|
|
|
|
newY = originalBounds.Y + delta.Y;
|
|
|
|
|
|
newWidth = originalBounds.Width - delta.X;
|
|
|
|
|
|
newHeight = originalBounds.Height - delta.Y;
|
2025-09-07 01:45:50 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case "TopRightHandle":
|
2025-09-07 07:59:21 +08:00
|
|
|
|
newY = originalBounds.Y + delta.Y;
|
|
|
|
|
|
newWidth = originalBounds.Width + delta.X;
|
|
|
|
|
|
newHeight = originalBounds.Height - delta.Y;
|
2025-09-07 01:45:50 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case "BottomLeftHandle":
|
2025-09-07 07:59:21 +08:00
|
|
|
|
newX = originalBounds.X + delta.X;
|
|
|
|
|
|
newWidth = originalBounds.Width - delta.X;
|
|
|
|
|
|
newHeight = originalBounds.Height + delta.Y;
|
2025-09-07 01:45:50 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case "BottomRightHandle":
|
2025-09-07 07:59:21 +08:00
|
|
|
|
newWidth = originalBounds.Width + delta.X;
|
|
|
|
|
|
newHeight = originalBounds.Height + delta.Y;
|
2025-09-07 01:45:50 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case "TopHandle":
|
2025-09-07 07:59:21 +08:00
|
|
|
|
newY = originalBounds.Y + delta.Y;
|
|
|
|
|
|
newHeight = originalBounds.Height - delta.Y;
|
2025-09-07 01:45:50 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case "BottomHandle":
|
2025-09-07 07:59:21 +08:00
|
|
|
|
newHeight = originalBounds.Height + delta.Y;
|
2025-09-07 01:45:50 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case "LeftHandle":
|
2025-09-07 07:59:21 +08:00
|
|
|
|
newX = originalBounds.X + delta.X;
|
|
|
|
|
|
newWidth = originalBounds.Width - delta.X;
|
2025-09-07 01:45:50 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case "RightHandle":
|
2025-09-07 07:59:21 +08:00
|
|
|
|
newWidth = originalBounds.Width + delta.X;
|
2025-09-07 01:45:50 +08:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-07 07:59:21 +08:00
|
|
|
|
// 确保最小尺寸和正值
|
|
|
|
|
|
if (newWidth < 10) newWidth = 10;
|
|
|
|
|
|
if (newHeight < 10) newHeight = 10;
|
|
|
|
|
|
|
|
|
|
|
|
// 创建新的Rect,确保所有值都是有效的
|
|
|
|
|
|
newBounds = new Rect(newX, newY, newWidth, newHeight);
|
2025-09-07 01:45:50 +08:00
|
|
|
|
|
|
|
|
|
|
return newBounds;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ApplyBoundsToStrokes(Rect newBounds)
|
|
|
|
|
|
{
|
|
|
|
|
|
var selectedStrokes = inkCanvas.GetSelectedStrokes();
|
|
|
|
|
|
if (selectedStrokes.Count == 0) return;
|
|
|
|
|
|
|
|
|
|
|
|
var originalBounds = inkCanvas.GetSelectionBounds();
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 01:45:50 +08:00
|
|
|
|
// 计算缩放比例
|
|
|
|
|
|
var scaleX = newBounds.Width / originalBounds.Width;
|
|
|
|
|
|
var scaleY = newBounds.Height / originalBounds.Height;
|
2025-09-07 13:30:46 +08:00
|
|
|
|
|
2025-09-07 01:45:50 +08:00
|
|
|
|
// 计算平移量
|
|
|
|
|
|
var translateX = newBounds.X - originalBounds.X;
|
|
|
|
|
|
var translateY = newBounds.Y - originalBounds.Y;
|
|
|
|
|
|
|
|
|
|
|
|
// 创建变换矩阵
|
|
|
|
|
|
var matrix = new Matrix();
|
|
|
|
|
|
matrix.Translate(translateX, translateY);
|
|
|
|
|
|
matrix.ScaleAt(scaleX, scaleY, originalBounds.X + originalBounds.Width / 2, originalBounds.Y + originalBounds.Height / 2);
|
|
|
|
|
|
|
|
|
|
|
|
// 应用变换到选中的墨迹
|
|
|
|
|
|
foreach (var stroke in selectedStrokes)
|
|
|
|
|
|
{
|
|
|
|
|
|
stroke.Transform(matrix, false);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2025-05-25 09:29:48 +08:00
|
|
|
|
}
|
2025-08-30 21:18:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|