Merge pull request #465 from InkCanvasForClass/net6

合并462
This commit is contained in:
CJK_mkp
2026-05-02 17:45:07 +08:00
committed by GitHub
41 changed files with 1736 additions and 247 deletions
+2 -2
View File
@@ -34,8 +34,8 @@ namespace Ink_Canvas
else
{
AnimationsHelper.HideWithSlideAndFade(EraserSizePanel);
AnimationsHelper.HideWithSlideAndFade(BorderTools);
AnimationsHelper.HideWithSlideAndFade(BoardBorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BoardBorderToolsPopup);
AnimationsHelper.HideWithSlideAndFade(PenPalette);
AnimationsHelper.HideWithSlideAndFade(BoardPenPalette);
AnimationsHelper.HideWithSlideAndFade(BorderDrawShape);
+110 -20
View File
@@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Forms;
using System.Windows.Ink;
using System.Windows.Input;
@@ -205,6 +206,7 @@ namespace Ink_Canvas
/// </summary>
private Point pointPPT = new Point(-1, -1);
private DispatcherTimer _floatingBarScreenFollowTimer;
private DispatcherTimer _popupRefreshTimer; // Popup 位置刷新节流定时器
private string _lastFloatingBarScreenDeviceName;
private string _lastCanvasScreenDeviceName;
private bool _isRebuildingCanvasForScreen;
@@ -227,6 +229,95 @@ namespace Ink_Canvas
pointPPT = new Point(xPos, yPos);
else
pointDesktop = new Point(xPos, yPos);
// 刷新 Popup 菜单位置(带节流)
RefreshPopupPositionThrottled();
}
}
/// <summary>
/// 刷新 Popup 菜单位置(带节流,避免频繁调用)
/// </summary>
private void RefreshPopupPositionThrottled()
{
try
{
// 如果没有打开的 Popup,直接返回
if (!BorderTools.IsOpen && !BoardBorderToolsPopup.IsOpen) return;
// 如果定时器不存在,创建一个(16ms ≈ 60fps)
if (_popupRefreshTimer == null)
{
_popupRefreshTimer = new DispatcherTimer();
_popupRefreshTimer.Interval = TimeSpan.FromMilliseconds(16);
_popupRefreshTimer.Tick += (s, e) =>
{
_popupRefreshTimer?.Stop();
RefreshPopupPositionInternal();
};
}
// 重启定时器(如果已经在运行,会重新计时)
_popupRefreshTimer.Stop();
_popupRefreshTimer.Start();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"RefreshPopupPositionThrottled error: {ex.Message}");
}
}
/// <summary>
/// 实际执行 Popup 位置刷新(强力版本)
/// </summary>
private void RefreshPopupPositionInternal()
{
try
{
RefreshPopupForcefully(BorderTools);
RefreshPopupForcefully(BoardBorderToolsPopup);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"RefreshPopupPositionInternal error: {ex.Message}");
}
}
/// <summary>
/// 强制刷新单个 Popup 的位置
/// 使用多种策略确保位置更新生效
/// </summary>
private void RefreshPopupForcefully(Popup popup)
{
if (popup == null || !popup.IsOpen || popup.PlacementTarget == null) return;
try
{
// 策略1:强制失效测量和布局
popup.InvalidateMeasure();
popup.InvalidateArrange();
// 策略2:修改 Offset 触发重新定位
var originalHorizontalOffset = popup.HorizontalOffset;
var originalVerticalOffset = popup.VerticalOffset;
popup.HorizontalOffset = originalHorizontalOffset + 0.001;
popup.VerticalOffset = originalVerticalOffset + 0.001;
popup.HorizontalOffset = originalHorizontalOffset;
popup.VerticalOffset = originalVerticalOffset;
// 策略3:强制更新布局
popup.UpdateLayout();
// 策略4:使用 Win32 API 强制刷新窗口位置(终极方案)
AnimationsHelper.ForceRefreshPopupPosition(popup);
System.Diagnostics.Debug.WriteLine($"[PopupRefresh] Forcefully refreshed popup position");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[PopupRefresh] Error: {ex.Message}");
}
}
@@ -294,8 +385,8 @@ namespace Ink_Canvas
/// </summary>
private void HideSubPanelsImmediately()
{
BorderTools.Visibility = Visibility.Collapsed;
BoardBorderTools.Visibility = Visibility.Collapsed;
BorderTools.IsOpen = false;
BoardBorderToolsPopup.IsOpen = false;
PenPalette.Visibility = Visibility.Collapsed;
BoardPenPalette.Visibility = Visibility.Collapsed;
BoardEraserSizePanel.Visibility = Visibility.Collapsed;
@@ -376,8 +467,8 @@ namespace Ink_Canvas
/// </param>
internal async void HideSubPanels(string mode = null, bool autoAlignCenter = false)
{
AnimationsHelper.HideWithSlideAndFade(BorderTools);
AnimationsHelper.HideWithSlideAndFade(BoardBorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BoardBorderToolsPopup);
AnimationsHelper.HideWithSlideAndFade(PenPalette);
AnimationsHelper.HideWithSlideAndFade(BoardPenPalette);
AnimationsHelper.HideWithSlideAndFade(BoardEraserSizePanel);
@@ -1099,8 +1190,8 @@ namespace Ink_Canvas
{
LeftUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed;
RightUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed;
AnimationsHelper.HideWithSlideAndFade(BorderTools);
AnimationsHelper.HideWithSlideAndFade(BoardBorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BoardBorderToolsPopup);
AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel);
if (Settings.RandSettings?.UseNewStyleUI == true)
@@ -1151,8 +1242,8 @@ namespace Ink_Canvas
/// <param name="e">路由事件参数</param>
private void OperatingGuideWindowIcon_MouseUp(object sender, MouseButtonEventArgs e)
{
AnimationsHelper.HideWithSlideAndFade(BorderTools);
AnimationsHelper.HideWithSlideAndFade(BoardBorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BoardBorderToolsPopup);
AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel);
new OperatingGuideWindow().Show();
@@ -1171,8 +1262,8 @@ namespace Ink_Canvas
LeftUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed;
RightUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed;
AnimationsHelper.HideWithSlideAndFade(BorderTools);
AnimationsHelper.HideWithSlideAndFade(BoardBorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BoardBorderToolsPopup);
AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel);
// 根据设置决定使用哪个点名窗口
@@ -1306,8 +1397,8 @@ namespace Ink_Canvas
LeftUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed;
RightUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed;
AnimationsHelper.HideWithSlideAndFade(BorderTools);
AnimationsHelper.HideWithSlideAndFade(BoardBorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BoardBorderToolsPopup);
AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel);
// 检查是否启用了外部点名功能
@@ -1385,8 +1476,8 @@ namespace Ink_Canvas
{
//if (lastBorderMouseDownObject != sender) return;
AnimationsHelper.HideWithSlideAndFade(BorderTools);
AnimationsHelper.HideWithSlideAndFade(BoardBorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BoardBorderToolsPopup);
AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel);
CollapseBorderDrawShape();
@@ -1687,22 +1778,21 @@ namespace Ink_Canvas
/// <param name="e">鼠标按钮事件参数</param>
internal void SymbolIconTools_MouseUp(object sender, MouseButtonEventArgs e)
{
if (BorderTools.Visibility == Visibility.Visible || BoardBorderTools.Visibility == Visibility.Visible)
if (BorderTools.IsOpen || BoardBorderToolsPopup.IsOpen)
{
AnimationsHelper.HideWithSlideAndFade(BorderTools);
AnimationsHelper.HideWithSlideAndFade(BoardBorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BoardBorderToolsPopup);
}
else
{
HideSubPanels();
if (currentMode == 0)
{
UpdateBorderToolsPosition();
AnimationsHelper.ShowWithSlideFromBottomAndFade(BorderTools);
AnimationsHelper.ShowPopupWithSlideAndFade(BorderTools);
}
else
{
AnimationsHelper.ShowWithSlideFromBottomAndFade(BoardBorderTools);
AnimationsHelper.ShowPopupWithSlideAndFade(BoardBorderToolsPopup);
}
}
}
@@ -98,8 +98,8 @@ namespace Ink_Canvas
{
if (lastBorderMouseDownObject != sender || inkCanvas.Visibility != Visibility.Visible) return;
AnimationsHelper.HideWithSlideAndFade(BorderTools);
AnimationsHelper.HideWithSlideAndFade(BoardBorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BoardBorderToolsPopup);
GridNotifications.Visibility = Visibility.Collapsed;
@@ -916,8 +916,8 @@ namespace Ink_Canvas
private void SymbolIconOpenStrokes_MouseUp(object sender, MouseButtonEventArgs e)
{
if (lastBorderMouseDownObject != sender) return;
AnimationsHelper.HideWithSlideAndFade(BorderTools);
AnimationsHelper.HideWithSlideAndFade(BoardBorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BorderTools);
AnimationsHelper.HidePopupWithSlideAndFade(BoardBorderToolsPopup);
var openFileDialog = new OpenFileDialog();
openFileDialog.InitialDirectory = Settings.Automation.AutoSavedStrokesLocation;
+2
View File
@@ -915,6 +915,8 @@ namespace Ink_Canvas
Settings.Canvas.DisablePressure = false;
Settings.Canvas.AutoStraightenLine = true;
Settings.Canvas.AutoStraightenLineThreshold = 80;
Settings.Canvas.PauseStraightenLine = false;
Settings.Canvas.PauseStraightenDelay = 300;
Settings.Canvas.LineEndpointSnapping = true;
Settings.Canvas.LineEndpointSnappingThreshold = 15;
Settings.Canvas.UsingWhiteboard = false;
@@ -2517,6 +2517,7 @@ namespace Ink_Canvas
_isMouseRealtimeInking = true;
inkCanvas.EditingMode = InkCanvasEditingMode.None;
var p = e.GetPosition(inkCanvas);
CancelPauseStraightenTimer(MouseRealtimeStrokeId);
InitializeRealtimeBrushTipStateFromPoint(MouseRealtimeStrokeId, p);
var sv = GetStrokeVisual(MouseRealtimeStrokeId);
TryAppendRealtimeVelocityBrushTipPoint(sv, MouseRealtimeStrokeId, p);
@@ -2547,7 +2548,10 @@ namespace Ink_Canvas
{
var sv = GetStrokeVisual(MouseRealtimeStrokeId);
if (TryAppendRealtimeVelocityBrushTipPoint(sv, MouseRealtimeStrokeId, e.GetPosition(inkCanvas)))
{
sv.ForceRedraw();
ResetPauseStraightenTimer(MouseRealtimeStrokeId);
}
else
{
_isMouseRealtimeInking = false;
@@ -2612,6 +2616,7 @@ namespace Ink_Canvas
VisualCanvasList.Remove(MouseRealtimeStrokeId);
TouchDownPointsList.Remove(MouseRealtimeStrokeId);
CleanupRealtimeBrushTipState(MouseRealtimeStrokeId);
CancelPauseStraightenTimer(MouseRealtimeStrokeId);
_isMouseRealtimeInking = false;
}
}
+45 -17
View File
@@ -1,5 +1,7 @@
using System;
using Ink_Canvas.Controls;
using Ink_Canvas.Controls.Toolbar;
using Ink_Canvas.Helpers;
using System.Collections.Generic;
using System.Windows.Controls;
@@ -7,8 +9,6 @@ namespace Ink_Canvas
{
public partial class MainWindow
{
// 这批属性替代了 XAML 中原有的 x:Name 自动生成字段;外部代码继续按原名访问。
// 由对应 Toolbar Item 的 AfterBuild 回填,Populate 发生在 Window_Loaded 早期。
internal ToolbarImageButton SymbolIconDelete { get; private set; }
internal ToolbarImageButton Eraser_Icon { get; private set; }
internal ToolbarImageButton EraserByStrokes_Icon { get; private set; }
@@ -32,25 +32,53 @@ namespace Ink_Canvas
internal void AttachSymbolIconRedo(ToolbarImageButton btn) => SymbolIconRedo = btn;
internal void AttachCursorWithDelBtn(ToolbarImageButton btn) => CursorWithDelFloatingBarBtn = btn;
internal void AttachWhiteboardBtn(ToolbarImageButton btn) => WhiteboardFloatingBarBtn = btn;
internal void AttachToolsBtn(ToolbarImageButton btn) => ToolsFloatingBarBtn = btn;
internal void AttachToolsBtn(ToolbarImageButton btn)
{
ToolsFloatingBarBtn = btn;
BorderTools.PlacementTarget = btn;
}
internal void AttachFoldIcon(ToolbarImageButton btn) => Fold_Icon = btn;
/// <summary>
/// 在 Window_Loaded 早期调用:按 Settings.Toolbar 配置把插件化按钮填充到对应容器。
/// 必须在 LoadSettings 之前,因为 LoadSettings 会访问 Cursor_Icon/Pen_Icon/Eraser_Icon 等。
/// </summary>
internal void InitializeToolbarPlugins()
{
ToolbarHost = new ToolbarHost(this);
var slots = new Dictionary<ToolbarSlot, Panel>
LogHelper.WriteLogToFile("MW_Toolbar: InitializeToolbarPlugins 开始", LogHelper.LogType.Info);
try
{
{ ToolbarSlot.FloatingBarMain, StackPanelFloatingBar },
{ ToolbarSlot.FloatingBarCanvasControls, StackPanelCanvasControls },
{ ToolbarSlot.FloatingBarEnd, StackPanelFloatingBarEnd },
{ ToolbarSlot.BlackboardLeft, BlackboardLeftSide },
{ ToolbarSlot.BlackboardRight, BlackboardRightSide }
};
ToolbarRegistry.Populate(ToolbarHost, slots, Settings?.Toolbar);
ToolbarHost = new ToolbarHost(this);
var slots = new Dictionary<ToolbarSlot, Panel>
{
{ ToolbarSlot.FloatingBarMain, StackPanelFloatingBar },
{ ToolbarSlot.FloatingBarCanvasControls, StackPanelCanvasControls },
{ ToolbarSlot.FloatingBarEnd, StackPanelFloatingBarEnd },
{ ToolbarSlot.BlackboardLeft, BlackboardLeftSide },
{ ToolbarSlot.BlackboardRight, BlackboardRightSide }
};
ToolbarRegistry.Populate(ToolbarHost, slots, Settings?.Toolbar);
LogHelper.WriteLogToFile("MW_Toolbar: InitializeToolbarPlugins 完成", LogHelper.LogType.Info);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"MW_Toolbar: InitializeToolbarPlugins 异常: {ex.GetType().Name}: {ex.Message}\n{ex.StackTrace}", LogHelper.LogType.Error);
}
}
internal void RebuildToolbar()
{
LogHelper.WriteLogToFile("MW_Toolbar: RebuildToolbar 开始", LogHelper.LogType.Info);
try
{
ToolbarRegistry.ClearInjected(StackPanelFloatingBar);
ToolbarRegistry.ClearInjected(StackPanelCanvasControls);
ToolbarRegistry.ClearInjected(StackPanelFloatingBarEnd);
ToolbarRegistry.ClearInjected(BlackboardLeftSide);
ToolbarRegistry.ClearInjected(BlackboardRightSide);
InitializeToolbarPlugins();
LogHelper.WriteLogToFile("MW_Toolbar: RebuildToolbar 完成", LogHelper.LogType.Info);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"MW_Toolbar: RebuildToolbar 异常: {ex.GetType().Name}: {ex.Message}\n{ex.StackTrace}", LogHelper.LogType.Error);
}
}
}
}
}
+147 -1
View File
@@ -1,6 +1,7 @@
using Ink_Canvas.Helpers;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
@@ -8,6 +9,7 @@ using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Point = System.Windows.Point;
namespace Ink_Canvas
@@ -54,6 +56,9 @@ namespace Ink_Canvas
private readonly HashSet<int> _activeRealtimeTouchStrokeIds = new HashSet<int>();
private readonly HashSet<int> _activeTouchStrokeIds = new HashSet<int>();
private readonly Dictionary<int, DispatcherTimer> _pauseStraightenTimers = new Dictionary<int, DispatcherTimer>();
private const int PauseStraightenDelayMs = 300;
private sealed class OneEuroFilter
{
private readonly float _minCutoff;
@@ -762,6 +767,9 @@ namespace Ink_Canvas
|| inkCanvas.EditingMode == InkCanvasEditingMode.Select) return;
InitializeRealtimeBrushTipState(e.StylusDevice.Id, e);
CancelPauseStraightenTimer(e.StylusDevice.Id);
_pauseStraightenInkModeStartPos = e.GetPosition(inkCanvas);
_pauseStraightenInkModeTracking = true;
TouchDownPointsList[e.StylusDevice.Id] = InkCanvasEditingMode.None;
}
@@ -865,6 +873,9 @@ namespace Ink_Canvas
VisualCanvasList.Remove(e.StylusDevice.Id);
TouchDownPointsList.Remove(e.StylusDevice.Id);
CleanupRealtimeBrushTipState(e.StylusDevice.Id);
CancelPauseStraightenTimer(e.StylusDevice.Id);
CancelPauseStraightenTimer(-200001);
_pauseStraightenInkModeTracking = false;
if (StrokeVisualList.Count == 0 || VisualCanvasList.Count == 0 || TouchDownPointsList.Count == 0)
{
// 只清除手写笔预览相关的Canvas,不清除所有子元素
@@ -921,7 +932,14 @@ namespace Ink_Canvas
return;
}
if (GetTouchDownPointsList(e.StylusDevice.Id) != InkCanvasEditingMode.None) return;
if (GetTouchDownPointsList(e.StylusDevice.Id) != InkCanvasEditingMode.None)
{
// Regular Ink mode — InkCanvas builds the stroke internally.
// Track position for pause-straighten.
if (inkCanvas.EditingMode == InkCanvasEditingMode.Ink && drawingShapeMode == 0)
ResetPauseStraightenTimerInkMode(e.GetPosition(inkCanvas));
return;
}
try
{
if (e.StylusDevice.StylusButtons[1].StylusButtonState == StylusButtonState.Down) return;
@@ -938,6 +956,8 @@ namespace Ink_Canvas
strokeVisual.Add(new StylusPoint(stylusPoint.X, stylusPoint.Y, stylusPoint.PressureFactor));
}
ResetPauseStraightenTimer(e.StylusDevice.Id);
if (isHandledByRealtime)
strokeVisual.ForceRedraw();
else
@@ -987,6 +1007,126 @@ namespace Ink_Canvas
return VisualCanvasList.TryGetValue(id, out var visualCanvas) ? visualCanvas : null;
}
private void ResetPauseStraightenTimer(int stylusId)
{
if (!Settings.Canvas.PauseStraightenLine) return;
Debug.WriteLine($"ResetPauseStraightenTimer: id={stylusId}");
if (_pauseStraightenTimers.TryGetValue(stylusId, out var existing))
{
existing.Stop();
existing.Interval = TimeSpan.FromMilliseconds(Settings.Canvas.PauseStraightenDelay);
existing.Start();
return;
}
var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(Settings.Canvas.PauseStraightenDelay) };
var capturedId = stylusId;
timer.Tick += (s, e) =>
{
timer.Stop();
_pauseStraightenTimers.Remove(capturedId);
Debug.WriteLine($"PauseStraightenTimer fired: id={capturedId}");
TryPauseStraighten(capturedId);
};
_pauseStraightenTimers[stylusId] = timer;
timer.Start();
}
private void ResetPauseStraightenTimerInkMode(Point currentPos)
{
if (!Settings.Canvas.PauseStraightenLine) return;
const int inkModeId = -200001;
_pauseStraightenInkModeLastPos = currentPos;
if (_pauseStraightenTimers.TryGetValue(inkModeId, out var existing))
{
existing.Stop();
existing.Interval = TimeSpan.FromMilliseconds(Settings.Canvas.PauseStraightenDelay);
existing.Start();
return;
}
var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(Settings.Canvas.PauseStraightenDelay) };
timer.Tick += (s, e) =>
{
timer.Stop();
_pauseStraightenTimers.Remove(inkModeId);
TryPauseStraightenInkMode();
};
_pauseStraightenTimers[inkModeId] = timer;
timer.Start();
}
private Point _pauseStraightenInkModeLastPos;
private Point _pauseStraightenInkModeStartPos;
private bool _pauseStraightenInkModeTracking;
private void TryPauseStraightenInkMode()
{
if (!Settings.Canvas.PauseStraightenLine) return;
if (!_pauseStraightenInkModeTracking) return;
if (inkCanvas.EditingMode != InkCanvasEditingMode.Ink) return;
if (drawingShapeMode != 0) return;
var start = _pauseStraightenInkModeStartPos;
var end = _pauseStraightenInkModeLastPos;
double lineLength = GetDistance(start, end);
if (lineLength < 2) return;
// Commit current stroke by briefly switching mode
inkCanvas.EditingMode = InkCanvasEditingMode.None;
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
// The just-committed stroke should now be last in inkCanvas.Strokes
if (inkCanvas.Strokes.Count == 0) return;
var stroke = inkCanvas.Strokes[inkCanvas.Strokes.Count - 1];
if (stroke.StylusPoints.Count < 2) return;
var newPoints = new StylusPointCollection();
newPoints.Add(new StylusPoint(start.X, start.Y, 0.5f));
if (lineLength > 100)
{
newPoints.Add(new StylusPoint(start.X + (end.X - start.X) / 3.0, start.Y + (end.Y - start.Y) / 3.0, 0.5f));
newPoints.Add(new StylusPoint(start.X + (end.X - start.X) * 2.0 / 3.0, start.Y + (end.Y - start.Y) * 2.0 / 3.0, 0.5f));
}
newPoints.Add(new StylusPoint(end.X, end.Y, 0.5f));
stroke.StylusPoints = newPoints;
_pauseStraightenInkModeTracking = false;
}
private void CancelPauseStraightenTimer(int stylusId)
{
if (_pauseStraightenTimers.TryGetValue(stylusId, out var timer))
{
timer.Stop();
_pauseStraightenTimers.Remove(stylusId);
}
}
private void TryPauseStraighten(int stylusId)
{
if (!Settings.Canvas.PauseStraightenLine) { Debug.WriteLine("PauseStraighten: disabled"); return; }
var strokeVisual = StrokeVisualList.TryGetValue(stylusId, out var sv) ? sv : null;
if (strokeVisual?.Stroke == null) { Debug.WriteLine($"PauseStraighten: no stroke for id={stylusId}"); return; }
var stroke = strokeVisual.Stroke;
Debug.WriteLine($"PauseStraighten: points={stroke.StylusPoints.Count}");
if (stroke.StylusPoints.Count < 2) return;
var start = stroke.StylusPoints[0].ToPoint();
var end = stroke.StylusPoints[stroke.StylusPoints.Count - 1].ToPoint();
double lineLength = GetDistance(start, end);
Debug.WriteLine($"PauseStraighten: length={lineLength:F1}, STRAIGHTENING!");
var newPoints = new StylusPointCollection();
newPoints.Add(new StylusPoint(start.X, start.Y, 0.5f));
if (lineLength > 100)
{
newPoints.Add(new StylusPoint(start.X + (end.X - start.X) / 3.0, start.Y + (end.Y - start.Y) / 3.0, 0.5f));
newPoints.Add(new StylusPoint(start.X + (end.X - start.X) * 2.0 / 3.0, start.Y + (end.Y - start.Y) * 2.0 / 3.0, 0.5f));
}
newPoints.Add(new StylusPoint(end.X, end.Y, 0.5f));
stroke.StylusPoints = newPoints;
strokeVisual.ForceRedraw();
}
/// <summary>
/// 获取触摸按下点的编辑模式方法
/// </summary>
@@ -1191,6 +1331,7 @@ namespace Ink_Canvas
var touchId = e.TouchDevice.Id;
var p = e.GetTouchPoint(inkCanvas).Position;
_activeRealtimeTouchStrokeIds.Add(touchId);
CancelPauseStraightenTimer(touchId);
InitializeRealtimeBrushTipStateFromPoint(touchId, p);
var sv = GetStrokeVisual(touchId);
TryAppendRealtimeVelocityBrushTipPoint(sv, touchId, p);
@@ -1214,6 +1355,7 @@ namespace Ink_Canvas
var touchId = e.TouchDevice.Id;
var p = e.GetTouchPoint(inkCanvas).Position;
_activeTouchStrokeIds.Add(touchId);
CancelPauseStraightenTimer(touchId);
var sv = GetStrokeVisual(touchId);
sv.Add(new StylusPoint(p.X, p.Y, 0.5f));
sv.Redraw();
@@ -1348,6 +1490,7 @@ namespace Ink_Canvas
var sv = GetStrokeVisual(touchId);
if (TryAppendRealtimeVelocityBrushTipPoint(sv, touchId, p))
sv.ForceRedraw();
ResetPauseStraightenTimer(touchId);
}
catch (Exception ex)
{
@@ -1364,6 +1507,7 @@ namespace Ink_Canvas
var sv = GetStrokeVisual(touchId);
sv.Add(new StylusPoint(p.X, p.Y, 0.5f));
sv.Redraw();
ResetPauseStraightenTimer(touchId);
}
catch (Exception ex)
{
@@ -1424,6 +1568,7 @@ namespace Ink_Canvas
VisualCanvasList.Remove(touchId);
TouchDownPointsList.Remove(touchId);
CleanupRealtimeBrushTipState(touchId);
CancelPauseStraightenTimer(touchId);
_activeRealtimeTouchStrokeIds.Remove(touchId);
}
}
@@ -1452,6 +1597,7 @@ namespace Ink_Canvas
VisualCanvasList.Remove(touchId);
TouchDownPointsList.Remove(touchId);
CleanupRealtimeBrushTipState(touchId);
CancelPauseStraightenTimer(touchId);
_activeTouchStrokeIds.Remove(touchId);
}
}