add:issue #131
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Threading;
|
||||
using System.Windows.Ink;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Ink_Canvas.Helpers
|
||||
{
|
||||
@@ -34,6 +39,8 @@ namespace Ink_Canvas.Helpers
|
||||
private readonly Dispatcher _dispatcher;
|
||||
private readonly Dictionary<Stroke, DispatcherTimer> _fadeTimers;
|
||||
private readonly Dictionary<Stroke, UIElement> _strokeVisuals;
|
||||
private readonly Dictionary<Stroke, Point> _strokeStartPoints;
|
||||
private readonly Dictionary<Stroke, Point> _strokeEndPoints;
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
@@ -43,6 +50,8 @@ namespace Ink_Canvas.Helpers
|
||||
_dispatcher = _mainWindow.Dispatcher;
|
||||
_fadeTimers = new Dictionary<Stroke, DispatcherTimer>();
|
||||
_strokeVisuals = new Dictionary<Stroke, UIElement>();
|
||||
_strokeStartPoints = new Dictionary<Stroke, Point>();
|
||||
_strokeEndPoints = new Dictionary<Stroke, Point>();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -51,15 +60,31 @@ namespace Ink_Canvas.Helpers
|
||||
/// 添加需要渐隐的墨迹
|
||||
/// </summary>
|
||||
/// <param name="stroke">墨迹对象</param>
|
||||
/// <param name="visual">墨迹的视觉元素</param>
|
||||
public void AddFadingStroke(Stroke stroke, UIElement visual)
|
||||
/// <param name="startPoint">落笔点</param>
|
||||
/// <param name="endPoint">抬笔点</param>
|
||||
public void AddFadingStroke(Stroke stroke, Point startPoint, Point endPoint)
|
||||
{
|
||||
if (!IsEnabled || stroke == null || visual == null) return;
|
||||
LogHelper.WriteLogToFile($"AddFadingStroke 被调用,IsEnabled: {IsEnabled}, stroke: {(stroke != null ? "非空" : "空")}", LogHelper.LogType.Info);
|
||||
|
||||
if (!IsEnabled || stroke == null)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AddFadingStroke 被拒绝,IsEnabled: {IsEnabled}, stroke: {(stroke != null ? "非空" : "空")}", LogHelper.LogType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 记录墨迹和视觉元素的对应关系
|
||||
_strokeVisuals[stroke] = visual;
|
||||
LogHelper.WriteLogToFile($"开始添加渐隐墨迹,渐隐时间:{FadeTime}ms,动画时间:{AnimationDuration}ms", LogHelper.LogType.Info);
|
||||
|
||||
// 记录墨迹的起点和终点
|
||||
_strokeStartPoints[stroke] = startPoint;
|
||||
_strokeEndPoints[stroke] = endPoint;
|
||||
|
||||
// 创建墨迹的视觉元素(湿墨迹状态)
|
||||
var strokeVisual = CreateStrokeVisual(stroke);
|
||||
if (strokeVisual == null) return;
|
||||
|
||||
_strokeVisuals[stroke] = strokeVisual;
|
||||
|
||||
// 创建定时器,在指定时间后开始渐隐动画
|
||||
var timer = new DispatcherTimer
|
||||
@@ -69,6 +94,7 @@ namespace Ink_Canvas.Helpers
|
||||
|
||||
timer.Tick += (sender, e) =>
|
||||
{
|
||||
LogHelper.WriteLogToFile("定时器触发,开始渐隐动画", LogHelper.LogType.Info);
|
||||
StartFadeAnimation(stroke);
|
||||
timer.Stop();
|
||||
_fadeTimers.Remove(stroke);
|
||||
@@ -77,6 +103,8 @@ namespace Ink_Canvas.Helpers
|
||||
_fadeTimers[stroke] = timer;
|
||||
timer.Start();
|
||||
|
||||
LogHelper.WriteLogToFile($"定时器已启动,将在 {FadeTime}ms 后开始渐隐", LogHelper.LogType.Info);
|
||||
|
||||
// 将视觉元素添加到画布上
|
||||
_dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
@@ -84,7 +112,20 @@ namespace Ink_Canvas.Helpers
|
||||
{
|
||||
if (_mainWindow.inkCanvas != null)
|
||||
{
|
||||
_mainWindow.inkCanvas.Children.Add(visual);
|
||||
// 将墨迹添加到 inkCanvas 的父容器中,而不是 inkCanvas.Children
|
||||
// 这样可以避免坐标系统问题
|
||||
var parent = _mainWindow.inkCanvas.Parent as System.Windows.Controls.Panel;
|
||||
if (parent != null)
|
||||
{
|
||||
parent.Children.Add(strokeVisual);
|
||||
LogHelper.WriteLogToFile("墨迹已添加到父容器", LogHelper.LogType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果无法获取父容器,则添加到 inkCanvas.Children
|
||||
_mainWindow.inkCanvas.Children.Add(strokeVisual);
|
||||
LogHelper.WriteLogToFile("墨迹已添加到 inkCanvas.Children", LogHelper.LogType.Info);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -121,7 +162,13 @@ namespace Ink_Canvas.Helpers
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
|
||||
// 从父容器中移除墨迹
|
||||
var parent = _mainWindow.inkCanvas?.Parent as System.Windows.Controls.Panel;
|
||||
if (parent != null && parent.Children.Contains(visual))
|
||||
{
|
||||
parent.Children.Remove(visual);
|
||||
}
|
||||
else if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
|
||||
{
|
||||
_mainWindow.inkCanvas.Children.Remove(visual);
|
||||
}
|
||||
@@ -134,6 +181,9 @@ namespace Ink_Canvas.Helpers
|
||||
|
||||
_strokeVisuals.Remove(stroke);
|
||||
}
|
||||
|
||||
_strokeStartPoints.Remove(stroke);
|
||||
_strokeEndPoints.Remove(stroke);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -161,9 +211,14 @@ namespace Ink_Canvas.Helpers
|
||||
{
|
||||
if (_mainWindow.inkCanvas != null)
|
||||
{
|
||||
var parent = _mainWindow.inkCanvas.Parent as System.Windows.Controls.Panel;
|
||||
foreach (var visual in _strokeVisuals.Values)
|
||||
{
|
||||
if (_mainWindow.inkCanvas.Children.Contains(visual))
|
||||
if (parent != null && parent.Children.Contains(visual))
|
||||
{
|
||||
parent.Children.Remove(visual);
|
||||
}
|
||||
else if (_mainWindow.inkCanvas.Children.Contains(visual))
|
||||
{
|
||||
_mainWindow.inkCanvas.Children.Remove(visual);
|
||||
}
|
||||
@@ -177,6 +232,8 @@ namespace Ink_Canvas.Helpers
|
||||
});
|
||||
|
||||
_strokeVisuals.Clear();
|
||||
_strokeStartPoints.Clear();
|
||||
_strokeEndPoints.Clear();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -203,17 +260,107 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 更新动画持续时间设置
|
||||
/// 启用墨迹渐隐功能
|
||||
/// </summary>
|
||||
/// <param name="animationDuration">新的动画持续时间(毫秒)</param>
|
||||
public void UpdateAnimationDuration(int animationDuration)
|
||||
public void Enable()
|
||||
{
|
||||
AnimationDuration = animationDuration;
|
||||
IsEnabled = true;
|
||||
LogHelper.WriteLogToFile("墨迹渐隐功能已启用", LogHelper.LogType.Info);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 禁用墨迹渐隐功能
|
||||
/// </summary>
|
||||
public void Disable()
|
||||
{
|
||||
IsEnabled = false;
|
||||
LogHelper.WriteLogToFile("墨迹渐隐功能已禁用", LogHelper.LogType.Info);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// 创建墨迹的视觉元素
|
||||
/// </summary>
|
||||
/// <param name="stroke">墨迹对象</param>
|
||||
/// <returns>视觉元素</returns>
|
||||
private UIElement CreateStrokeVisual(Stroke stroke)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogHelper.WriteLogToFile("开始创建墨迹视觉元素", LogHelper.LogType.Info);
|
||||
|
||||
// 创建路径几何,使用墨迹的实际位置
|
||||
var geometry = stroke.GetGeometry();
|
||||
if (geometry == null)
|
||||
{
|
||||
LogHelper.WriteLogToFile("墨迹几何为空,无法创建视觉元素", LogHelper.LogType.Error);
|
||||
return null;
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile($"墨迹几何边界:{geometry.Bounds}", LogHelper.LogType.Info);
|
||||
|
||||
// 获取绘画属性
|
||||
var drawingAttribs = stroke.DrawingAttributes;
|
||||
|
||||
// 创建路径元素,确保使用正确的绘画属性
|
||||
var path = new Path
|
||||
{
|
||||
Data = geometry,
|
||||
Stroke = new SolidColorBrush(drawingAttribs.Color),
|
||||
StrokeThickness = drawingAttribs.Width, // 使用原始墨迹的粗细
|
||||
StrokeStartLineCap = PenLineCap.Round,
|
||||
StrokeEndLineCap = PenLineCap.Round,
|
||||
StrokeLineJoin = PenLineJoin.Round,
|
||||
Fill = drawingAttribs.IsHighlighter ? new SolidColorBrush(drawingAttribs.Color) : null, // 高亮笔需要填充
|
||||
Opacity = 0.95, // 初始透明度更高,显得更自然
|
||||
|
||||
// 优化渲染质量
|
||||
UseLayoutRounding = false,
|
||||
SnapsToDevicePixels = false
|
||||
};
|
||||
|
||||
// 如果是高亮笔,调整透明度和混合模式
|
||||
if (drawingAttribs.IsHighlighter)
|
||||
{
|
||||
path.Opacity = 0.4; // 高亮笔初始透明度更低,更符合荧光笔特性
|
||||
|
||||
// 为高亮笔添加特殊的混合效果
|
||||
// 使用更柔和的笔触样式
|
||||
path.StrokeStartLineCap = PenLineCap.Flat;
|
||||
path.StrokeEndLineCap = PenLineCap.Flat;
|
||||
path.StrokeLineJoin = PenLineJoin.Miter;
|
||||
|
||||
// 高亮笔通常需要更宽的笔触来覆盖下面的内容
|
||||
if (drawingAttribs.Width < 20)
|
||||
{
|
||||
path.StrokeThickness = Math.Max(drawingAttribs.Width * 1.5, 20);
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile($"高亮笔特殊处理:透明度={path.Opacity},笔触宽度={path.StrokeThickness}", LogHelper.LogType.Info);
|
||||
}
|
||||
|
||||
// 不设置任何变换,保持墨迹原有粗细
|
||||
var bounds = geometry.Bounds;
|
||||
|
||||
// 设置墨迹的初始位置
|
||||
System.Windows.Controls.Canvas.SetLeft(path, bounds.Left);
|
||||
System.Windows.Controls.Canvas.SetTop(path, bounds.Top);
|
||||
|
||||
LogHelper.WriteLogToFile($"墨迹视觉元素创建完成,位置:({bounds.Left}, {bounds.Top}),大小:{bounds.Width} x {bounds.Height},粗细:{drawingAttribs.Width},高亮笔:{drawingAttribs.IsHighlighter}", LogHelper.LogType.Info);
|
||||
|
||||
return path;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"创建墨迹视觉元素失败: {ex}", LogHelper.LogType.Error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始渐隐动画
|
||||
/// </summary>
|
||||
@@ -224,34 +371,23 @@ namespace Ink_Canvas.Helpers
|
||||
|
||||
try
|
||||
{
|
||||
LogHelper.WriteLogToFile("开始执行渐隐动画", LogHelper.LogType.Info);
|
||||
|
||||
_dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
var fadeAnimation = new DoubleAnimation
|
||||
// 获取当前透明度和判断是否为高亮笔
|
||||
var currentOpacity = visual.Opacity;
|
||||
var isHighlighter = stroke.DrawingAttributes.IsHighlighter;
|
||||
|
||||
// 根据墨迹类型选择不同的动画效果
|
||||
if (isHighlighter)
|
||||
{
|
||||
From = 1.0,
|
||||
To = 0.0,
|
||||
Duration = TimeSpan.FromMilliseconds(AnimationDuration),
|
||||
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut }
|
||||
};
|
||||
|
||||
fadeAnimation.Completed += (sender, e) =>
|
||||
StartHighlighterFadeAnimation(visual, stroke, currentOpacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
|
||||
{
|
||||
_mainWindow.inkCanvas.Children.Remove(visual);
|
||||
}
|
||||
|
||||
RemoveStroke(stroke);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"渐隐动画完成后清理墨迹失败: {ex}", LogHelper.LogType.Error);
|
||||
}
|
||||
};
|
||||
|
||||
visual.BeginAnimation(UIElement.OpacityProperty, fadeAnimation);
|
||||
StartNormalStrokeFadeAnimation(visual, stroke, currentOpacity);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -259,6 +395,481 @@ namespace Ink_Canvas.Helpers
|
||||
LogHelper.WriteLogToFile($"开始渐隐动画失败: {ex}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始普通墨迹的渐隐动画
|
||||
/// </summary>
|
||||
private void StartNormalStrokeFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogHelper.WriteLogToFile("开始普通墨迹渐进式渐隐动画", LogHelper.LogType.Info);
|
||||
StartProgressiveFadeAnimation(visual, stroke, currentOpacity, AnimationDuration);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"开始普通墨迹渐隐动画失败: {ex}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始高亮笔的渐隐动画
|
||||
/// </summary>
|
||||
private void StartHighlighterFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogHelper.WriteLogToFile("开始高亮笔渐进式渐隐动画", LogHelper.LogType.Info);
|
||||
StartProgressiveFadeAnimation(visual, stroke, currentOpacity, (int)(AnimationDuration * 1.5));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"开始高亮笔渐隐动画失败: {ex}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 渐进式渐隐动画 - 从起点到终点逐渐消失
|
||||
/// </summary>
|
||||
private void StartProgressiveFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity, int duration)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogHelper.WriteLogToFile($"开始渐进式渐隐动画,墨迹点数:{stroke.StylusPoints.Count}", LogHelper.LogType.Info);
|
||||
|
||||
// 确保所有墨迹都能显示动画,包括短墨迹
|
||||
if (stroke.StylusPoints.Count < 2)
|
||||
{
|
||||
// 只有1个点的墨迹也使用分段动画,确保视觉效果
|
||||
CreateSegmentedStroke(visual, stroke, currentOpacity, duration);
|
||||
return;
|
||||
}
|
||||
|
||||
// 将墨迹分段并创建多个 Path
|
||||
CreateSegmentedStroke(visual, stroke, currentOpacity, duration);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"渐进式渐隐动画失败: {ex}", LogHelper.LogType.Error);
|
||||
// 失败时回退到简单动画
|
||||
StartSimpleFadeAnimation(visual, stroke, currentOpacity, duration);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建分段墨迹并开始渐进消失
|
||||
/// </summary>
|
||||
private void CreateSegmentedStroke(UIElement originalVisual, Stroke stroke, double opacity, int duration)
|
||||
{
|
||||
try
|
||||
{
|
||||
var stylusPoints = stroke.StylusPoints;
|
||||
var totalPoints = stylusPoints.Count;
|
||||
|
||||
// 分段算法 - 确保所有墨迹都有足够的动画效果
|
||||
var strokeLength = CalculateStrokeLength(stylusPoints);
|
||||
var segmentCount = CalculateOptimalSegmentCount(totalPoints, strokeLength);
|
||||
|
||||
// 强制最小分段数量,确保短墨迹也有动画效果
|
||||
segmentCount = Math.Max(segmentCount, 4);
|
||||
|
||||
var pointsPerSegment = Math.Max(1, totalPoints / segmentCount);
|
||||
|
||||
LogHelper.WriteLogToFile($"创建 {segmentCount} 个分段,每段约 {pointsPerSegment} 个点", LogHelper.LogType.Info);
|
||||
|
||||
// 隐藏原始视觉元素
|
||||
originalVisual.Visibility = Visibility.Hidden;
|
||||
|
||||
var segments = new List<UIElement>();
|
||||
var parent = _mainWindow.inkCanvas?.Parent as System.Windows.Controls.Panel;
|
||||
if (parent == null)
|
||||
{
|
||||
// 如果父容器不是Panel,直接使用InkCanvas
|
||||
parent = null; // 稍后会检查并使用InkCanvas.Children
|
||||
}
|
||||
|
||||
// 创建各个分段 - 确保短墨迹也能正确分段
|
||||
for (int i = 0; i < segmentCount; i++)
|
||||
{
|
||||
var startIndex = i * pointsPerSegment;
|
||||
var endIndex = (i == segmentCount - 1) ? totalPoints - 1 : (i + 1) * pointsPerSegment;
|
||||
|
||||
// 确保有足够的点来创建分段,对于短墨迹特殊处理
|
||||
if (endIndex <= startIndex && totalPoints > 1)
|
||||
{
|
||||
// 短墨迹:每个点作为一个分段
|
||||
startIndex = i;
|
||||
endIndex = Math.Min(i + 1, totalPoints - 1);
|
||||
}
|
||||
|
||||
// 为每个分段添加重叠,确保连接处平滑
|
||||
var overlap = Math.Max(1, pointsPerSegment / 6); // 15%的重叠,平衡平滑与速度
|
||||
var actualStartIndex = Math.Max(0, startIndex - overlap);
|
||||
var actualEndIndex = Math.Min(totalPoints - 1, endIndex + overlap);
|
||||
|
||||
var segment = CreateStrokeSegment(stroke, actualStartIndex, actualEndIndex, opacity);
|
||||
if (segment != null)
|
||||
{
|
||||
segments.Add(segment);
|
||||
if (parent != null)
|
||||
{
|
||||
parent.Children.Add(segment);
|
||||
}
|
||||
else if (_mainWindow.inkCanvas != null)
|
||||
{
|
||||
_mainWindow.inkCanvas.Children.Add(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 开始分段渐隐动画
|
||||
StartSegmentedFadeAnimation(segments, stroke, originalVisual, duration);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"创建分段墨迹失败: {ex}", LogHelper.LogType.Error);
|
||||
StartSimpleFadeAnimation(originalVisual, stroke, opacity, duration);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建墨迹分段
|
||||
/// </summary>
|
||||
private UIElement CreateStrokeSegment(Stroke originalStroke, int startIndex, int endIndex, double opacity)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 创建分段的 StylusPoint 集合
|
||||
var segmentPoints = new StylusPointCollection();
|
||||
for (int i = startIndex; i <= endIndex && i < originalStroke.StylusPoints.Count; i++)
|
||||
{
|
||||
segmentPoints.Add(originalStroke.StylusPoints[i]);
|
||||
}
|
||||
|
||||
if (segmentPoints.Count < 2) return null;
|
||||
|
||||
// 创建分段墨迹
|
||||
var segmentStroke = new Stroke(segmentPoints)
|
||||
{
|
||||
DrawingAttributes = originalStroke.DrawingAttributes.Clone()
|
||||
};
|
||||
|
||||
// 创建分段的视觉元素
|
||||
var geometry = segmentStroke.GetGeometry();
|
||||
if (geometry == null) return null;
|
||||
|
||||
var drawingAttribs = segmentStroke.DrawingAttributes;
|
||||
var path = new Path
|
||||
{
|
||||
Data = geometry,
|
||||
Stroke = new SolidColorBrush(drawingAttribs.Color),
|
||||
StrokeThickness = drawingAttribs.Width,
|
||||
StrokeStartLineCap = drawingAttribs.IsHighlighter ? PenLineCap.Flat : PenLineCap.Round,
|
||||
StrokeEndLineCap = drawingAttribs.IsHighlighter ? PenLineCap.Flat : PenLineCap.Round,
|
||||
StrokeLineJoin = drawingAttribs.IsHighlighter ? PenLineJoin.Miter : PenLineJoin.Round,
|
||||
Fill = drawingAttribs.IsHighlighter ? new SolidColorBrush(drawingAttribs.Color) : null,
|
||||
Opacity = opacity,
|
||||
UseLayoutRounding = false,
|
||||
SnapsToDevicePixels = false
|
||||
};
|
||||
|
||||
// 设置位置
|
||||
var bounds = geometry.Bounds;
|
||||
System.Windows.Controls.Canvas.SetLeft(path, bounds.Left);
|
||||
System.Windows.Controls.Canvas.SetTop(path, bounds.Top);
|
||||
|
||||
return path;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"创建墨迹分段失败: {ex}", LogHelper.LogType.Error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始分段渐隐动画
|
||||
/// </summary>
|
||||
private void StartSegmentedFadeAnimation(List<UIElement> segments, Stroke originalStroke, UIElement originalVisual, int totalDuration)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogHelper.WriteLogToFile($"开始 {segments.Count} 个分段的渐隐动画", LogHelper.LogType.Info);
|
||||
|
||||
// 动画时序算法
|
||||
var segmentDuration = CalculateOptimalSegmentDuration(totalDuration, segments.Count);
|
||||
var animationCurve = CreateAppleStyleAnimationCurve(segments.Count, totalDuration);
|
||||
|
||||
// 跟踪动画完成状态
|
||||
var completedSegments = new HashSet<UIElement>();
|
||||
var totalSegments = segments.Count;
|
||||
|
||||
// 渐隐效果 - 使用自然的动画曲线
|
||||
for (int i = 0; i < segments.Count; i++)
|
||||
{
|
||||
var segment = segments[i];
|
||||
|
||||
// 使用预计算的动画曲线获取延迟时间
|
||||
var delay = animationCurve[i];
|
||||
|
||||
// 使用定时器延迟启动每个分段的动画
|
||||
var timer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(delay)
|
||||
};
|
||||
|
||||
int segmentIndex = i; // 捕获当前索引
|
||||
timer.Tick += (sender, e) =>
|
||||
{
|
||||
StartSingleSegmentFadeAnimation(segment, segmentDuration, () =>
|
||||
{
|
||||
// 动画完成回调
|
||||
lock (completedSegments)
|
||||
{
|
||||
completedSegments.Add(segment);
|
||||
LogHelper.WriteLogToFile($"分段 {segmentIndex} 动画完成,已完成 {completedSegments.Count}/{totalSegments}", LogHelper.LogType.Info);
|
||||
|
||||
// 检查是否所有分段都完成了
|
||||
if (completedSegments.Count >= totalSegments)
|
||||
{
|
||||
LogHelper.WriteLogToFile("所有分段动画完成,开始清理", LogHelper.LogType.Info);
|
||||
CleanupSegmentedAnimation(segments, originalStroke, originalVisual);
|
||||
}
|
||||
}
|
||||
});
|
||||
timer.Stop();
|
||||
};
|
||||
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
// 设置一个安全超时定时器,防止无限等待
|
||||
var safetyTimeout = totalDuration + (segments.Count * segmentDuration) + 1200; // 额外1.2秒缓冲,确保动画完整
|
||||
var safetyTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(safetyTimeout)
|
||||
};
|
||||
|
||||
safetyTimer.Tick += (sender, e) =>
|
||||
{
|
||||
LogHelper.WriteLogToFile($"安全超时触发,强制清理动画", LogHelper.LogType.Warning);
|
||||
CleanupSegmentedAnimation(segments, originalStroke, originalVisual);
|
||||
safetyTimer.Stop();
|
||||
};
|
||||
|
||||
safetyTimer.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"分段渐隐动画失败: {ex}", LogHelper.LogType.Error);
|
||||
CleanupSegmentedAnimation(segments, originalStroke, originalVisual);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单个分段的渐隐动画
|
||||
/// </summary>
|
||||
private void StartSingleSegmentFadeAnimation(UIElement segment, int duration, Action onCompleted = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 只使用透明度动画,保持墨迹原有粗细
|
||||
var fadeAnimation = new DoubleAnimation
|
||||
{
|
||||
From = segment.Opacity,
|
||||
To = 0.0,
|
||||
Duration = TimeSpan.FromMilliseconds(duration),
|
||||
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut } // 更平滑的缓动
|
||||
};
|
||||
|
||||
// 添加动画完成事件
|
||||
if (onCompleted != null)
|
||||
{
|
||||
fadeAnimation.Completed += (sender, e) =>
|
||||
{
|
||||
onCompleted?.Invoke();
|
||||
};
|
||||
}
|
||||
|
||||
// 只应用透明度动画,不改变墨迹大小
|
||||
segment.BeginAnimation(UIElement.OpacityProperty, fadeAnimation);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"单个分段渐隐动画失败: {ex}", LogHelper.LogType.Error);
|
||||
// 即使失败也要调用完成回调
|
||||
onCompleted?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理分段动画
|
||||
/// </summary>
|
||||
private void CleanupSegmentedAnimation(List<UIElement> segments, Stroke originalStroke, UIElement originalVisual)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogHelper.WriteLogToFile("清理分段渐隐动画", LogHelper.LogType.Info);
|
||||
|
||||
// 移除所有分段
|
||||
var parent = _mainWindow.inkCanvas?.Parent as System.Windows.Controls.Panel;
|
||||
|
||||
foreach (var segment in segments)
|
||||
{
|
||||
if (parent != null && parent.Children.Contains(segment))
|
||||
{
|
||||
parent.Children.Remove(segment);
|
||||
}
|
||||
else if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(segment))
|
||||
{
|
||||
_mainWindow.inkCanvas.Children.Remove(segment);
|
||||
}
|
||||
}
|
||||
|
||||
// 清理原始墨迹
|
||||
OnAnimationCompleted(originalVisual, originalStroke);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"清理分段动画失败: {ex}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 简单渐隐动画(备用方案)
|
||||
/// </summary>
|
||||
private void StartSimpleFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity, int duration)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogHelper.WriteLogToFile("使用简单渐隐动画", LogHelper.LogType.Info);
|
||||
|
||||
var fadeAnimation = new DoubleAnimation
|
||||
{
|
||||
From = currentOpacity,
|
||||
To = 0.0,
|
||||
Duration = TimeSpan.FromMilliseconds(duration),
|
||||
EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseIn }
|
||||
};
|
||||
|
||||
fadeAnimation.Completed += (sender, e) => OnAnimationCompleted(visual, stroke);
|
||||
visual.BeginAnimation(UIElement.OpacityProperty, fadeAnimation);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"简单渐隐动画失败: {ex}", LogHelper.LogType.Error);
|
||||
OnAnimationCompleted(visual, stroke);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算墨迹的实际长度
|
||||
/// </summary>
|
||||
private double CalculateStrokeLength(StylusPointCollection points)
|
||||
{
|
||||
if (points.Count < 2) return 0;
|
||||
|
||||
double totalLength = 0;
|
||||
for (int i = 1; i < points.Count; i++)
|
||||
{
|
||||
var p1 = points[i - 1].ToPoint();
|
||||
var p2 = points[i].ToPoint();
|
||||
totalLength += Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2));
|
||||
}
|
||||
return totalLength;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据墨迹特性计算最优分段数量 - 平衡速度与完整性
|
||||
/// </summary>
|
||||
private int CalculateOptimalSegmentCount(int pointCount, double strokeLength)
|
||||
{
|
||||
// 平衡速度与完整性,确保动画效果的同时提高速度
|
||||
const double PIXELS_PER_SEGMENT = 12.0; // 每段适中长度,平衡效果与速度
|
||||
const int MIN_SEGMENTS = 5; // 适当的最小分段数,确保动画效果
|
||||
const int MAX_SEGMENTS = 100; // 适中的最大分段数,平衡性能与效果
|
||||
|
||||
// 根据长度计算基础分段数
|
||||
var lengthBasedSegments = Math.Max(MIN_SEGMENTS, (int)(strokeLength / PIXELS_PER_SEGMENT));
|
||||
|
||||
// 根据点密度调整,平衡效果与速度
|
||||
var density = pointCount > 0 ? strokeLength / pointCount : 1;
|
||||
var densityFactor = Math.Max(0.4, Math.Min(2.5, density / 1.8));
|
||||
|
||||
var finalSegments = (int)(lengthBasedSegments * densityFactor);
|
||||
|
||||
// 对于短墨迹,确保至少有4个分段
|
||||
if (pointCount <= 5)
|
||||
{
|
||||
finalSegments = Math.Max(finalSegments, 4);
|
||||
}
|
||||
|
||||
// 限制在合理范围内
|
||||
return Math.Min(MAX_SEGMENTS, Math.Max(MIN_SEGMENTS, finalSegments));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算最优的单段动画持续时间 - 平衡速度与完整性
|
||||
/// </summary>
|
||||
private int CalculateOptimalSegmentDuration(int totalDuration, int segmentCount)
|
||||
{
|
||||
// 平衡速度与动画完整性
|
||||
var baseDuration = totalDuration / Math.Max(segmentCount, 1);
|
||||
var minDuration = 150; // 每段最少150ms,确保动画完整显示
|
||||
var maxDuration = 500; // 每段最多500ms,平衡速度与完整性
|
||||
|
||||
return Math.Max(minDuration, Math.Min(maxDuration, baseDuration));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建优化的动画时间曲线 - 平衡速度与完整性
|
||||
/// </summary>
|
||||
private int[] CreateAppleStyleAnimationCurve(int segmentCount, int totalDuration)
|
||||
{
|
||||
var curve = new int[segmentCount];
|
||||
|
||||
// 平衡速度与完整性,确保动画有足够时间播放
|
||||
var availableTime = totalDuration * 0.6; // 使用60%的总时间,给动画留足够缓冲
|
||||
var delayBetweenSegments = Math.Max(60, availableTime / Math.Max(segmentCount, 1));
|
||||
|
||||
for (int i = 0; i < segmentCount; i++)
|
||||
{
|
||||
// 线性延迟,确保每个分段都有足够时间
|
||||
curve[i] = (int)(i * delayBetweenSegments);
|
||||
}
|
||||
|
||||
return curve;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 动画完成后的统一处理
|
||||
/// </summary>
|
||||
private void OnAnimationCompleted(UIElement visual, Stroke stroke)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogHelper.WriteLogToFile("渐隐动画完成,开始清理墨迹", LogHelper.LogType.Info);
|
||||
|
||||
// 从父容器中移除墨迹
|
||||
var parent = _mainWindow.inkCanvas?.Parent as System.Windows.Controls.Panel;
|
||||
if (parent != null && parent.Children.Contains(visual))
|
||||
{
|
||||
parent.Children.Remove(visual);
|
||||
LogHelper.WriteLogToFile("墨迹已从父容器移除", LogHelper.LogType.Info);
|
||||
}
|
||||
else if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
|
||||
{
|
||||
_mainWindow.inkCanvas.Children.Remove(visual);
|
||||
LogHelper.WriteLogToFile("墨迹已从 inkCanvas.Children 移除", LogHelper.LogType.Info);
|
||||
}
|
||||
|
||||
RemoveStroke(stroke);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"渐隐动画完成后清理墨迹失败: {ex}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
+60
-28
@@ -832,6 +832,27 @@
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchAdvancedBezierSmoothing_Toggled" />
|
||||
</ui:SimpleStackPanel>
|
||||
<Line HorizontalAlignment="Center" X1="0" Y1="0" X2="400" Y2="0" Stroke="#3f3f46"
|
||||
StrokeThickness="1" Margin="0,4,0,4" />
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<TextBlock Foreground="#fafafa" Text="启用墨迹渐隐功能" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchEnableInkFade"
|
||||
IsOn="False" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchEnableInkFade_Toggled" />
|
||||
</ui:SimpleStackPanel>
|
||||
<TextBlock Text="# 开启后墨迹不会绘制到画布上,而是保持湿墨迹状态,根据设置的渐隐时间自动消失" TextWrapping="Wrap" Foreground="#a1a1aa" />
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left"
|
||||
Visibility="{Binding ElementName=ToggleSwitchEnableInkFade, Path=IsOn, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<TextBlock Foreground="#fafafa" Text="墨迹渐隐时间" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<Slider Name="InkFadeTimeSlider" Width="150" Minimum="1000" Maximum="10000"
|
||||
Value="3000" TickFrequency="1000" IsSnapToTickEnabled="True"
|
||||
ValueChanged="InkFadeTimeSlider_ValueChanged" />
|
||||
<TextBlock Foreground="#fafafa" Text="{Binding ElementName=InkFadeTimeSlider, Path=Value, StringFormat={}{0:0}ms}"
|
||||
VerticalAlignment="Center" FontSize="14" Margin="16,0,0,0" />
|
||||
</ui:SimpleStackPanel>
|
||||
|
||||
</ui:SimpleStackPanel>
|
||||
</GroupBox>
|
||||
<!-- 新增:崩溃后操作设置 -->
|
||||
@@ -1197,16 +1218,16 @@
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Width="190">
|
||||
<TextBlock Foreground="#fafafa" Text="显示形状按钮" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,8,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchShowShapeButton"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchShowShapeButton_Toggled" />
|
||||
<CheckBox Name="CheckBoxShowShapeButton"
|
||||
IsChecked="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Checked="CheckBoxShowShapeButton_Checked" Unchecked="CheckBoxShowShapeButton_Unchecked" />
|
||||
</ui:SimpleStackPanel>
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Width="190">
|
||||
<TextBlock Foreground="#fafafa" Text="显示撤销按钮" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,8,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchShowUndoButton"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchShowUndoButton_Toggled" />
|
||||
<CheckBox Name="CheckBoxShowUndoButton"
|
||||
IsChecked="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Checked="CheckBoxShowUndoButton_Checked" Unchecked="CheckBoxShowUndoButton_Unchecked" />
|
||||
</ui:SimpleStackPanel>
|
||||
</ui:SimpleStackPanel>
|
||||
|
||||
@@ -1215,16 +1236,16 @@
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Width="190">
|
||||
<TextBlock Foreground="#fafafa" Text="显示重做按钮" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,8,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchShowRedoButton"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchShowRedoButton_Toggled" />
|
||||
<CheckBox Name="CheckBoxShowRedoButton"
|
||||
IsChecked="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Checked="CheckBoxShowRedoButton_Checked" Unchecked="CheckBoxShowRedoButton_Unchecked" />
|
||||
</ui:SimpleStackPanel>
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Width="190">
|
||||
<TextBlock Foreground="#fafafa" Text="显示清空按钮" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,8,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchShowClearButton"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchShowClearButton_Toggled" />
|
||||
<CheckBox Name="CheckBoxShowClearButton"
|
||||
IsChecked="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Checked="CheckBoxShowClearButton_Checked" Unchecked="CheckBoxShowClearButton_Unchecked" />
|
||||
</ui:SimpleStackPanel>
|
||||
</ui:SimpleStackPanel>
|
||||
|
||||
@@ -1233,16 +1254,16 @@
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Width="190">
|
||||
<TextBlock Foreground="#fafafa" Text="显示白板按钮" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,8,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchShowWhiteboardButton"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchShowWhiteboardButton_Toggled" />
|
||||
<CheckBox Name="CheckBoxShowWhiteboardButton"
|
||||
IsChecked="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Checked="CheckBoxShowWhiteboardButton_Checked" Unchecked="CheckBoxShowWhiteboardButton_Unchecked" />
|
||||
</ui:SimpleStackPanel>
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Width="190">
|
||||
<TextBlock Foreground="#fafafa" Text="显示隐藏按钮" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,8,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchShowHideButton"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchShowHideButton_Toggled" />
|
||||
<CheckBox Name="CheckBoxShowHideButton"
|
||||
IsChecked="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Checked="CheckBoxShowHideButton_Checked" Unchecked="CheckBoxShowHideButton_Unchecked" />
|
||||
</ui:SimpleStackPanel>
|
||||
</ui:SimpleStackPanel>
|
||||
|
||||
@@ -1251,16 +1272,16 @@
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Width="190">
|
||||
<TextBlock Foreground="#fafafa" Text="显示套索选择按钮" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,8,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchShowLassoSelectButton"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchShowLassoSelectButton_Toggled" />
|
||||
<CheckBox Name="CheckBoxShowLassoSelectButton"
|
||||
IsChecked="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Checked="CheckBoxShowLassoSelectButton_Checked" Unchecked="CheckBoxShowLassoSelectButton_Unchecked" />
|
||||
</ui:SimpleStackPanel>
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Width="190">
|
||||
<TextBlock Foreground="#fafafa" Text="显示清并鼠按钮" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,8,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchShowClearAndMouseButton"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchShowClearAndMouseButton_Toggled" />
|
||||
<CheckBox Name="CheckBoxShowClearAndMouseButton"
|
||||
IsChecked="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Checked="CheckBoxShowClearAndMouseButton_Checked" Unchecked="CheckBoxShowClearAndMouseButton_Unchecked" />
|
||||
</ui:SimpleStackPanel>
|
||||
</ui:SimpleStackPanel>
|
||||
|
||||
@@ -1268,9 +1289,9 @@
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,0,0,8">
|
||||
<TextBlock Foreground="#fafafa" Text="显示快捷调色盘" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,8,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchShowQuickColorPalette"
|
||||
IsOn="False" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchShowQuickColorPalette_Toggled" />
|
||||
<CheckBox Name="CheckBoxShowQuickColorPalette"
|
||||
IsChecked="False" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Checked="CheckBoxShowQuickColorPalette_Checked" Unchecked="CheckBoxShowQuickColorPalette_Unchecked" />
|
||||
</ui:SimpleStackPanel>
|
||||
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
@@ -7948,7 +7969,7 @@
|
||||
<Border x:Name="BorderDrawShape" Background="#fafafa" Opacity="1"
|
||||
Visibility="Visible" BorderBrush="#2563eb"
|
||||
BorderThickness="1"
|
||||
CornerRadius="5" Margin="-170,-122,-147,37">
|
||||
CornerRadius="5" Margin="-170,-140,-147,37">
|
||||
<ui:SimpleStackPanel Spacing="0" Orientation="Vertical">
|
||||
<!--<TextBlock FontSize="16" Foreground="{DynamicResource FloatBarForeground}" HorizontalAlignment="Left" Margin="10,8">
|
||||
<Run Text="图形"/>
|
||||
@@ -7973,6 +7994,17 @@
|
||||
</Canvas>
|
||||
</ui:SimpleStackPanel>
|
||||
</Border>
|
||||
<!-- 墨迹渐隐开关 -->
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left"
|
||||
Margin="8,8,8,4" Spacing="8">
|
||||
<TextBlock Foreground="#1e3a8a" Text="墨迹渐隐" FontSize="12"
|
||||
VerticalAlignment="Center" FontWeight="SemiBold" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchInkFadeInPanel"
|
||||
IsOn="False" FontFamily="Microsoft YaHei UI"
|
||||
FontWeight="Bold" Toggled="ToggleSwitchInkFadeInPanel_Toggled" />
|
||||
</ui:SimpleStackPanel>
|
||||
<Line HorizontalAlignment="Center" X1="0" Y1="0" X2="315" Y2="0"
|
||||
Stroke="#e5e7eb" StrokeThickness="1" Margin="8,0,8,4" />
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" Height="38" Spacing="2"
|
||||
Margin="4,6,4,0">
|
||||
<ui:SimpleStackPanel Name="BoardImageDrawLine"
|
||||
|
||||
@@ -45,6 +45,9 @@ namespace Ink_Canvas
|
||||
// 全局快捷键管理器
|
||||
private GlobalHotkeyManager _globalHotkeyManager;
|
||||
|
||||
// 墨迹渐隐管理器
|
||||
private InkFadeManager _inkFadeManager;
|
||||
|
||||
|
||||
|
||||
#region Window Initialization
|
||||
@@ -155,6 +158,9 @@ namespace Ink_Canvas
|
||||
// 初始化墨迹平滑管理器
|
||||
_inkSmoothingManager = new InkSmoothingManager(Dispatcher);
|
||||
|
||||
// 初始化墨迹渐隐管理器
|
||||
_inkFadeManager = new InkFadeManager(this);
|
||||
|
||||
// 注册输入事件
|
||||
inkCanvas.PreviewMouseDown += inkCanvas_PreviewMouseDown;
|
||||
inkCanvas.StylusDown += inkCanvas_StylusDown;
|
||||
@@ -501,6 +507,9 @@ namespace Ink_Canvas
|
||||
|
||||
// 初始化全局快捷键管理器
|
||||
InitializeGlobalHotkeyManager();
|
||||
|
||||
// 初始化墨迹渐隐管理器
|
||||
InitializeInkFadeManager();
|
||||
}
|
||||
|
||||
private void SystemEventsOnDisplaySettingsChanged(object sender, EventArgs e)
|
||||
@@ -637,6 +646,13 @@ namespace Ink_Canvas
|
||||
_globalHotkeyManager = null;
|
||||
}
|
||||
|
||||
// 清理墨迹渐隐管理器
|
||||
if (_inkFadeManager != null)
|
||||
{
|
||||
_inkFadeManager.ClearAllFadingStrokes();
|
||||
_inkFadeManager = null;
|
||||
}
|
||||
|
||||
// 停止置顶维护定时器
|
||||
StopTopmostMaintenance();
|
||||
|
||||
@@ -1967,6 +1983,31 @@ namespace Ink_Canvas
|
||||
#endregion
|
||||
|
||||
#region 全局快捷键管理
|
||||
/// <summary>
|
||||
/// 初始化墨迹渐隐管理器
|
||||
/// </summary>
|
||||
private void InitializeInkFadeManager()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 确保墨迹渐隐管理器已初始化
|
||||
if (_inkFadeManager == null)
|
||||
{
|
||||
_inkFadeManager = new InkFadeManager(this);
|
||||
}
|
||||
|
||||
// 同步设置状态
|
||||
_inkFadeManager.IsEnabled = Settings.Canvas.EnableInkFade;
|
||||
_inkFadeManager.UpdateFadeTime(Settings.Canvas.InkFadeTime);
|
||||
|
||||
LogHelper.WriteLogToFile("墨迹渐隐管理器已初始化", LogHelper.LogType.Event);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"初始化墨迹渐隐管理器时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化全局快捷键管理器
|
||||
/// </summary>
|
||||
@@ -2006,5 +2047,74 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 墨迹渐隐功能
|
||||
/// <summary>
|
||||
/// 墨迹渐隐开关切换事件处理
|
||||
/// </summary>
|
||||
private void ToggleSwitchEnableInkFade_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Settings.Canvas.EnableInkFade = ToggleSwitchEnableInkFade.IsOn;
|
||||
_inkFadeManager.IsEnabled = Settings.Canvas.EnableInkFade;
|
||||
|
||||
// 同步批注子面板中的开关状态
|
||||
if (ToggleSwitchInkFadeInPanel != null)
|
||||
{
|
||||
ToggleSwitchInkFadeInPanel.IsOn = Settings.Canvas.EnableInkFade;
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile($"墨迹渐隐功能已{(Settings.Canvas.EnableInkFade ? "启用" : "禁用")}", LogHelper.LogType.Event);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"切换墨迹渐隐功能时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 墨迹渐隐时间滑块值改变事件处理
|
||||
/// </summary>
|
||||
private void InkFadeTimeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Settings.Canvas.InkFadeTime = (int)e.NewValue;
|
||||
_inkFadeManager.UpdateFadeTime(Settings.Canvas.InkFadeTime);
|
||||
LogHelper.WriteLogToFile($"墨迹渐隐时间已更新为 {Settings.Canvas.InkFadeTime}ms", LogHelper.LogType.Event);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"更新墨迹渐隐时间时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 批注子面板中墨迹渐隐开关切换事件处理
|
||||
/// </summary>
|
||||
private void ToggleSwitchInkFadeInPanel_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Settings.Canvas.EnableInkFade = ToggleSwitchInkFadeInPanel.IsOn;
|
||||
_inkFadeManager.IsEnabled = Settings.Canvas.EnableInkFade;
|
||||
|
||||
// 同步设置面板中的开关状态
|
||||
if (ToggleSwitchEnableInkFade != null)
|
||||
{
|
||||
ToggleSwitchEnableInkFade.IsOn = Settings.Canvas.EnableInkFade;
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile($"批注子面板中墨迹渐隐功能已{(Settings.Canvas.EnableInkFade ? "启用" : "禁用")}", LogHelper.LogType.Event);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"批注子面板中切换墨迹渐隐功能时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2405,74 +2405,146 @@ namespace Ink_Canvas
|
||||
|
||||
#region 浮动栏按钮显示控制
|
||||
|
||||
private void ToggleSwitchShowShapeButton_Toggled(object sender, RoutedEventArgs e)
|
||||
private void CheckBoxShowShapeButton_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowShapeButton = ToggleSwitchShowShapeButton.IsOn;
|
||||
Settings.Appearance.IsShowShapeButton = CheckBoxShowShapeButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void ToggleSwitchShowUndoButton_Toggled(object sender, RoutedEventArgs e)
|
||||
private void CheckBoxShowShapeButton_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowUndoButton = ToggleSwitchShowUndoButton.IsOn;
|
||||
Settings.Appearance.IsShowShapeButton = CheckBoxShowShapeButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void ToggleSwitchShowRedoButton_Toggled(object sender, RoutedEventArgs e)
|
||||
private void CheckBoxShowUndoButton_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowRedoButton = ToggleSwitchShowRedoButton.IsOn;
|
||||
Settings.Appearance.IsShowUndoButton = CheckBoxShowUndoButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void ToggleSwitchShowClearButton_Toggled(object sender, RoutedEventArgs e)
|
||||
private void CheckBoxShowUndoButton_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowClearButton = ToggleSwitchShowClearButton.IsOn;
|
||||
Settings.Appearance.IsShowUndoButton = CheckBoxShowUndoButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void ToggleSwitchShowWhiteboardButton_Toggled(object sender, RoutedEventArgs e)
|
||||
private void CheckBoxShowRedoButton_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowWhiteboardButton = ToggleSwitchShowWhiteboardButton.IsOn;
|
||||
Settings.Appearance.IsShowRedoButton = CheckBoxShowRedoButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void CheckBoxShowRedoButton_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowRedoButton = CheckBoxShowRedoButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void CheckBoxShowClearButton_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowClearButton = CheckBoxShowClearButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void CheckBoxShowClearButton_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowClearButton = CheckBoxShowClearButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void CheckBoxShowWhiteboardButton_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowWhiteboardButton = CheckBoxShowWhiteboardButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void CheckBoxShowWhiteboardButton_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowWhiteboardButton = CheckBoxShowWhiteboardButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void ToggleSwitchShowLassoSelectButton_Toggled(object sender, RoutedEventArgs e)
|
||||
private void CheckBoxShowLassoSelectButton_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowLassoSelectButton = ToggleSwitchShowLassoSelectButton.IsOn;
|
||||
Settings.Appearance.IsShowLassoSelectButton = CheckBoxShowLassoSelectButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void ToggleSwitchShowClearAndMouseButton_Toggled(object sender, RoutedEventArgs e)
|
||||
private void CheckBoxShowLassoSelectButton_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowClearAndMouseButton = ToggleSwitchShowClearAndMouseButton.IsOn;
|
||||
Settings.Appearance.IsShowLassoSelectButton = CheckBoxShowLassoSelectButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void ToggleSwitchShowHideButton_Toggled(object sender, RoutedEventArgs e)
|
||||
private void CheckBoxShowClearAndMouseButton_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowHideButton = ToggleSwitchShowHideButton.IsOn;
|
||||
Settings.Appearance.IsShowClearAndMouseButton = CheckBoxShowClearAndMouseButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void ToggleSwitchShowQuickColorPalette_Toggled(object sender, RoutedEventArgs e)
|
||||
private void CheckBoxShowClearAndMouseButton_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowQuickColorPalette = ToggleSwitchShowQuickColorPalette.IsOn;
|
||||
Settings.Appearance.IsShowClearAndMouseButton = CheckBoxShowClearAndMouseButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void CheckBoxShowHideButton_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowHideButton = CheckBoxShowHideButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void CheckBoxShowHideButton_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowHideButton = CheckBoxShowHideButton.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void CheckBoxShowQuickColorPalette_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowQuickColorPalette = CheckBoxShowQuickColorPalette.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
private void CheckBoxShowQuickColorPalette_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Appearance.IsShowQuickColorPalette = CheckBoxShowQuickColorPalette.IsChecked ?? false;
|
||||
UpdateFloatingBarButtonsVisibility();
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
@@ -307,15 +307,15 @@ namespace Ink_Canvas
|
||||
Settings.Appearance.EnableChickenSoupInWhiteboardMode;
|
||||
|
||||
// 浮动栏按钮显示控制开关初始化
|
||||
ToggleSwitchShowShapeButton.IsOn = Settings.Appearance.IsShowShapeButton;
|
||||
ToggleSwitchShowUndoButton.IsOn = Settings.Appearance.IsShowUndoButton;
|
||||
ToggleSwitchShowRedoButton.IsOn = Settings.Appearance.IsShowRedoButton;
|
||||
ToggleSwitchShowClearButton.IsOn = Settings.Appearance.IsShowClearButton;
|
||||
ToggleSwitchShowWhiteboardButton.IsOn = Settings.Appearance.IsShowWhiteboardButton;
|
||||
ToggleSwitchShowHideButton.IsOn = Settings.Appearance.IsShowHideButton;
|
||||
ToggleSwitchShowQuickColorPalette.IsOn = Settings.Appearance.IsShowQuickColorPalette;
|
||||
ToggleSwitchShowLassoSelectButton.IsOn = Settings.Appearance.IsShowLassoSelectButton;
|
||||
ToggleSwitchShowClearAndMouseButton.IsOn = Settings.Appearance.IsShowClearAndMouseButton;
|
||||
CheckBoxShowShapeButton.IsChecked = Settings.Appearance.IsShowShapeButton;
|
||||
CheckBoxShowUndoButton.IsChecked = Settings.Appearance.IsShowUndoButton;
|
||||
CheckBoxShowRedoButton.IsChecked = Settings.Appearance.IsShowRedoButton;
|
||||
CheckBoxShowClearButton.IsChecked = Settings.Appearance.IsShowClearButton;
|
||||
CheckBoxShowWhiteboardButton.IsChecked = Settings.Appearance.IsShowWhiteboardButton;
|
||||
CheckBoxShowHideButton.IsChecked = Settings.Appearance.IsShowHideButton;
|
||||
CheckBoxShowQuickColorPalette.IsChecked = Settings.Appearance.IsShowQuickColorPalette;
|
||||
CheckBoxShowLassoSelectButton.IsChecked = Settings.Appearance.IsShowLassoSelectButton;
|
||||
CheckBoxShowClearAndMouseButton.IsChecked = Settings.Appearance.IsShowClearAndMouseButton;
|
||||
ComboBoxEraserDisplayOption.SelectedIndex = Settings.Appearance.EraserDisplayOption;
|
||||
ComboBoxQuickColorPaletteDisplayMode.SelectedIndex = Settings.Appearance.QuickColorPaletteDisplayMode;
|
||||
|
||||
@@ -883,6 +883,51 @@ namespace Ink_Canvas
|
||||
{
|
||||
ViewboxFloatingBarMarginAnimation(100, true);
|
||||
}
|
||||
|
||||
// 加载墨迹渐隐设置
|
||||
LoadInkFadeSettings();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载墨迹渐隐设置
|
||||
/// </summary>
|
||||
private void LoadInkFadeSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 同步设置面板中的开关状态
|
||||
if (ToggleSwitchEnableInkFade != null)
|
||||
{
|
||||
ToggleSwitchEnableInkFade.IsOn = Settings.Canvas.EnableInkFade;
|
||||
}
|
||||
|
||||
// 同步批注子面板中的开关状态
|
||||
if (ToggleSwitchInkFadeInPanel != null)
|
||||
{
|
||||
ToggleSwitchInkFadeInPanel.IsOn = Settings.Canvas.EnableInkFade;
|
||||
}
|
||||
|
||||
// 同步滑块值
|
||||
if (InkFadeTimeSlider != null)
|
||||
{
|
||||
InkFadeTimeSlider.Value = Settings.Canvas.InkFadeTime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 同步墨迹渐隐管理器的状态
|
||||
if (_inkFadeManager != null)
|
||||
{
|
||||
_inkFadeManager.IsEnabled = Settings.Canvas.EnableInkFade;
|
||||
_inkFadeManager.UpdateFadeTime(Settings.Canvas.InkFadeTime);
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile("墨迹渐隐设置已加载", LogHelper.LogType.Event);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"加载墨迹渐隐设置时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,36 @@ namespace Ink_Canvas
|
||||
|
||||
private void inkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
|
||||
{
|
||||
// 检查是否启用墨迹渐隐功能
|
||||
if (Settings.Canvas.EnableInkFade)
|
||||
{
|
||||
LogHelper.WriteLogToFile("StrokeCollected: 进入墨迹渐隐模式", LogHelper.LogType.Info);
|
||||
|
||||
// 获取墨迹的起点和终点
|
||||
var startPoint = e.Stroke.StylusPoints.Count > 0 ? e.Stroke.StylusPoints[0].ToPoint() : new Point();
|
||||
var endPoint = e.Stroke.StylusPoints.Count > 0 ? e.Stroke.StylusPoints[e.Stroke.StylusPoints.Count - 1].ToPoint() : new Point();
|
||||
|
||||
// 从InkCanvas中移除墨迹,因为我们要用渐隐管理器来管理它
|
||||
if (inkCanvas.Strokes.Contains(e.Stroke))
|
||||
{
|
||||
inkCanvas.Strokes.Remove(e.Stroke);
|
||||
}
|
||||
|
||||
// 添加到墨迹渐隐管理器
|
||||
if (_inkFadeManager != null)
|
||||
{
|
||||
_inkFadeManager.AddFadingStroke(e.Stroke, startPoint, endPoint);
|
||||
LogHelper.WriteLogToFile($"StrokeCollected: 墨迹已添加到渐隐管理器,起点:{startPoint},终点:{endPoint}", LogHelper.LogType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile("StrokeCollected: 墨迹渐隐管理器为空,无法添加墨迹", LogHelper.LogType.Error);
|
||||
}
|
||||
|
||||
// 墨迹渐隐模式下不参与墨迹纠正和其他处理,直接返回
|
||||
return;
|
||||
}
|
||||
|
||||
// 标记是否进行了直线拉直
|
||||
bool wasStraightened = false;
|
||||
|
||||
|
||||
@@ -139,10 +139,13 @@ namespace Ink_Canvas
|
||||
|
||||
private void MainWindow_StylusDown(object sender, StylusDownEventArgs e)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"MainWindow_StylusDown 被调用,笔尾状态: {e.StylusDevice.Inverted}, 当前 drawingShapeMode: {drawingShapeMode}, 当前 EditingMode: {inkCanvas.EditingMode}", LogHelper.LogType.Info);
|
||||
|
||||
// 新增:根据是否为笔尾自动切换橡皮擦/画笔模式
|
||||
if (e.StylusDevice.Inverted)
|
||||
{
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.EraseByPoint;
|
||||
LogHelper.WriteLogToFile("检测到笔尾,设置 EditingMode 为 EraseByPoint", LogHelper.LogType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -151,12 +154,18 @@ namespace Ink_Canvas
|
||||
{
|
||||
// 确保几何绘制模式下不切换到Ink模式,避免触摸轨迹被收集
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.None;
|
||||
LogHelper.WriteLogToFile("几何绘制模式,设置 EditingMode 为 None", LogHelper.LogType.Info);
|
||||
return;
|
||||
}
|
||||
// 修复:保持当前的线擦模式,不要强制切换到Ink模式
|
||||
if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke)
|
||||
{
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
|
||||
LogHelper.WriteLogToFile("设置 EditingMode 为 Ink", LogHelper.LogType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile("保持当前线擦模式", LogHelper.LogType.Info);
|
||||
}
|
||||
}
|
||||
SetCursorBasedOnEditingMode(inkCanvas);
|
||||
@@ -198,15 +207,25 @@ namespace Ink_Canvas
|
||||
{
|
||||
try
|
||||
{
|
||||
inkCanvas.Strokes.Add(GetStrokeVisual(e.StylusDevice.Id).Stroke);
|
||||
LogHelper.WriteLogToFile($"MainWindow_StylusUp 被调用,EditingMode: {inkCanvas.EditingMode}, EnableInkFade: {Settings.Canvas.EnableInkFade}", LogHelper.LogType.Info);
|
||||
|
||||
var stroke = GetStrokeVisual(e.StylusDevice.Id).Stroke;
|
||||
LogHelper.WriteLogToFile($"获取到墨迹,StylusPoints数量: {stroke.StylusPoints.Count}", LogHelper.LogType.Info);
|
||||
|
||||
// 正常模式:添加到画布并参与墨迹纠正
|
||||
// 墨迹渐隐功能现在在 StrokeCollected 事件中统一处理所有输入方式
|
||||
LogHelper.WriteLogToFile("StylusUp: 添加墨迹到画布", LogHelper.LogType.Info);
|
||||
|
||||
inkCanvas.Strokes.Add(stroke);
|
||||
await Task.Delay(5); // 避免渲染墨迹完成前预览墨迹被删除导致墨迹闪烁
|
||||
inkCanvas.Children.Remove(GetVisualCanvas(e.StylusDevice.Id));
|
||||
|
||||
inkCanvas_StrokeCollected(inkCanvas,
|
||||
new InkCanvasStrokeCollectedEventArgs(GetStrokeVisual(e.StylusDevice.Id).Stroke));
|
||||
new InkCanvasStrokeCollectedEventArgs(stroke));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"MainWindow_StylusUp 出错: {ex}", LogHelper.LogType.Error);
|
||||
Label.Content = ex.ToString();
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,13 @@ namespace Ink_Canvas
|
||||
public bool ClearCanvasAlsoClearImages { get; set; } = true;
|
||||
[JsonProperty("showCircleCenter")]
|
||||
public bool ShowCircleCenter { get; set; } = false;
|
||||
|
||||
// 墨迹渐隐功能设置
|
||||
[JsonProperty("enableInkFade")]
|
||||
public bool EnableInkFade { get; set; } = false; // 是否启用墨迹渐隐功能
|
||||
[JsonProperty("inkFadeTime")]
|
||||
public int InkFadeTime { get; set; } = 3000; // 墨迹渐隐时间(毫秒)
|
||||
|
||||
}
|
||||
|
||||
public enum OptionalOperation
|
||||
|
||||
Reference in New Issue
Block a user