[update] IccInkCanvas with IccBoard
This commit is contained in:
parent
a6775bd324
commit
ab24d8240e
@ -94,5 +94,11 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="App.config" />
|
<None Include="App.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\InkCanvasForClass.IccInkCanvas\InkCanvasForClass.IccInkCanvas.csproj">
|
||||||
|
<Project>{43929d8f-5630-4786-b75d-e203ea3e992f}</Project>
|
||||||
|
<Name>InkCanvasForClass.IccInkCanvas</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
@ -4,9 +4,17 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:InkCanvasForClass.IccInkCanvas.Demo"
|
xmlns:local="clr-namespace:InkCanvasForClass.IccInkCanvas.Demo"
|
||||||
|
xmlns:iccInkCanvas="clr-namespace:InkCanvasForClass.IccInkCanvas;assembly=InkCanvasForClass.IccInkCanvas"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="MainWindow" Height="450" Width="800">
|
Title="MainWindow" Height="850" Width="800">
|
||||||
<Grid>
|
<Grid>
|
||||||
|
<StackPanel Orientation="Vertical" Margin="8">
|
||||||
|
<TextBlock FontSize="24">IccInkCanvasDemo</TextBlock>
|
||||||
|
<iccInkCanvas:IccBoard Name="IccBoard" Width="512" Height="512"/>
|
||||||
|
<WrapPanel Orientation="Horizontal">
|
||||||
|
<Button Content="EditingMode = None" Click="EditingModeChangeToNone_ButtonClick"/>
|
||||||
|
<Button Content="EditingMode = Writing" Click="EditingModeChangeToWriting_ButtonClick"/>
|
||||||
|
</WrapPanel>
|
||||||
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -12,6 +13,7 @@ using System.Windows.Media;
|
|||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Navigation;
|
using System.Windows.Navigation;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
|
using InkCanvasForClass.IccInkCanvas.Settings;
|
||||||
|
|
||||||
namespace InkCanvasForClass.IccInkCanvas.Demo {
|
namespace InkCanvasForClass.IccInkCanvas.Demo {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -21,5 +23,12 @@ namespace InkCanvasForClass.IccInkCanvas.Demo {
|
|||||||
public MainWindow() {
|
public MainWindow() {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EditingModeChangeToNone_ButtonClick(object sender, RoutedEventArgs e) {
|
||||||
|
IccBoard.EditingMode = EditingMode.None;
|
||||||
|
}
|
||||||
|
private void EditingModeChangeToWriting_ButtonClick(object sender, RoutedEventArgs e) {
|
||||||
|
IccBoard.EditingMode = EditingMode.Writing;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
InkCanvasForClass.IccInkCanvas/IccBoard.xaml
Normal file
16
InkCanvasForClass.IccInkCanvas/IccBoard.xaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<UserControl x:Class="InkCanvasForClass.IccInkCanvas.IccBoard"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:InkCanvasForClass.IccInkCanvas"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<Grid Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type UserControl}}, Path=ActualWidth}"
|
||||||
|
Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type UserControl}}, Path=ActualHeight}">
|
||||||
|
<Canvas Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type UserControl}}, Path=ActualWidth}"
|
||||||
|
Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type UserControl}}, Path=ActualHeight}"
|
||||||
|
ClipToBounds="True" x:Name="InkCanvasHostCanvas" x:FieldModifier="private">
|
||||||
|
<local:IccInkCanvas x:Name="InkCanvas" x:FieldModifier="private" Loaded="IccInkCanvas_Loaded"/>
|
||||||
|
</Canvas>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
129
InkCanvasForClass.IccInkCanvas/IccBoard.xaml.cs
Normal file
129
InkCanvasForClass.IccInkCanvas/IccBoard.xaml.cs
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
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.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
using InkCanvasForClass.IccInkCanvas.Settings;
|
||||||
|
|
||||||
|
namespace InkCanvasForClass.IccInkCanvas {
|
||||||
|
/// <summary>
|
||||||
|
/// IccBoard.xaml 的交互逻辑
|
||||||
|
/// </summary>
|
||||||
|
public partial class IccBoard : UserControl {
|
||||||
|
|
||||||
|
public BoardSettings BoardSettings { get; private set; } = new BoardSettings();
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
private bool _isEditingModePropertyAccessdByCodeBehind = false;
|
||||||
|
public EditingMode EditingMode {
|
||||||
|
get => (EditingMode)GetValue(EditingModeProperty);
|
||||||
|
set {
|
||||||
|
if (value == EditingMode.ShapeDrawing) throw new Exception("EditingMode.ShapeDrawing 不能被用户手动设定");
|
||||||
|
_isEditingModePropertyAccessdByCodeBehind = true;
|
||||||
|
SetValue(EditingModeProperty, value);
|
||||||
|
_isEditingModePropertyAccessdByCodeBehind = false;
|
||||||
|
UpdateEditingMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static readonly System.Windows.DependencyProperty EditingModeProperty =
|
||||||
|
System.Windows.DependencyProperty.Register(
|
||||||
|
nameof(EditingMode),
|
||||||
|
typeof(EditingMode),
|
||||||
|
typeof(IccBoard),
|
||||||
|
new FrameworkPropertyMetadata(EditingMode.Writing,
|
||||||
|
FrameworkPropertyMetadataOptions.AffectsRender,
|
||||||
|
propertyChangedCallback: OnEditingModePropertyChanged));
|
||||||
|
private static void OnEditingModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
|
||||||
|
var iccboard = d as IccBoard;
|
||||||
|
if (iccboard != null && iccboard._isEditingModePropertyAccessdByCodeBehind) return;
|
||||||
|
iccboard?.UpdateEditingMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region EditingMode
|
||||||
|
|
||||||
|
private void UpdateEditingMode() {
|
||||||
|
if (EditingMode == EditingMode.None || EditingMode == EditingMode.NoneWithHitTest)
|
||||||
|
InkCanvas.EditingMode = InkCanvasEditingMode.None;
|
||||||
|
IsHitTestVisible = EditingMode != EditingMode.None;
|
||||||
|
if (EditingMode == EditingMode.Writing) InkCanvas.EditingMode = InkCanvasEditingMode.Ink;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
private static readonly System.Windows.RoutedEvent EditingModeChangedEvent = EventManager.RegisterRoutedEvent(
|
||||||
|
name: "EditingModeChanged",
|
||||||
|
routingStrategy: RoutingStrategy.Bubble,
|
||||||
|
handlerType: typeof(System.Windows.RoutedEventHandler),
|
||||||
|
ownerType: typeof(IccBoard));
|
||||||
|
private static readonly System.Windows.RoutedEvent ActiveEditingModeChangedEvent = EventManager.RegisterRoutedEvent(
|
||||||
|
name: "ActiveEditingModeChanged",
|
||||||
|
routingStrategy: RoutingStrategy.Bubble,
|
||||||
|
handlerType: typeof(System.Windows.RoutedEventHandler),
|
||||||
|
ownerType: typeof(IccBoard));
|
||||||
|
|
||||||
|
public event System.Windows.RoutedEventHandler EditingModeChanged {
|
||||||
|
add => AddHandler(EditingModeChangedEvent, value);
|
||||||
|
remove => RemoveHandler(EditingModeChangedEvent, value);
|
||||||
|
}
|
||||||
|
public event System.Windows.RoutedEventHandler ActiveEditingModeChanged {
|
||||||
|
add => AddHandler(ActiveEditingModeChangedEvent, value);
|
||||||
|
remove => RemoveHandler(ActiveEditingModeChangedEvent, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RaiseEditingModeChangedEvent() {
|
||||||
|
RoutedEventArgs routedEventArgs = new RoutedEventArgs(routedEvent: EditingModeChangedEvent);
|
||||||
|
RaiseEvent(routedEventArgs);
|
||||||
|
}
|
||||||
|
private void RaiseActiveEditingModeChangedEvent() {
|
||||||
|
RoutedEventArgs routedEventArgs = new RoutedEventArgs(routedEvent: ActiveEditingModeChangedEvent);
|
||||||
|
RaiseEvent(routedEventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public IccBoard() {
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void IccInkCanvas_Loaded(object sender, RoutedEventArgs e) {
|
||||||
|
var ic = (IccInkCanvas)sender;
|
||||||
|
|
||||||
|
// 启动时自动修改 InkCanvas 的大小
|
||||||
|
var screenW = SystemParameters.PrimaryScreenWidth;
|
||||||
|
var screenH = SystemParameters.PrimaryScreenHeight;
|
||||||
|
|
||||||
|
var fullWidth = screenW * 257;
|
||||||
|
var fullHeight = screenH * 417;
|
||||||
|
|
||||||
|
var left = 0 - screenW * 128;
|
||||||
|
var top = 0 - screenH * 208;
|
||||||
|
|
||||||
|
ic.Width = fullWidth;
|
||||||
|
ic.Height = fullHeight;
|
||||||
|
Canvas.SetLeft(ic, left);
|
||||||
|
Canvas.SetTop(ic, top);
|
||||||
|
|
||||||
|
ic.DefaultDrawingAttributes.Width = BoardSettings.NibWidth;
|
||||||
|
ic.DefaultDrawingAttributes.Height = BoardSettings.NibHeight;
|
||||||
|
ic.DefaultDrawingAttributes.Color = BoardSettings.NibColor;
|
||||||
|
|
||||||
|
ic.BoardSettings = BoardSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
211
InkCanvasForClass.IccInkCanvas/IccInkCanvas.cs
Normal file
211
InkCanvasForClass.IccInkCanvas/IccInkCanvas.cs
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
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.Input.StylusPlugIns;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using InkCanvasForClass.IccInkCanvas.Settings;
|
||||||
|
|
||||||
|
namespace InkCanvasForClass.IccInkCanvas {
|
||||||
|
class CustomDynamicRenderer : DynamicRenderer {
|
||||||
|
|
||||||
|
private Point prevPoint;
|
||||||
|
|
||||||
|
private IccInkCanvas _inkCanvas;
|
||||||
|
|
||||||
|
private List<StylusPoint> pointsList = new List<StylusPoint>();
|
||||||
|
|
||||||
|
private void ClearPointsList() {
|
||||||
|
pointsList.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PushPoint(StylusPoint point) {
|
||||||
|
pointsList.Add(point);
|
||||||
|
if (pointsList.Count > 15) {
|
||||||
|
pointsList.RemoveRange(0,pointsList.Count - 15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomDynamicRenderer(IccInkCanvas iccInkCanvas) {
|
||||||
|
_inkCanvas = iccInkCanvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStylusDown(RawStylusInput rawStylusInput) {
|
||||||
|
prevPoint = new Point(double.NegativeInfinity, double.NegativeInfinity);
|
||||||
|
ClearPointsList();
|
||||||
|
var pts = rawStylusInput.GetStylusPoints();
|
||||||
|
if (pts.Count == 1) {
|
||||||
|
PushPoint(pts.Single());
|
||||||
|
} else if (pts.Count > 1) {
|
||||||
|
PushPoint(pts[pts.Count-1]);
|
||||||
|
}
|
||||||
|
Trace.WriteLine(pointsList.Count);
|
||||||
|
base.OnStylusDown(rawStylusInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStylusMove(RawStylusInput rawStylusInput) {
|
||||||
|
base.OnStylusMove(rawStylusInput);
|
||||||
|
var pts = rawStylusInput.GetStylusPoints();
|
||||||
|
if (pts.Count == 1) {
|
||||||
|
PushPoint(pts.Single());
|
||||||
|
} else if (pts.Count > 1) {
|
||||||
|
PushPoint(pts[pts.Count-1]);
|
||||||
|
}
|
||||||
|
Trace.WriteLine(pointsList.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDraw(DrawingContext drawingContext,
|
||||||
|
StylusPointCollection stylusPoints,
|
||||||
|
Geometry geometry, Brush fillBrush) {
|
||||||
|
if (_inkCanvas.BoardSettings.StrokeNibStyle == StrokeNibStyle.Beautiful) {
|
||||||
|
try {
|
||||||
|
var sp = new StylusPointCollection();
|
||||||
|
var n = pointsList.Count - 1;
|
||||||
|
var pressure = 0.1;
|
||||||
|
var x = 10;
|
||||||
|
if (n == 1) return;
|
||||||
|
if (n >= x) {
|
||||||
|
for (var i = 0; i < n - x; i++) {
|
||||||
|
var point = new StylusPoint();
|
||||||
|
|
||||||
|
point.PressureFactor = (float)0.5;
|
||||||
|
point.X = pointsList[i].X;
|
||||||
|
point.Y = pointsList[i].Y;
|
||||||
|
sp.Add(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = n - x; i <= n; i++) {
|
||||||
|
var point = new StylusPoint();
|
||||||
|
|
||||||
|
point.PressureFactor = (float)((0.5 - pressure) * (n - i) / x + pressure);
|
||||||
|
point.X = pointsList[i].X;
|
||||||
|
point.Y = pointsList[i].Y;
|
||||||
|
sp.Add(point);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i <= n; i++) {
|
||||||
|
var point = new StylusPoint();
|
||||||
|
|
||||||
|
point.PressureFactor = (float)(0.4 * (n - i) / n + pressure);
|
||||||
|
point.X = pointsList[i].X;
|
||||||
|
point.Y = pointsList[i].Y;
|
||||||
|
sp.Add(point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var da = DrawingAttributes.Clone();
|
||||||
|
da.Width -= 0.5;
|
||||||
|
da.Height -= 0.5;
|
||||||
|
var stk = new Stroke(sp, da);
|
||||||
|
stk.Draw(drawingContext);
|
||||||
|
} catch {}
|
||||||
|
} else {
|
||||||
|
base.OnDraw(drawingContext, stylusPoints, geometry, fillBrush);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IccInkCanvas : InkCanvas {
|
||||||
|
|
||||||
|
CustomDynamicRenderer customDynamicRenderer;
|
||||||
|
|
||||||
|
public BoardSettings BoardSettings { get; set; } = new BoardSettings();
|
||||||
|
|
||||||
|
public IccInkCanvas() {
|
||||||
|
customDynamicRenderer = new CustomDynamicRenderer(this);
|
||||||
|
DynamicRenderer = customDynamicRenderer;
|
||||||
|
|
||||||
|
// 通过反射移除InkCanvas自带的默认 Delete按键事件
|
||||||
|
var commandBindingsField =
|
||||||
|
typeof(CommandManager).GetField("_classCommandBindings", BindingFlags.NonPublic | BindingFlags.Static);
|
||||||
|
var bnds = commandBindingsField.GetValue(null) as HybridDictionary;
|
||||||
|
var inkCanvasBindings = bnds[typeof(InkCanvas)] as CommandBindingCollection;
|
||||||
|
var enumerator = inkCanvasBindings.GetEnumerator();
|
||||||
|
while (enumerator.MoveNext()) {
|
||||||
|
var item = (CommandBinding)enumerator.Current;
|
||||||
|
if (item.Command == ApplicationCommands.Delete) {
|
||||||
|
var executedField =
|
||||||
|
typeof(CommandBinding).GetField("Executed", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
var canExecuteField =
|
||||||
|
typeof(CommandBinding).GetField("CanExecute", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
executedField.SetValue(item, new ExecutedRoutedEventHandler((sender, args) => { }));
|
||||||
|
canExecuteField.SetValue(item, new CanExecuteRoutedEventHandler((sender, args) => { }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为IccInkCanvas注册自定义的 Delete按键Command并Invoke OnDeleteCommandFired。
|
||||||
|
CommandManager.RegisterClassCommandBinding(typeof(IccInkCanvas), new CommandBinding(ApplicationCommands.Delete,
|
||||||
|
(sender, args) => {
|
||||||
|
DeleteKeyCommandFired?.Invoke(this, new RoutedEventArgs());
|
||||||
|
}, (sender, args) => {
|
||||||
|
args.CanExecute = GetSelectedStrokes().Count != 0;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStrokeCollected(InkCanvasStrokeCollectedEventArgs e) {
|
||||||
|
IccStroke customStroke = new IccStroke(e.Stroke.StylusPoints, e.Stroke.DrawingAttributes);
|
||||||
|
if (e.Stroke is IccStroke) {
|
||||||
|
this.Strokes.Add(e.Stroke);
|
||||||
|
} else {
|
||||||
|
this.Strokes.Remove(e.Stroke);
|
||||||
|
this.Strokes.Add(customStroke);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BoardSettings.StrokeNibStyle == StrokeNibStyle.Beautiful) {
|
||||||
|
try {
|
||||||
|
var stylusPoints = new StylusPointCollection();
|
||||||
|
var n = customStroke.StylusPoints.Count - 1;
|
||||||
|
var pressure = 0.1;
|
||||||
|
var x = 10;
|
||||||
|
if (n == 1) return;
|
||||||
|
if (n >= x) {
|
||||||
|
for (var i = 0; i < n - x; i++) {
|
||||||
|
var point = new StylusPoint();
|
||||||
|
|
||||||
|
point.PressureFactor = (float)0.5;
|
||||||
|
point.X = customStroke.StylusPoints[i].X;
|
||||||
|
point.Y = customStroke.StylusPoints[i].Y;
|
||||||
|
stylusPoints.Add(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = n - x; i <= n; i++) {
|
||||||
|
var point = new StylusPoint();
|
||||||
|
|
||||||
|
point.PressureFactor = (float)((0.5 - pressure) * (n - i) / x + pressure);
|
||||||
|
point.X = customStroke.StylusPoints[i].X;
|
||||||
|
point.Y = customStroke.StylusPoints[i].Y;
|
||||||
|
stylusPoints.Add(point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (var i = 0; i <= n; i++) {
|
||||||
|
var point = new StylusPoint();
|
||||||
|
|
||||||
|
point.PressureFactor = (float)(0.4 * (n - i) / n + pressure);
|
||||||
|
point.X = customStroke.StylusPoints[i].X;
|
||||||
|
point.Y = customStroke.StylusPoints[i].Y;
|
||||||
|
stylusPoints.Add(point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customStroke.StylusPoints = stylusPoints;
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
InkCanvasStrokeCollectedEventArgs args =
|
||||||
|
new InkCanvasStrokeCollectedEventArgs(customStroke);
|
||||||
|
base.OnStrokeCollected(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<RoutedEventArgs> DeleteKeyCommandFired;
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +0,0 @@
|
|||||||
<UserControl x:Class="InkCanvasForClass.IccInkCanvas.IccInkCanvas"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:local="clr-namespace:InkCanvasForClass.IccInkCanvas"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
|
||||||
<Grid>
|
|
||||||
|
|
||||||
</Grid>
|
|
||||||
</UserControl>
|
|
@ -1,25 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using System.Windows.Navigation;
|
|
||||||
using System.Windows.Shapes;
|
|
||||||
|
|
||||||
namespace InkCanvasForClass.IccInkCanvas {
|
|
||||||
/// <summary>
|
|
||||||
/// IccInkCanvas.xaml 的交互逻辑
|
|
||||||
/// </summary>
|
|
||||||
public partial class IccInkCanvas : UserControl {
|
|
||||||
public IccInkCanvas() {
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
214
InkCanvasForClass.IccInkCanvas/IccStroke.cs
Normal file
214
InkCanvasForClass.IccInkCanvas/IccStroke.cs
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Ink;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace InkCanvasForClass.IccInkCanvas {
|
||||||
|
|
||||||
|
static class ToPointsHelper {
|
||||||
|
public static Point[] ToPoints(this IEnumerable<StylusPoint> stylusPoints)
|
||||||
|
{
|
||||||
|
List<Point> pointList = new List<Point>();
|
||||||
|
foreach (StylusPoint stylusPoint in stylusPoints)
|
||||||
|
pointList.Add(stylusPoint.ToPoint());
|
||||||
|
return pointList.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ShapeDrawingType {
|
||||||
|
Line,
|
||||||
|
DottedLine,
|
||||||
|
DashedLine,
|
||||||
|
ArrowOneSide,
|
||||||
|
ArrowTwoSide,
|
||||||
|
Rectangle,
|
||||||
|
Ellipse,
|
||||||
|
PieEllipse,
|
||||||
|
Triangle,
|
||||||
|
RightTriangle,
|
||||||
|
Diamond,
|
||||||
|
Parallelogram,
|
||||||
|
FourLine,
|
||||||
|
Staff,
|
||||||
|
Axis2D,
|
||||||
|
Axis2DA,
|
||||||
|
Axis2DB,
|
||||||
|
Axis2DC,
|
||||||
|
Axis3D,
|
||||||
|
Hyperbola,
|
||||||
|
HyperbolaF,
|
||||||
|
Parabola,
|
||||||
|
ParabolaA,
|
||||||
|
ParabolaAF,
|
||||||
|
Cylinder,
|
||||||
|
Cube,
|
||||||
|
Cone,
|
||||||
|
EllipseC,
|
||||||
|
RectangleC
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ShapeDrawingHelper {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据给定的两个点计算角度
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPoint"></param>
|
||||||
|
/// <param name="lastPoint"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static double CaculateRotateAngleByGivenTwoPoints(Point firstPoint, Point lastPoint) {
|
||||||
|
var vec1 = new double[] {
|
||||||
|
lastPoint.X - firstPoint.X ,
|
||||||
|
lastPoint.Y - firstPoint.Y
|
||||||
|
};
|
||||||
|
var vec_base = new double[] { 0, firstPoint.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 = lastPoint.X <= firstPoint.X;
|
||||||
|
var rotateAngle = Math.Round(180 + 180 * (angle / Math.PI) * (isIn2And3Quadrant ? 1 : -1), 0);
|
||||||
|
return rotateAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static List<Point> DistributePointsOnLine(Point start, Point end, double interval=16) {
|
||||||
|
List<Point> points = new List<Point>();
|
||||||
|
|
||||||
|
double dx = end.X - start.X;
|
||||||
|
double dy = end.Y - start.Y;
|
||||||
|
double distance = Math.Sqrt(dx * dx + dy * dy);
|
||||||
|
int numPoints = (int)(distance / interval);
|
||||||
|
|
||||||
|
for (int i = 0; i <= numPoints; i++) {
|
||||||
|
double ratio = (interval * i) / distance;
|
||||||
|
double x = start.X + ratio * dx;
|
||||||
|
double y = start.Y + ratio * dy;
|
||||||
|
points.Add(new Point(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ArrowLineConfig {
|
||||||
|
public int ArrowWidth { get; set; } = 20;
|
||||||
|
public int ArrowHeight { get; set; } = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IccStroke : Stroke {
|
||||||
|
|
||||||
|
public IccStroke(StylusPointCollection stylusPoints, DrawingAttributes drawingAttributes)
|
||||||
|
: base(stylusPoints, drawingAttributes) { }
|
||||||
|
|
||||||
|
public static Guid StrokeShapeTypeGuid = new Guid("6537b29c-557f-487f-800b-cb30a8f1de78");
|
||||||
|
public static Guid StrokeIsShapeGuid = new Guid("40eff5db-9346-4e42-bd46-7b0eb19d0018");
|
||||||
|
|
||||||
|
public StylusPointCollection RawStylusPointCollection { get; set; }
|
||||||
|
|
||||||
|
public ShapeDrawingHelper.ArrowLineConfig ArrowLineConfig { get; set; } =
|
||||||
|
new ShapeDrawingHelper.ArrowLineConfig();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据这个属性判断当前 Stroke 是否是原始输入
|
||||||
|
/// </summary>
|
||||||
|
public bool IsRawStylusPoints = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据这个属性决定在绘制 Stroke 时是否需要在直线形状中,在两点构成直线上分布点,用于墨迹的范围框选。
|
||||||
|
/// </summary>
|
||||||
|
public bool IsDistributePointsOnLineShape = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 指示该墨迹是否来自一个完整墨迹被擦除后的一部分墨迹,仅用于形状墨迹。
|
||||||
|
/// </summary>
|
||||||
|
public bool IsErasedStrokePart = false;
|
||||||
|
|
||||||
|
// 自定义的墨迹渲染
|
||||||
|
protected override void DrawCore(DrawingContext drawingContext,
|
||||||
|
DrawingAttributes drawingAttributes) {
|
||||||
|
if (!(this.ContainsPropertyData(StrokeIsShapeGuid) &&
|
||||||
|
(bool)this.GetPropertyData(StrokeIsShapeGuid) == true)) {
|
||||||
|
base.DrawCore(drawingContext, drawingAttributes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.DashedLine ||
|
||||||
|
(int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.Line ||
|
||||||
|
(int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.DottedLine ||
|
||||||
|
(int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.ArrowOneSide ||
|
||||||
|
(int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.ArrowTwoSide) {
|
||||||
|
if (StylusPoints.Count < 2) {
|
||||||
|
base.DrawCore(drawingContext, drawingAttributes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pts = new List<Point>(this.StylusPoints.ToPoints());
|
||||||
|
if (IsDistributePointsOnLineShape && (
|
||||||
|
(int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.DashedLine ||
|
||||||
|
(int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.Line ||
|
||||||
|
(int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.DottedLine) && IsRawStylusPoints) {
|
||||||
|
IsRawStylusPoints = false;
|
||||||
|
RawStylusPointCollection = StylusPoints.Clone();
|
||||||
|
var pointList = new List<Point> { new Point(StylusPoints[0].X, StylusPoints[0].Y) };
|
||||||
|
pointList.AddRange(ShapeDrawingHelper.DistributePointsOnLine(new Point(StylusPoints[0].X, StylusPoints[0].Y),new Point(StylusPoints[1].X, StylusPoints[1].Y)));
|
||||||
|
pointList.Add(new Point(StylusPoints[1].X, StylusPoints[1].Y));
|
||||||
|
StylusPoints = new StylusPointCollection(pointList);
|
||||||
|
}
|
||||||
|
StreamGeometry geometry = new StreamGeometry();
|
||||||
|
using (StreamGeometryContext ctx = geometry.Open()) {
|
||||||
|
ctx.BeginFigure(pts[0], false , false);
|
||||||
|
pts.RemoveAt(0);
|
||||||
|
ctx.PolyLineTo(pts,true, true);
|
||||||
|
}
|
||||||
|
var pen = new Pen(new SolidColorBrush(DrawingAttributes.Color),
|
||||||
|
(drawingAttributes.Width + drawingAttributes.Height) / 2) {
|
||||||
|
DashCap = PenLineCap.Round,
|
||||||
|
StartLineCap = PenLineCap.Round,
|
||||||
|
EndLineCap = PenLineCap.Round,
|
||||||
|
};
|
||||||
|
if ((int)this.GetPropertyData(StrokeShapeTypeGuid) != (int)ShapeDrawingType.Line &&
|
||||||
|
(int)this.GetPropertyData(StrokeShapeTypeGuid) != (int)ShapeDrawingType.ArrowOneSide &&
|
||||||
|
(int)this.GetPropertyData(StrokeShapeTypeGuid) != (int)ShapeDrawingType.ArrowTwoSide)
|
||||||
|
pen.DashStyle = (int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.DottedLine ? DashStyles.Dot : DashStyles.Dash;
|
||||||
|
|
||||||
|
if ((int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.ArrowOneSide && IsRawStylusPoints) {
|
||||||
|
IsRawStylusPoints = false;
|
||||||
|
pts = new List<Point>(this.StylusPoints.ToPoints());
|
||||||
|
RawStylusPointCollection = StylusPoints.Clone();
|
||||||
|
double w = ArrowLineConfig.ArrowWidth, h = ArrowLineConfig.ArrowHeight;
|
||||||
|
var theta = Math.Atan2(pts[0].Y - pts[1].Y, pts[0].X - pts[1].X);
|
||||||
|
var sint = Math.Sin(theta);
|
||||||
|
var cost = Math.Cos(theta);
|
||||||
|
var pointList = new List<Point> {
|
||||||
|
new Point(pts[0].X, pts[0].Y),
|
||||||
|
};
|
||||||
|
if (IsDistributePointsOnLineShape) pointList.AddRange(ShapeDrawingHelper.DistributePointsOnLine(new Point(pts[0].X, pts[0].Y),new Point(pts[1].X, pts[1].Y)));
|
||||||
|
pointList.AddRange(new List<Point> {
|
||||||
|
new Point(pts[1].X, pts[1].Y),
|
||||||
|
new Point(pts[1].X + (w * cost - h * sint), pts[1].Y + (w * sint + h * cost)),
|
||||||
|
new Point(pts[1].X, pts[1].Y),
|
||||||
|
new Point(pts[1].X + (w * cost + h * sint), pts[1].Y - (h * cost - w * sint)),
|
||||||
|
});
|
||||||
|
StylusPoints = new StylusPointCollection(pointList);
|
||||||
|
var _pts = new List<Point>(this.StylusPoints.ToPoints());
|
||||||
|
using (StreamGeometryContext ctx = geometry.Open()) {
|
||||||
|
ctx.BeginFigure(_pts[0], false , false);
|
||||||
|
_pts.RemoveAt(0);
|
||||||
|
ctx.PolyLineTo(_pts,true, true);
|
||||||
|
}
|
||||||
|
drawingContext.DrawGeometry(new SolidColorBrush(DrawingAttributes.Color),pen, geometry);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
drawingContext.DrawGeometry(new SolidColorBrush(Colors.Transparent),pen, geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -48,9 +48,12 @@
|
|||||||
<Reference Include="PresentationFramework" />
|
<Reference Include="PresentationFramework" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="IccInkCanvas.xaml.cs">
|
<Compile Include="Settings\BoardSettings.cs" />
|
||||||
<DependentUpon>IccInkCanvas.xaml</DependentUpon>
|
<Compile Include="IccBoard.xaml.cs">
|
||||||
|
<DependentUpon>IccBoard.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="IccInkCanvas.cs" />
|
||||||
|
<Compile Include="IccStroke.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs">
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
@ -64,6 +67,8 @@
|
|||||||
<DependentUpon>Settings.settings</DependentUpon>
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Settings\EditingMode.cs" />
|
||||||
|
<Compile Include="Settings\Nib.cs" />
|
||||||
<EmbeddedResource Include="Properties\Resources.resx">
|
<EmbeddedResource Include="Properties\Resources.resx">
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
@ -74,10 +79,11 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Include="IccInkCanvas.xaml">
|
<Page Include="IccBoard.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
6
InkCanvasForClass.IccInkCanvas/README.md
Normal file
6
InkCanvasForClass.IccInkCanvas/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# IccInkCanvas
|
||||||
|
|
||||||
|
`InkCanvasForClass.IccInkCanvas`
|
||||||
|
|
||||||
|
## 方法
|
||||||
|
|
42
InkCanvasForClass.IccInkCanvas/Settings/BoardSettings.cs
Normal file
42
InkCanvasForClass.IccInkCanvas/Settings/BoardSettings.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace InkCanvasForClass.IccInkCanvas.Settings {
|
||||||
|
public class BoardSettings {
|
||||||
|
public BoardSettings() {}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 笔尖长度
|
||||||
|
/// </summary>
|
||||||
|
public double NibWidth { get; set; } = 4.00;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 笔尖高度
|
||||||
|
/// </summary>
|
||||||
|
public double NibHeight { get; set; } = 4.00;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 笔尖大小,适合笔尖类型为普通笔时使用
|
||||||
|
/// </summary>
|
||||||
|
public double NibSize {
|
||||||
|
get => (NibWidth + NibHeight) / 2;
|
||||||
|
set => NibWidth = NibHeight = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NibType NibType { get; set; } = NibType.Default;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 笔尖颜色
|
||||||
|
/// </summary>
|
||||||
|
public Color NibColor { get; set; } = Colors.Black;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 笔锋样式类型,默认有笔锋
|
||||||
|
/// </summary>
|
||||||
|
public StrokeNibStyle StrokeNibStyle { get; set; } = StrokeNibStyle.Beautiful;
|
||||||
|
}
|
||||||
|
}
|
54
InkCanvasForClass.IccInkCanvas/Settings/EditingMode.cs
Normal file
54
InkCanvasForClass.IccInkCanvas/Settings/EditingMode.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace InkCanvasForClass.IccInkCanvas.Settings {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IccBoard的编辑模式
|
||||||
|
/// </summary>
|
||||||
|
public enum EditingMode {
|
||||||
|
/// <summary>
|
||||||
|
/// 仅显示墨迹,不会接收任何输入事件,没有HitTest
|
||||||
|
/// </summary>
|
||||||
|
None,
|
||||||
|
/// <summary>
|
||||||
|
/// 仅显示墨迹,不会接收任何输入事件,有HitTest
|
||||||
|
/// </summary>
|
||||||
|
NoneWithHitTest,
|
||||||
|
/// <summary>
|
||||||
|
/// 书写模式,该模式下允许临时切换到橡皮擦模式
|
||||||
|
/// </summary>
|
||||||
|
Writing,
|
||||||
|
/// <summary>
|
||||||
|
/// 墨迹擦模式
|
||||||
|
/// </summary>
|
||||||
|
StrokeErasing,
|
||||||
|
/// <summary>
|
||||||
|
/// 板擦模式
|
||||||
|
/// </summary>
|
||||||
|
GeometryErasing,
|
||||||
|
/// <summary>
|
||||||
|
/// 区域擦除模式
|
||||||
|
/// </summary>
|
||||||
|
AreaErasing,
|
||||||
|
/// <summary>
|
||||||
|
/// 墨迹选择模式
|
||||||
|
/// </summary>
|
||||||
|
Select,
|
||||||
|
/// <summary>
|
||||||
|
/// 仅显示墨迹,仅接受手势输入
|
||||||
|
/// </summary>
|
||||||
|
Gestures,
|
||||||
|
/// <summary>
|
||||||
|
/// 形状绘制模式,该模式不能被用户直接设置
|
||||||
|
/// </summary>
|
||||||
|
ShapeDrawing,
|
||||||
|
/// <summary>
|
||||||
|
/// 漫游模式
|
||||||
|
/// </summary>
|
||||||
|
RoamingMode
|
||||||
|
}
|
||||||
|
}
|
36
InkCanvasForClass.IccInkCanvas/Settings/Nib.cs
Normal file
36
InkCanvasForClass.IccInkCanvas/Settings/Nib.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace InkCanvasForClass.IccInkCanvas.Settings {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 定义了笔尖类型
|
||||||
|
/// </summary>
|
||||||
|
public enum NibType {
|
||||||
|
/// <summary>
|
||||||
|
/// 默认笔
|
||||||
|
/// </summary>
|
||||||
|
Default,
|
||||||
|
/// <summary>
|
||||||
|
/// 荧光笔
|
||||||
|
/// </summary>
|
||||||
|
Highlighter
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 笔锋样式
|
||||||
|
/// </summary>
|
||||||
|
public enum StrokeNibStyle {
|
||||||
|
/// <summary>
|
||||||
|
/// 无笔锋
|
||||||
|
/// </summary>
|
||||||
|
Solid,
|
||||||
|
/// <summary>
|
||||||
|
/// 有笔锋,基于固定点集算法计算
|
||||||
|
/// </summary>
|
||||||
|
Beautiful
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user