155 lines
6.0 KiB
C#
155 lines
6.0 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Diagnostics;
|
||
|
|
using System.Linq;
|
||
|
|
using System.Text;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
using System.Windows;
|
||
|
|
using System.Windows.Controls;
|
||
|
|
using System.Windows.Ink;
|
||
|
|
using System.Windows.Input;
|
||
|
|
using System.Windows.Media;
|
||
|
|
using Ink_Canvas.Helpers;
|
||
|
|
|
||
|
|
namespace Ink_Canvas {
|
||
|
|
public partial class MainWindow : PerformanceTransparentWin {
|
||
|
|
|
||
|
|
public bool isUsingGeometryEraser = false;
|
||
|
|
private IncrementalStrokeHitTester hitTester = null;
|
||
|
|
|
||
|
|
public double eraserWidth = 64;
|
||
|
|
public bool isEraserCircleShape = false;
|
||
|
|
public bool isUsingStrokesEraser = false;
|
||
|
|
|
||
|
|
private Matrix scaleMatrix = new Matrix();
|
||
|
|
|
||
|
|
private void EraserOverlay_Loaded(object sender, RoutedEventArgs e) {
|
||
|
|
var bd = (Border)sender;
|
||
|
|
bd.StylusDown += ((o, args) => {
|
||
|
|
e.Handled = true;
|
||
|
|
if (args.StylusDevice.TabletDevice.Type == TabletDeviceType.Stylus) ((Border)o).CaptureStylus();
|
||
|
|
EraserOverlay_PointerDown(sender);
|
||
|
|
});
|
||
|
|
bd.StylusUp += ((o, args) => {
|
||
|
|
e.Handled = true;
|
||
|
|
if (args.StylusDevice.TabletDevice.Type == TabletDeviceType.Stylus) ((Border)o).ReleaseStylusCapture();
|
||
|
|
EraserOverlay_PointerUp(sender);
|
||
|
|
});
|
||
|
|
bd.StylusMove += ((o, args) => {
|
||
|
|
e.Handled = true;
|
||
|
|
EraserOverlay_PointerMove(sender, args.GetPosition(Main_Grid));
|
||
|
|
});
|
||
|
|
bd.MouseDown += ((o, args) => {
|
||
|
|
((Border)o).CaptureMouse();
|
||
|
|
EraserOverlay_PointerDown(sender);
|
||
|
|
});
|
||
|
|
bd.MouseUp += ((o, args) => {
|
||
|
|
((Border)o).ReleaseMouseCapture();
|
||
|
|
EraserOverlay_PointerUp(sender);
|
||
|
|
});
|
||
|
|
bd.MouseMove += ((o, args) => {
|
||
|
|
EraserOverlay_PointerMove(sender, args.GetPosition(Main_Grid));
|
||
|
|
});
|
||
|
|
bd.StylusButtonUp += (o, args) => {
|
||
|
|
Trace.WriteLine("ButtonUp!!!!!");
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
private void EraserOverlay_PointerDown(object sender) {
|
||
|
|
if (isUsingGeometryEraser) return;
|
||
|
|
|
||
|
|
// lock
|
||
|
|
isUsingGeometryEraser = true;
|
||
|
|
|
||
|
|
// caculate height
|
||
|
|
var _h = eraserWidth * 56 / 38;
|
||
|
|
|
||
|
|
// init hittester
|
||
|
|
hitTester = inkCanvas.Strokes.GetIncrementalStrokeHitTester(new RectangleStylusShape(
|
||
|
|
eraserWidth, _h));
|
||
|
|
hitTester.StrokeHit += EraserGeometry_StrokeHit;
|
||
|
|
|
||
|
|
// eraser bitmap cache
|
||
|
|
EraserOverlay_DrawingVisual.CacheMode = new BitmapCache();
|
||
|
|
|
||
|
|
// caculate scale matrix
|
||
|
|
var scaleX = eraserWidth / 38;
|
||
|
|
var scaleY = _h / 56;
|
||
|
|
scaleMatrix = new Matrix();
|
||
|
|
scaleMatrix.ScaleAt(scaleX,scaleY,0,0);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void EraserOverlay_PointerUp(object sender) {
|
||
|
|
if (!isUsingGeometryEraser) return;
|
||
|
|
|
||
|
|
// unlock
|
||
|
|
isUsingGeometryEraser = false;
|
||
|
|
|
||
|
|
// release capture
|
||
|
|
((Border)sender).ReleaseMouseCapture();
|
||
|
|
|
||
|
|
// hide eraser feedback
|
||
|
|
var ct = EraserOverlay_DrawingVisual.DrawingVisual.RenderOpen();
|
||
|
|
ct.DrawRectangle(new SolidColorBrush(Colors.Transparent),null,new Rect(0,0,ActualWidth,ActualHeight));
|
||
|
|
ct.Close();
|
||
|
|
|
||
|
|
// end hittest
|
||
|
|
hitTester.EndHitTesting();
|
||
|
|
|
||
|
|
// commit stroke erased history
|
||
|
|
// 我有受虐倾向,被这个bug硬控10秒钟,请大家嘲笑我
|
||
|
|
if (ReplacedStroke != null || AddedStroke != null) {
|
||
|
|
timeMachine.CommitStrokeEraseHistory(ReplacedStroke, AddedStroke);
|
||
|
|
AddedStroke = null;
|
||
|
|
ReplacedStroke = null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void EraserGeometry_StrokeHit(object sender,
|
||
|
|
StrokeHitEventArgs args) {
|
||
|
|
StrokeCollection eraseResult =
|
||
|
|
args.GetPointEraseResults();
|
||
|
|
StrokeCollection strokesToReplace = new StrokeCollection {
|
||
|
|
args.HitStroke
|
||
|
|
};
|
||
|
|
|
||
|
|
// replace the old stroke with the new one.
|
||
|
|
var filtered_2replace = strokesToReplace.Where(stroke => !stroke.ContainsPropertyData(IsLockGuid));
|
||
|
|
var filtered2Replace = filtered_2replace as Stroke[] ?? filtered_2replace.ToArray();
|
||
|
|
if (!filtered2Replace.Any()) return;
|
||
|
|
var filtered_result = eraseResult.Where(stroke=>!stroke.ContainsPropertyData(IsLockGuid));
|
||
|
|
var filteredResult = filtered_result as Stroke[] ?? filtered_result.ToArray();
|
||
|
|
if (filteredResult.Any()) {
|
||
|
|
inkCanvas.Strokes.Replace(new StrokeCollection(filtered2Replace), new StrokeCollection(filteredResult));
|
||
|
|
} else {
|
||
|
|
inkCanvas.Strokes.Remove(new StrokeCollection(filtered2Replace));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void EraserOverlay_PointerMove(object sender, Point pt) {
|
||
|
|
if (!isUsingGeometryEraser) return;
|
||
|
|
|
||
|
|
if (isUsingStrokesEraser) {
|
||
|
|
var _filtered = inkCanvas.Strokes.HitTest(pt).Where(stroke => !stroke.ContainsPropertyData(IsLockGuid));
|
||
|
|
var filtered = _filtered as Stroke[] ?? _filtered.ToArray();
|
||
|
|
if (!filtered.Any()) return;
|
||
|
|
inkCanvas.Strokes.Remove(new StrokeCollection(filtered));
|
||
|
|
} else {
|
||
|
|
// draw eraser feedback
|
||
|
|
var ct = EraserOverlay_DrawingVisual.DrawingVisual.RenderOpen();
|
||
|
|
var mt = scaleMatrix;
|
||
|
|
var _h = eraserWidth * 56 / 38;
|
||
|
|
mt.Translate(pt.X - eraserWidth / 2, pt.Y - _h / 2);
|
||
|
|
ct.PushTransform(new MatrixTransform(mt));
|
||
|
|
ct.DrawDrawing(FindResource(isEraserCircleShape?"EraserCircleDrawingGroup":"EraserDrawingGroup") as DrawingGroup);
|
||
|
|
ct.Pop();
|
||
|
|
ct.Close();
|
||
|
|
|
||
|
|
// add point to hittester
|
||
|
|
hitTester.AddPoint(pt);
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|