diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 226e5906..a0f875d4 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -12,6 +12,7 @@ on: - patch - minor - major + - build prerelease: description: 'Create as pre-release' required: true @@ -51,7 +52,7 @@ jobs: echo "Found latest tag: $latestTag" } else { # 如果没有tag,使用默认版本 - $version = "1.0.0" + $version = "1.0.0.0" echo "No tags found, using default version" } echo "current_version=$version" >> $env:GITHUB_OUTPUT @@ -63,16 +64,18 @@ jobs: $currentVersion = "${{ steps.get_version.outputs.current_version }}" $versionParts = $currentVersion.Split('.') - # 确保版本号格式正确(至少3部分) + # 确保版本号格式正确(支持4部分) if ($versionParts.Length -ge 3) { $major = [int]$versionParts[0] $minor = [int]$versionParts[1] $patch = [int]$versionParts[2] + $build = [int]$versionParts[3] } else { # 如果版本号格式不正确,使用默认值 $major = 1 $minor = 0 $patch = 0 + $build = 0 } $versionType = "${{ github.event.inputs.version_type }}" @@ -82,18 +85,24 @@ jobs: $major++ $minor = 0 $patch = 0 + $build = 0 } "minor" { $minor++ $patch = 0 + $build = 0 } "patch" { $patch++ + $build = 0 + } + "build" { + $build++ } } - # 生成新版本号(保持3位格式,如1.7.13) - $newVersion = "$major.$minor.$patch" + # 生成新版本号(4位格式,如1.7.18.0) + $newVersion = "$major.$minor.$patch.$build" echo "new_version=$newVersion" >> $env:GITHUB_OUTPUT echo "New version: $newVersion" @@ -150,7 +159,7 @@ jobs: # 生成changelog内容 $version = "${{ steps.calc_version.outputs.new_version }}" - $changelog = "# ICC CE $version.0 更新日志`n`n## 修复 (Fixes)" + $changelog = "# ICC CE $version 更新日志`n`n## 修复 (Fixes)" if ($fixes.Count -gt 0) { foreach ($fix in $fixes) { @@ -236,7 +245,7 @@ jobs: - name: Create Release Archive run: | $version = "${{ steps.calc_version.outputs.new_version }}" - $archiveName = "InkCanvasForClass.CE.$version.0.zip" + $archiveName = "InkCanvasForClass.CE.$version.zip" # 创建发布目录 New-Item -ItemType Directory -Path "release" -Force @@ -254,7 +263,7 @@ jobs: with: name: release-files-${{ steps.calc_version.outputs.new_version }} path: | - InkCanvasForClass.CE.${{ steps.calc_version.outputs.new_version }}.0.zip + InkCanvasForClass.CE.${{ steps.calc_version.outputs.new_version }}.zip CHANGELOG_${{ steps.calc_version.outputs.new_version }}.md - name: Prepare Release Info @@ -265,14 +274,14 @@ jobs: - name: Create GitHub Release uses: softprops/action-gh-release@v1 with: - tag_name: ${{ steps.calc_version.outputs.new_version }}.0 - name: ICC CE ${{ steps.calc_version.outputs.new_version }}.0 + tag_name: ${{ steps.calc_version.outputs.new_version }} + name: ICC CE ${{ steps.calc_version.outputs.new_version }} body: | ${{ steps.changelog.outputs.changelog }} draft: false prerelease: ${{ github.event.inputs.prerelease }} files: | - InkCanvasForClass.CE.${{ steps.calc_version.outputs.new_version }}.0.zip + InkCanvasForClass.CE.${{ steps.calc_version.outputs.new_version }}.zip env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -285,7 +294,7 @@ jobs: $changelogContent = Get-Content $changelogFile -Raw # 生成预览内容 - $previewContent = "ICC CE $version.0 更新日志`n" + $changelogContent + $previewContent = "ICC CE $version 更新日志`n" + $changelogContent echo "UpdateLog preview generated (not written to file):" echo $previewContent diff --git a/Ink Canvas/Helpers/PPTInkManager.cs b/Ink Canvas/Helpers/PPTInkManager.cs index b450aae8..7f60ffce 100644 --- a/Ink Canvas/Helpers/PPTInkManager.cs +++ b/Ink Canvas/Helpers/PPTInkManager.cs @@ -273,7 +273,9 @@ namespace Ink_Canvas.Helpers /// /// 保存所有墨迹到文件 /// - public void SaveAllStrokesToFile(Presentation presentation) + /// 演示文稿对象 + /// 当前播放的页码,如果提供则使用此值保存位置,否则使用_lockedSlideIndex + public void SaveAllStrokesToFile(Presentation presentation, int currentSlideIndex = -1) { if (!IsAutoSaveEnabled || string.IsNullOrEmpty(AutoSaveLocation) || presentation == null) return; @@ -290,7 +292,18 @@ namespace Ink_Canvas.Helpers // 保存位置信息 try { - File.WriteAllText(Path.Combine(folderPath, "Position"), _lockedSlideIndex.ToString()); + // 优先使用传入的当前页码,否则使用锁定的页码 + int positionToSave = currentSlideIndex > 0 ? currentSlideIndex : _lockedSlideIndex; + // 如果都没有有效值,尝试使用最后切换的页码 + if (positionToSave <= 0 && _lastSwitchSlideIndex > 0) + { + positionToSave = _lastSwitchSlideIndex; + } + + if (positionToSave > 0) + { + File.WriteAllText(Path.Combine(folderPath, "Position"), positionToSave.ToString()); + } } catch (Exception ex) { diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml index 3a6ecac9..bec6434a 100644 --- a/Ink Canvas/MainWindow.xaml +++ b/Ink Canvas/MainWindow.xaml @@ -12,7 +12,6 @@ AllowsTransparency="True" WindowStyle="None" ResizeMode="NoResize" - WindowState="Maximized" Loaded="Window_Loaded" Background="Transparent" ShowInTaskbar="False" @@ -605,6 +604,13 @@ IsOn="False" FontFamily="Microsoft YaHei UI" FontWeight="Bold" Toggled="ToggleSwitchNoFocusMode_Toggled" /> + + + + @@ -3214,14 +3220,14 @@ - - + diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs index 13e4676d..8863f794 100644 --- a/Ink Canvas/MainWindow.xaml.cs +++ b/Ink Canvas/MainWindow.xaml.cs @@ -514,6 +514,9 @@ namespace Ink_Canvas // 加载自定义背景颜色 LoadCustomBackgroundColor(); + // 设置窗口模式 + SetWindowMode(); + // 注册设置面板滚动事件 if (SettingsPanelScrollViewer != null) { @@ -769,6 +772,22 @@ namespace Ink_Canvas } } + private void SetWindowMode() + { + if (Settings.Advanced.WindowMode) + { + WindowState = WindowState.Normal; + Left = 0.0; + Top = 0.0; + Height = SystemParameters.PrimaryScreenHeight; + Width = SystemParameters.PrimaryScreenWidth; + } + else // 全屏 + { + WindowState = WindowState.Maximized; + } + } + private void Window_Closing(object sender, CancelEventArgs e) { LogHelper.WriteLogToFile("Ink Canvas closing", LogHelper.LogType.Event); @@ -3003,7 +3022,6 @@ namespace Ink_Canvas else if (!isInSlideShow && IsVisible) { Hide(); - LogHelper.WriteLogToFile("PPT放映结束,隐藏主窗口(仅PPT模式)", LogHelper.LogType.Trace); } } else diff --git a/Ink Canvas/MainWindow_cs/MW_BoardControls.cs b/Ink Canvas/MainWindow_cs/MW_BoardControls.cs index ab338002..681c0d79 100644 --- a/Ink Canvas/MainWindow_cs/MW_BoardControls.cs +++ b/Ink Canvas/MainWindow_cs/MW_BoardControls.cs @@ -206,9 +206,6 @@ namespace Ink_Canvas // 检查是否保存了多指书写模式状态 if (savedMultiTouchModeStates[pageIndex]) { - // 恢复多指书写模式 - EnterMultiTouchModeIfNeeded(); - // 更新UI状态 if (ToggleSwitchEnableMultiTouchMode != null) { @@ -219,9 +216,6 @@ namespace Ink_Canvas } else { - // 确保多指书写模式关闭 - ExitMultiTouchModeIfNeeded(); - // 更新UI状态 if (ToggleSwitchEnableMultiTouchMode != null) { diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs index 1aec6e11..87fa368c 100644 --- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs +++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs @@ -73,80 +73,67 @@ namespace Ink_Canvas /// /// 用於更新浮動工具欄的"手勢"按鈕和白板工具欄的"手勢"按鈕的樣式(開啟和關閉狀態) /// - private void CheckEnableTwoFingerGestureBtnColorPrompt() - { - if (ToggleSwitchEnableMultiTouchMode.IsOn) - { - // 多指书写模式启用时,手势功能被禁用 + private void CheckEnableTwoFingerGestureBtnColorPrompt() { + // 根据主题选择手势图标和颜色 + bool isDarkTheme = Settings.Appearance.Theme == 1 || + (Settings.Appearance.Theme == 2 && !IsSystemThemeLight()); + bool isLightTheme = !isDarkTheme; + string gestureIconPath = isLightTheme ? "/Resources/new-icons/gesture.png" : "/Resources/new-icons/gesture_white.png"; + + // 根据主题设置白板模式下的颜色 + Color boardBgColor, boardIconColor, boardTextColor, boardBorderColor; + if (isLightTheme) { + // 浅色主题 + boardBgColor = Color.FromRgb(244, 244, 245); + boardIconColor = Color.FromRgb(24, 24, 27); + boardTextColor = Color.FromRgb(24, 24, 27); + boardBorderColor = Color.FromRgb(161, 161, 170); + } else { + // 深色主题 + boardBgColor = Color.FromRgb(39, 39, 42); + boardIconColor = Color.FromRgb(244, 244, 245); + boardTextColor = Color.FromRgb(244, 244, 245); + boardBorderColor = Color.FromRgb(113, 113, 122); + } + + if (ToggleSwitchEnableMultiTouchMode.IsOn) { TwoFingerGestureSimpleStackPanel.Opacity = 0.5; TwoFingerGestureSimpleStackPanel.IsHitTestVisible = false; - EnableTwoFingerGestureBtn.Source = (BitmapImage)Application.Current.FindResource("GestureIcon"); - - // 根据主题设置颜色 - if (Settings.Appearance.Theme == 1) // 深色主题 - { - BoardGesture.Background = new SolidColorBrush(Color.FromRgb(42, 42, 42)); - BoardGestureGeometry.Brush = new SolidColorBrush(Color.FromRgb(255, 255, 255)); - BoardGestureGeometry2.Brush = new SolidColorBrush(Color.FromRgb(255, 255, 255)); - BoardGestureLabel.Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255)); - BoardGesture.BorderBrush = new SolidColorBrush(Color.FromRgb(85, 85, 85)); - } - else // 浅色主题或跟随系统 - { - BoardGesture.Background = new SolidColorBrush(Color.FromRgb(244, 244, 245)); - BoardGestureGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27)); - BoardGestureGeometry2.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27)); - BoardGestureLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27)); - BoardGesture.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170)); - } + EnableTwoFingerGestureBtn.Source = + new BitmapImage(new Uri(gestureIconPath, UriKind.Relative)); + + BoardGesture.Background = new SolidColorBrush(boardBgColor); + BoardGestureGeometry.Brush = new SolidColorBrush(boardIconColor); + BoardGestureGeometry2.Brush = new SolidColorBrush(boardIconColor); + BoardGestureLabel.Foreground = new SolidColorBrush(boardTextColor); + BoardGesture.BorderBrush = new SolidColorBrush(boardBorderColor); BoardGestureGeometry.Geometry = Geometry.Parse(XamlGraphicsIconGeometries.DisabledGestureIcon); BoardGestureGeometry2.Geometry = Geometry.Parse("F0 M24,24z M0,0z"); - - // 强制禁用所有双指手势功能 - ForceDisableTwoFingerGestures(); } - else - { - // 多指书写模式禁用时,根据实际手势功能状态显示 + else { TwoFingerGestureSimpleStackPanel.Opacity = 1; TwoFingerGestureSimpleStackPanel.IsHitTestVisible = true; - - // 检查是否有任何手势功能启用 - bool hasGestureEnabled = Settings.Gesture.IsEnableTwoFingerGesture; - - if (hasGestureEnabled) - { - EnableTwoFingerGestureBtn.Source = (BitmapImage)Application.Current.FindResource("GestureIconEnabled"); - + if (Settings.Gesture.IsEnableTwoFingerGesture) { + EnableTwoFingerGestureBtn.Source = + new BitmapImage(new Uri("/Resources/new-icons/gesture-enabled.png", UriKind.Relative)); + BoardGesture.Background = new SolidColorBrush(Color.FromRgb(37, 99, 235)); BoardGestureGeometry.Brush = new SolidColorBrush(Colors.GhostWhite); BoardGestureGeometry2.Brush = new SolidColorBrush(Colors.GhostWhite); BoardGestureLabel.Foreground = new SolidColorBrush(Colors.GhostWhite); BoardGesture.BorderBrush = new SolidColorBrush(Color.FromRgb(37, 99, 235)); BoardGestureGeometry.Geometry = Geometry.Parse(XamlGraphicsIconGeometries.EnabledGestureIcon); - BoardGestureGeometry2.Geometry = Geometry.Parse("F0 M24,24z M0,0z " + XamlGraphicsIconGeometries.EnabledGestureIconBadgeCheck); + BoardGestureGeometry2.Geometry = Geometry.Parse("F0 M24,24z M0,0z "+XamlGraphicsIconGeometries.EnabledGestureIconBadgeCheck); } - else - { - EnableTwoFingerGestureBtn.Source = (BitmapImage)Application.Current.FindResource("GestureIcon"); - - // 根据主题设置颜色 - if (Settings.Appearance.Theme == 1) // 深色主题 - { - BoardGesture.Background = new SolidColorBrush(Color.FromRgb(42, 42, 42)); - BoardGestureGeometry.Brush = new SolidColorBrush(Color.FromRgb(255, 255, 255)); - BoardGestureGeometry2.Brush = new SolidColorBrush(Color.FromRgb(255, 255, 255)); - BoardGestureLabel.Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255)); - BoardGesture.BorderBrush = new SolidColorBrush(Color.FromRgb(85, 85, 85)); - } - else // 浅色主题或跟随系统 - { - BoardGesture.Background = new SolidColorBrush(Color.FromRgb(244, 244, 245)); - BoardGestureGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27)); - BoardGestureGeometry2.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27)); - BoardGestureLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27)); - BoardGesture.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170)); - } + else { + EnableTwoFingerGestureBtn.Source = + new BitmapImage(new Uri(gestureIconPath, UriKind.Relative)); + + BoardGesture.Background = new SolidColorBrush(boardBgColor); + BoardGestureGeometry.Brush = new SolidColorBrush(boardIconColor); + BoardGestureGeometry2.Brush = new SolidColorBrush(boardIconColor); + BoardGestureLabel.Foreground = new SolidColorBrush(boardTextColor); + BoardGesture.BorderBrush = new SolidColorBrush(boardBorderColor); BoardGestureGeometry.Geometry = Geometry.Parse(XamlGraphicsIconGeometries.DisabledGestureIcon); BoardGestureGeometry2.Geometry = Geometry.Parse("F0 M24,24z M0,0z"); } @@ -486,13 +473,23 @@ namespace Ink_Canvas highlightColor = Color.FromRgb(30, 58, 138); // Keep current color for light theme } + bool useLegacyUI = Settings.Appearance.UseLegacyFloatingBarUI; + switch (mode) { case "pen": case "color": { - PenIconGeometry.Brush = new SolidColorBrush(highlightColor); - PenIconGeometry.Geometry = Geometry.Parse(GetCorrectIcon("pen", true)); + if (useLegacyUI) + { + PenIconGeometry.Brush = new SolidColorBrush(highlightColor); + PenIconGeometry.Geometry = Geometry.Parse(GetCorrectIcon("pen", false)); + } + else + { + PenIconGeometry.Brush = new SolidColorBrush(highlightColor); + PenIconGeometry.Geometry = Geometry.Parse(GetCorrectIcon("pen", true)); + } BoardPen.Background = new SolidColorBrush(Color.FromRgb(37, 99, 235)); BoardPen.BorderBrush = new SolidColorBrush(Color.FromRgb(37, 99, 235)); BoardPenGeometry.Brush = new SolidColorBrush(Colors.GhostWhite); @@ -503,9 +500,18 @@ namespace Ink_Canvas } case "eraser": { - CircleEraserIconGeometry.Brush = new SolidColorBrush(highlightColor); - CircleEraserIconGeometry.Geometry = - Geometry.Parse(GetCorrectIcon("eraserCircle", true)); + if (useLegacyUI) + { + CircleEraserIconGeometry.Brush = new SolidColorBrush(highlightColor); + CircleEraserIconGeometry.Geometry = + Geometry.Parse(GetCorrectIcon("eraserCircle", false)); + } + else + { + CircleEraserIconGeometry.Brush = new SolidColorBrush(highlightColor); + CircleEraserIconGeometry.Geometry = + Geometry.Parse(GetCorrectIcon("eraserCircle", true)); + } BoardEraser.Background = new SolidColorBrush(Color.FromRgb(37, 99, 235)); BoardEraser.BorderBrush = new SolidColorBrush(Color.FromRgb(37, 99, 235)); BoardEraserGeometry.Brush = new SolidColorBrush(Colors.GhostWhite); @@ -516,9 +522,18 @@ namespace Ink_Canvas } case "eraserByStrokes": { - StrokeEraserIconGeometry.Brush = new SolidColorBrush(highlightColor); - StrokeEraserIconGeometry.Geometry = - Geometry.Parse(GetCorrectIcon("eraserStroke", true)); + if (useLegacyUI) + { + StrokeEraserIconGeometry.Brush = new SolidColorBrush(highlightColor); + StrokeEraserIconGeometry.Geometry = + Geometry.Parse(GetCorrectIcon("eraserStroke", false)); + } + else + { + StrokeEraserIconGeometry.Brush = new SolidColorBrush(highlightColor); + StrokeEraserIconGeometry.Geometry = + Geometry.Parse(GetCorrectIcon("eraserStroke", true)); + } BoardEraser.Background = new SolidColorBrush(Color.FromRgb(37, 99, 235)); BoardEraser.BorderBrush = new SolidColorBrush(Color.FromRgb(37, 99, 235)); BoardEraserGeometry.Brush = new SolidColorBrush(Colors.GhostWhite); @@ -529,9 +544,18 @@ namespace Ink_Canvas } case "select": { - LassoSelectIconGeometry.Brush = new SolidColorBrush(highlightColor); - LassoSelectIconGeometry.Geometry = - Geometry.Parse(GetCorrectIcon("lassoSelect", true)); + if (useLegacyUI) + { + LassoSelectIconGeometry.Brush = new SolidColorBrush(highlightColor); + LassoSelectIconGeometry.Geometry = + Geometry.Parse(GetCorrectIcon("lassoSelect", false)); + } + else + { + LassoSelectIconGeometry.Brush = new SolidColorBrush(highlightColor); + LassoSelectIconGeometry.Geometry = + Geometry.Parse(GetCorrectIcon("lassoSelect", true)); + } BoardSelect.Background = new SolidColorBrush(Color.FromRgb(37, 99, 235)); BoardSelect.BorderBrush = new SolidColorBrush(Color.FromRgb(37, 99, 235)); BoardSelectGeometry.Brush = new SolidColorBrush(Colors.GhostWhite); @@ -542,9 +566,18 @@ namespace Ink_Canvas } case "cursor": { - CursorIconGeometry.Brush = new SolidColorBrush(highlightColor); - CursorIconGeometry.Geometry = - Geometry.Parse(GetCorrectIcon("cursor", true)); + if (useLegacyUI) + { + CursorIconGeometry.Brush = new SolidColorBrush(highlightColor); + CursorIconGeometry.Geometry = + Geometry.Parse(GetCorrectIcon("cursor", false)); + } + else + { + CursorIconGeometry.Brush = new SolidColorBrush(highlightColor); + CursorIconGeometry.Geometry = + Geometry.Parse(GetCorrectIcon("cursor", true)); + } // 根据主题设置颜色 if (Settings.Appearance.Theme == 1) // 深色主题 { @@ -1055,6 +1088,8 @@ namespace Ink_Canvas { if (TimerContainer != null && TimerControl != null) { + // 每次打开计时器窗口时重置计时器 + TimerControl.ResetTimerState(); TimerContainer.Visibility = Visibility.Visible; if (MinimizedTimerContainer != null) { @@ -1823,7 +1858,7 @@ namespace Ink_Canvas }); } - public async void PureViewboxFloatingBarMarginAnimationInPPTMode() + public async void PureViewboxFloatingBarMarginAnimationInPPTMode(bool isRetry = false) { // 新增:在白板模式下不执行浮动栏动画 if (currentMode == 1) @@ -1919,6 +1954,25 @@ namespace Ink_Canvas { ViewboxFloatingBar.Margin = new Thickness(pos.X, pos.Y, -2000, -200); }); + + if (Settings.ModeSettings.IsPPTOnlyMode && !isRetry) + { + await Task.Delay(2000); // 等待动画完成后再检查 + + bool isFloatingBarVisible = false; + await Dispatcher.InvokeAsync(() => + { + // 检查浮动栏是否真的显示了 + isFloatingBarVisible = ViewboxFloatingBar.Visibility == Visibility.Visible && + ViewboxFloatingBar.Margin.Left >= 0 && + ViewboxFloatingBar.Margin.Top >= 0; + }); + + if (!isFloatingBarVisible) + { + PureViewboxFloatingBarMarginAnimationInPPTMode(true); + } + } } internal async void CursorIcon_Click(object sender, RoutedEventArgs e) @@ -2062,7 +2116,6 @@ namespace Ink_Canvas { drawingShapeMode = 0; isLongPressSelected = false; - ResetAllShapeButtonsOpacity(); } // 使用集中化的工具模式切换方法 @@ -2270,7 +2323,6 @@ namespace Ink_Canvas internal void EraserIcon_Click(object sender, RoutedEventArgs e) { - EnterMultiTouchModeIfNeeded(); bool isAlreadyEraser = inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint; forceEraser = false; forcePointEraser = true; @@ -2322,7 +2374,6 @@ namespace Ink_Canvas private void BoardEraserIcon_Click(object sender, RoutedEventArgs e) { - EnterMultiTouchModeIfNeeded(); bool isAlreadyEraser = inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint; forceEraser = false; forcePointEraser = true; @@ -2361,7 +2412,6 @@ namespace Ink_Canvas private void EraserIconByStrokes_Click(object sender, RoutedEventArgs e) { - EnterMultiTouchModeIfNeeded(); if (lastBorderMouseDownObject != null && lastBorderMouseDownObject is Panel) ((Panel)lastBorderMouseDownObject).Background = new SolidColorBrush(Colors.Transparent); @@ -2914,12 +2964,6 @@ namespace Ink_Canvas // 清空触摸点计数器 dec.Clear(); - // 重置手掌擦状态 - if (isPalmEraserActive) - { - isPalmEraserActive = false; - } - // 确保触摸事件能正常响应 inkCanvas.IsHitTestVisible = true; inkCanvas.IsManipulationEnabled = true; @@ -3017,10 +3061,26 @@ namespace Ink_Canvas ClearStrokes(true); RestoreStrokes(true); - // 新增:在屏幕模式下恢复基础浮动栏的显示 + // 退出白板模式时取消全屏 + if (Settings.Advanced.IsEnableAvoidFullScreenHelper) + { + // 恢复为非画板模式,重新启用全屏限制 + AvoidFullScreenHelper.SetBoardMode(false); + + Dispatcher.BeginInvoke(new Action(() => + { + // 退出白板模式,恢复到工作区域大小 + var workingArea = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea; + MainWindow.MoveWindow(new WindowInteropHelper(this).Handle, + workingArea.Left, workingArea.Top, + workingArea.Width, workingArea.Height, true); + }), DispatcherPriority.ApplicationIdle); + } + + // 在屏幕模式下恢复基础浮动栏的显示 ViewboxFloatingBar.Visibility = Visibility.Visible; - // 新增:退出白板时自动收纳功能 - 等待浮动栏完全展开后再收纳 + // 退出白板时自动收纳功能 - 等待浮动栏完全展开后再收纳 if (Settings.Automation.IsAutoFoldWhenExitWhiteboard && !isFloatingBarFolded) { // 使用异步延迟,等待浮动栏展开动画完成后再收纳 @@ -3029,7 +3089,10 @@ namespace Ink_Canvas await Task.Delay(700); await Dispatcher.InvokeAsync(() => { - FoldFloatingBar_MouseUp(new object(), null); + if (_pptManager?.IsInSlideShow != true) + { + FoldFloatingBar_MouseUp(new object(), null); + } }); }); } @@ -3070,6 +3133,19 @@ namespace Ink_Canvas RestoreStrokes(); + // 进入白板模式时全屏 + if (Settings.Advanced.IsEnableAvoidFullScreenHelper) + { + // 设置为画板模式,允许全屏操作 + AvoidFullScreenHelper.SetBoardMode(true); + Dispatcher.BeginInvoke(new Action(() => + { + MainWindow.MoveWindow(new WindowInteropHelper(this).Handle, 0, 0, + System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width, + System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height, true); + }), DispatcherPriority.ApplicationIdle); + } + ViewboxFloatingBar.Visibility = Visibility.Collapsed; BtnSwitch.Content = "屏幕"; diff --git a/Ink Canvas/MainWindow_cs/MW_PPT.cs b/Ink Canvas/MainWindow_cs/MW_PPT.cs index 2906d5b1..8fdc8413 100644 --- a/Ink Canvas/MainWindow_cs/MW_PPT.cs +++ b/Ink Canvas/MainWindow_cs/MW_PPT.cs @@ -77,7 +77,6 @@ namespace Ink_Canvas #endregion #region PPT State Management - private bool wasFloatingBarFoldedWhenEnterSlideShow; private bool isEnteredSlideShowEndEvent; private bool isPresentationHaveBlackSpace; @@ -94,12 +93,16 @@ namespace Ink_Canvas // 上次播放位置相关字段 private int _lastPlaybackPage = 0; private bool _shouldNavigateToLastPage = false; + + // 当前播放页码跟踪 + private int _currentSlideShowPosition = 0; // 页面切换防抖机制 private DateTime _lastSlideSwitchTime = DateTime.MinValue; private int _pendingSlideIndex = -1; private System.Timers.Timer _slideSwitchDebounceTimer; - private const int SlideSwitchDebounceMs = 150; // 防抖延迟150毫秒 + private const int SlideSwitchDebounceMs = 150; + private bool _isInkClearedByButton = false; #endregion #region PPT Managers @@ -612,9 +615,6 @@ namespace Ink_Canvas { try { - // 始终记录进入放映时浮动栏收纳状态,用于退出时恢复 - wasFloatingBarFoldedWhenEnterSlideShow = isFloatingBarFolded; - if (Settings.Automation.IsAutoFoldInPPTSlideShow) { if (!isFloatingBarFolded) @@ -641,12 +641,16 @@ namespace Ink_Canvas activePresentation = wn.Presentation; currentSlide = wn.View.CurrentShowPosition; totalSlides = activePresentation.Slides.Count; + // 初始化当前播放页码跟踪 + _currentSlideShowPosition = currentSlide; } else { activePresentation = _pptManager?.GetCurrentActivePresentation(); currentSlide = _pptManager?.GetCurrentSlideNumber() ?? 0; totalSlides = _pptManager?.SlidesCount ?? 0; + // 初始化当前播放页码跟踪 + _currentSlideShowPosition = currentSlide; } if (activePresentation != null) @@ -765,19 +769,50 @@ namespace Ink_Canvas if (!isFloatingBarFolded) { - new Thread(() => + _ = Task.Run(async () => { - Thread.Sleep(100); - Application.Current.Dispatcher.Invoke(() => + try { - ViewboxFloatingBarMarginAnimation(60); - }); - }).Start(); + await Task.Delay(100); + + await Application.Current.Dispatcher.InvokeAsync(() => + { + ViewboxFloatingBar.UpdateLayout(); + + // 如果浮动栏宽度仍未计算好,再等待一段时间 + if (ViewboxFloatingBar.ActualWidth <= 0) + { + LogHelper.WriteLogToFile("浮动栏宽度未准备好,等待布局完成", LogHelper.LogType.Trace); + } + }); + + await Task.Delay(100); + + await Application.Current.Dispatcher.InvokeAsync(() => + { + PureViewboxFloatingBarMarginAnimationInPPTMode(false); + }); + } + catch (Exception) + { + + try + { + await Task.Delay(100); + await Application.Current.Dispatcher.InvokeAsync(() => + { + ViewboxFloatingBarMarginAnimation(60); + }); + } + catch (Exception) + { + } + } + }); } } - catch (Exception ex) + catch (Exception) { - LogHelper.WriteLogToFile($"处理幻灯片放映开始事件失败: {ex}", LogHelper.LogType.Error); } } @@ -785,7 +820,7 @@ namespace Ink_Canvas { try { - Application.Current.Dispatcher.InvokeAsync(() => + Application.Current.Dispatcher.Invoke(() => { if (wn?.View == null || wn.Presentation == null) { @@ -796,8 +831,58 @@ namespace Ink_Canvas var activePresentation = wn.Presentation; var totalSlides = activePresentation.Slides.Count; - // 使用防抖机制处理页面切换 - HandleSlideSwitchWithDebounce(currentSlide, totalSlides); + // 获取之前的页码(用于保存墨迹) + var previousSlide = _currentSlideShowPosition > 0 ? _currentSlideShowPosition : + (_pptManager?.GetCurrentSlideNumber() ?? 0); + + if (_isInkClearedByButton) + { + _isInkClearedByButton = false; + } + else + { + StrokeCollection strokesToSave = null; + if (previousSlide > 0 && previousSlide != currentSlide && inkCanvas.Strokes.Count > 0) + { + strokesToSave = inkCanvas.Strokes.Clone(); + } + + // 清除墨迹 + if (inkCanvas.Strokes.Count > 0) + { + ClearStrokes(true); + timeMachine.ClearStrokeHistory(); + } + + // 异步保存之前页面的墨迹 + if (strokesToSave != null && previousSlide > 0 && previousSlide != currentSlide) + { + Task.Run(() => + { + try + { + Application.Current.Dispatcher.Invoke(() => + { + bool canWrite = _singlePPTInkManager?.CanWriteInk(previousSlide) == true; + if (canWrite) + { + _singlePPTInkManager?.SaveCurrentSlideStrokes(previousSlide, strokesToSave); + } + }); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"异步保存PPT页面墨迹失败: {ex}", LogHelper.LogType.Error); + } + }); + } + } + + // 更新当前播放页码 + _currentSlideShowPosition = currentSlide; + + LoadCurrentSlideInk(currentSlide, skipClear: true); + _pptUIManager?.UpdateCurrentSlideNumber(currentSlide, totalSlides); }); } @@ -811,39 +896,39 @@ namespace Ink_Canvas { try { - if (Settings.Automation.IsAutoFoldAfterPPTSlideShow) + // PPT退出时自动收纳浮动栏 + if (!isFloatingBarFolded) { - if (wasFloatingBarFoldedWhenEnterSlideShow) - { - if (!isFloatingBarFolded) FoldFloatingBar_MouseUp(new object(), null); - } - else - { - if (isFloatingBarFolded) await UnFoldFloatingBar(new object()); - } - } - else - { - if (Settings.Automation.IsAutoFoldInPPTSlideShow) - { - if (isFloatingBarFolded) - { - await UnFoldFloatingBar(new object()); - } - } - else - { - if (isFloatingBarFolded) - { - await UnFoldFloatingBar(new object()); - } - } + FoldFloatingBar_MouseUp(new object(), null); } if (isEnteredSlideShowEndEvent) return; isEnteredSlideShowEndEvent = true; - _singlePPTInkManager?.SaveAllStrokesToFile(pres); + // 获取当前播放页码,优先使用跟踪的页码,否则尝试从PPT管理器获取 + int currentPage = _currentSlideShowPosition; + if (currentPage <= 0) + { + try + { + currentPage = _pptManager?.GetCurrentSlideNumber() ?? 0; + } + catch + { + // 如果无法获取,尝试从演示文稿的SlideShowWindow获取 + try + { + if (pres.SlideShowWindow != null && pres.SlideShowWindow.View != null) + { + currentPage = pres.SlideShowWindow.View.CurrentShowPosition; + } + } + catch { } + } + } + + // 保存墨迹和位置信息 + _singlePPTInkManager?.SaveAllStrokesToFile(pres, currentPage); await Application.Current.Dispatcher.InvokeAsync(() => { @@ -917,7 +1002,7 @@ namespace Ink_Canvas await Application.Current.Dispatcher.InvokeAsync(() => { PureViewboxFloatingBarMarginAnimationInDesktopMode(); - ViewboxFloatingBarMarginAnimation(100, true); + ViewboxFloatingBarMarginAnimation(-60); }); } catch (Exception ex) @@ -1098,13 +1183,16 @@ namespace Ink_Canvas } } - private void LoadCurrentSlideInk(int slideIndex) + private void LoadCurrentSlideInk(int slideIndex, bool skipClear = false) { try { - ClearStrokes(true); - timeMachine.ClearStrokeHistory(); - + // 如果未跳过清除,则清除当前墨迹 + if (!skipClear) + { + ClearStrokes(true); + timeMachine.ClearStrokeHistory(); + } StrokeCollection strokes = _singlePPTInkManager?.LoadSlideStrokes(slideIndex); if (strokes != null && strokes.Count > 0) @@ -1140,9 +1228,6 @@ namespace Ink_Canvas { try { - // 重置进入PPT时的浮动栏收纳状态记录 - wasFloatingBarFoldedWhenEnterSlideShow = false; - // 重置PPT放映结束事件标志 isEnteredSlideShowEndEvent = false; @@ -1152,6 +1237,9 @@ namespace Ink_Canvas // 重置上次播放位置相关字段 _lastPlaybackPage = 0; _shouldNavigateToLastPage = false; + + // 重置当前播放页码跟踪 + _currentSlideShowPosition = 0; // 重置页面切换防抖机制 _lastSlideSwitchTime = DateTime.MinValue; @@ -1170,51 +1258,14 @@ namespace Ink_Canvas /// private void HandleSlideSwitchWithDebounce(int currentSlide, int totalSlides) { - try - { - var now = DateTime.Now; - - // 如果距离上次切换时间太短,使用防抖机制 - if (now - _lastSlideSwitchTime < TimeSpan.FromMilliseconds(SlideSwitchDebounceMs)) - { - _pendingSlideIndex = currentSlide; - - // 停止之前的定时器 - _slideSwitchDebounceTimer?.Stop(); - - // 创建新的定时器 - _slideSwitchDebounceTimer = new System.Timers.Timer(SlideSwitchDebounceMs); - _slideSwitchDebounceTimer.Elapsed += (sender, e) => - { - Application.Current.Dispatcher.Invoke(() => - { - if (_pendingSlideIndex > 0) - { - SwitchSlideInk(_pendingSlideIndex); - _pptUIManager?.UpdateCurrentSlideNumber(_pendingSlideIndex, totalSlides); - _pendingSlideIndex = -1; - } - }); - _slideSwitchDebounceTimer?.Stop(); - }; - _slideSwitchDebounceTimer.Start(); - } - else - { - // 直接处理页面切换 - SwitchSlideInk(currentSlide); - _pptUIManager?.UpdateCurrentSlideNumber(currentSlide, totalSlides); - } - - _lastSlideSwitchTime = now; - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"处理页面切换防抖失败: {ex}", LogHelper.LogType.Error); - } } - private void SwitchSlideInk(int newSlideIndex) + /// + /// 切换页面墨迹 + /// + /// 新页面索引 + /// 是否跳过清除操作(如果已在翻页时立即清除,则设为true) + private void SwitchSlideInk(int newSlideIndex, bool skipClear = false) { try { @@ -1235,18 +1286,23 @@ namespace Ink_Canvas } // 如果有当前墨迹且不是第一次切换,先保存到当前页面 - if (inkCanvas.Strokes.Count > 0 && currentSlideIndex > 0 && currentSlideIndex != newSlideIndex) + if (currentSlideIndex > 0 && currentSlideIndex != newSlideIndex) { bool canWrite = _singlePPTInkManager?.CanWriteInk(currentSlideIndex) == true; - - if (canWrite) + + if (canWrite && inkCanvas.Strokes.Count > 0) { _singlePPTInkManager?.SaveCurrentSlideStrokes(currentSlideIndex, inkCanvas.Strokes); } } - ClearStrokes(true); - timeMachine.ClearStrokeHistory(); + if (!skipClear) + { + ClearStrokes(true); + timeMachine.ClearStrokeHistory(); + } + + // 加载新页面的墨迹 StrokeCollection newStrokes = _singlePPTInkManager?.SwitchToSlide(newSlideIndex, null); if (newStrokes != null && newStrokes.Count > 0) @@ -1383,25 +1439,72 @@ namespace Ink_Canvas { try { - // 保存当前页墨迹 - var currentSlide = _pptManager?.GetCurrentSlideNumber() ?? 0; - if (currentSlide > 0) + var previousSlideBeforeNavigate = _pptManager?.GetCurrentSlideNumber() ?? 0; + + StrokeCollection strokesToSave = null; + if (previousSlideBeforeNavigate > 0 && inkCanvas.Strokes.Count > 0) { - _singlePPTInkManager?.SaveCurrentSlideStrokes(currentSlide, inkCanvas.Strokes); + strokesToSave = inkCanvas.Strokes.Clone(); } - // 保存截图(如果启用) - if (inkCanvas.Strokes.Count > Settings.Automation.MinimumAutomationStrokeNumber && - Settings.PowerPointSettings.IsAutoSaveScreenShotInPowerPoint) - { - var presentationName = _pptManager?.GetPresentationName() ?? ""; - SaveScreenShot(true, $"{presentationName}/{currentSlide}"); - } - - // 执行翻页 if (_pptManager?.TryNavigatePrevious() == true) { - // 翻页成功,等待事件处理墨迹切换 + var currentSlideAfterNavigate = _pptManager?.GetCurrentSlideNumber() ?? 0; + + if (previousSlideBeforeNavigate == currentSlideAfterNavigate && previousSlideBeforeNavigate > 0) + { + Thread.Sleep(50); + currentSlideAfterNavigate = _pptManager?.GetCurrentSlideNumber() ?? 0; + } + + if (previousSlideBeforeNavigate != currentSlideAfterNavigate && previousSlideBeforeNavigate > 0) + { + if (inkCanvas.Strokes.Count > 0) + { + ClearStrokes(true); + timeMachine.ClearStrokeHistory(); + _isInkClearedByButton = true; + } + + if (strokesToSave != null && previousSlideBeforeNavigate > 0) + { + Task.Run(() => + { + try + { + Application.Current.Dispatcher.Invoke(() => + { + _singlePPTInkManager?.SaveCurrentSlideStrokes(previousSlideBeforeNavigate, strokesToSave); + }); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"异步保存PPT上一页墨迹失败: {ex}", LogHelper.LogType.Error); + } + }); + + // 异步保存截图(如果启用) + if (strokesToSave.Count > Settings.Automation.MinimumAutomationStrokeNumber && + Settings.PowerPointSettings.IsAutoSaveScreenShotInPowerPoint) + { + Task.Run(() => + { + try + { + Application.Current.Dispatcher.Invoke(() => + { + var presentationName = _pptManager?.GetPresentationName() ?? ""; + SaveScreenShot(true, $"{presentationName}/{previousSlideBeforeNavigate}"); + }); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"异步保存PPT上一页截图失败: {ex}", LogHelper.LogType.Error); + } + }); + } + } + } } else { @@ -1423,25 +1526,72 @@ namespace Ink_Canvas { try { - // 保存当前页墨迹 - var currentSlide = _pptManager?.GetCurrentSlideNumber() ?? 0; - if (currentSlide > 0) + var previousSlideBeforeNavigate = _pptManager?.GetCurrentSlideNumber() ?? 0; + + StrokeCollection strokesToSave = null; + if (previousSlideBeforeNavigate > 0 && inkCanvas.Strokes.Count > 0) { - _singlePPTInkManager?.SaveCurrentSlideStrokes(currentSlide, inkCanvas.Strokes); + strokesToSave = inkCanvas.Strokes.Clone(); } - // 保存截图(如果启用) - if (inkCanvas.Strokes.Count > Settings.Automation.MinimumAutomationStrokeNumber && - Settings.PowerPointSettings.IsAutoSaveScreenShotInPowerPoint) - { - var presentationName = _pptManager?.GetPresentationName() ?? ""; - SaveScreenShot(true, $"{presentationName}/{currentSlide}"); - } - - // 执行翻页 if (_pptManager?.TryNavigateNext() == true) { - // 翻页成功,等待事件处理墨迹切换 + var currentSlideAfterNavigate = _pptManager?.GetCurrentSlideNumber() ?? 0; + + if (previousSlideBeforeNavigate == currentSlideAfterNavigate && previousSlideBeforeNavigate > 0) + { + Thread.Sleep(50); + currentSlideAfterNavigate = _pptManager?.GetCurrentSlideNumber() ?? 0; + } + + if (previousSlideBeforeNavigate != currentSlideAfterNavigate && previousSlideBeforeNavigate > 0) + { + if (inkCanvas.Strokes.Count > 0) + { + ClearStrokes(true); + timeMachine.ClearStrokeHistory(); + _isInkClearedByButton = true; + } + + if (strokesToSave != null && previousSlideBeforeNavigate > 0) + { + Task.Run(() => + { + try + { + Application.Current.Dispatcher.Invoke(() => + { + _singlePPTInkManager?.SaveCurrentSlideStrokes(previousSlideBeforeNavigate, strokesToSave); + }); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"异步保存PPT下一页墨迹失败: {ex}", LogHelper.LogType.Error); + } + }); + + // 异步保存截图(如果启用) + if (strokesToSave.Count > Settings.Automation.MinimumAutomationStrokeNumber && + Settings.PowerPointSettings.IsAutoSaveScreenShotInPowerPoint) + { + Task.Run(() => + { + try + { + Application.Current.Dispatcher.Invoke(() => + { + var presentationName = _pptManager?.GetPresentationName() ?? ""; + SaveScreenShot(true, $"{presentationName}/{previousSlideBeforeNavigate}"); + }); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"异步保存PPT下一页截图失败: {ex}", LogHelper.LogType.Error); + } + }); + } + } + } } else { @@ -1609,7 +1759,7 @@ namespace Ink_Canvas LogHelper.WriteLogToFile("手动更新放映结束UI状态", LogHelper.LogType.Trace); }); - // 手动处理收纳状态恢复,因为OnPPTSlideShowEnd事件可能未触发 + // 手动处理自动收纳,因为OnPPTSlideShowEnd事件可能未触发 await HandleManualSlideShowEnd(); } @@ -1617,28 +1767,8 @@ namespace Ink_Canvas SetCurrentToolMode(InkCanvasEditingMode.None); await Task.Delay(150); - if (Settings.Automation.IsAutoFoldAfterPPTSlideShow) - { - if (wasFloatingBarFoldedWhenEnterSlideShow) - { - ViewboxFloatingBarMarginAnimation(-60); - } - else - { - ViewboxFloatingBarMarginAnimation(100, true); - } - } - else - { - if (isFloatingBarFolded) - { - ViewboxFloatingBarMarginAnimation(-60); - } - else - { - ViewboxFloatingBarMarginAnimation(100, true); - } - } + // PPT退出时自动收纳,使用收纳状态的边距动画 + ViewboxFloatingBarMarginAnimation(-60); } catch (Exception ex) { @@ -1651,76 +1781,31 @@ namespace Ink_Canvas _pptUIManager?.UpdateSidebarExitButtons(false); }); - // 异常情况下也手动处理收纳状态恢复 + // 异常情况下也手动处理自动收纳 await HandleManualSlideShowEnd(); - // 异常情况下也要根据设置决定浮动栏边距 + // 异常情况下也要自动收纳,使用收纳状态的边距动画 await Task.Delay(150); - if (Settings.Automation.IsAutoFoldAfterPPTSlideShow) - { - if (wasFloatingBarFoldedWhenEnterSlideShow) - { - ViewboxFloatingBarMarginAnimation(-60); - } - else - { - ViewboxFloatingBarMarginAnimation(100, true); - } - } - else - { - if (isFloatingBarFolded) - { - ViewboxFloatingBarMarginAnimation(-60); - } - else - { - ViewboxFloatingBarMarginAnimation(100, true); - } - } + ViewboxFloatingBarMarginAnimation(-60); } } /// - /// 手动处理PPT放映结束时的收纳状态恢复 + /// 手动处理PPT放映结束时的自动收纳 /// private async Task HandleManualSlideShowEnd() { try { - if (Settings.Automation.IsAutoFoldAfterPPTSlideShow) + // PPT退出时自动收纳浮动栏 + if (!isFloatingBarFolded) { - if (wasFloatingBarFoldedWhenEnterSlideShow) - { - if (!isFloatingBarFolded) FoldFloatingBar_MouseUp(new object(), null); - } - else - { - if (isFloatingBarFolded) await UnFoldFloatingBar(new object()); - } - } - else - { - if (Settings.Automation.IsAutoFoldInPPTSlideShow) - { - if (isFloatingBarFolded) - { - await UnFoldFloatingBar(new object()); - } - } - else - { - // 如果两个功能都关闭,确保浮动栏展开 - if (isFloatingBarFolded) - { - await UnFoldFloatingBar(new object()); - } - } + FoldFloatingBar_MouseUp(new object(), null); } } catch (Exception ex) { - LogHelper.WriteLogToFile($"手动处理PPT放映结束收纳状态恢复失败: {ex}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"手动处理PPT放映结束自动收纳失败: {ex}", LogHelper.LogType.Error); } } diff --git a/Ink Canvas/MainWindow_cs/MW_SelectionGestures.cs b/Ink Canvas/MainWindow_cs/MW_SelectionGestures.cs index 892527ad..df0121e2 100644 --- a/Ink Canvas/MainWindow_cs/MW_SelectionGestures.cs +++ b/Ink Canvas/MainWindow_cs/MW_SelectionGestures.cs @@ -354,7 +354,6 @@ namespace Ink_Canvas private void BtnSelect_Click(object sender, RoutedEventArgs e) { - ExitMultiTouchModeIfNeeded(); forceEraser = true; drawingShapeMode = 0; inkCanvas.IsManipulationEnabled = false; @@ -709,7 +708,6 @@ namespace Ink_Canvas private void LassoSelect_Click(object sender, RoutedEventArgs e) { - ExitMultiTouchModeIfNeeded(); forceEraser = false; forcePointEraser = false; drawingShapeMode = 0; @@ -720,7 +718,6 @@ namespace Ink_Canvas private void BtnLassoSelect_Click(object sender, RoutedEventArgs e) { - ExitMultiTouchModeIfNeeded(); forceEraser = false; forcePointEraser = false; drawingShapeMode = 0; diff --git a/Ink Canvas/MainWindow_cs/MW_Settings.cs b/Ink Canvas/MainWindow_cs/MW_Settings.cs index 0c29fcfe..033d48f3 100644 --- a/Ink Canvas/MainWindow_cs/MW_Settings.cs +++ b/Ink Canvas/MainWindow_cs/MW_Settings.cs @@ -2532,6 +2532,14 @@ namespace Ink_Canvas SaveSettingsToFile(); } + private void ToggleSwitchWindowMode_Toggled(object sender, RoutedEventArgs e) + { + if (!isLoaded) return; + Settings.Advanced.WindowMode = ToggleSwitchWindowMode.IsOn; + SaveSettingsToFile(); + SetWindowMode(); + } + private void ToggleSwitchIsAutoBackupBeforeUpdate_Toggled(object sender, RoutedEventArgs e) { if (!isLoaded) return; diff --git a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs index bde4b36b..76c46951 100644 --- a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs +++ b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs @@ -795,6 +795,7 @@ namespace Ink_Canvas ToggleSwitchIsLogEnabled.IsOn = Settings.Advanced.IsLogEnabled; ToggleSwitchIsSaveLogByDate.IsOn = Settings.Advanced.IsSaveLogByDate; ToggleSwitchIsSecondConfimeWhenShutdownApp.IsOn = Settings.Advanced.IsSecondConfirmWhenShutdownApp; + ToggleSwitchWindowMode.IsOn = Settings.Advanced.WindowMode; ToggleSwitchIsSpecialScreen.IsOn = Settings.Advanced.IsSpecialScreen; ToggleSwitchIsQuadIR.IsOn = Settings.Advanced.IsQuadIR; ToggleSwitchEraserBindTouchMultiplier.IsOn = Settings.Advanced.EraserBindTouchMultiplier; diff --git a/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs b/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs index 17d1511a..f8869cf3 100644 --- a/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs +++ b/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs @@ -117,436 +117,355 @@ namespace Ink_Canvas } } - private void BtnPen_Click(object sender, RoutedEventArgs e) - { - // 如果当前有选中的图片元素,先取消选中 - if (currentSelectedElement != null) - { - UnselectElement(currentSelectedElement); - currentSelectedElement = null; - } - - // 禁用高级橡皮擦系统 - DisableEraserOverlay(); - ExitMultiTouchModeIfNeeded(); - - // 如果当前已是批注模式,再次点击弹出批注子面板 - if (penType == 0 && inkCanvas.EditingMode == InkCanvasEditingMode.Ink && !drawingAttributes.IsHighlighter) - { - return; - } - // 否则只切换到批注模式,不弹出子面板 + private void BtnPen_Click(object sender, RoutedEventArgs e) { forceEraser = false; - forcePointEraser = false; drawingShapeMode = 0; - penType = 0; - drawingAttributes.IsHighlighter = false; - drawingAttributes.StylusTip = StylusTip.Ellipse; - // 禁止几何绘制模式下切换到Ink - if (drawingShapeMode != 0) - { - return; - } inkCanvas.EditingMode = InkCanvasEditingMode.Ink; - - - // 更新lastInkCanvasEditingMode以确保多指手势逻辑正确 - lastInkCanvasEditingMode = InkCanvasEditingMode.Ink; - - ResetAllShapeButtonsOpacity(); - - SetCursorBasedOnEditingMode(inkCanvas); + inkCanvas.IsManipulationEnabled = true; + CancelSingleFingerDragMode(); + isLongPressSelected = false; } - private Task CheckIsDrawingShapesInMultiTouchMode() - { - if (isInMultiTouchMode) - { - // 不关闭多指书写模式,而是保存状态,暂时禁用多指书写相关的事件处理 - // 不再调用 ToggleSwitchEnableMultiTouchMode.IsOn = false; - - // 暂时禁用多指书写事件处理,以避免冲突 - inkCanvas.StylusDown -= MainWindow_StylusDown; - inkCanvas.StylusMove -= MainWindow_StylusMove; - inkCanvas.StylusUp -= MainWindow_StylusUp; - inkCanvas.TouchDown -= MainWindow_TouchDown; - - // 记录已暂时禁用多指书写模式,但实际上多指书写开关仍然为打开状态 + private Task CheckIsDrawingShapesInMultiTouchMode() { + if (isInMultiTouchMode) { + ToggleSwitchEnableMultiTouchMode.IsOn = false; lastIsInMultiTouchMode = true; } - if (drawingShapeMode != 0) - { - inkCanvas.EditingMode = InkCanvasEditingMode.None; - } - return Task.FromResult(true); } - internal async void BtnDrawLine_Click(object sender, MouseButtonEventArgs e) - { + public async void BtnDrawLine_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(1); - lastMouseDownSender = null; - - // 先保存长按状态,避免被CancelSingleFingerDragMode重置 - bool wasLongPressed = isLongPressSelected; - + if (lastMouseDownSender == sender) { + forceEraser = true; + drawingShapeMode = 1; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); + } - if (wasLongPressed) - { + lastMouseDownSender = null; + if (isLongPressSelected) { if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape(); var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0))); ImageDrawLine.BeginAnimation(OpacityProperty, dA); - // 恢复长按状态,保持工具选中 - isLongPressSelected = true; } + DrawShapePromptToPen(); } - private async void BtnDrawDashedLine_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawDashedLine_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(8); - lastMouseDownSender = null; - - // 先保存长按状态,避免被CancelSingleFingerDragMode重置 - bool wasLongPressed = isLongPressSelected; - + if (lastMouseDownSender == sender) { + forceEraser = true; + drawingShapeMode = 8; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); + } - if (wasLongPressed) - { + lastMouseDownSender = null; + if (isLongPressSelected) { if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape(); var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0))); ImageDrawDashedLine.BeginAnimation(OpacityProperty, dA); - // 恢复长按状态,保持工具选中 - isLongPressSelected = true; } + DrawShapePromptToPen(); } - private async void BtnDrawDotLine_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawDotLine_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(18); - lastMouseDownSender = null; - - // 先保存长按状态,避免被CancelSingleFingerDragMode重置 - bool wasLongPressed = isLongPressSelected; - + if (lastMouseDownSender == sender) { + forceEraser = true; + drawingShapeMode = 18; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); + } - if (wasLongPressed) - { + lastMouseDownSender = null; + if (isLongPressSelected) { if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape(); var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0))); ImageDrawDotLine.BeginAnimation(OpacityProperty, dA); - // 恢复长按状态,保持工具选中 - isLongPressSelected = true; } + DrawShapePromptToPen(); } - private async void BtnDrawArrow_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawArrow_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(2); - lastMouseDownSender = null; - - // 先保存长按状态,避免被CancelSingleFingerDragMode重置 - bool wasLongPressed = isLongPressSelected; - + if (lastMouseDownSender == sender) { + forceEraser = true; + drawingShapeMode = 2; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); + } - if (wasLongPressed) - { + lastMouseDownSender = null; + if (isLongPressSelected) { if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape(); var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0))); ImageDrawArrow.BeginAnimation(OpacityProperty, dA); - // 恢复长按状态,保持工具选中 - isLongPressSelected = true; } + DrawShapePromptToPen(); } - private async void BtnDrawParallelLine_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawParallelLine_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(15); - lastMouseDownSender = null; - - // 先保存长按状态,避免被CancelSingleFingerDragMode重置 - bool wasLongPressed = isLongPressSelected; - + if (lastMouseDownSender == sender) { + forceEraser = true; + drawingShapeMode = 15; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); + } - if (wasLongPressed) - { + lastMouseDownSender = null; + if (isLongPressSelected) { if (ToggleSwitchDrawShapeBorderAutoHide.IsOn) CollapseBorderDrawShape(); var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0))); ImageDrawParallelLine.BeginAnimation(OpacityProperty, dA); - // 恢复长按状态,保持工具选中 - isLongPressSelected = true; } + DrawShapePromptToPen(); } - private async void BtnDrawCoordinate1_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawCoordinate1_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(11); + forceEraser = true; + drawingShapeMode = 11; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawCoordinate2_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawCoordinate2_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(12); + forceEraser = true; + drawingShapeMode = 12; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawCoordinate3_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawCoordinate3_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(13); + forceEraser = true; + drawingShapeMode = 13; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawCoordinate4_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawCoordinate4_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(14); + forceEraser = true; + drawingShapeMode = 14; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawCoordinate5_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawCoordinate5_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(17); + forceEraser = true; + drawingShapeMode = 17; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawRectangle_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawRectangle_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(3); + forceEraser = true; + drawingShapeMode = 3; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - isLongPressSelected = false; - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawRectangleCenter_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawRectangleCenter_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(19); + forceEraser = true; + drawingShapeMode = 19; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawEllipse_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawEllipse_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(4); + forceEraser = true; + drawingShapeMode = 4; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawCircle_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawCircle_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(5); + forceEraser = true; + drawingShapeMode = 5; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawCenterEllipse_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawCenterEllipse_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(16); + forceEraser = true; + drawingShapeMode = 16; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawCenterEllipseWithFocalPoint_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawCenterEllipseWithFocalPoint_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(23); + forceEraser = true; + drawingShapeMode = 23; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawDashedCircle_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawDashedCircle_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(10); + forceEraser = true; + drawingShapeMode = 10; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawHyperbola_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawHyperbola_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(24); + forceEraser = true; + drawingShapeMode = 24; drawMultiStepShapeCurrentStep = 0; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawHyperbolaWithFocalPoint_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawHyperbolaWithFocalPoint_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(25); + forceEraser = true; + drawingShapeMode = 25; drawMultiStepShapeCurrentStep = 0; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawParabola1_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawParabola1_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(20); + forceEraser = true; + drawingShapeMode = 20; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawParabolaWithFocalPoint_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawParabolaWithFocalPoint_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(22); + forceEraser = true; + drawingShapeMode = 22; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawParabola2_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawParabola2_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(21); + forceEraser = true; + drawingShapeMode = 21; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawCylinder_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawCylinder_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(6); + forceEraser = true; + drawingShapeMode = 6; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawCone_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawCone_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(7); + forceEraser = true; + drawingShapeMode = 7; + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } - private async void BtnDrawCuboid_Click(object sender, MouseButtonEventArgs e) - { + private async void BtnDrawCuboid_Click(object sender, MouseButtonEventArgs e) { await CheckIsDrawingShapesInMultiTouchMode(); - EnterShapeDrawingMode(9); + forceEraser = true; + drawingShapeMode = 9; isFirstTouchCuboid = true; CuboidFrontRectIniP = new Point(); CuboidFrontRectEndP = new Point(); + inkCanvas.EditingMode = InkCanvasEditingMode.None; + inkCanvas.IsManipulationEnabled = true; CancelSingleFingerDragMode(); - lastMouseDownSender = null; DrawShapePromptToPen(); } #endregion - private void inkCanvas_TouchMove(object sender, TouchEventArgs e) - { - // 确保套索选择模式下触摸移动时光标保持可见 - if (inkCanvas.EditingMode == InkCanvasEditingMode.Select) - { - SetCursorBasedOnEditingMode(inkCanvas); - } - - if (drawingShapeMode != 0) - { - inkCanvas.EditingMode = InkCanvasEditingMode.None; - - if (!isTouchDown) return; - - if (isWaitUntilNextTouchDown && dec.Count > 1) return; - - // 对于多笔图形绘制,允许第二笔绘制,即使dec.Count > 1 - if (dec.Count > 1 && !((drawingShapeMode == 24 || drawingShapeMode == 25) && drawMultiStepShapeCurrentStep == 1)) - { - // 其他情况正常删除临时笔画 - try - { + private void inkCanvas_TouchMove(object sender, TouchEventArgs e) { + if (isSingleFingerDragMode) return; + if (drawingShapeMode != 0) { + //EraserContainer.Background = null; + //ImageEraser.Visibility = Visibility.Visible; + if (isWaitUntilNextTouchDown) return; + if (dec.Count > 1) { + isWaitUntilNextTouchDown = true; + try { inkCanvas.Strokes.Remove(lastTempStroke); inkCanvas.Strokes.Remove(lastTempStrokeCollection); } - catch - { + catch { Trace.WriteLine("lastTempStrokeCollection failed."); } + return; } - // 第二笔绘制双曲线时,只删除第二笔的临时笔画,保留第一笔的辅助线 - if ((drawingShapeMode == 24 || drawingShapeMode == 25) && drawMultiStepShapeCurrentStep == 1) - { - try - { - inkCanvas.Strokes.Remove(lastTempStroke); - } - catch { } - // 不直接返回,继续执行绘制逻辑 - } - - Point touchPoint = e.GetTouchPoint(inkCanvas).Position; - if ((drawingShapeMode == 24 || drawingShapeMode == 25) && drawMultiStepShapeCurrentStep == 1) - { - // 第二笔绘制双曲线时,使用触摸位置作为终点,但保持第一笔的起点 - // 这里不需要特殊处理,因为MouseTouchMove函数内部已经正确处理了双曲线的绘制逻辑 - MouseTouchMove(touchPoint); - } - else - { - // 其他情况正常处理 - MouseTouchMove(touchPoint); - } - - return; // 处理完几何绘制后直接返回,不执行后面的代码 + if (inkCanvas.EditingMode != InkCanvasEditingMode.None) + inkCanvas.EditingMode = InkCanvasEditingMode.None; } - // 其它模式下,允许橡皮、套索、批注等正常工作,不覆盖EditingMode - if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint || - inkCanvas.EditingMode == InkCanvasEditingMode.Select || - inkCanvas.EditingMode == InkCanvasEditingMode.Ink) - { - // 允许正常橡皮、套索、批注 - } + MouseTouchMove(e.GetTouchPoint(inkCanvas).Position); } private int drawMultiStepShapeCurrentStep; //多笔完成的图形 当前所处在的笔画 @@ -559,8 +478,7 @@ namespace Ink_Canvas #region 形状绘制主函数 - private void MouseTouchMove(Point endP) - { + private void MouseTouchMove(Point endP) { // 禁用原有的FitToCurve,使用新的高级贝塞尔曲线平滑 if (Settings.Canvas.FitToCurve) drawingAttributes.FitToCurve = false; // 在绘制过程中禁用浮动栏交互,避免干扰绘制 @@ -580,24 +498,42 @@ namespace Ink_Canvas new Point(endP.X, endP.Y) }; point = new StylusPointCollection(pointList); - stroke = new Stroke(point) - { + stroke = new Stroke(point) { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; + try { + inkCanvas.Strokes.Remove(lastTempStroke); + } + catch { } - UpdateTempStrokeSafely(stroke); + lastTempStroke = stroke; + inkCanvas.Strokes.Add(stroke); break; case 8: _currentCommitType = CommitReason.ShapeDrawing; strokes.Add(GenerateDashedLineStrokeCollection(iniP, endP)); + try { + inkCanvas.Strokes.Remove(lastTempStrokeCollection); + } + catch { + Trace.WriteLine("lastTempStrokeCollection failed."); + } - UpdateTempStrokeCollectionSafely(strokes); + lastTempStrokeCollection = strokes; + inkCanvas.Strokes.Add(strokes); break; case 18: _currentCommitType = CommitReason.ShapeDrawing; strokes.Add(GenerateDotLineStrokeCollection(iniP, endP)); + try { + inkCanvas.Strokes.Remove(lastTempStrokeCollection); + } + catch { + Trace.WriteLine("lastTempStrokeCollection failed."); + } - UpdateTempStrokeCollectionSafely(strokes); + lastTempStrokeCollection = strokes; + inkCanvas.Strokes.Add(strokes); break; case 2: _currentCommitType = CommitReason.ShapeDrawing; @@ -614,13 +550,16 @@ namespace Ink_Canvas new Point(endP.X + (w * cost + h * sint), endP.Y - (h * cost - w * sint)) }; point = new StylusPointCollection(pointList); - stroke = new Stroke(point) - { + stroke = new Stroke(point) { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; + try { + inkCanvas.Strokes.Remove(lastTempStroke); + } + catch { } - // 优化:使用更安全的临时笔画更新方式,减少闪烁 - UpdateTempStrokeSafely(stroke); + lastTempStroke = stroke; + inkCanvas.Strokes.Add(stroke); break; case 15: _currentCommitType = CommitReason.ShapeDrawing; @@ -676,12 +615,10 @@ namespace Ink_Canvas new Point(endP.X + x * sinTheta, endP.Y + x * cosTheta))); strokes.Add(GenerateLineStroke(new Point(iniP.X + 3 * x * sinTheta, iniP.Y + 3 * x * cosTheta), new Point(endP.X + 3 * x * sinTheta, endP.Y + 3 * x * cosTheta))); - try - { + try { inkCanvas.Strokes.Remove(lastTempStrokeCollection); } - catch - { + catch { Trace.WriteLine("lastTempStrokeCollection failed."); } @@ -694,12 +631,10 @@ namespace Ink_Canvas new Point(endP.X, iniP.Y))); strokes.Add(GenerateArrowLineStroke(new Point(iniP.X, 2 * iniP.Y - (endP.Y + 20)), new Point(iniP.X, endP.Y))); - try - { + try { inkCanvas.Strokes.Remove(lastTempStrokeCollection); } - catch - { + catch { Trace.WriteLine("lastTempStrokeCollection failed."); } @@ -714,12 +649,10 @@ namespace Ink_Canvas new Point(endP.X, iniP.Y))); strokes.Add(GenerateArrowLineStroke(new Point(iniP.X, 2 * iniP.Y - (endP.Y + 20)), new Point(iniP.X, endP.Y))); - try - { + try { inkCanvas.Strokes.Remove(lastTempStrokeCollection); } - catch - { + catch { Trace.WriteLine("lastTempStrokeCollection failed."); } @@ -734,12 +667,10 @@ namespace Ink_Canvas strokes.Add(GenerateArrowLineStroke( new Point(iniP.X, iniP.Y + (iniP.Y - endP.Y) / Math.Abs(iniP.Y - endP.Y) * 25), new Point(iniP.X, endP.Y))); - try - { + try { inkCanvas.Strokes.Remove(lastTempStrokeCollection); } - catch - { + catch { Trace.WriteLine("lastTempStrokeCollection failed."); } @@ -755,12 +686,10 @@ namespace Ink_Canvas strokes.Add(GenerateArrowLineStroke( new Point(iniP.X, iniP.Y + (iniP.Y - endP.Y) / Math.Abs(iniP.Y - endP.Y) * 25), new Point(iniP.X, endP.Y))); - try - { + try { inkCanvas.Strokes.Remove(lastTempStrokeCollection); } - catch - { + catch { Trace.WriteLine("lastTempStrokeCollection failed."); } @@ -776,12 +705,10 @@ namespace Ink_Canvas d = (Math.Abs(iniP.X - endP.X) + Math.Abs(iniP.Y - endP.Y)) / 2; strokes.Add(GenerateArrowLineStroke(new Point(iniP.X, iniP.Y), new Point(iniP.X - d / 1.76, iniP.Y + d / 1.76))); - try - { + try { inkCanvas.Strokes.Remove(lastTempStrokeCollection); } - catch - { + catch { Trace.WriteLine("lastTempStrokeCollection failed."); } @@ -798,12 +725,10 @@ namespace Ink_Canvas new Point(iniP.X, iniP.Y) }; point = new StylusPointCollection(pointList); - stroke = new Stroke(point) - { + stroke = new Stroke(point) { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; - try - { + try { inkCanvas.Strokes.Remove(lastTempStroke); } catch { } @@ -823,12 +748,10 @@ namespace Ink_Canvas new Point(iniP.X - a, iniP.Y - b) }; point = new StylusPointCollection(pointList); - stroke = new Stroke(point) - { + stroke = new Stroke(point) { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; - try - { + try { inkCanvas.Strokes.Remove(lastTempStroke); } catch { } @@ -840,12 +763,10 @@ namespace Ink_Canvas _currentCommitType = CommitReason.ShapeDrawing; pointList = GenerateEllipseGeometry(iniP, endP); point = new StylusPointCollection(pointList); - stroke = new Stroke(point) - { + stroke = new Stroke(point) { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; - try - { + try { inkCanvas.Strokes.Remove(lastTempStroke); } catch { } @@ -859,12 +780,10 @@ namespace Ink_Canvas pointList = GenerateEllipseGeometry(new Point(iniP.X - R, iniP.Y - R), new Point(iniP.X + R, iniP.Y + R)); point = new StylusPointCollection(pointList); - stroke = new Stroke(point) - { + stroke = new Stroke(point) { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; - try - { + try { inkCanvas.Strokes.Remove(lastTempStroke); } catch { } @@ -873,8 +792,7 @@ namespace Ink_Canvas inkCanvas.Strokes.Add(stroke); // 如果启用了圆心标记功能,则绘制圆心 - if (Settings.Canvas.ShowCircleCenter) - { + if (Settings.Canvas.ShowCircleCenter) { DrawCircleCenter(iniP); } break; @@ -885,12 +803,10 @@ namespace Ink_Canvas pointList = GenerateEllipseGeometry(new Point(iniP.X - halfA, iniP.Y - halfB), new Point(iniP.X + halfA, iniP.Y + halfB)); point = new StylusPointCollection(pointList); - stroke = new Stroke(point) - { + stroke = new Stroke(point) { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; - try - { + try { inkCanvas.Strokes.Remove(lastTempStroke); } catch { } @@ -905,54 +821,46 @@ namespace Ink_Canvas pointList = GenerateEllipseGeometry(new Point(iniP.X - a, iniP.Y - b), new Point(iniP.X + a, iniP.Y + b)); point = new StylusPointCollection(pointList); - stroke = new Stroke(point) - { + stroke = new Stroke(point) { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; strokes.Add(stroke); var c = Math.Sqrt(Math.Abs(a * a - b * b)); StylusPoint stylusPoint; - if (a > b) - { + if (a > b) { stylusPoint = new StylusPoint(iniP.X + c, iniP.Y, (float)1.0); point = new StylusPointCollection(); point.Add(stylusPoint); - stroke = new Stroke(point) - { + stroke = new Stroke(point) { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; strokes.Add(stroke.Clone()); stylusPoint = new StylusPoint(iniP.X - c, iniP.Y, (float)1.0); point = new StylusPointCollection(); point.Add(stylusPoint); - stroke = new Stroke(point) - { + stroke = new Stroke(point) { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; strokes.Add(stroke.Clone()); } - else if (a < b) - { + else if (a < b) { stylusPoint = new StylusPoint(iniP.X, iniP.Y - c, (float)1.0); point = new StylusPointCollection(); point.Add(stylusPoint); - stroke = new Stroke(point) - { + stroke = new Stroke(point) { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; strokes.Add(stroke.Clone()); stylusPoint = new StylusPoint(iniP.X, iniP.Y + c, (float)1.0); point = new StylusPointCollection(); point.Add(stylusPoint); - stroke = new Stroke(point) - { + stroke = new Stroke(point) { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; strokes.Add(stroke.Clone()); } - try - { + try { inkCanvas.Strokes.Remove(lastTempStrokeCollection); } catch { } @@ -965,23 +873,15 @@ namespace Ink_Canvas R = GetDistance(iniP, endP); strokes = GenerateDashedLineEllipseStrokeCollection(new Point(iniP.X - R, iniP.Y - R), new Point(iniP.X + R, iniP.Y + R)); - try - { + try { inkCanvas.Strokes.Remove(lastTempStrokeCollection); } - catch - { + catch { Trace.WriteLine("lastTempStrokeCollection failed."); } lastTempStrokeCollection = strokes; inkCanvas.Strokes.Add(strokes); - - // 如果启用了圆心标记功能,则绘制圆心 - if (Settings.Canvas.ShowCircleCenter) - { - DrawCircleCenter(iniP); - } break; case 24: case 25: @@ -991,8 +891,7 @@ namespace Ink_Canvas var pointList2 = new List(); var pointList3 = new List(); var pointList4 = new List(); - if (drawMultiStepShapeCurrentStep == 0) - { + if (drawMultiStepShapeCurrentStep == 0) { //第一笔:画渐近线 var k = Math.Abs((endP.Y - iniP.Y) / (endP.X - iniP.X)); strokes.Add( @@ -1002,29 +901,25 @@ namespace Ink_Canvas new Point(endP.X, 2 * iniP.Y - endP.Y))); drawMultiStepShapeSpecialParameter3 = k; drawMultiStepShapeSpecialStrokeCollection = strokes; - - try - { - inkCanvas.Strokes.Remove(lastTempStrokeCollection); - } - catch { } - lastTempStrokeCollection = strokes; - inkCanvas.Strokes.Add(strokes); } - else - { + else { //第二笔:画双曲线 + // 先将第一笔的渐近线添加到strokes中 + if (drawMultiStepShapeSpecialStrokeCollection != null && drawMultiStepShapeSpecialStrokeCollection.Count > 0) { + foreach (var asymptoteStroke in drawMultiStepShapeSpecialStrokeCollection) { + strokes.Add(asymptoteStroke.Clone()); + } + } + var k = drawMultiStepShapeSpecialParameter3; var isHyperbolaFocalPointOnXAxis = Math.Abs((endP.Y - iniP.Y) / (endP.X - iniP.X)) < k; - if (isHyperbolaFocalPointOnXAxis) - { + if (isHyperbolaFocalPointOnXAxis) { // 焦点在 x 轴上 a = Math.Sqrt(Math.Abs((endP.X - iniP.X) * (endP.X - iniP.X) - (endP.Y - iniP.Y) * (endP.Y - iniP.Y) / (k * k))); b = a * k; pointList = new List(); - for (var i = a; i <= Math.Abs(endP.X - iniP.X); i += 0.5) - { + for (var i = a; i <= Math.Abs(endP.X - iniP.X); i += 0.5) { var rY = Math.Sqrt(Math.Abs(k * k * i * i - b * b)); pointList.Add(new Point(iniP.X + i, iniP.Y - rY)); pointList2.Add(new Point(iniP.X + i, iniP.Y + rY)); @@ -1032,15 +927,13 @@ namespace Ink_Canvas pointList4.Add(new Point(iniP.X - i, iniP.Y + rY)); } } - else - { + else { // 焦点在 y 轴上 a = Math.Sqrt(Math.Abs((endP.Y - iniP.Y) * (endP.Y - iniP.Y) - (endP.X - iniP.X) * (endP.X - iniP.X) * (k * k))); b = a / k; pointList = new List(); - for (var i = a; i <= Math.Abs(endP.Y - iniP.Y); i += 0.5) - { + for (var i = a; i <= Math.Abs(endP.Y - iniP.Y); i += 0.5) { var rX = Math.Sqrt(Math.Abs(i * i / k / k - b * b)); pointList.Add(new Point(iniP.X - rX, iniP.Y + i)); pointList2.Add(new Point(iniP.X + rX, iniP.Y + i)); @@ -1049,8 +942,7 @@ namespace Ink_Canvas } } - try - { + try { point = new StylusPointCollection(pointList); stroke = new Stroke(point) { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; @@ -1067,8 +959,7 @@ namespace Ink_Canvas stroke = new Stroke(point) { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; strokes.Add(stroke.Clone()); - if (drawingShapeMode == 25) - { + if (drawingShapeMode == 25) { //画焦点 c = Math.Sqrt(a * a + b * b); stylusPoint = isHyperbolaFocalPointOnXAxis @@ -1077,7 +968,7 @@ namespace Ink_Canvas point = new StylusPointCollection(); point.Add(stylusPoint); stroke = new Stroke(point) - { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; + { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; strokes.Add(stroke.Clone()); stylusPoint = isHyperbolaFocalPointOnXAxis ? new StylusPoint(iniP.X - c, iniP.Y, (float)1.0) @@ -1085,49 +976,24 @@ namespace Ink_Canvas point = new StylusPointCollection(); point.Add(stylusPoint); stroke = new Stroke(point) - { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; + { DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone() }; strokes.Add(stroke.Clone()); } } - catch - { + catch { return; } } - try - { - // 删除第二笔的临时笔画 + try { inkCanvas.Strokes.Remove(lastTempStrokeCollection); - - // 创建包含辅助线和双曲线的完整笔画集合 - var completeStrokes = new StrokeCollection(); - - // 添加第一笔的辅助线 - if (drawMultiStepShapeSpecialStrokeCollection != null && drawMultiStepShapeSpecialStrokeCollection.Count > 0) - { - foreach (var stroke1 in drawMultiStepShapeSpecialStrokeCollection) - { - completeStrokes.Add(stroke1.Clone()); - } - } - - // 添加第二笔的双曲线 - foreach (var stroke1 in strokes) - { - completeStrokes.Add(stroke1.Clone()); - } - - lastTempStrokeCollection = completeStrokes; - inkCanvas.Strokes.Add(completeStrokes); } - catch (Exception ex) - { - Trace.WriteLine($"双曲线绘制完成处理失败: {ex.Message}"); - // 如果合并失败,至少添加双曲线部分 + catch { + Trace.WriteLine("lastTempStrokeCollection failed."); + } + lastTempStrokeCollection = strokes; inkCanvas.Strokes.Add(strokes); - } break; case 20: _currentCommitType = CommitReason.ShapeDrawing; @@ -1791,10 +1657,8 @@ namespace Ink_Canvas ViewboxFloatingBar.IsHitTestVisible = true; BlackboardUIGridForInkReplay.IsHitTestVisible = true; - if (drawingShapeMode == 5) - { - if (lastTempStroke != null) - { + if (drawingShapeMode == 5) { + if (lastTempStroke != null) { var circle = new Circle(new Point(), 0, lastTempStroke); circle.R = GetDistance(circle.Stroke.StylusPoints[0].ToPoint(), circle.Stroke.StylusPoints[circle.Stroke.StylusPoints.Count / 2].ToPoint()) / 2; @@ -1806,52 +1670,25 @@ namespace Ink_Canvas circles.Add(circle); } - if (lastIsInMultiTouchMode) - { - // 不再重新启用开关,而是恢复多指书写相关的事件处理 - // ToggleSwitchEnableMultiTouchMode.IsOn = true; - - // 恢复多指书写事件处理 - inkCanvas.StylusDown += MainWindow_StylusDown; - inkCanvas.StylusMove += MainWindow_StylusMove; - inkCanvas.StylusUp += MainWindow_StylusUp; - inkCanvas.TouchDown += MainWindow_TouchDown; - + if (lastIsInMultiTouchMode) { + ToggleSwitchEnableMultiTouchMode.IsOn = true; lastIsInMultiTouchMode = false; } } - // 修改此处逻辑,确保在正确的情况下才切换回笔模式 - if (drawingShapeMode != 9 && drawingShapeMode != 0 && drawingShapeMode != 24 && drawingShapeMode != 25) - { - if (isLongPressSelected) - { - // 如果是长按选中的情况,保持图形模式,不做任何切换 - isWaitUntilNextTouchDown = true; // 保持当前绘图模式直到下一次触摸 - } - else - { + if (drawingShapeMode != 9 && drawingShapeMode != 0 && drawingShapeMode != 24 && drawingShapeMode != 25) { + if (isLongPressSelected) { } + else { BtnPen_Click(null, null); //画完一次还原到笔模式 - if (lastIsInMultiTouchMode) - { - // 不再重新启用开关,而是恢复多指书写相关的事件处理 - // ToggleSwitchEnableMultiTouchMode.IsOn = true; - - // 恢复多指书写事件处理 - inkCanvas.StylusDown += MainWindow_StylusDown; - inkCanvas.StylusMove += MainWindow_StylusMove; - inkCanvas.StylusUp += MainWindow_StylusUp; - inkCanvas.TouchDown += MainWindow_TouchDown; - + if (lastIsInMultiTouchMode) { + ToggleSwitchEnableMultiTouchMode.IsOn = true; lastIsInMultiTouchMode = false; } } } - if (drawingShapeMode == 9) - { - if (isFirstTouchCuboid) - { + if (drawingShapeMode == 9) { + if (isFirstTouchCuboid) { if (CuboidStrokeCollection == null) CuboidStrokeCollection = new StrokeCollection(); isFirstTouchCuboid = false; var newIniP = new Point(Math.Min(CuboidFrontRectIniP.X, CuboidFrontRectEndP.X), @@ -1860,40 +1697,25 @@ namespace Ink_Canvas Math.Max(CuboidFrontRectIniP.Y, CuboidFrontRectEndP.Y)); CuboidFrontRectIniP = newIniP; CuboidFrontRectEndP = newEndP; - try - { + try { CuboidStrokeCollection.Add(lastTempStrokeCollection); } - catch - { + catch { Trace.WriteLine("lastTempStrokeCollection failed."); } } - else - { + else { BtnPen_Click(null, null); //画完还原到笔模式 - if (lastIsInMultiTouchMode) - { - // 不再重新启用开关,而是恢复多指书写相关的事件处理 - // ToggleSwitchEnableMultiTouchMode.IsOn = true; - - // 恢复多指书写事件处理 - inkCanvas.StylusDown += MainWindow_StylusDown; - inkCanvas.StylusMove += MainWindow_StylusMove; - inkCanvas.StylusUp += MainWindow_StylusUp; - inkCanvas.TouchDown += MainWindow_TouchDown; - + if (lastIsInMultiTouchMode) { + ToggleSwitchEnableMultiTouchMode.IsOn = true; lastIsInMultiTouchMode = false; } - if (_currentCommitType == CommitReason.ShapeDrawing) - { - try - { + if (_currentCommitType == CommitReason.ShapeDrawing) { + try { CuboidStrokeCollection.Add(lastTempStrokeCollection); } - catch - { + catch { Trace.WriteLine("lastTempStrokeCollection failed."); } @@ -1904,20 +1726,15 @@ namespace Ink_Canvas } } - if (drawingShapeMode == 24 || drawingShapeMode == 25) - { - if (drawMultiStepShapeCurrentStep == 0) - { + if (drawingShapeMode == 24 || drawingShapeMode == 25) { + if (drawMultiStepShapeCurrentStep == 0) { drawMultiStepShapeCurrentStep = 1; } - else - { + else { drawMultiStepShapeCurrentStep = 0; - if (drawMultiStepShapeSpecialStrokeCollection != null) - { + if (drawMultiStepShapeSpecialStrokeCollection != null) { var opFlag = false; - switch (Settings.Canvas.HyperbolaAsymptoteOption) - { + switch (Settings.Canvas.HyperbolaAsymptoteOption) { case OptionalOperation.Yes: opFlag = true; break; @@ -1935,17 +1752,8 @@ namespace Ink_Canvas } BtnPen_Click(null, null); //画完还原到笔模式 - if (lastIsInMultiTouchMode) - { - // 不再重新启用开关,而是恢复多指书写相关的事件处理 - // ToggleSwitchEnableMultiTouchMode.IsOn = true; - - // 恢复多指书写事件处理 - inkCanvas.StylusDown += MainWindow_StylusDown; - inkCanvas.StylusMove += MainWindow_StylusMove; - inkCanvas.StylusUp += MainWindow_StylusUp; - inkCanvas.TouchDown += MainWindow_TouchDown; - + if (lastIsInMultiTouchMode) { + ToggleSwitchEnableMultiTouchMode.IsOn = true; lastIsInMultiTouchMode = false; } } @@ -1992,32 +1800,7 @@ namespace Ink_Canvas } } - // 应用高级贝塞尔曲线平滑 - if (Settings.Canvas.UseAdvancedBezierSmoothing) - { - try - { - // 对临时笔画应用平滑 - if (lastTempStroke != null && _inkSmoothingManager != null) - { - var smoothedStroke = _inkSmoothingManager.SmoothStroke(lastTempStroke); - if (smoothedStroke != lastTempStroke) - { - inkCanvas.Strokes.Remove(lastTempStroke); - lastTempStroke = smoothedStroke; - inkCanvas.Strokes.Add(smoothedStroke); - } - } - } - catch (Exception ex) - { - Debug.WriteLine($"形状绘制高级贝塞尔曲线平滑失败: {ex.Message}"); - } - } - else if (Settings.Canvas.FitToCurve) - { - drawingAttributes.FitToCurve = true; - } + if (Settings.Canvas.FitToCurve == true) drawingAttributes.FitToCurve = true; } private bool NeedUpdateIniP() @@ -2029,79 +1812,6 @@ namespace Ink_Canvas } return true; } - - private void MainWindow_OnMouseMove(object sender, MouseEventArgs e) - { - if (e.StylusDevice == null) - { - // 鼠标移动时保持光标可见 - System.Windows.Forms.Cursor.Show(); - - // 如果用户设置了显示光标,则确保光标显示正确 - if (Settings.Canvas.IsShowCursor && inkCanvas != null) - { - inkCanvas.ForceCursor = true; - inkCanvas.UseCustomCursor = true; - } - } - else - { - // 只有当用户未设置显示光标时才隐藏 - if (!Settings.Canvas.IsShowCursor) - { - System.Windows.Forms.Cursor.Hide(); - } - else if (inkCanvas != null) - { - // 如果用户设置了显示光标,则确保光标显示正确 - inkCanvas.ForceCursor = true; - inkCanvas.UseCustomCursor = true; - System.Windows.Forms.Cursor.Show(); - } - } - } - - private void EnterShapeDrawingMode(int mode) - { - forceEraser = true; - forcePointEraser = false; - drawingShapeMode = mode; - inkCanvas.EditingMode = InkCanvasEditingMode.None; - SetCursorBasedOnEditingMode(inkCanvas); - ResetAllShapeButtonsOpacity(); - } - - /// - /// 重置所有几何绘制按钮的透明度状态 - /// - private void ResetAllShapeButtonsOpacity() - { - try - { - // 重置所有几何绘制按钮的透明度为1(完全不透明) - var buttons = new UIElement[] { - ImageDrawLine, BoardImageDrawLine, - ImageDrawDashedLine, BoardImageDrawDashedLine, - ImageDrawDotLine, BoardImageDrawDotLine, - ImageDrawArrow, BoardImageDrawArrow, - ImageDrawParallelLine, BoardImageDrawParallelLine, - }; - - foreach (var button in buttons) - { - if (button != null) - { - var dA = new DoubleAnimation(1, 1, new Duration(TimeSpan.FromMilliseconds(0))); - button.BeginAnimation(OpacityProperty, dA); - } - } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"重置几何绘制按钮透明度失败: {ex.Message}", LogHelper.LogType.Error); - } - } - /// /// 绘制圆心标记 /// @@ -2142,5 +1852,12 @@ namespace Ink_Canvas Debug.WriteLine($"绘制圆心标记失败: {ex.Message}"); } } + private void MainWindow_OnMouseMove(object sender, MouseEventArgs e) { + if (e.StylusDevice == null) { + System.Windows.Forms.Cursor.Show(); + } else { + System.Windows.Forms.Cursor.Hide(); + } + } } } diff --git a/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs b/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs index e56b1ac3..d6542764 100644 --- a/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs +++ b/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs @@ -18,21 +18,19 @@ namespace Ink_Canvas { private StrokeCollection newStrokes = new StrokeCollection(); private List circles = new List(); - private const double LINE_STRAIGHTEN_THRESHOLD = 0.20; // 默认灵敏度阈值,与UI默认值对应 + private const double LINE_STRAIGHTEN_THRESHOLD = 0.20; - // 矩形参考线系统 private List rectangleGuideLines = new List(); - private const double RECTANGLE_ENDPOINT_THRESHOLD = 30.0; // 端点相交判断阈值 - private const double RECTANGLE_ANGLE_THRESHOLD = 15.0; // 角度判断阈值(度) + private const double RECTANGLE_ENDPOINT_THRESHOLD = 30.0; + private const double RECTANGLE_ANGLE_THRESHOLD = 15.0; - // 矩形参考线数据结构 private class RectangleGuideLine { public Stroke OriginalStroke { get; set; } public Point StartPoint { get; set; } public Point EndPoint { get; set; } public DateTime CreatedTime { get; set; } - public double Angle { get; set; } // 直线角度(弧度) + public double Angle { get; set; } public bool IsHorizontal { get; set; } public bool IsVertical { get; set; } @@ -64,7 +62,6 @@ namespace Ink_Canvas 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保持Ink编辑模式,防止自动切换到鼠标模式 if (inkCanvas.EditingMode != InkCanvasEditingMode.Ink) { inkCanvas.EditingMode = InkCanvasEditingMode.Ink; @@ -80,19 +77,15 @@ namespace Ink_Canvas LogHelper.WriteLogToFile("StrokeCollected: 墨迹渐隐管理器为空,无法添加墨迹", LogHelper.LogType.Error); } - // 延迟移除墨迹,避免立即移除导致模式切换 - // 使用Dispatcher.BeginInvoke确保在UI线程上异步执行 Dispatcher.BeginInvoke(new Action(() => { try { - // 再次确保InkCanvas保持Ink编辑模式 if (inkCanvas.EditingMode != InkCanvasEditingMode.Ink) { inkCanvas.EditingMode = InkCanvasEditingMode.Ink; } - // 从InkCanvas中移除墨迹,因为我们要用渐隐管理器来管理它 if (inkCanvas.Strokes.Contains(e.Stroke)) { inkCanvas.Strokes.Remove(e.Stroke); @@ -104,21 +97,18 @@ namespace Ink_Canvas } }), DispatcherPriority.Background); - // 墨迹渐隐模式下不参与墨迹纠正和其他处理,直接返回 return; } // 标记是否进行了直线拉直 bool wasStraightened = false; - // 禁用原有的FitToCurve,使用新的高级贝塞尔曲线平滑 if (Settings.Canvas.FitToCurve) drawingAttributes.FitToCurve = false; try { inkCanvas.Opacity = 1; - // 应用屏蔽压感功能 - 如果启用,所有笔画都使用统一粗细 if (Settings.Canvas.DisablePressure) { var uniformPoints = new StylusPointCollection(); @@ -129,13 +119,11 @@ namespace Ink_Canvas } e.Stroke.StylusPoints = uniformPoints; } - // 应用压感触屏模式 - 如果启用并且检测到触屏输入 else if (Settings.Canvas.EnablePressureTouchMode) { bool isTouchInput = true; foreach (StylusPoint point in e.Stroke.StylusPoints) { - // 检测是否为压感笔输入(压感笔的PressureFactor不等于0.5或0) if ((point.PressureFactor > 0.501 || point.PressureFactor < 0.5) && point.PressureFactor != 0) { isTouchInput = false; @@ -143,7 +131,6 @@ namespace Ink_Canvas } } - // 如果是触屏输入,则应用模拟压感 if (isTouchInput) { switch (Settings.Canvas.InkStyle) @@ -859,30 +846,61 @@ namespace Ink_Canvas // 快速检查:计算几个关键点与直线的距离 if (stroke.StylusPoints.Count >= 10) { - // 取中点和1/4、3/4位置的点,快速检查偏差 - int quarterIdx = stroke.StylusPoints.Count / 4; - int midIdx = stroke.StylusPoints.Count / 2; - int threeQuarterIdx = quarterIdx * 3; - - Point quarterPoint = stroke.StylusPoints[quarterIdx].ToPoint(); - Point midPoint = stroke.StylusPoints[midIdx].ToPoint(); - Point threeQuarterPoint = stroke.StylusPoints[threeQuarterIdx].ToPoint(); - - double quarterDeviation = DistanceFromLineToPoint(start, end, quarterPoint); - double midDeviation = DistanceFromLineToPoint(start, end, midPoint); - double threeQuarterDeviation = DistanceFromLineToPoint(start, end, threeQuarterPoint); - - // 使用相对偏差:偏差与线长的比例,并使用灵敏度进行调整 - double quickRelativeThreshold = lineLength * quickThreshold; - - // 记录检测到的偏差 - Debug.WriteLine($"Deviations: q={quarterDeviation}, m={midDeviation}, tq={threeQuarterDeviation}, threshold={quickRelativeThreshold}"); - - if (quarterDeviation > quickRelativeThreshold || - midDeviation > quickRelativeThreshold || - threeQuarterDeviation > quickRelativeThreshold) + List checkPoints; + + // 使用采样点进行更准确的判断 + if (Settings.Canvas.HighPrecisionLineStraighten) { - return false; + var allPoints = stroke.StylusPoints.Select(p => p.ToPoint()).ToList(); + checkPoints = SamplePointsByDistance(allPoints, 10.0); + Debug.WriteLine($"高精度模式快速检查:原始点数={allPoints.Count}, 采样点数={checkPoints.Count}"); + } + else + { + // 取中点和1/4、3/4位置的点 + int quarterIdx = stroke.StylusPoints.Count / 4; + int midIdx = stroke.StylusPoints.Count / 2; + int threeQuarterIdx = quarterIdx * 3; + + checkPoints = new List + { + stroke.StylusPoints[quarterIdx].ToPoint(), + stroke.StylusPoints[midIdx].ToPoint(), + stroke.StylusPoints[threeQuarterIdx].ToPoint() + }; + } + + // 计算所有检查点与直线的平均偏差 + double totalDeviation = 0; + double maxDeviation = 0; + int validPointCount = 0; + + foreach (Point checkPoint in checkPoints) + { + double deviation = DistanceFromLineToPoint(start, end, checkPoint); + totalDeviation += deviation; + maxDeviation = Math.Max(maxDeviation, deviation); + validPointCount++; + } + + if (validPointCount > 0) + { + double avgDeviation = totalDeviation / validPointCount; + // 使用相对偏差:偏差与线长的比例,并使用灵敏度进行调整 + double quickRelativeThreshold = lineLength * quickThreshold; + + // 使用平均偏差和最大偏差的综合判断 + double deviationThreshold = Settings.Canvas.HighPrecisionLineStraighten + ? Math.Max(avgDeviation, maxDeviation * 0.7) // 高精度模式更严格 + : maxDeviation; + + // 记录检测到的偏差 + Debug.WriteLine($"Deviations: avg={avgDeviation:F2}, max={maxDeviation:F2}, threshold={quickRelativeThreshold:F2}, highPrecision={Settings.Canvas.HighPrecisionLineStraighten}"); + + if (deviationThreshold > quickRelativeThreshold) + { + return false; + } } } @@ -1177,14 +1195,29 @@ namespace Ink_Canvas return false; } + List workingPoints = points; + if (Settings.Canvas.HighPrecisionLineStraighten) + { + workingPoints = SamplePointsByDistance(points, 10.0); + Debug.WriteLine($"高精度模式:原始点数={points.Count}, 采样后点数={workingPoints.Count}"); + } + // 使用总最小二乘法(TLS/PCA)进行直线拟合 - int n = points.Count - 8; + int n = workingPoints.Count - 8; + if (n < 1) + { + // 如果采样后点数太少,回退到原始方法 + n = points.Count - 8; + workingPoints = points; + } + List filteredPoints = new List(); // 收集过滤后的点(跳过前 4 个和后 4 个点,用于计算直线方向) - for (int i = 4; i < n + 4; i++) + int skipCount = Math.Min(4, n / 2); // 确保跳过数量不超过一半 + for (int i = skipCount; i < n + skipCount && i < workingPoints.Count; i++) { - filteredPoints.Add(points[i]); + filteredPoints.Add(workingPoints[i]); } // 计算中心点(使用过滤后的点) @@ -1244,7 +1277,8 @@ namespace Ink_Canvas double maxProjection = double.MinValue; // 计算所有点在直线方向上的投影 - foreach (Point p in points) + List pointsForProjection = Settings.Canvas.HighPrecisionLineStraighten ? workingPoints : points; + foreach (Point p in pointsForProjection) { // 相对于过滤点中心的投影 double projection = (p.X - centerX) * directionX + (p.Y - centerY) * directionY; @@ -1453,6 +1487,43 @@ namespace Ink_Canvas return points; } + /// + /// 高精度模式 + /// + private List SamplePointsByDistance(List points, double sampleInterval = 10.0) + { + if (points == null || points.Count < 2) + return points; + + List sampledPoints = new List(); + sampledPoints.Add(points[0]); // 总是包含起点 + + double accumulatedDistance = 0; + Point lastSampledPoint = points[0]; + + for (int i = 1; i < points.Count; i++) + { + double segmentDistance = GetDistance(lastSampledPoint, points[i]); + accumulatedDistance += segmentDistance; + + // 当累积距离达到采样间隔时,添加当前点 + if (accumulatedDistance >= sampleInterval) + { + sampledPoints.Add(points[i]); + lastSampledPoint = points[i]; + accumulatedDistance = 0; // 重置累积距离 + } + } + + // 总是包含终点(如果还没有包含) + if (sampledPoints.Count == 0 || GetDistance(sampledPoints.Last(), points.Last()) > 1.0) + { + sampledPoints.Add(points.Last()); + } + + return sampledPoints; + } + // New method: Gets distance from point to a line defined by two points private double DistanceFromLineToPoint(Point lineStart, Point lineEnd, Point point) { @@ -1467,11 +1538,66 @@ namespace Ink_Canvas return distance; } + /// + /// 判断一个 stroke 是否是直线(排除虚线和点线) + /// + /// 要检查的 stroke + /// 如果是直线返回 true,否则返回 false + private bool IsStraightLine(Stroke stroke) + { + if (stroke == null || stroke.StylusPoints.Count == 0) + return false; + + int pointCount = stroke.StylusPoints.Count; + + if (pointCount == 1) + return false; + + // 最简单的直线:只有2个点 + if (pointCount == 2) + { + Point p1 = stroke.StylusPoints[0].ToPoint(); + Point p2 = stroke.StylusPoints[1].ToPoint(); + double lineLength = GetDistance(p1, p2); + + if (lineLength < 10) + return false; + + return true; + } + + if (pointCount > 3) + return false; + + // 对于3个点的情况,检查它们是否基本在一条直线上 + if (pointCount == 3) + { + Point p1 = stroke.StylusPoints[0].ToPoint(); + Point p2 = stroke.StylusPoints[1].ToPoint(); + Point p3 = stroke.StylusPoints[2].ToPoint(); + + double totalLength = GetDistance(p1, p3); + if (totalLength < 10) + return false; + + // 计算点到直线的距离 + // 使用 p1 和 p3 作为直线端点,检查 p2 是否在这条直线上 + double distance = DistanceFromLineToPoint(p1, p3, p2); + + // 如果点到直线的距离相对于线段长度很小,认为是直线 + // 使用相对误差阈值(比如 1%) + if (totalLength > 0 && distance / totalLength < 0.01) + return true; + + return false; + } + + return false; + } + // New method: Attempts to snap endpoints to existing stroke endpoints private Point[] GetSnappedEndpoints(Point start, Point end) { - // 如果端点吸附功能关闭,直接返回null - // 这里不再返回原始点,因为调用此方法的地方会判断返回值是否为null if (!Settings.Canvas.LineEndpointSnapping) return null; @@ -1488,6 +1614,10 @@ namespace Ink_Canvas { if (stroke.StylusPoints.Count == 0) continue; + // 只对直线进行端点吸附,跳过虚线和点线 + if (!IsStraightLine(stroke)) + continue; + // Get stroke endpoints Point strokeStart = stroke.StylusPoints.First().ToPoint(); Point strokeEnd = stroke.StylusPoints.Last().ToPoint(); diff --git a/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs b/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs index 31525760..592d8aba 100644 --- a/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs +++ b/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs @@ -325,7 +325,7 @@ namespace Ink_Canvas // 根据当前编辑模式设置不同的光标 if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint) { - inkCanvas.Cursor = Cursors.Cross; + inkCanvas.Cursor = Cursors.Arrow; } else if (inkCanvas.EditingMode == InkCanvasEditingMode.Ink) { @@ -533,13 +533,6 @@ namespace Ink_Canvas if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint) { - // 橡皮状态下只return,保证橡皮状态可保持 - return; - } - if (inkCanvas.EditingMode == InkCanvasEditingMode.Select) - { - // 套索选状态下不直接return,允许触摸事件继续处理 - dec.Add(e.TouchDevice.Id); return; } if (drawingShapeMode != 0) @@ -556,6 +549,11 @@ namespace Ink_Canvas return; } + if (inkCanvas.EditingMode == InkCanvasEditingMode.Select) + { + dec.Add(e.TouchDevice.Id); + return; + } if (inkCanvas.EditingMode == InkCanvasEditingMode.Ink) { return; @@ -571,171 +569,30 @@ namespace Ink_Canvas } } - // 手掌擦相关变量 - private bool isPalmEraserActive; - private InkCanvasEditingMode palmEraserLastEditingMode = InkCanvasEditingMode.Ink; - private bool palmEraserLastIsHighlighter; - private bool palmEraserWasEnabledBeforeMultiTouch; - public double GetTouchBoundWidth(TouchEventArgs e) { var args = e.GetTouchPoint(null).Bounds; - if (!Settings.Advanced.IsQuadIR) return args.Width; - else return Math.Sqrt(args.Width * args.Height); // 四边红外 + double value; + if (!Settings.Advanced.IsQuadIR) value = args.Width; + else value = Math.Sqrt(args.Width * args.Height); //四边红外 + if (Settings.Advanced.IsSpecialScreen) value *= Settings.Advanced.TouchMultiplier; + return value; } private void inkCanvas_PreviewTouchDown(object sender, TouchEventArgs e) { - // 检查触摸是否发生在浮动栏区域,如果是则允许事件传播到浮动栏按钮 - var touchPoint = e.GetTouchPoint(this); - var floatingBarBounds = ViewboxFloatingBar.TransformToAncestor(this).TransformBounds( - new Rect(0, 0, ViewboxFloatingBar.ActualWidth, ViewboxFloatingBar.ActualHeight)); - - // 如果触摸发生在浮动栏区域,不阻止事件传播,让浮动栏按钮能够接收触摸事件 - if (floatingBarBounds.Contains(touchPoint.Position)) - { - // 不设置 ViewboxFloatingBar.IsHitTestVisible = false,让浮动栏按钮能够接收触摸事件 - return; - } - - // 橡皮状态下不做任何切换,直接return,保证橡皮可持续 - if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint - || inkCanvas.EditingMode == InkCanvasEditingMode.EraseByStroke) - { - return; - } - if (drawingShapeMode != 0) - { - inkCanvas.EditingMode = InkCanvasEditingMode.None; - SetCursorBasedOnEditingMode(inkCanvas); - inkCanvas.CaptureTouch(e.TouchDevice); - ViewboxFloatingBar.IsHitTestVisible = false; - BlackboardUIGridForInkReplay.IsHitTestVisible = false; - - isTouchDown = true; - - if (dec.Count == 0) - { - var inkTouchPoint = e.GetTouchPoint(inkCanvas); - // 对于双曲线绘制,第一笔时记录起点,第二笔时不更新起点 - if (drawingShapeMode == 24 || drawingShapeMode == 25) - { - // 双曲线绘制:第一笔记录起点,第二笔保持第一笔的起点 - if (drawMultiStepShapeCurrentStep == 0) - { - iniP = inkTouchPoint.Position; - } - // 第二笔时不更新iniP,保持第一笔的起点 - } - else - { - // 其他图形正常记录起点 - iniP = inkTouchPoint.Position; - } - lastTouchDownStrokeCollection = inkCanvas.Strokes.Clone(); - } - dec.Add(e.TouchDevice.Id); - return; - } - - // 非几何绘制模式下的正常触摸处理 - SetCursorBasedOnEditingMode(inkCanvas); inkCanvas.CaptureTouch(e.TouchDevice); ViewboxFloatingBar.IsHitTestVisible = false; BlackboardUIGridForInkReplay.IsHitTestVisible = false; - lastTouchDownTime = DateTime.Now; + dec.Add(e.TouchDevice.Id); - - // Palm Eraser 逻辑 - if (Settings.Canvas.EnablePalmEraser && !isPalmEraserActive) - { - touchPoint = e.GetTouchPoint(inkCanvas); - double boundWidth = GetTouchBoundWidth(e); - - - if ((Settings.Advanced.TouchMultiplier != 0 || !Settings.Advanced.IsSpecialScreen) - && (boundWidth > BoundsWidth)) - { - // 根据敏感度调整阈值倍数 - double thresholdMultiplier; - switch (Settings.Canvas.PalmEraserSensitivity) - { - case 0: // 低敏感度 - thresholdMultiplier = 3.0; - break; - case 1: // 中敏感度 - thresholdMultiplier = 2.5; - break; - case 2: // 高敏感度 - default: - thresholdMultiplier = 2.0; - break; - } - - double EraserThresholdValue = Settings.Startup.IsEnableNibMode ? - Settings.Advanced.NibModeBoundsWidthThresholdValue : - Settings.Advanced.FingerModeBoundsWidthThresholdValue; - - if (boundWidth > BoundsWidth * EraserThresholdValue * thresholdMultiplier) - { - // 记录当前编辑模式和高光状态 - palmEraserLastEditingMode = inkCanvas.EditingMode; - palmEraserLastIsHighlighter = drawingAttributes.IsHighlighter; - - // 动态调整橡皮大小 - boundWidth *= (Settings.Startup.IsEnableNibMode ? - Settings.Advanced.NibModeBoundsWidthEraserSize : - Settings.Advanced.FingerModeBoundsWidthEraserSize); - - if (Settings.Advanced.IsSpecialScreen) - boundWidth *= Settings.Advanced.TouchMultiplier; - inkCanvas.EditingMode = InkCanvasEditingMode.EraseByPoint; - isPalmEraserActive = true; - - // 启用橡皮擦覆盖层显示手掌擦样式 - EnableEraserOverlay(); - // 更新橡皮擦大小以匹配手掌擦面积 - eraserWidth = boundWidth; - UpdateEraserStyle(); - // 显示初始橡皮擦反馈位置 - touchPoint = e.GetTouchPoint(inkCanvas); - EraserOverlay_PointerDown(sender); - EraserOverlay_PointerMove(sender, touchPoint.Position); - if (Settings.Canvas.IsShowCursor) - { - inkCanvas.ForceCursor = false; - inkCanvas.UseCustomCursor = false; - } - } - } - } - - // 设备1个的时候,记录中心点 + //设备1个的时候,记录中心点 if (dec.Count == 1) { - touchPoint = e.GetTouchPoint(inkCanvas); + var touchPoint = e.GetTouchPoint(inkCanvas); centerPoint = touchPoint.Position; - if (drawingShapeMode != 0) - { - // 对于双曲线绘制,第一笔时记录起点,第二笔时不更新起点 - if (drawingShapeMode == 24 || drawingShapeMode == 25) - { - // 双曲线绘制:第一笔记录起点,第二笔保持第一笔的起点 - if (drawMultiStepShapeCurrentStep == 0) - { - iniP = touchPoint.Position; - } - // 第二笔时不更新iniP,保持第一笔的起点 - } - else - { - // 其他图形正常记录起点 - iniP = touchPoint.Position; - } - } - - // 记录第一根手指点击时的 StrokeCollection + //记录第一根手指点击时的 StrokeCollection lastTouchDownStrokeCollection = inkCanvas.Strokes.Clone(); } //设备两个及两个以上,将画笔功能关闭 @@ -744,61 +601,25 @@ namespace Ink_Canvas if (isInMultiTouchMode || !Settings.Gesture.IsEnableTwoFingerGesture) return; if (inkCanvas.EditingMode == InkCanvasEditingMode.None || inkCanvas.EditingMode == InkCanvasEditingMode.Select) return; - var timeSinceLastTouch = (DateTime.Now - lastTouchDownTime).TotalMilliseconds; - if (timeSinceLastTouch < MULTI_TOUCH_DELAY_MS && inkCanvas.EditingMode == InkCanvasEditingMode.Ink) - { - if (!isMultiTouchTimerActive) - { - isMultiTouchTimerActive = true; - var remainingTime = MULTI_TOUCH_DELAY_MS - timeSinceLastTouch; - System.Threading.Tasks.Task.Delay((int)remainingTime).ContinueWith(_ => - { - Dispatcher.Invoke(() => - { - if (dec.Count > 1 && inkCanvas.EditingMode == InkCanvasEditingMode.Ink) - { - inkCanvas.EditingMode = InkCanvasEditingMode.None; - } - isMultiTouchTimerActive = false; - }); - }); - } - return; - } - lastInkCanvasEditingMode = inkCanvas.EditingMode; - if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint - && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke - && drawingShapeMode == 0) - { - inkCanvas.EditingMode = InkCanvasEditingMode.None; - } + inkCanvas.EditingMode = InkCanvasEditingMode.None; } } private void inkCanvas_PreviewTouchMove(object sender, TouchEventArgs e) { - - // 如果手掌擦激活,更新橡皮擦反馈位置 - if (isPalmEraserActive) - { - var touchPoint = e.GetTouchPoint(inkCanvas); - EraserOverlay_PointerMove(sender, touchPoint.Position); - } } private void inkCanvas_PreviewTouchUp(object sender, TouchEventArgs e) { - // 橡皮状态下不做任何切换,直接return,保证橡皮可持续 - if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint && !isPalmEraserActive) - { - return; - } inkCanvas.ReleaseAllTouchCaptures(); ViewboxFloatingBar.IsHitTestVisible = true; BlackboardUIGridForInkReplay.IsHitTestVisible = true; - // Palm Eraser 逻辑 + //手势完成后切回之前的状态 + if (dec.Count > 1) + if (inkCanvas.EditingMode == InkCanvasEditingMode.None) + inkCanvas.EditingMode = lastInkCanvasEditingMode; dec.Remove(e.TouchDevice.Id); // 重置多触控点定时器状态 @@ -807,17 +628,30 @@ namespace Ink_Canvas isMultiTouchTimerActive = false; } + if (dec.Count == 0) + { + isSingleFingerDragMode = false; + if (drawingShapeMode == 0 + && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint + && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke + && inkCanvas.EditingMode != InkCanvasEditingMode.Select + && inkCanvas.EditingMode != InkCanvasEditingMode.None) + { + if (lastInkCanvasEditingMode != InkCanvasEditingMode.None) + { + inkCanvas.EditingMode = lastInkCanvasEditingMode; + } + } + } + if (drawingShapeMode != 0) { isTouchDown = false; ViewboxFloatingBar.IsHitTestVisible = true; BlackboardUIGridForInkReplay.IsHitTestVisible = true; - // 对于双曲线等需要多步绘制的图形,触摸抬手时应该进入下一步 if (drawingShapeMode == 24 || drawingShapeMode == 25) { - // 双曲线绘制:触摸抬手时进入下一步,但不自动触发鼠标抬起事件 - // 让用户继续绘制第二笔 if (drawMultiStepShapeCurrentStep == 0) { // 第一笔完成,进入第二笔 @@ -836,7 +670,6 @@ namespace Ink_Canvas } else { - // 其他单步绘制的图形,触摸抬手时完成绘制 var mouseArgs = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = MouseLeftButtonUpEvent, @@ -846,82 +679,6 @@ namespace Ink_Canvas } } - // 手势完成后切回之前的状态 - if (drawingShapeMode == 0) - { - if (dec.Count > 1) - { - if (inkCanvas.EditingMode == InkCanvasEditingMode.None) - { - if (lastInkCanvasEditingMode != InkCanvasEditingMode.EraseByPoint) - { - inkCanvas.EditingMode = lastInkCanvasEditingMode; - } - } - } - else if (dec.Count == 0) - { - // 当所有触摸点都抬起时,确保正确恢复编辑模式 - // 这对于从橡皮擦切换到笔后恢复多指手势功能很重要 - if (inkCanvas.EditingMode == InkCanvasEditingMode.None && - lastInkCanvasEditingMode != InkCanvasEditingMode.None && - lastInkCanvasEditingMode != InkCanvasEditingMode.EraseByPoint) - { - inkCanvas.EditingMode = lastInkCanvasEditingMode; - } - - if (isPalmEraserActive) - { - LogHelper.WriteLogToFile("Palm eraser force recovery - all touch points cleared"); - - // 恢复高光状态 - drawingAttributes.IsHighlighter = palmEraserLastIsHighlighter; - - // 恢复编辑模式 - try - { - if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint) - { - switch (palmEraserLastEditingMode) - { - case InkCanvasEditingMode.Ink: - PenIcon_Click(null, null); - break; - case InkCanvasEditingMode.Select: - SymbolIconSelect_MouseUp(null, null); - break; - default: - inkCanvas.EditingMode = palmEraserLastEditingMode; - break; - } - LogHelper.WriteLogToFile($"Palm eraser force recovered to mode: {palmEraserLastEditingMode}"); - } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"Palm eraser force recovery failed: {ex.Message}, forcing to Ink mode", LogHelper.LogType.Error); - inkCanvas.EditingMode = InkCanvasEditingMode.Ink; - } - - // 如果手掌擦还在激活状态但触摸点已清空,强制重置状态 - isPalmEraserActive = false; - inkCanvas.IsHitTestVisible = true; - inkCanvas.IsManipulationEnabled = true; - - ViewboxFloatingBar.IsHitTestVisible = true; - BlackboardUIGridForInkReplay.IsHitTestVisible = true; - - DisableEraserOverlay(); - if (Settings.Canvas.IsShowCursor) - { - inkCanvas.ForceCursor = true; - inkCanvas.UseCustomCursor = true; - } - - LogHelper.WriteLogToFile("Palm eraser force recovery completed"); - } - } - } inkCanvas.Opacity = 1; if (dec.Count == 0) @@ -943,61 +700,37 @@ namespace Ink_Canvas private void Main_Grid_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { - if (e.Manipulators.Count() != 0) return; - if (drawingShapeMode == 0 - && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint - && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke - && inkCanvas.EditingMode != InkCanvasEditingMode.Select) + if (e.Manipulators.Count() == 0) { - inkCanvas.EditingMode = InkCanvasEditingMode.Ink; - lastInkCanvasEditingMode = InkCanvasEditingMode.Ink; + if (dec.Count > 0) + { + dec.Clear(); + } + isSingleFingerDragMode = false; + + if (drawingShapeMode == 0 + && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint + && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke + && inkCanvas.EditingMode != InkCanvasEditingMode.Select) + { + inkCanvas.EditingMode = InkCanvasEditingMode.Ink; + lastInkCanvasEditingMode = InkCanvasEditingMode.Ink; + } } } private void Main_Grid_ManipulationDelta(object sender, ManipulationDeltaEventArgs e) { - // 手掌擦时禁止移动/缩放 - if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint) - return; - // 三指及以上禁止缩放 - bool disableScale = dec.Count >= 3; - - if (isInMultiTouchMode) return; - - if (dec.Count == 0 && (isSingleFingerDragMode || isInMultiTouchMode)) - { - ResetTouchStates(); - return; - } - - // 如果是单指拖动选中的墨迹,允许处理 - if (dec.Count == 1 && inkCanvas.GetSelectedStrokes().Count > 0) - { - var md = e.DeltaManipulation; - var trans = md.Translation; // 获得位移矢量 - - if (trans.X != 0 || trans.Y != 0) - { - var m = new Matrix(); - m.Translate(trans.X, trans.Y); // 移动 - - var strokes = inkCanvas.GetSelectedStrokes(); - foreach (var stroke in strokes) - { - stroke.Transform(m, false); - } - - // 更新选择框位置 - updateBorderStrokeSelectionControlLocation(); - } - return; - } - - if (!Settings.Gesture.IsEnableTwoFingerGesture) return; - if ((dec.Count >= 2 && (Settings.PowerPointSettings.IsEnableTwoFingerGestureInPresentationMode || - StackPanelPPTControls.Visibility != Visibility.Visible || - StackPanelPPTButtons.Visibility == Visibility.Collapsed)) || - isSingleFingerDragMode) + if (isInMultiTouchMode || !Settings.Gesture.IsEnableTwoFingerGesture) return; + + bool hasMultipleManipulators = e.Manipulators.Count() >= 2; + bool shouldUseTwoFingerGesture = (dec.Count >= 2 && hasMultipleManipulators && + (Settings.PowerPointSettings.IsEnableTwoFingerGestureInPresentationMode || + StackPanelPPTControls.Visibility != Visibility.Visible || + StackPanelPPTButtons.Visibility == Visibility.Collapsed)) || + isSingleFingerDragMode; + + if (shouldUseTwoFingerGesture) { var md = e.DeltaManipulation; var trans = md.Translation; // 获得位移矢量 @@ -1007,20 +740,23 @@ namespace Ink_Canvas if (Settings.Gesture.IsEnableTwoFingerTranslate) m.Translate(trans.X, trans.Y); // 移动 + // 计算中心点(用于缩放和旋转) + var fe = e.Source as FrameworkElement; + var center = new Point(fe.ActualWidth / 2, fe.ActualHeight / 2); + center = m.Transform(center); // 转换为矩阵缩放和旋转的中心点 + if (Settings.Gesture.IsEnableTwoFingerGestureTranslateOrRotation) { var rotate = md.Rotation; // 获得旋转角度 - var scale = md.Scale; // 获得缩放倍数 - - // Find center of element and then transform to get current location of center - var fe = e.Source as FrameworkElement; - var center = new Point(fe.ActualWidth / 2, fe.ActualHeight / 2); - center = m.Transform(center); // 转换为矩阵缩放和旋转的中心点 if (Settings.Gesture.IsEnableTwoFingerRotation) m.RotateAt(rotate, center.X, center.Y); // 旋转 - if (Settings.Gesture.IsEnableTwoFingerZoom && !disableScale) - m.ScaleAt(scale.X, scale.Y, center.X, center.Y); // 缩放 + } + + if (Settings.Gesture.IsEnableTwoFingerZoom) + { + var scale = md.Scale; // 获得缩放倍数 + m.ScaleAt(scale.X, scale.Y, center.X, center.Y); // 缩放 } var strokes = inkCanvas.GetSelectedStrokes(); @@ -1043,6 +779,13 @@ namespace Ink_Canvas break; } + if (!Settings.Gesture.IsEnableTwoFingerZoom) continue; + try + { + stroke.DrawingAttributes.Width *= md.Scale.X; + stroke.DrawingAttributes.Height *= md.Scale.Y; + } + catch { } } } else @@ -1165,69 +908,6 @@ namespace Ink_Canvas LogHelper.WriteLogToFile($"应用媒体元素变换失败: {ex.Message}", LogHelper.LogType.Error); } } - - // 退出多指书写模式,恢复InkCanvas的TouchDown事件绑定 - private void ExitMultiTouchModeIfNeeded() - { - if (isInMultiTouchMode) - { - inkCanvas.StylusDown -= MainWindow_StylusDown; - inkCanvas.StylusMove -= MainWindow_StylusMove; - inkCanvas.StylusUp -= MainWindow_StylusUp; - inkCanvas.TouchDown -= MainWindow_TouchDown; - inkCanvas.TouchDown += Main_Grid_TouchDown; - if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint - && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke - && drawingShapeMode == 0) - { - inkCanvas.EditingMode = InkCanvasEditingMode.Ink; - } - // 保存非笔画元素(如图片) - var preservedElements = PreserveNonStrokeElements(); - inkCanvas.Children.Clear(); - // 恢复非笔画元素 - RestoreNonStrokeElements(preservedElements); - isInMultiTouchMode = false; - // 关闭多指书写时,恢复手掌擦开关 - if (palmEraserWasEnabledBeforeMultiTouch) - { - Settings.Canvas.EnablePalmEraser = true; - if (ToggleSwitchEnablePalmEraser != null) - ToggleSwitchEnablePalmEraser.IsOn = true; - } - } - } - - // 进入多指书写模式,绑定Main_Grid_TouchDown - private void EnterMultiTouchModeIfNeeded() - { - if (!isInMultiTouchMode) - { - inkCanvas.StylusDown += MainWindow_StylusDown; - inkCanvas.StylusMove += MainWindow_StylusMove; - inkCanvas.StylusUp += MainWindow_StylusUp; - inkCanvas.TouchDown += MainWindow_TouchDown; - inkCanvas.TouchDown -= Main_Grid_TouchDown; - if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint - && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke - && drawingShapeMode == 0) - { - inkCanvas.EditingMode = InkCanvasEditingMode.None; - } - // 保存非笔画元素(如图片) - var preservedElements = PreserveNonStrokeElements(); - inkCanvas.Children.Clear(); - // 恢复非笔画元素 - RestoreNonStrokeElements(preservedElements); - isInMultiTouchMode = true; - // 启用多指书写时,自动禁用手掌擦 - palmEraserWasEnabledBeforeMultiTouch = Settings.Canvas.EnablePalmEraser; - Settings.Canvas.EnablePalmEraser = false; - if (ToggleSwitchEnablePalmEraser != null) - ToggleSwitchEnablePalmEraser.IsOn = false; - } - } - - } } + diff --git a/Ink Canvas/Resources/Settings.cs b/Ink Canvas/Resources/Settings.cs index 5ef12f77..27a54c41 100644 --- a/Ink Canvas/Resources/Settings.cs +++ b/Ink Canvas/Resources/Settings.cs @@ -602,6 +602,9 @@ namespace Ink_Canvas [JsonProperty("enableUIAccessTopMost")] public bool EnableUIAccessTopMost { get; set; } = false; + + [JsonProperty("windowMode")] + public bool WindowMode { get; set; } = true; } public class InkToShape diff --git a/Ink Canvas/Windows/NewStyleRollCallWindow.cs b/Ink Canvas/Windows/NewStyleRollCallWindow.cs index adc03650..ae7a5042 100644 --- a/Ink Canvas/Windows/NewStyleRollCallWindow.cs +++ b/Ink Canvas/Windows/NewStyleRollCallWindow.cs @@ -598,13 +598,52 @@ namespace Ink_Canvas historyData.NameProbabilities = new Dictionary(); } + // 过滤掉已选择的人员 + var candidateNames = availableNames.Where(name => !alreadySelected.Contains(name)).ToList(); + if (candidateNames.Count == 0) return null; + if (candidateNames.Count == 1) return candidateNames[0]; + + // 检查极差:当极差达到3时,从被抽选次数最少的人中抽选 + if (historyData.NameFrequency != null && historyData.NameFrequency.Count > 0) + { + // 获取所有候选人员的被抽选次数 + var candidateFrequencies = new Dictionary(); + foreach (string name in candidateNames) + { + int count = historyData.NameFrequency.ContainsKey(name) ? historyData.NameFrequency[name] : 0; + candidateFrequencies[name] = count; + } + + // 计算极差(最大值 - 最小值) + if (candidateFrequencies.Count > 0) + { + int maxCount = candidateFrequencies.Values.Max(); + int minCount = candidateFrequencies.Values.Min(); + int range = maxCount - minCount; + + // 当极差达到3时,只从被抽选次数最少的人中抽选 + if (range >= 3) + { + var leastSelectedNames = candidateFrequencies + .Where(kvp => kvp.Value == minCount) + .Select(kvp => kvp.Key) + .ToList(); + + if (leastSelectedNames.Count > 0) + { + // 只从被抽选次数最少的人中随机选择 + int randomIndex = random.Next(0, leastSelectedNames.Count); + return leastSelectedNames[randomIndex]; + } + } + } + } + // 获取每个人员的概率 var nameProbabilities = new Dictionary(); - foreach (string name in availableNames) + foreach (string name in candidateNames) { - if (alreadySelected.Contains(name)) continue; - // 获取基础概率 double baseProbability = GetNameProbability(name); diff --git a/Ink Canvas/Windows/TimerControl.xaml.cs b/Ink Canvas/Windows/TimerControl.xaml.cs index 4ea97948..857dd325 100644 --- a/Ink Canvas/Windows/TimerControl.xaml.cs +++ b/Ink Canvas/Windows/TimerControl.xaml.cs @@ -70,7 +70,7 @@ namespace Ink_Canvas.Windows } /// - /// 刷新主题(供外部调用) + /// 刷新主题 /// public void RefreshTheme() { @@ -1505,6 +1505,72 @@ namespace Ink_Canvas.Windows private void HandleTimerCompletion() { + // 计时器结束时,如果显示的是最小化视图,恢复到主窗口视图 + Application.Current.Dispatcher.Invoke(() => + { + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow != null) + { + var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement; + var minimizedContainer = mainWindow.FindName("MinimizedTimerContainer") as FrameworkElement; + + // 如果最小化视图可见,恢复到主窗口视图 + if (minimizedContainer != null && minimizedContainer.Visibility == Visibility.Visible) + { + HideMinimizedRequested?.Invoke(this, EventArgs.Empty); + } + } + }); + + // 重置计时器状态 + ResetTimerState(); + } + + /// + /// 重置计时器状态 + /// + public void ResetTimerState() + { + Application.Current.Dispatcher.Invoke(() => + { + // 停止计时器 + if (isTimerRunning) + { + timer.Stop(); + isTimerRunning = false; + isPaused = false; + + if (hideTimer != null) + { + hideTimer.Stop(); + } + } + + // 重置时间到默认值 + hour = 0; + minute = 5; + second = 0; + + // 更新显示 + UpdateDigitDisplays(); + SetColonDisplay(false); + + // 重置图标 + if (StartPauseIcon != null) + { + StartPauseIcon.Data = Geometry.Parse(PlayIconData); + } + + // 重置状态标志 + isOvertimeMode = false; + hasPlayedProgressiveReminder = false; + + // 禁用全屏按钮 + if (FullscreenBtn != null) + { + FullscreenBtn.IsEnabled = false; + } + }); } private void HideTimer_Elapsed(object sender, ElapsedEventArgs e)