Files

1362 lines
67 KiB
C#
Raw Permalink Normal View History

2025-08-23 21:39:21 +08:00
using iNKORE.UI.WPF.Modern.Controls;
using Microsoft.Office.Interop.PowerPoint;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Resources;
using Ink_Canvas.Popups;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;
using Application = System.Windows.Application;
using Matrix = System.Windows.Media.Matrix;
using Point = System.Windows.Point;
using Ink_Canvas.Helpers;
namespace Ink_Canvas {
public partial class MainWindow : PerformanceTransparentWin {
#region Floating Control
private object lastBorderMouseDownObject;
private void Border_MouseDown(object sender, MouseButtonEventArgs e) {
lastBorderMouseDownObject = sender;
}
private bool isStrokeSelectionCloneOn = false;
#region StrokesSelectionToolbarButtons
private Border BorderStrokeSelectionToolButtonMouseDown = null;
private void BorderStrokeSelectionToolButton_MouseDown(object sender, MouseButtonEventArgs e) {
var bd = (Border)sender;
BorderStrokeSelectionToolButtonMouseDown = bd;
var innerBd = (Border)bd.Child;
if (bd.Name != "BorderStrokeSelectionDelete") innerBd.Background = new SolidColorBrush(Color.FromArgb(24, 9, 9, 11));
else innerBd.Background = new SolidColorBrush(Color.FromRgb(254, 202, 202));
}
private void BorderStrokeSelectionToolButton_MouseLeave(object sender, MouseEventArgs e) {
if (BorderStrokeSelectionToolButtonMouseDown == null) return;
var innerBd = (Border)BorderStrokeSelectionToolButtonMouseDown.Child;
innerBd.Background = new SolidColorBrush(Colors.Transparent);
BorderStrokeSelectionToolButtonMouseDown = null;
}
private void UpdateStrokesSelectionCloneToolButtonLimitStatus() {
UpdateSelectionToolbarOtherIconLockedStatus(isStrokeSelectionCloneOn);
BorderStrokeSelectionLock.IsHitTestVisible = !isStrokeSelectionCloneOn;
BorderStrokeSelectionLock.Opacity = isStrokeSelectionCloneOn ? 0.5 : 1;
BorderStrokeSelectionLock.IsEnabled = !isStrokeSelectionCloneOn;
BorderStrokeSelectionClone.IsHitTestVisible = true;
BorderStrokeSelectionClone.Opacity = 1;
BorderStrokeSelectionClone.IsEnabled = true;
}
/// <summary>
/// 墨迹克隆按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BorderStrokeSelectionClone_MouseUp(object sender, MouseButtonEventArgs e) {
if (BorderStrokeSelectionToolButtonMouseDown != (Border)sender) return;
var bd = (Border)sender;
var innerBd = (Border)bd.Child;
// toolbutton
BorderStrokeSelectionToolButton_MouseLeave(sender, e);
if (isStrokeSelectionCloneOn) {
isStrokeSelectionCloneOn = false;
innerBd.Background = new SolidColorBrush(Colors.Transparent);
BorderStrokeSelectionCloneGeometryIcon.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
} else {
isStrokeSelectionCloneOn = true;
innerBd.Background = new SolidColorBrush(Color.FromRgb(187, 247, 208));
BorderStrokeSelectionCloneGeometryIcon.Brush = new SolidColorBrush(Color.FromRgb(21, 128, 61));
}
UpdateStrokesSelectionCloneToolButtonLimitStatus();
}
/// <summary>
/// 复制到白板或复制到新页面
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BorderStrokeSelectionCloneToNewBoard_MouseUp(object sender, MouseButtonEventArgs e) {
if (BorderStrokeSelectionToolButtonMouseDown != (Border)sender) return;
// toolbutton
BorderStrokeSelectionToolButton_MouseLeave(sender, e);
var strokes = inkCanvas.GetSelectedStrokes();
inkCanvas.Select(new StrokeCollection());
CancelCurrentStrokesSelection();
strokes = strokes.Clone();
if (currentMode == 0) ImageBlackboard_MouseUp(null, null);
else BtnWhiteBoardAdd_Click(null, null);
inkCanvas.Strokes.Add(strokes);
}
/// <summary>
/// 删除墨迹
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BorderStrokeSelectionDelete_MouseUp(object sender, MouseButtonEventArgs e) {
if (BorderStrokeSelectionToolButtonMouseDown != (Border)sender) return;
SymbolIconDelete_MouseUp(sender, e);
// toolbutton
BorderStrokeSelectionToolButton_MouseLeave(sender, e);
}
/// <summary>
/// 墨迹的 更多 菜单
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BorderStrokeMoreMenuButton_MouseUp(object sender, MouseButtonEventArgs e) {
if (BorderStrokeSelectionToolButtonMouseDown != (Border)sender) return;
var cm = this.FindResource("StrokesSelectionMoreMenuButtonContextMenu") as ContextMenu;
cm.IsOpen = true;
// toolbutton
BorderStrokeSelectionToolButton_MouseLeave(sender, e);
}
/// <summary>
/// 通用的墨迹矩阵操作
/// </summary>
/// <param name="func"></param>
private void MatrixStrokes(Func<Matrix,Point,Matrix> func) {
var m = new Matrix();
Point center = new Point(inkCanvas.GetSelectionBounds().Left + inkCanvas.GetSelectionBounds().Width / 2,
inkCanvas.GetSelectionBounds().Top + inkCanvas.GetSelectionBounds().Height / 2);
center = m.Transform(center); // 转换为矩阵缩放和旋转的中心点
m = func(m,center);
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();
}
}
}
private void __tb_preview__(object sender, MouseButtonEventArgs e) {
// toolbutton
BorderStrokeSelectionToolButton_MouseLeave(sender, e);
// update preview and border
InkSelectionStrokesOverlay.DrawStrokes(inkCanvas.GetSelectedStrokes(), new Matrix());
UpdateStrokeSelectionBorder(true, inkCanvas.GetSelectionBounds());
updateBorderStrokeSelectionControlLocation();
}
/// <summary>
/// 旋转墨迹按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ImageRotate_MouseUp(object sender, MouseButtonEventArgs e) {
if (BorderStrokeSelectionToolButtonMouseDown != (Border)sender) return;
MatrixStrokes((m, cent) => {
m.RotateAt((((Border)sender).Name=="BorderImageRotate45"?45:90) * (StrokesRotateClockwise == 0 ? 1 : -1), cent.X, cent.Y);
return m;
});
__tb_preview__(sender, e);
}
/// <summary>
/// 翻转墨迹按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ImageFlip_MouseUp(object sender, MouseButtonEventArgs e) {
if (BorderStrokeSelectionToolButtonMouseDown != (Border)sender) return;
MatrixStrokes((m, cent) => {
m.ScaleAt((((Border)sender).Name=="BorderImageFlipHorizontal"?-1:1),(((Border)sender).Name=="BorderImageFlipVertical"?-1:1),cent.X,cent.Y);
return m;
});
__tb_preview__(sender, e);
}
#endregion
private void GridPenWidthDecrease_MouseUp(object sender, MouseButtonEventArgs e) {
if (lastBorderMouseDownObject != sender) return;
ChangeStrokeThickness(0.8);
}
private void GridPenWidthIncrease_MouseUp(object sender, MouseButtonEventArgs e) {
if (lastBorderMouseDownObject != sender) return;
ChangeStrokeThickness(1.25);
}
private void ChangeStrokeThickness(double multipler) {
foreach (var stroke in inkCanvas.GetSelectedStrokes()) {
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;
}
if (DrawingAttributesHistory.Count > 0)
{
timeMachine.CommitStrokeDrawingAttributesHistory(DrawingAttributesHistory);
DrawingAttributesHistory = new Dictionary<Stroke, Tuple<DrawingAttributes, DrawingAttributes>>();
foreach (var item in DrawingAttributesHistoryFlag)
{
item.Value.Clear();
}
}
}
private void GridPenWidthRestore_MouseUp(object sender, MouseButtonEventArgs e) {
if (lastBorderMouseDownObject != sender) return;
foreach (var stroke in inkCanvas.GetSelectedStrokes()) {
stroke.DrawingAttributes.Width = inkCanvas.DefaultDrawingAttributes.Width;
stroke.DrawingAttributes.Height = inkCanvas.DefaultDrawingAttributes.Height;
}
}
private enum StrokesRotateClockwiseEnum {
RotateClockwise,
RotateCounterClockwise,
}
private StrokesRotateClockwiseEnum StrokesRotateClockwise = StrokesRotateClockwiseEnum.RotateClockwise;
private void ImageRotateClockwise_MouseUp(object sender, MouseButtonEventArgs e) {
if (BorderStrokeSelectionToolButtonMouseDown != (Border)sender) return;
StrokesRotateClockwise = (StrokesRotateClockwiseEnum)(StrokesRotateClockwise == 0 ? 1 : 0);
BorderImageRotateClockwise.RenderTransform = new ScaleTransform(StrokesRotateClockwise == 0 ? 1 : -1, 1);
// toolbutton
BorderStrokeSelectionToolButton_MouseLeave(sender, e);
}
#endregion
private bool isGridInkCanvasSelectionCoverMouseDown = false;
private StrokeCollection StrokesSelectionClone = new StrokeCollection();
private bool isRectangleSelectionMouseDown = false;
// 矩形框选
private Point rectangleSelection_FirstPoint = new Point(0, 0);
private Point rectangleSelection_LastPoint = new Point(0, 0);
// 套索框选
private PointCollection rectangleSelection_LassoPoints = new PointCollection();
private void GridInkCanvasSelectionCover_MouseDown(object sender, MouseButtonEventArgs e) {
isGridInkCanvasSelectionCoverMouseDown = true;
}
private void GridInkCanvasSelectionCover_MouseUp(object sender, MouseButtonEventArgs e) {
isGridInkCanvasSelectionCoverMouseDown = false;
CancelCurrentStrokesSelection();
}
private void InkCanvasDeleteCommandFiredEvent(object sender, RoutedEventArgs e) {
SymbolIconDelete_MouseUp(null, null);
}
private void RectangleSelectionHitTestBorder_MouseDown(object sender, MouseButtonEventArgs e) {
var pt = e.GetPosition(Main_Grid);
var nt = inkCanvas.Strokes.HitTest(pt, 8);
if (nt.Count > 0 && !(e.RightButton == MouseButtonState.Pressed)) {
if (nt.Count > 1) {
var nodia = nt.HitTest(pt);
if (nodia.Count > 0) {
if (nodia[nodia.Count - 1].ContainsPropertyData(IsLockGuid) && Settings.Canvas.AllowClickToSelectLockedStroke) return;
inkCanvas.Select(new StrokeCollection() {nodia[nodia.Count-1]});
} else {
if (nt[0].ContainsPropertyData(IsLockGuid) && Settings.Canvas.AllowClickToSelectLockedStroke) return;
inkCanvas.Select(new StrokeCollection() { nt[0] });
}
} else if (nt.Count == 1) {
if (nt[0].ContainsPropertyData(IsLockGuid) && Settings.Canvas.AllowClickToSelectLockedStroke) return;
inkCanvas.Select(nt);
}
} else {
RectangleSelectionHitTestBorder.CaptureMouse();
isRectangleSelectionMouseDown = true;
if (Settings.Canvas.SelectionMethod == 1) {
rectangleSelection_FirstPoint = pt;
} else {
rectangleSelection_LassoPoints.Clear();
rectangleSelection_LassoPoints.Add(pt);
}
}
}
private void RectangleSelectionHitTestBorder_MouseMove(object sender, MouseEventArgs e) {
var pt = e.GetPosition(Main_Grid);
if (!isRectangleSelectionMouseDown) return;
if (Settings.Canvas.SelectionMethod == 1) {
rectangleSelection_LastPoint = pt;
RectangleSelection.DrawSelectionBox(new Rect(rectangleSelection_FirstPoint, rectangleSelection_LastPoint));
} else {
rectangleSelection_LassoPoints.Add(pt);
RectangleSelection.DrawLassoLine(rectangleSelection_LassoPoints);
}
}
private void RectangleSelectionHitTestBorder_MouseUp(object sender, MouseButtonEventArgs e) {
if (!isRectangleSelectionMouseDown) return;
RectangleSelectionHitTestBorder.ReleaseMouseCapture();
isRectangleSelectionMouseDown = false;
var pt = e.GetPosition(Main_Grid);
var ilh = inkCanvas.Strokes.GetIncrementalLassoHitTester(Settings.Canvas.OnlyHitTestFullyContainedStrokes ? 100 : 1);
void func(object s, LassoSelectionChangedEventArgs _e) {
var _ilh = s as IncrementalLassoHitTester;
if (_e.SelectedStrokes.Count==0) UpdateStrokeSelectionBorder(false, null);
inkCanvas.Select(_e.SelectedStrokes);
_ilh.EndHitTesting();
}
ilh.SelectionChanged += func;
if (Settings.Canvas.SelectionMethod == 1) {
rectangleSelection_LastPoint = pt;
var rct = new Rect(rectangleSelection_FirstPoint, rectangleSelection_LastPoint);
ilh.AddPoints(new Point[] {
rct.TopLeft,
rct.TopRight,
rct.BottomRight,
rct.BottomLeft,
rct.TopLeft
});
} else {
rectangleSelection_LassoPoints.Add(pt);
ilh.AddPoints(rectangleSelection_LassoPoints);
}
RectangleSelection.ClearDrawing();
}
private Border[] StrokeSelectionBorderHandles = new Border[] { };
#region StrokeSelectionBorder
private bool isLockedStrokeSelectionHandle = false;
private Border lockedStrokeSelectionHandle = null;
private StrokeSelectionBorderHandlesEnum? lockedStrokeSelectionBorderHandleType = null;
private Rect? originalSelectionBounds = null;
private Rect? resizedSelectionBounds = null;
private Point? resizingFirstPoint = null;
private Point? resizingLastPoint = null;
private void StrokeSelectionBorderHandle_MouseDown(object sender, MouseButtonEventArgs e) {
if (isStrokeSelectionBorderLocked) return;
if (isLockedStrokeSelectionHandle || isLockedStrokeSelectionMove || isLockedStrokeSelectionRotate) return;
// lock
isLockedStrokeSelectionHandle = true;
var bd = (Border)sender;
lockedStrokeSelectionHandle = bd;
if (bd.Name != "StrokeSelectionRotateHandle") {
var index = StrokeSelectionBorderGrid.Children.IndexOf((Border)sender) - 3;
lockedStrokeSelectionBorderHandleType = (StrokeSelectionBorderHandlesEnum)index;
} else {
lockedStrokeSelectionBorderHandleType = StrokeSelectionBorderHandlesEnum.Rotate;
}
// capture
// TODO 这里还需要对触摸屏幕的单个TouchDevice进行Capture
bd.CaptureMouse();
// hide selectionToolBar
BorderStrokeSelectionControl.Visibility = Visibility.Collapsed;
// resize toast
var sb = inkCanvas.GetSelectionBounds();
if (!(sb.Width < 96 && sb.Height < 64)) {
StrokeSelectionSizeToast.Visibility = Visibility.Visible;
((TextBlock)StrokeSelectionSizeToastInner.Children[0]).Text = Math.Round(sb.Width, 2).ToString();
((TextBlock)StrokeSelectionSizeToastInner.Children[2]).Text = Math.Round(sb.Height, 2).ToString();
var lti = (int)lockedStrokeSelectionBorderHandleType;
System.Windows.Controls.Canvas.SetLeft(StrokeSelectionSizeToast, double.NaN);
System.Windows.Controls.Canvas.SetRight(StrokeSelectionSizeToast, double.NaN);
System.Windows.Controls.Canvas.SetTop(StrokeSelectionSizeToast, double.NaN);
System.Windows.Controls.Canvas.SetBottom(StrokeSelectionSizeToast, double.NaN);
if (lti == 0 || lti == 2 || lti == 4 || lti == 7) System.Windows.Controls.Canvas.SetLeft(StrokeSelectionSizeToast,1);
else System.Windows.Controls.Canvas.SetRight(StrokeSelectionSizeToast, 1);
if (lti == 0 || lti == 1 || lti == 4 || lti == 6) System.Windows.Controls.Canvas.SetTop(StrokeSelectionSizeToast, 1);
else System.Windows.Controls.Canvas.SetBottom(StrokeSelectionSizeToast, 1);
} else {
StrokeSelectionSizeToast.Visibility = Visibility.Collapsed;
}
// record first pt
var nowWindowPosition = e.GetPosition(Main_Grid);
resizingFirstPoint = nowWindowPosition;
// record original bounds
var transform = StrokeSelectionBorder.TransformToVisual(Main_Grid);
var ori_lt = transform.Transform(new Point(0, 0));
var ori_rb = transform.Transform(new Point(StrokeSelectionBorder.Width, StrokeSelectionBorder.Height));
originalSelectionBounds = new Rect(ori_lt, ori_rb);
}
private void StrokeSelectionBorderHandle_MouseUp(object sender, MouseButtonEventArgs e) {
if (isStrokeSelectionBorderLocked) return;
if (!isLockedStrokeSelectionHandle || isLockedStrokeSelectionMove || isLockedStrokeSelectionRotate) return;
// resize strokes and preview strokes
SelectedStrokesResize(inkCanvas.GetSelectedStrokes(), (StrokeSelectionBorderHandlesEnum)lockedStrokeSelectionBorderHandleType,
(Rect)originalSelectionBounds, (Rect)resizedSelectionBounds);
InkSelectionStrokesOverlay.DrawStrokes(inkCanvas.GetSelectedStrokes(), new Matrix());
// display selectionToolBar
var bd = new Binding("Visibility");
bd.Source = GridInkCanvasSelectionCover;
BorderStrokeSelectionControl.SetBinding(Border.VisibilityProperty, bd);
// unlock
isLockedStrokeSelectionHandle = false;
lockedStrokeSelectionBorderHandleType = null;
// release capture
// TODO 这里还需要对触摸屏幕的单个TouchDevice进行ReleaseCapture
lockedStrokeSelectionHandle.ReleaseMouseCapture();
// unlock
lockedStrokeSelectionHandle = null;
// resize toast
StrokeSelectionSizeToast.Visibility = Visibility.Collapsed;
// update selection border size
UpdateStrokeSelectionBorder(true, inkCanvas.GetSelectionBounds());
updateBorderStrokeSelectionControlLocation();
}
private void StrokeSelectionBorderHandle_MouseMove(object sender, MouseEventArgs e) {
if (isStrokeSelectionBorderLocked) return;
if (!isLockedStrokeSelectionHandle || isLockedStrokeSelectionMove || isLockedStrokeSelectionRotate) return;
var bd = (Border)sender;
var nowWindowPosition = e.GetPosition(Main_Grid);
// record last pt
var rlp = nowWindowPosition;
// resize preview border
var isReverseWidth = false; // 是否逆向 resize Width,true 為調小,false為調大
var isReverseHeight = false; // 是否逆向 resize Height,true 為調小,false為調大
if (lockedStrokeSelectionBorderHandleType == StrokeSelectionBorderHandlesEnum.LeftTop) {
isReverseWidth = ((Point)rlp).X > ((Point)resizingFirstPoint).X;
isReverseHeight = ((Point)rlp).Y > ((Point)resizingFirstPoint).Y;
} else if (lockedStrokeSelectionBorderHandleType == StrokeSelectionBorderHandlesEnum.RightTop) {
isReverseWidth = ((Point)rlp).X < ((Point)resizingFirstPoint).X;
isReverseHeight = ((Point)rlp).Y > ((Point)resizingFirstPoint).Y;
} else if (lockedStrokeSelectionBorderHandleType == StrokeSelectionBorderHandlesEnum.LeftBottom) {
isReverseWidth = ((Point)rlp).X > ((Point)resizingFirstPoint).X;
isReverseHeight = ((Point)rlp).Y < ((Point)resizingFirstPoint).Y;
} else if (lockedStrokeSelectionBorderHandleType == StrokeSelectionBorderHandlesEnum.RightBottom) {
isReverseWidth = ((Point)rlp).X < ((Point)resizingFirstPoint).X;
isReverseHeight = ((Point)rlp).Y < ((Point)resizingFirstPoint).Y;
} else if (lockedStrokeSelectionBorderHandleType == StrokeSelectionBorderHandlesEnum.Top) {
isReverseWidth = false;
isReverseHeight = ((Point)rlp).Y > ((Point)resizingFirstPoint).Y;
} else if (lockedStrokeSelectionBorderHandleType == StrokeSelectionBorderHandlesEnum.Bottom) {
isReverseWidth = false;
isReverseHeight = ((Point)rlp).Y < ((Point)resizingFirstPoint).Y;
} else if (lockedStrokeSelectionBorderHandleType == StrokeSelectionBorderHandlesEnum.Left) {
isReverseWidth = ((Point)rlp).X > ((Point)resizingFirstPoint).X;
isReverseHeight = false;
} else if (lockedStrokeSelectionBorderHandleType == StrokeSelectionBorderHandlesEnum.Right) {
isReverseWidth = ((Point)rlp).X < ((Point)resizingFirstPoint).X;
isReverseHeight = false;
}
// caculate height width left top
var l = Math.Round(
((Rect)originalSelectionBounds).Left +
((int)lockedStrokeSelectionBorderHandleType == 0 || (int)lockedStrokeSelectionBorderHandleType == 2 || (int)lockedStrokeSelectionBorderHandleType == 4
? new Rect(((Point)resizingFirstPoint), ((Point)rlp)).Width *
(isReverseWidth ? 1 : -1)
: 0), 0);
var t = Math.Round(
((Rect)originalSelectionBounds).Top +
((int)lockedStrokeSelectionBorderHandleType == 0 || (int)lockedStrokeSelectionBorderHandleType == 1 || (int)lockedStrokeSelectionBorderHandleType == 6
? new Rect(((Point)resizingFirstPoint), ((Point)rlp)).Height *
(isReverseHeight ? 1 : -1)
: 0), 0);
var w = (int)lockedStrokeSelectionBorderHandleType != 6 && (int)lockedStrokeSelectionBorderHandleType != 7 ? Math.Round(((Rect)originalSelectionBounds).Width + new Rect(((Point)resizingFirstPoint),
((Point)rlp)).Width * (isReverseWidth ? -1 : 1), 0) : ((Rect)originalSelectionBounds).Width;
var h = (int)lockedStrokeSelectionBorderHandleType != 4 && (int)lockedStrokeSelectionBorderHandleType != 5 ? Math.Round(((Rect)originalSelectionBounds).Height + new Rect(((Point)resizingFirstPoint),
((Point)rlp)).Height * (isReverseHeight ? -1 : 1), 0) : ((Rect)originalSelectionBounds).Height;
var final_w = Math.Round(w,0);
var final_h = Math.Round(h,0);
if (isShiftKeyDown) {
var scaleW = w / ((Rect)originalSelectionBounds).Width;
var scaleH = h / ((Rect)originalSelectionBounds).Height;
final_w = Math.Round(((Rect)originalSelectionBounds).Width * Math.Max(scaleW, scaleH),0);
final_h = Math.Round(((Rect)originalSelectionBounds).Height * Math.Max(scaleW, scaleH),0);
}
if (final_w >= 1 && final_h >= 1) {
// TODO 此處還需要修改行為,讓其能夠縮放到1x1;
StrokeSelectionBorder.Width = final_w >=1 ? final_w : 1;
StrokeSelectionBorder.Height = final_h >=1 ? final_h : 1;
System.Windows.Controls.Canvas.SetLeft(StrokeSelectionBorder, l);
System.Windows.Controls.Canvas.SetTop(StrokeSelectionBorder, t);
resizingLastPoint = rlp;
if (!(final_w < 96 && final_h < 64)) StrokeSelectionSizeToast.Visibility = Visibility.Visible;
else StrokeSelectionSizeToast.Visibility = Visibility.Collapsed;
// resize toast text
((TextBlock)StrokeSelectionSizeToastInner.Children[0]).Text = final_w.ToString();
((TextBlock)StrokeSelectionSizeToastInner.Children[2]).Text = final_h.ToString();
// record resized bounds
var transform = StrokeSelectionBorder.TransformToVisual(Main_Grid);
var ori_lt = transform.Transform(new Point(0, 0));
var ori_rb = transform.Transform(new Point(StrokeSelectionBorder.Width, StrokeSelectionBorder.Height));
resizedSelectionBounds = new Rect(ori_lt, ori_rb);
// preview resize
SelectedStrokesResize(inkCanvas.GetSelectedStrokes(), (StrokeSelectionBorderHandlesEnum)lockedStrokeSelectionBorderHandleType,
(Rect)originalSelectionBounds, (Rect)resizedSelectionBounds, true);
}
}
private Point? movingFirstPoint = null;
private Point? movingLastPoint = null;
private double movingFirstBorderLeft = 0;
private double movingFirstBorderTop = 0;
private bool isLockedStrokeSelectionMove = false;
private bool isProgramChangeStrokesSelection = false;
private void StrokeSelectionBorder_MouseUp(object sender, MouseButtonEventArgs e) {
if (isStrokeSelectionBorderLocked) return;
if (isLockedStrokeSelectionHandle || isLockedStrokeSelectionRotate || !isLockedStrokeSelectionMove) return;
// release capture
var bd = (Border)sender;
bd.ReleaseMouseCapture();
// record last move point
var pt = e.GetPosition(Main_Grid);
movingLastPoint = pt;
// caculate offset
var offX = ((Point)movingLastPoint).X - ((Point)movingFirstPoint).X;
var offY = ((Point)movingLastPoint).Y - ((Point)movingFirstPoint).Y;
// unlock
isLockedStrokeSelectionMove = false;
if (isStrokeSelectionCloneOn) {
// transform strokes
var matrix = new Matrix();
matrix.Translate(((Point)movingLastPoint).X-((Point)movingFirstPoint).X, ((Point)movingLastPoint).Y - ((Point)movingFirstPoint).Y);
isProgramChangeStrokesSelection = true;
var ori = inkCanvas.GetSelectedStrokes();
inkCanvas.Select(new StrokeCollection());
clonedStrokes = ori.Clone();
inkCanvas.Select(ori);
isProgramChangeStrokesSelection = false;
clonedStrokes.Transform(matrix,false);
// add to inkcanvas
inkCanvas.Strokes.Add(clonedStrokes);
InkSelectionStrokesOverlay.DrawStrokes(inkCanvas.GetSelectedStrokes(), new Matrix());
InkSelectionStrokesBackgroundInkCanvas.Strokes.Add(clonedStrokes);
} else {
if (isStrokesSelectionBorderMovingUseRenderTransform) {
StrokeSelectionBorderTranslateTransform.X = 0;
StrokeSelectionBorderTranslateTransform.Y = 0;
System.Windows.Controls.Canvas.SetLeft(StrokeSelectionBorder, movingFirstBorderLeft + offX);
System.Windows.Controls.Canvas.SetTop(StrokeSelectionBorder, movingFirstBorderTop + offY);
}
// preview
SelectedStrokesMove(inkCanvas.GetSelectedStrokes(), (Point)movingFirstPoint, (Point)movingLastPoint, true);
// transform strokes
SelectedStrokesMove(inkCanvas.GetSelectedStrokes(), (Point)movingFirstPoint, (Point)movingLastPoint);
// display selectionToolBar
var _bd = new Binding("Visibility");
_bd.Source = GridInkCanvasSelectionCover;
BorderStrokeSelectionControl.SetBinding(Border.VisibilityProperty, _bd);
updateBorderStrokeSelectionControlLocation();
// hide move toast
StrokeSelectionMoveToast.Visibility = Visibility.Collapsed;
}
}
private void StrokeSelectionBorder_MouseDown(object sender, MouseButtonEventArgs e) {
if (isStrokeSelectionBorderLocked) return;
if (isLockedStrokeSelectionHandle || isLockedStrokeSelectionRotate || isLockedStrokeSelectionMove) return;
// record first move point
var pt = e.GetPosition(Main_Grid);
movingFirstPoint = pt;
// capture mouse
var bd = (Border)sender;
bd.CaptureMouse();
// lock
isLockedStrokeSelectionMove = true;
// record first border position
movingFirstBorderLeft = System.Windows.Controls.Canvas.GetLeft(StrokeSelectionBorder);
movingFirstBorderTop = System.Windows.Controls.Canvas.GetTop(StrokeSelectionBorder);
}
private bool isStrokesSelectionBorderMovingUseRenderTransform = true;
private StrokeCollection clonedStrokes;
private void StrokeSelectionBorder_MouseMove(object sender, MouseEventArgs e) {
if (isStrokeSelectionBorderLocked) return;
if (isLockedStrokeSelectionHandle || isLockedStrokeSelectionRotate || !isLockedStrokeSelectionMove) return;
// record last move point
var pt = e.GetPosition(Main_Grid);
movingLastPoint = pt;
// caculate offset
var offX = ((Point)movingLastPoint).X - ((Point)movingFirstPoint).X;
var offY = ((Point)movingLastPoint).Y - ((Point)movingFirstPoint).Y;
if (isStrokeSelectionCloneOn) {
var matrix = new Matrix();
matrix.Translate(((Point)movingLastPoint).X-((Point)movingFirstPoint).X, ((Point)movingLastPoint).Y - ((Point)movingFirstPoint).Y);
InkSelectionStrokesOverlay.Open();
InkSelectionStrokesOverlay.DrawStrokes(inkCanvas.GetSelectedStrokes(), new Matrix(), false);
InkSelectionStrokesOverlay.DrawStrokes(inkCanvas.GetSelectedStrokes(), matrix, false);
InkSelectionStrokesOverlay.Close();
} else {
// preview
SelectedStrokesMove(inkCanvas.GetSelectedStrokes(), (Point)movingFirstPoint, (Point)movingLastPoint, true);
// relocate border position
if (isStrokesSelectionBorderMovingUseRenderTransform) {
StrokeSelectionBorderTranslateTransform.X = offX;
StrokeSelectionBorderTranslateTransform.Y = offY;
} else {
System.Windows.Controls.Canvas.SetLeft(StrokeSelectionBorder, movingFirstBorderLeft + offX);
System.Windows.Controls.Canvas.SetTop(StrokeSelectionBorder, movingFirstBorderTop + offY);
}
// display move toast
if (StrokeSelectionMoveToast.Visibility == Visibility.Collapsed) StrokeSelectionMoveToast.Visibility = Visibility.Visible;
// move toast text
((TextBlock)((StackPanel)StrokeSelectionMoveToastInner.Children[0]).Children[0]).Text =
$"X: {Math.Round(System.Windows.Controls.Canvas.GetLeft(StrokeSelectionBorder), 2)}";
((TextBlock)((StackPanel)StrokeSelectionMoveToastInner.Children[0]).Children[1]).Text =
$"Y: {Math.Round(System.Windows.Controls.Canvas.GetTop(StrokeSelectionBorder),2)}";
((TextBlock)((StackPanel)StrokeSelectionMoveToastInner.Children[1]).Children[1]).Text =
$"Δx: {Math.Round(offX,2)}";
((TextBlock)((StackPanel)StrokeSelectionMoveToastInner.Children[1]).Children[2]).Text =
$"Δy: {Math.Round(offY,2)}";
// hide selectionToolBar
if (BorderStrokeSelectionControl.Visibility != Visibility.Collapsed) BorderStrokeSelectionControl.Visibility = Visibility.Collapsed;
}
}
private Point? StrokesRotateSelectionBoundsCenterPoint = null;
private Point? rotatingLastPoint = null;
private bool isLockedStrokeSelectionRotate = false;
private void StrokeSelectionRotateHandle_MouseUp(object sender, MouseButtonEventArgs e) {
if (isStrokeSelectionBorderLocked) return;
if (isLockedStrokeSelectionHandle || isLockedStrokeSelectionMove || !isLockedStrokeSelectionRotate) return;
// unlock
isLockedStrokeSelectionRotate = false;
// record last point
var pt = e.GetPosition(Main_Grid);
rotatingLastPoint = pt;
// caculate rotate angle
var vec1 = new double[] {
((Point)rotatingLastPoint).X - ((Point)StrokesRotateSelectionBoundsCenterPoint).X ,
((Point)rotatingLastPoint).Y - ((Point)StrokesRotateSelectionBoundsCenterPoint).Y
};
var vec_base = new double[] {
0,
((Point)StrokesRotateSelectionBoundsCenterPoint).Y
};
var cosine = (vec_base[0] * vec1[0] + vec_base[1] * vec1[1]) /
(Math.Sqrt(Math.Pow(vec_base[0], 2) + Math.Pow(vec_base[1], 2)) *
Math.Sqrt(Math.Pow(vec1[0], 2) + Math.Pow(vec1[1], 2)));
var angle = Math.Acos(cosine);
// 判斷在第幾象限
var isIn2And3Quadrant = ((Point)rotatingLastPoint).X <= ((Point)StrokesRotateSelectionBoundsCenterPoint).X;
// final angle
var rotateAngle = Math.Round(180 + 180 * (angle / Math.PI) * (isIn2And3Quadrant ? 1 : -1), 0);
// release capture
var bd = (Border)sender;
bd.ReleaseMouseCapture();
// hide rotate toast
StrokeSelectionRotateToast.Visibility = Visibility.Collapsed;
// hide guideline overlay
InkSelectionRotateGuidelineOverlay.Visibility = Visibility.Collapsed;
// border rotate reset
StrokeSelectionBorderRotateTransform.Angle = 0;
StrokeSelectionBorderRotateTransform.CenterX = 0;
StrokeSelectionBorderRotateTransform.CenterY = 0;
// rotate stroke
SelectedStrokesRotate(inkCanvas.GetSelectedStrokes(), rotateAngle,
(Point)StrokesRotateSelectionBoundsCenterPoint);
// border re-caculate strokes bounds
UpdateStrokeSelectionBorder(true, inkCanvas.GetSelectionBounds());
// display selectionToolBar
var _bd = new Binding("Visibility");
_bd.Source = GridInkCanvasSelectionCover;
BorderStrokeSelectionControl.SetBinding(Border.VisibilityProperty, _bd);
updateBorderStrokeSelectionControlLocation();
}
private void StrokeSelectionRotateHandle_MouseDown(object sender, MouseButtonEventArgs e) {
if (isStrokeSelectionBorderLocked) return;
if (isLockedStrokeSelectionHandle || isLockedStrokeSelectionMove || isLockedStrokeSelectionRotate) return;
// lock
isLockedStrokeSelectionRotate = true;
// record center point
var bounds = inkCanvas.GetSelectionBounds();
StrokesRotateSelectionBoundsCenterPoint = new Point(bounds.Left + bounds.Width / 2, bounds.Top + bounds.Height / 2);
// capture mouse
var bd = (Border)sender;
bd.CaptureMouse();
}
private void StrokeSelectionRotateHandle_MouseMove(object sender, MouseEventArgs e) {
if (isStrokeSelectionBorderLocked) return;
if (isLockedStrokeSelectionHandle || isLockedStrokeSelectionMove || !isLockedStrokeSelectionRotate) return;
// record last point
var pt = e.GetPosition(Main_Grid);
rotatingLastPoint = pt;
// caculate rotate angle
var vec1 = new double[] {
((Point)rotatingLastPoint).X - ((Point)StrokesRotateSelectionBoundsCenterPoint).X ,
((Point)rotatingLastPoint).Y - ((Point)StrokesRotateSelectionBoundsCenterPoint).Y
};
var vec_base = new double[] {
0,
((Point)StrokesRotateSelectionBoundsCenterPoint).Y
};
var cosine = (vec_base[0] * vec1[0] + vec_base[1] * vec1[1]) /
(Math.Sqrt(Math.Pow(vec_base[0],2) + Math.Pow(vec_base[1],2)) *
Math.Sqrt(Math.Pow(vec1[0],2) + Math.Pow(vec1[1],2)));
var angle = Math.Acos(cosine);
// 判斷在第幾象限
var isIn2And3Quadrant = ((Point)rotatingLastPoint).X <= ((Point)StrokesRotateSelectionBoundsCenterPoint).X;
// final angle
var rotateAngle = Math.Round(180 + 180 * (angle / Math.PI) * (isIn2And3Quadrant ? 1 : -1), 0);
// display guideline overlay
if (InkSelectionRotateGuidelineOverlay.Visibility == Visibility.Collapsed)
InkSelectionRotateGuidelineOverlay.Visibility = Visibility.Visible;
var guidelinePen1 = new Pen(); // guideline1 thickness1 dash yellow opacity255
guidelinePen1.Brush = new SolidColorBrush(Color.FromRgb(245, 158, 11));
guidelinePen1.DashStyle = DashStyles.Dash;
guidelinePen1.Thickness = 1;
var guidelinePen2 = new Pen(); // guideline2 thickness2 dash yellow opacity255
guidelinePen2.Brush = new SolidColorBrush(Color.FromRgb(245, 158, 11));
guidelinePen2.DashStyle = DashStyles.Dash;
guidelinePen2.Thickness = 2.5;
var guidelinePen3 = new Pen(); // guideline3 thickness1 dash yellow opacity72
guidelinePen3.Brush = new SolidColorBrush(Color.FromArgb(72, 245, 158, 11));
guidelinePen3.DashStyle = DashStyles.Dash;
guidelinePen3.Thickness = 1;
var guidelinePen4 = new Pen(); // guideline4 thickness1 dot green opacity255
guidelinePen4.Brush = new SolidColorBrush(Color.FromRgb(34, 197, 94));
guidelinePen4.DashStyle = DashStyles.Dot;
guidelinePen4.Thickness = 1;
var guidelineSnapAngle = 0;
// draw guideline
var dv = InkSelectionRotateGuidelineOverlay.DrawingVisual;
using (DrawingContext dc = dv.RenderOpen()) {
dc.DrawLine(guidelinePen1, (Point)StrokesRotateSelectionBoundsCenterPoint, new Point(((Point)StrokesRotateSelectionBoundsCenterPoint).X,0));
dc.DrawLine(guidelinePen3, (Point)StrokesRotateSelectionBoundsCenterPoint, new Point(((Point)StrokesRotateSelectionBoundsCenterPoint).X,Main_Grid.ActualHeight));
dc.DrawLine(guidelinePen2, (Point)StrokesRotateSelectionBoundsCenterPoint, (Point)rotatingLastPoint);
var QuadrantOneLongest = Math.Max(
Main_Grid.ActualWidth - ((Point)StrokesRotateSelectionBoundsCenterPoint).X,
((Point)StrokesRotateSelectionBoundsCenterPoint).Y);
//30 angle
if (rotateAngle >= 26 && rotateAngle <= 34) {
dc.DrawLine(guidelinePen4, (Point)StrokesRotateSelectionBoundsCenterPoint, new Point(((Point)StrokesRotateSelectionBoundsCenterPoint).X + QuadrantOneLongest, ((Point)StrokesRotateSelectionBoundsCenterPoint).Y - QuadrantOneLongest * Math.Sqrt(3)));
guidelineSnapAngle = 30;
}
//45 angle
if (rotateAngle >= 41 && rotateAngle <= 49) {
dc.DrawLine(guidelinePen4, (Point)StrokesRotateSelectionBoundsCenterPoint, new Point(((Point)StrokesRotateSelectionBoundsCenterPoint).X+QuadrantOneLongest, ((Point)StrokesRotateSelectionBoundsCenterPoint).Y - QuadrantOneLongest));
guidelineSnapAngle = 45;
}
//60 angle
if (rotateAngle >= 56 && rotateAngle <= 64) {
dc.DrawLine(guidelinePen4, (Point)StrokesRotateSelectionBoundsCenterPoint, new Point(((Point)StrokesRotateSelectionBoundsCenterPoint).X + QuadrantOneLongest *Math.Sqrt(3), ((Point)StrokesRotateSelectionBoundsCenterPoint).Y - QuadrantOneLongest));
guidelineSnapAngle = 60;
}
//90 angle
if (rotateAngle >= 86 && rotateAngle <= 94) {
dc.DrawLine(guidelinePen4, (Point)StrokesRotateSelectionBoundsCenterPoint, new Point(((Point)StrokesRotateSelectionBoundsCenterPoint).X + QuadrantOneLongest, ((Point)StrokesRotateSelectionBoundsCenterPoint).Y));
guidelineSnapAngle = 90;
}
var QuadrantFourLongest = Math.Max(
Main_Grid.ActualWidth - ((Point)StrokesRotateSelectionBoundsCenterPoint).X,
Main_Grid.ActualHeight - ((Point)StrokesRotateSelectionBoundsCenterPoint).Y);
//120 angle
if (rotateAngle >= 116 && rotateAngle <= 124) {
dc.DrawLine(guidelinePen4, (Point)StrokesRotateSelectionBoundsCenterPoint, new Point(((Point)StrokesRotateSelectionBoundsCenterPoint).X + QuadrantFourLongest * Math.Sqrt(3), ((Point)StrokesRotateSelectionBoundsCenterPoint).Y + QuadrantFourLongest));
guidelineSnapAngle = 120;
}
//150 angle
if (rotateAngle >= 146 && rotateAngle <= 154) {
dc.DrawLine(guidelinePen4, (Point)StrokesRotateSelectionBoundsCenterPoint, new Point(((Point)StrokesRotateSelectionBoundsCenterPoint).X + QuadrantFourLongest, ((Point)StrokesRotateSelectionBoundsCenterPoint).Y + QuadrantFourLongest * Math.Sqrt(3)));
guidelineSnapAngle = 150;
}
//180 angle
if (rotateAngle >= 176 && rotateAngle <= 184)
{
dc.DrawLine(guidelinePen4, (Point)StrokesRotateSelectionBoundsCenterPoint, new Point(((Point)StrokesRotateSelectionBoundsCenterPoint).X, ((Point)StrokesRotateSelectionBoundsCenterPoint).Y + QuadrantFourLongest));
guidelineSnapAngle = 180;
}
}
// preview
SelectedStrokesRotate(inkCanvas.GetSelectedStrokes(), guidelineSnapAngle!=0?guidelineSnapAngle:rotateAngle,
(Point)StrokesRotateSelectionBoundsCenterPoint, true);
// border rotate
StrokeSelectionBorderRotateTransform.Angle = guidelineSnapAngle != 0 ? guidelineSnapAngle : rotateAngle;
StrokeSelectionBorderRotateTransform.CenterX = StrokeSelectionBorder.Width / 2;
StrokeSelectionBorderRotateTransform.CenterY = StrokeSelectionBorder.Height / 2;
// display rotate toast
if (StrokeSelectionRotateToast.Visibility == Visibility.Collapsed) StrokeSelectionRotateToast.Visibility = Visibility.Visible;
// update rotate toast
((TextBlock)StrokeSelectionRotateToast.Child).Text =
(guidelineSnapAngle != 0 ? guidelineSnapAngle : rotateAngle) == 360
? "360° = 0°" : $"{(guidelineSnapAngle != 0 ? guidelineSnapAngle : rotateAngle)}°";
// hide selectionToolBar
if (BorderStrokeSelectionControl.Visibility != Visibility.Collapsed) BorderStrokeSelectionControl.Visibility = Visibility.Collapsed;
}
private void StrokeSelectionBorder_MouseEnter(object sender, MouseEventArgs e) {
if (isStrokeSelectionBorderLocked) {
StrokeSelectionCursorArea.Background = new SolidColorBrush(Color.FromArgb(5, 96, 165, 250));
return;
};
StrokeSelectionCursorArea.Background = new SolidColorBrush(Color.FromArgb(17, 96, 165, 250));
}
private void StrokeSelectionBorder_MouseLeave(object sender, MouseEventArgs e) {
if (isStrokeSelectionBorderLocked) {
StrokeSelectionCursorArea.Background = new SolidColorBrush(Color.FromArgb(5, 96, 165, 250));
return;
};
StrokeSelectionCursorArea.Background = new SolidColorBrush(Color.FromArgb(5, 96, 165, 250));
}
private void ApplyCursorToStrokeSelectionBorder() {
StrokeSelectionCursorArea.ForceCursor = true;
StreamResourceInfo sri_move = Application.GetResourceStream(
new Uri("Resources/Cursors/cursor-move.cur", UriKind.Relative));
StrokeSelectionCursorArea.Cursor = new Cursor(sri_move.Stream);
StreamResourceInfo sri_lr = Application.GetResourceStream(
new Uri("Resources/Cursors/cursor-resize-lr.cur", UriKind.Relative));
StreamResourceInfo sri_tb = Application.GetResourceStream(
new Uri("Resources/Cursors/cursor-resize-tb.cur", UriKind.Relative));
StreamResourceInfo sri_lt_rb = Application.GetResourceStream(
new Uri("Resources/Cursors/cursor-resize-lt-rb.cur", UriKind.Relative));
StreamResourceInfo sri_rt_lb = Application.GetResourceStream(
new Uri("Resources/Cursors/cursor-resize-rt-lb.cur", UriKind.Relative));
foreach (var bd in StrokeSelectionBorderHandles) {
bd.ForceCursor = true;
}
StrokeSelectionBorderHandles[0].Cursor = StrokeSelectionBorderHandles[3].Cursor = new Cursor(sri_lt_rb.Stream);
StrokeSelectionBorderHandles[1].Cursor = StrokeSelectionBorderHandles[2].Cursor = new Cursor(sri_rt_lb.Stream);
StrokeSelectionBorderHandles[4].Cursor = StrokeSelectionBorderHandles[5].Cursor = new Cursor(sri_lr.Stream);
StrokeSelectionBorderHandles[6].Cursor = StrokeSelectionBorderHandles[7].Cursor = new Cursor(sri_tb.Stream);
StreamResourceInfo sri_open_hand = Application.GetResourceStream(
new Uri("Resources/Cursors/open-hand-cursor.cur", UriKind.Relative));
StrokeSelectionBorderHandles[8].Cursor = new Cursor(sri_open_hand.Stream);
}
public enum StrokeSelectionBorderHandlesEnum {
LeftTop, RightTop, LeftBottom, RightBottom,
Left, Right, Top, Bottom,
Rotate
}
private void AddStrokeSelectionHandlesToArr() {
StrokeSelectionBorderHandles = new Border[] {
StrokeSelectionLTHandle,
StrokeSelectionRTHandle,
StrokeSelectionLBHandle,
StrokeSelectionRBHandle,
StrokeSelectionLHandle,
StrokeSelectionRHandle,
StrokeSelectionTHandle,
StrokeSelectionBHandle,
StrokeSelectionRotateHandle
};
foreach (var hd in StrokeSelectionBorderHandles) {
if (hd.Name== "StrokeSelectionRotateHandle") continue;
hd.MouseUp += StrokeSelectionBorderHandle_MouseUp;
hd.MouseDown += StrokeSelectionBorderHandle_MouseDown;
hd.MouseMove += StrokeSelectionBorderHandle_MouseMove;
}
StrokeSelectionRotateHandle.MouseUp += StrokeSelectionRotateHandle_MouseUp;
StrokeSelectionRotateHandle.MouseDown += StrokeSelectionRotateHandle_MouseDown;
StrokeSelectionRotateHandle.MouseMove += StrokeSelectionRotateHandle_MouseMove;
ApplyCursorToStrokeSelectionBorder();
}
private void SelectedStrokesRotate(StrokeCollection strokes, double angle, Point? centerPoint, bool isPreview = false) {
if (centerPoint == null) return;
var matrix = new Matrix();
matrix.RotateAt(angle, ((Point)centerPoint).X, ((Point)centerPoint).Y);
if (isPreview) {
InkSelectionStrokesOverlay.DrawStrokes(strokes, matrix);
} else {
strokes.Transform(matrix, Settings.Canvas.ApplyScaleToStylusTip);
}
}
private void SelectedStrokesMove(StrokeCollection strokes, Point firstPoint, Point lastPoint, bool isPreview = false) {
var matrix = new Matrix();
matrix.Translate(lastPoint.X-firstPoint.X, lastPoint.Y - firstPoint.Y);
if (isPreview) {
InkSelectionStrokesOverlay.DrawStrokes(strokes, matrix);
} else {
strokes.Transform(matrix, Settings.Canvas.ApplyScaleToStylusTip);
}
}
/// <summary>
/// 調整選中墨跡的大小
/// </summary>
/// <param name="strokes"></param>
/// <param name="handleType"></param>
/// <param name="originalRect"></param>
/// <param name="resizedRect"></param>
/// <param name="isPreview"></param>
/// <returns></returns>
private Rect? SelectedStrokesResize(StrokeCollection strokes, StrokeSelectionBorderHandlesEnum handleType, Rect originalRect, Rect resizedRect, bool isPreview = false) {
if ((strokes?.Count ?? 0) == 0 || handleType == null || originalRect.Width == 0 || originalRect.Height == 0
|| resizedRect.Width == 0 || resizedRect.Height == 0) return null;
Matrix matrix = new Matrix();
if ((int)handleType <= 3) {
var asidePt = (int)handleType == 0 ? originalRect.BottomRight :
(int)handleType == 1 ? originalRect.BottomLeft :
(int)handleType == 2 ? originalRect.TopRight : originalRect.TopLeft;
matrix.ScaleAt(Math.Round(resizedRect.Width / originalRect.Width, 2),
Math.Round(resizedRect.Height / originalRect.Height, 2),
asidePt.X, asidePt.Y);
} else if ((int)handleType == 4 || (int)handleType == 5) {
var asideX = (int)handleType == 5 ? originalRect.Left : originalRect.Right;
matrix.ScaleAt(Math.Round(resizedRect.Width / originalRect.Width, 2),1D,asideX, 0);
} else if ((int)handleType == 6 || (int)handleType == 7) {
var asideY = (int)handleType == 7 ? originalRect.Top : originalRect.Bottom;
matrix.ScaleAt(1D, Math.Round(resizedRect.Height / originalRect.Height, 2), 0, asideY);
}
if (isPreview) {
InkSelectionStrokesOverlay.DrawStrokes(strokes, matrix);
} else {
strokes.Transform(matrix, Settings.Canvas.ApplyScaleToStylusTip);
}
return strokes.GetBounds();
}
private void UpdateStrokeSelectionBorder(bool isDisplay, Rect? rect) {
if (isDisplay) {
if (rect == null) return;
var r = (Rect)rect;
if (r.Height == 0 || r.Width == 0) return;
InkCanvasSelectFakeAdornerCanvas.Visibility = Visibility.Visible;
System.Windows.Controls.Canvas.SetLeft(StrokeSelectionBorder,r.Left);
System.Windows.Controls.Canvas.SetTop(StrokeSelectionBorder,r.Top);
StrokeSelectionBorder.Width = r.Width;
StrokeSelectionBorder.Height = r.Height;
if (StrokeSelectionBorderHandles.Length == 0) AddStrokeSelectionHandlesToArr();
StrokeSelectionBorder.Visibility = Visibility.Visible;
} else {
InkCanvasSelectFakeAdornerCanvas.Visibility = Visibility.Collapsed;
StrokeSelectionBorder.Visibility = Visibility.Collapsed;
}
}
/// <summary>
/// 取消选中本次选中的墨迹或对象,准备继续进行矩形选框操作。
/// </summary>
private void CancelCurrentStrokesSelection() {
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
inkCanvas.Select(new StrokeCollection());
UpdateStrokeSelectionBorder(false, null);
RectangleSelectionHitTestBorder.Visibility = Visibility.Visible;
var cm = this.FindResource("StrokesSelectionMoreMenuButtonContextMenu") as ContextMenu;
cm.IsOpen = false;
}
#endregion
private void inkCanvas_SelectionChanged(object sender, EventArgs e) {
if (isProgramChangeStrokesSelection) return;
isStrokeSelectionCloneOn = false;
if (inkCanvas.GetSelectedStrokes().Count == 0) {
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
UpdateStrokeSelectionBorder(false,null);
inkCanvas.Opacity = 1;
InkSelectionStrokesOverlay.Visibility = Visibility.Collapsed;
InkSelectionStrokesBackgroundInkCanvas.Visibility = Visibility.Collapsed;
InkSelectionStrokesOverlay.DrawStrokes(new StrokeCollection(), new Matrix());
}
else {
var isAllStrokesLocked = false;
if (inkCanvas.GetSelectedStrokes().Count > 1) {
List<Stroke> lockedStrokes = new List<Stroke>();
var stks = inkCanvas.GetSelectedStrokes();
foreach (var stk in stks) {
if (stk.ContainsPropertyData(IsLockGuid)) lockedStrokes.Add(stk);
}
if (lockedStrokes.Count != stks.Count && lockedStrokes.Count!=0) {
stks.Remove(new StrokeCollection(lockedStrokes));
inkCanvas.Select(stks);
return;
} else if (lockedStrokes.Count == stks.Count) {
isAllStrokesLocked = true;
}
} else {
isAllStrokesLocked = inkCanvas.GetSelectedStrokes().Single().ContainsPropertyData(IsLockGuid);
}
GridInkCanvasSelectionCover.Visibility = Visibility.Visible;
BorderStrokeSelectionClone.Background = Brushes.Transparent;
RectangleSelectionHitTestBorder.Visibility = Visibility.Collapsed;
UpdateStrokeSelectionBorder(true, inkCanvas.GetSelectionBounds());
inkCanvas.Opacity = 0;
InkSelectionStrokesOverlay.Visibility = Visibility.Visible;
InkSelectionStrokesBackgroundInkCanvas.Visibility = Visibility.Visible;
InkSelectionStrokesBackgroundInkCanvas.Strokes.Clear();
InkSelectionStrokesBackgroundInkCanvas.Strokes.Add(inkCanvas.Strokes);
InkSelectionStrokesBackgroundInkCanvas.Strokes.Remove(inkCanvas.GetSelectedStrokes());
InkSelectionStrokesOverlay.DrawStrokes(inkCanvas.GetSelectedStrokes(), new Matrix());
UpdateStrokesSelectionCloneToolButtonLimitStatus();
updateBorderStrokeSelectionControlLocation();
UpdateSelectionToolbarOtherIconLockedStatus(isAllStrokesLocked);
UpdateSelectionToolBarLockIcon(isAllStrokesLocked);
UpdateSelectionBorderHandlesLockStatus(isAllStrokesLocked);
}
}
private void updateBorderStrokeSelectionControlLocation() {
if (currentMode == 0) BorderStrokeSelectionCloneToNewBoardTextBlock.Text = "克隆到白板";
else BorderStrokeSelectionCloneToNewBoardTextBlock.Text = "克隆到新页";
var _w = 660;
BorderStrokeSelectionControl.Width = _w;
var borderLeft = (inkCanvas.GetSelectionBounds().Left + inkCanvas.GetSelectionBounds().Right - _w) / 2;
var borderTop = inkCanvas.GetSelectionBounds().Bottom + 24;
if (borderLeft < 0) borderLeft = 0;
if (borderTop < 0) borderTop = 0;
if (Width - borderLeft < _w || double.IsNaN(borderLeft))
borderLeft = Width - _w;
if (Height - borderTop < 48 || double.IsNaN(borderTop))
borderTop = Height - 48;
//if (borderTop > 60) borderTop -= 60;
BorderStrokeSelectionControl.Margin = new Thickness(borderLeft, borderTop, 0, 0);
}
#region Strokes Lock
public Guid IsLockGuid = new Guid("b701bb3f-16bf-43ce-a88f-30eab85cd77b");
private void UpdateSelectionToolBarLockIcon(bool isLocked) {
BorderStrokeSelectionLock_LockClose.Visibility = !isLocked ? Visibility.Visible : Visibility.Collapsed;
BorderStrokeSelectionLock_LockOpen.Visibility = isLocked ? Visibility.Visible : Visibility.Collapsed;
}
private void UpdateSelectionToolbarOtherIconLockedStatus(bool isLocked) {
var toolbtns = new Border[] {
BorderStrokeSelectionClone,
BorderStrokeSelectionCloneToNewBoard,
BorderImageRotate45,
BorderImageRotate90,
BorderImageFlipHorizontal,
BorderImageFlipVertical,
BorderStrokePaletteButton,
BorderStrokeSelectionDelete,
BorderImageRotateClockwise
};
foreach (var tb in toolbtns)
{
tb.IsHitTestVisible = !isLocked;
tb.Opacity = isLocked ? 0.5 : 1;
tb.IsEnabled = !isLocked;
}
}
private bool isStrokeSelectionBorderLocked = false;
private void UpdateSelectionBorderHandlesLockStatus(bool isLocked) {
var _v = !isLocked ? Visibility.Visible : Visibility.Collapsed;
foreach (var hd in StrokeSelectionBorderHandles) hd.Visibility = _v;
StrokeSelectionRotateHandleConnectLine.Visibility = _v;
isStrokeSelectionBorderLocked = isLocked;
if (isLocked) {
StrokeSelectionCursorArea.ForceCursor = false;
StrokeSelectionCursorArea.Cursor = Cursors.Arrow;
} else {
StrokeSelectionCursorArea.ForceCursor = true;
StreamResourceInfo sri_move = Application.GetResourceStream(
new Uri("Resources/Cursors/cursor-move.cur", UriKind.Relative));
StrokeSelectionCursorArea.Cursor = new Cursor(sri_move.Stream);
}
}
private void BorderStrokeSelectionLock_MouseUp(object sender, MouseButtonEventArgs e) {
if (BorderStrokeSelectionToolButtonMouseDown != (Border)sender) return;
var isAllStrokesLocked = BorderStrokeSelectionLock_LockOpen.Visibility == Visibility.Visible;
var stks = inkCanvas.GetSelectedStrokes();
if (isAllStrokesLocked) {
foreach (var stk in stks) {
stk.RemovePropertyData(IsLockGuid);
}
} else {
foreach (var stk in stks) {
stk.AddPropertyData(IsLockGuid, "Locked");
}
}
UpdateSelectionToolBarLockIcon(!isAllStrokesLocked);
UpdateSelectionToolbarOtherIconLockedStatus(!isAllStrokesLocked);
UpdateSelectionBorderHandlesLockStatus(!isAllStrokesLocked);
// toolbutton
BorderStrokeSelectionToolButton_MouseLeave(sender, e);
}
#endregion
private void GridInkCanvasSelectionCover_ManipulationStarting(object sender, ManipulationStartingEventArgs e) {
e.Mode = ManipulationModes.All;
}
private void GridInkCanvasSelectionCover_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) {
if (StrokeManipulationHistory?.Count > 0)
{
timeMachine.CommitStrokeManipulationHistory(StrokeManipulationHistory);
foreach (var item in StrokeManipulationHistory)
{
StrokeInitialHistory[item.Key] = item.Value.Item2;
}
StrokeManipulationHistory = null;
}
if (DrawingAttributesHistory.Count > 0)
{
timeMachine.CommitStrokeDrawingAttributesHistory(DrawingAttributesHistory);
DrawingAttributesHistory = new Dictionary<Stroke, Tuple<DrawingAttributes, DrawingAttributes>>();
foreach (var item in DrawingAttributesHistoryFlag)
{
item.Value.Clear();
}
}
}
private void GridInkCanvasSelectionCover_ManipulationDelta(object sender, ManipulationDeltaEventArgs e) {
try {
if (dec.Count >= 1) {
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); // 移动
m.ScaleAt(scale.X, scale.Y, center.X, center.Y); // 缩放
var strokes = inkCanvas.GetSelectedStrokes();
if (StrokesSelectionClone.Count != 0)
strokes = StrokesSelectionClone;
else if (Settings.Gesture.IsEnableTwoFingerRotationOnSelection)
m.RotateAt(rotate, center.X, center.Y); // 旋转
foreach (var stroke in strokes) {
stroke.Transform(m, false);
try {
stroke.DrawingAttributes.Width *= md.Scale.X;
stroke.DrawingAttributes.Height *= md.Scale.Y;
}
catch { }
}
updateBorderStrokeSelectionControlLocation();
}
}
catch { }
}
#region SelectionV2 Popup
private void SelectionV2Init() {
FloatingToolBarV2.SelectionV2_SelectAllEvent += (sender, args) => {
inkCanvas.Select(inkCanvas.Strokes);
FloatingToolBarV2.SelectionPopupV2.IsOpen = false;
};
FloatingToolBarV2.SelectionV2_UnSelectEvent += (sender, args) => {
CancelCurrentStrokesSelection();
FloatingToolBarV2.SelectionPopupV2.IsOpen = false;
};
FloatingToolBarV2.SelectionV2_ReverseSelectEvent += (sender, args) => {
var strokes = new StrokeCollection(inkCanvas.Strokes.Where(stroke =>
!inkCanvas.GetSelectedStrokes().Contains(stroke)).Where(stroke=>!stroke.ContainsPropertyData(IsLockGuid)));
if (strokes.Any()) {
inkCanvas.Select(strokes);
} else {
CancelCurrentStrokesSelection();
}
FloatingToolBarV2.SelectionPopupV2.IsOpen = false;
};
FloatingToolBarV2.SelectionV2.ApplyScaleToStylusTip = Settings.Canvas.ApplyScaleToStylusTip;
FloatingToolBarV2.SelectionV2.OnlyHitTestFullyContainedStrokes = Settings.Canvas.OnlyHitTestFullyContainedStrokes;
FloatingToolBarV2.SelectionV2.AllowClickToSelectLockedStroke = Settings.Canvas.AllowClickToSelectLockedStroke;
FloatingToolBarV2.SelectionV2.SelectionModeSelected = (SelectionPopup.SelectionMode)Settings.Canvas.SelectionMethod;
FloatingToolBarV2.SelectionV2_ApplyScaleToStylusTipChanged += (sender, args) => {
if (!isLoaded) return;
Settings.Canvas.ApplyScaleToStylusTip = FloatingToolBarV2.SelectionV2.ApplyScaleToStylusTip;
ToggleSwitchApplyScaleToStylusTip.IsOn = FloatingToolBarV2.SelectionV2.ApplyScaleToStylusTip;
SaveSettingsToFile();
};
FloatingToolBarV2.SelectionV2_OnlyHitTestFullyContainedStrokesChanged += (sender, args) => {
if (!isLoaded) return;
Settings.Canvas.OnlyHitTestFullyContainedStrokes = FloatingToolBarV2.SelectionV2.OnlyHitTestFullyContainedStrokes;
ToggleSwitchOnlyHitTestFullyContainedStrokes.IsOn = FloatingToolBarV2.SelectionV2.OnlyHitTestFullyContainedStrokes;
SaveSettingsToFile();
};
FloatingToolBarV2.SelectionV2_AllowClickToSelectLockedStrokeChanged += (sender, args) => {
if (!isLoaded) return;
Settings.Canvas.AllowClickToSelectLockedStroke = FloatingToolBarV2.SelectionV2.AllowClickToSelectLockedStroke;
ToggleSwitchAllowClickToSelectLockedStroke.IsOn = FloatingToolBarV2.SelectionV2.AllowClickToSelectLockedStroke;
SaveSettingsToFile();
};
FloatingToolBarV2.SelectionV2_SelectionModeChanged += (sender, args) => {
if (!isLoaded) return;
Settings.Canvas.SelectionMethod = (int)args.NowMode;
ComboBoxSelectionMethod.SelectedIndex = (int)args.NowMode;
SaveSettingsToFile();
};
}
#endregion
}
}