Files
community/Ink Canvas/MainWindow.xaml.cs
T

1015 lines
45 KiB
C#
Raw Normal View History

2025-05-25 09:29:48 +08:00
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern;
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Media;
using System.Diagnostics;
using File = System.IO.File;
using MessageBox = System.Windows.MessageBox;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Windows.Controls.Primitives;
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32;
2025-06-11 15:09:34 +08:00
using System.Windows.Input;
2025-06-18 09:08:38 +08:00
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media.Animation;
using System.Reflection;
2025-07-15 21:10:49 +08:00
using Point = System.Windows.Point;
2025-05-25 09:29:48 +08:00
namespace Ink_Canvas {
public partial class MainWindow : Window {
#region Window Initialization
public MainWindow() {
/*
处于画板模式内:Topmost == false / currentMode != 0
处于 PPT 放映内:BtnPPTSlideShowEnd.Visibility
*/
InitializeComponent();
BlackboardLeftSide.Visibility = Visibility.Collapsed;
BlackboardCenterSide.Visibility = Visibility.Collapsed;
BlackboardRightSide.Visibility = Visibility.Collapsed;
BorderTools.Visibility = Visibility.Collapsed;
BorderSettings.Visibility = Visibility.Collapsed;
LeftSidePanelForPPTNavigation.Visibility = Visibility.Collapsed;
RightSidePanelForPPTNavigation.Visibility = Visibility.Collapsed;
BorderSettings.Margin = new Thickness(0, 0, 0, 0);
TwoFingerGestureBorder.Visibility = Visibility.Collapsed;
BoardTwoFingerGestureBorder.Visibility = Visibility.Collapsed;
BorderDrawShape.Visibility = Visibility.Collapsed;
BoardBorderDrawShape.Visibility = Visibility.Collapsed;
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
//if (!App.StartArgs.Contains("-o"))
ViewBoxStackPanelMain.Visibility = Visibility.Collapsed;
ViewBoxStackPanelShapes.Visibility = Visibility.Collapsed;
2025-06-06 16:09:28 +08:00
var workingArea = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea;
ViewboxFloatingBar.Margin = new Thickness(
(workingArea.Width - 284) / 2,
workingArea.Bottom - 60 - workingArea.Top,
-2000, -200);
2025-05-25 09:29:48 +08:00
ViewboxFloatingBarMarginAnimation(100, true);
try {
if (File.Exists("debug.ini")) Label.Visibility = Visibility.Visible;
}
catch (Exception ex) {
LogHelper.WriteLogToFile(ex.ToString(), LogHelper.LogType.Error);
}
try {
if (File.Exists("Log.txt")) {
var fileInfo = new FileInfo("Log.txt");
var fileSizeInKB = fileInfo.Length / 1024;
if (fileSizeInKB > 512)
try {
File.Delete("Log.txt");
LogHelper.WriteLogToFile(
"The Log.txt file has been successfully deleted. Original file size: " + fileSizeInKB +
" KB", LogHelper.LogType.Info);
}
catch (Exception ex) {
LogHelper.WriteLogToFile(
ex + " | Can not delete the Log.txt file. File size: " + fileSizeInKB + " KB",
LogHelper.LogType.Error);
}
}
}
catch (Exception ex) {
LogHelper.WriteLogToFile(ex.ToString(), LogHelper.LogType.Error);
}
InitTimers();
timeMachine.OnRedoStateChanged += TimeMachine_OnRedoStateChanged;
timeMachine.OnUndoStateChanged += TimeMachine_OnUndoStateChanged;
inkCanvas.Strokes.StrokesChanged += StrokesOnStrokesChanged;
Microsoft.Win32.SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;
try {
if (File.Exists("SpecialVersion.ini")) SpecialVersionResetToSuggestion_Click();
}
catch (Exception ex) {
LogHelper.WriteLogToFile(ex.ToString(), LogHelper.LogType.Error);
}
CheckColorTheme(true);
CheckPenTypeUIState();
2025-06-12 11:21:45 +08:00
// 注册输入事件
inkCanvas.PreviewMouseDown += inkCanvas_PreviewMouseDown;
inkCanvas.StylusDown += inkCanvas_StylusDown;
inkCanvas.TouchDown += inkCanvas_TouchDown;
inkCanvas.TouchUp += inkCanvas_TouchUp;
2025-05-25 09:29:48 +08:00
}
#endregion
#region Ink Canvas Functions
private System.Windows.Media.Color Ink_DefaultColor = Colors.Red;
private DrawingAttributes drawingAttributes;
private void loadPenCanvas() {
try {
//drawingAttributes = new DrawingAttributes();
drawingAttributes = inkCanvas.DefaultDrawingAttributes;
drawingAttributes.Color = Ink_DefaultColor;
drawingAttributes.Height = 2.5;
drawingAttributes.Width = 2.5;
drawingAttributes.IsHighlighter = false;
drawingAttributes.FitToCurve = Settings.Canvas.FitToCurve;
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
inkCanvas.Gesture += InkCanvas_Gesture;
}
catch { }
}
//ApplicationGesture lastApplicationGesture = ApplicationGesture.AllGestures;
private DateTime lastGestureTime = DateTime.Now;
private void InkCanvas_Gesture(object sender, InkCanvasGestureEventArgs e) {
var gestures = e.GetGestureRecognitionResults();
try {
foreach (var gest in gestures)
//Trace.WriteLine(string.Format("Gesture: {0}, Confidence: {1}", gest.ApplicationGesture, gest.RecognitionConfidence));
if (StackPanelPPTControls.Visibility == Visibility.Visible) {
if (gest.ApplicationGesture == ApplicationGesture.Left)
BtnPPTSlidesDown_Click(BtnPPTSlidesDown, null);
if (gest.ApplicationGesture == ApplicationGesture.Right)
BtnPPTSlidesUp_Click(BtnPPTSlidesUp, null);
}
}
catch { }
}
private void inkCanvas_EditingModeChanged(object sender, RoutedEventArgs e) {
var inkCanvas1 = sender as InkCanvas;
if (inkCanvas1 == null) return;
2025-06-18 09:08:38 +08:00
// 使用辅助方法设置光标
SetCursorBasedOnEditingMode(inkCanvas1);
2025-05-25 09:29:48 +08:00
if (inkCanvas1.EditingMode == InkCanvasEditingMode.Ink) forcePointEraser = !forcePointEraser;
}
#endregion Ink Canvas
#region Definations and Loading
public static Settings Settings = new Settings();
public static string settingsFileName = "Settings.json";
private bool isLoaded = false;
private void Window_Loaded(object sender, RoutedEventArgs e) {
loadPenCanvas();
//加载设置
LoadSettings(true);
2025-07-15 21:10:49 +08:00
// 注册设置面板滚动事件
if (SettingsPanelScrollViewer != null)
{
SettingsPanelScrollViewer.ScrollChanged += SettingsPanelScrollViewer_ScrollChanged;
}
2025-05-25 09:29:48 +08:00
// HasNewUpdateWindow hasNewUpdateWindow = new HasNewUpdateWindow();
if (Environment.Is64BitProcess) GroupBoxInkRecognition.Visibility = Visibility.Collapsed;
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Light;
SystemEvents_UserPreferenceChanged(null, null);
//TextBlockVersion.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString();
LogHelper.WriteLogToFile("Ink Canvas Loaded", LogHelper.LogType.Event);
isLoaded = true;
BlackBoardLeftSidePageListView.ItemsSource = blackBoardSidePageListViewObservableCollection;
BlackBoardRightSidePageListView.ItemsSource = blackBoardSidePageListViewObservableCollection;
BtnLeftWhiteBoardSwitchPreviousGeometry.Brush =
new SolidColorBrush(System.Windows.Media.Color.FromArgb(127, 24, 24, 27));
BtnLeftWhiteBoardSwitchPreviousLabel.Opacity = 0.5;
BtnRightWhiteBoardSwitchPreviousGeometry.Brush =
new SolidColorBrush(System.Windows.Media.Color.FromArgb(127, 24, 24, 27));
BtnRightWhiteBoardSwitchPreviousLabel.Opacity = 0.5;
BtnWhiteBoardSwitchPrevious.IsEnabled = CurrentWhiteboardIndex != 1;
BorderInkReplayToolBox.Visibility = Visibility.Collapsed;
// 提前加载IA库,优化第一笔等待时间
if (Settings.InkToShape.IsInkToShapeEnabled && !Environment.Is64BitProcess) {
var strokeEmpty = new StrokeCollection();
InkRecognizeHelper.RecognizeShape(strokeEmpty);
}
SystemEvents.DisplaySettingsChanged += SystemEventsOnDisplaySettingsChanged;
2025-05-31 21:13:02 +08:00
// 自动收纳到侧边栏
if (Settings.Startup.IsFoldAtStartup)
{
2025-06-29 15:07:13 +08:00
FoldFloatingBar_MouseUp(new object(), null);
2025-05-31 21:13:02 +08:00
}
2025-06-12 10:13:47 +08:00
// 恢复崩溃后操作设置
if (App.CrashAction == App.CrashActionType.SilentRestart)
RadioCrashSilentRestart.IsChecked = true;
else
RadioCrashNoAction.IsChecked = true;
2025-07-15 18:09:38 +08:00
// 注册系统关机事件处理
RegisterShutdownHandler();
2025-05-25 09:29:48 +08:00
}
private void SystemEventsOnDisplaySettingsChanged(object sender, EventArgs e) {
if (!Settings.Advanced.IsEnableResolutionChangeDetection) return;
2025-07-15 20:30:10 +08:00
ShowNotification($"检测到显示器信息变化,变为{System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width}x{System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height}");
2025-05-25 09:29:48 +08:00
new Thread(() => {
var isFloatingBarOutsideScreen = false;
var isInPPTPresentationMode = false;
Dispatcher.Invoke(() => {
isFloatingBarOutsideScreen = IsOutsideOfScreenHelper.IsOutsideOfScreen(ViewboxFloatingBar);
isInPPTPresentationMode = BtnPPTSlideShowEnd.Visibility == Visibility.Visible;
});
if (isFloatingBarOutsideScreen) dpiChangedDelayAction.DebounceAction(3000, null, () => {
if (!isFloatingBarFolded)
{
if (isInPPTPresentationMode) ViewboxFloatingBarMarginAnimation(60);
else ViewboxFloatingBarMarginAnimation(100, true);
}
});
}).Start();
}
public DelayAction dpiChangedDelayAction = new DelayAction();
private void MainWindow_OnDpiChanged(object sender, DpiChangedEventArgs e)
{
if (e.OldDpi.DpiScaleX != e.NewDpi.DpiScaleX && e.OldDpi.DpiScaleY != e.NewDpi.DpiScaleY && Settings.Advanced.IsEnableDPIChangeDetection)
{
ShowNotification($"系统DPI发生变化,从 {e.OldDpi.DpiScaleX}x{e.OldDpi.DpiScaleY} 变化为 {e.NewDpi.DpiScaleX}x{e.NewDpi.DpiScaleY}");
new Thread(() => {
var isFloatingBarOutsideScreen = false;
var isInPPTPresentationMode = false;
Dispatcher.Invoke(() => {
isFloatingBarOutsideScreen = IsOutsideOfScreenHelper.IsOutsideOfScreen(ViewboxFloatingBar);
isInPPTPresentationMode = BtnPPTSlideShowEnd.Visibility == Visibility.Visible;
});
if (isFloatingBarOutsideScreen) dpiChangedDelayAction.DebounceAction(3000,null, () => {
if (!isFloatingBarFolded)
{
if (isInPPTPresentationMode) ViewboxFloatingBarMarginAnimation(60);
else ViewboxFloatingBarMarginAnimation(100, true);
}
});
}).Start();
}
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
LogHelper.WriteLogToFile("Ink Canvas closing", LogHelper.LogType.Event);
if (!CloseIsFromButton && Settings.Advanced.IsSecondConfirmWhenShutdownApp) {
e.Cancel = true;
if (MessageBox.Show("是否继续关闭 InkCanvasForClass,这将丢失当前未保存的墨迹。", "InkCanvasForClass",
MessageBoxButton.OKCancel, MessageBoxImage.Warning) == MessageBoxResult.OK)
if (MessageBox.Show("真的狠心关闭 InkCanvasForClass吗?", "InkCanvasForClass", MessageBoxButton.OKCancel,
MessageBoxImage.Error) == MessageBoxResult.OK)
if (MessageBox.Show("是否取消关闭 InkCanvasForClass", "InkCanvasForClass", MessageBoxButton.OKCancel,
MessageBoxImage.Error) != MessageBoxResult.OK)
e.Cancel = false;
}
if (e.Cancel) LogHelper.WriteLogToFile("Ink Canvas closing cancelled", LogHelper.LogType.Event);
}
[DllImport("user32.dll", SetLastError = true)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
2025-06-13 09:19:44 +08:00
private void MainWindow_OnSizeChanged(object sender, SizeChangedEventArgs e) {
2025-05-25 09:29:48 +08:00
if (Settings.Advanced.IsEnableForceFullScreen) {
if (isLoaded) ShowNotification(
$"检测到窗口大小变化,已自动恢复到全屏:{System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width}x{System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height}(缩放比例为{System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width / SystemParameters.PrimaryScreenWidth}x{System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height / SystemParameters.PrimaryScreenHeight}");
WindowState = WindowState.Maximized;
MoveWindow(new WindowInteropHelper(this).Handle, 0, 0,
System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width,
System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height, true);
}
}
2025-06-06 16:09:28 +08:00
2025-05-25 09:29:48 +08:00
private void Window_Closed(object sender, EventArgs e) {
SystemEvents.DisplaySettingsChanged -= SystemEventsOnDisplaySettingsChanged;
LogHelper.WriteLogToFile("Ink Canvas closed", LogHelper.LogType.Event);
// 检查是否有待安装的更新
CheckPendingUpdates();
}
private void CheckPendingUpdates()
{
try
{
// 如果有可用的更新版本且启用了自动更新
if (AvailableLatestVersion != null && Settings.Startup.IsAutoUpdate)
{
// 检查更新文件是否已下载
string updatesFolderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "AutoUpdate");
string statusFilePath = Path.Combine(updatesFolderPath, $"DownloadV{AvailableLatestVersion}Status.txt");
if (File.Exists(statusFilePath) && File.ReadAllText(statusFilePath).Trim().ToLower() == "true")
{
LogHelper.WriteLogToFile($"AutoUpdate | Installing pending update v{AvailableLatestVersion} on application close");
// 设置为用户主动退出,避免被看门狗判定为崩溃
App.IsAppExitByUser = true;
// 创建批处理脚本并启动,软件关闭后会执行更新操作
AutoUpdateHelper.InstallNewVersionApp(AvailableLatestVersion, true);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"AutoUpdate | Error checking pending updates: {ex.Message}", LogHelper.LogType.Error);
}
2025-05-25 09:29:48 +08:00
}
private async void AutoUpdate() {
2025-06-29 11:56:38 +08:00
// 使用当前选择的更新通道检查更新
AvailableLatestVersion = await AutoUpdateHelper.CheckForUpdates(null, Settings.Startup.UpdateChannel);
// 声明下载状态变量,用于整个方法
bool isDownloadSuccessful = false;
2025-05-25 09:29:48 +08:00
if (AvailableLatestVersion != null) {
2025-06-29 11:56:38 +08:00
// 检测到新版本
LogHelper.WriteLogToFile($"AutoUpdate | New version available: {AvailableLatestVersion}");
2025-06-29 11:56:38 +08:00
// 检查是否是用户选择跳过的版本
if (!string.IsNullOrEmpty(Settings.Startup.SkippedVersion) &&
Settings.Startup.SkippedVersion == AvailableLatestVersion) {
LogHelper.WriteLogToFile($"AutoUpdate | Version {AvailableLatestVersion} was marked to be skipped by the user");
return; // 跳过此版本,不执行更新操作
}
// 如果检测到的版本与跳过的版本不同,则清除跳过版本记录
// 这确保用户只能跳过当前最新版本,而不是永久跳过所有更新
if (!string.IsNullOrEmpty(Settings.Startup.SkippedVersion) &&
Settings.Startup.SkippedVersion != AvailableLatestVersion) {
LogHelper.WriteLogToFile($"AutoUpdate | Detected new version {AvailableLatestVersion} different from skipped version {Settings.Startup.SkippedVersion}, clearing skip record");
Settings.Startup.SkippedVersion = "";
SaveSettingsToFile();
}
// 获取当前版本
string currentVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
2025-06-29 11:56:38 +08:00
// 如果启用了静默更新,则自动下载更新而不显示提示
if (Settings.Startup.IsAutoUpdateWithSilence) {
LogHelper.WriteLogToFile("AutoUpdate | Silent update enabled, downloading update automatically without notification");
// 静默下载更新,传递当前选择的更新通道
isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFileAndSaveStatus(AvailableLatestVersion, "", Settings.Startup.UpdateChannel);
if (isDownloadSuccessful) {
LogHelper.WriteLogToFile("AutoUpdate | Update downloaded successfully, will install when conditions are met");
// 启动检查定时器,定期检查是否可以安装
timerCheckAutoUpdateWithSilence.Start();
} else {
LogHelper.WriteLogToFile("AutoUpdate | Silent update download failed", LogHelper.LogType.Error);
}
return;
}
// 如果没有启用静默更新,则显示常规更新窗口
string releaseDate = DateTime.Now.ToString("yyyy年MM月dd日");
2025-06-29 11:56:38 +08:00
// 从服务器获取更新日志
string releaseNotes = await AutoUpdateHelper.GetUpdateLog(Settings.Startup.UpdateChannel);
2025-06-29 11:56:38 +08:00
// 如果获取失败,使用默认文本
if (string.IsNullOrEmpty(releaseNotes))
{
releaseNotes = $@"# InkCanvasForClass v{AvailableLatestVersion}更新
2025-06-29 14:15:20 +08:00
2025-06-29 11:56:38 +08:00
无法获取更新日志,但新版本已准备就绪。";
}
// 创建并显示更新窗口
HasNewUpdateWindow updateWindow = new HasNewUpdateWindow(currentVersion, AvailableLatestVersion, releaseDate, releaseNotes);
bool? dialogResult = updateWindow.ShowDialog();
2025-06-29 11:56:38 +08:00
// 如果窗口被关闭但没有点击按钮,则不执行任何操作
if (dialogResult != true) {
LogHelper.WriteLogToFile("AutoUpdate | Update dialog closed without selection");
return;
}
2025-06-29 11:56:38 +08:00
// 不再从更新窗口获取自动更新设置
// 根据用户选择处理更新
switch (updateWindow.Result) {
case HasNewUpdateWindow.UpdateResult.UpdateNow:
// 立即更新:显示下载进度,下载完成后立即安装
LogHelper.WriteLogToFile("AutoUpdate | User chose to update now");
// 显示下载进度提示
MessageBox.Show("开始下载更新,请稍候...", "正在更新", MessageBoxButton.OK, MessageBoxImage.Information);
2025-06-29 11:56:38 +08:00
// 下载更新文件,传递当前选择的更新通道
isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFileAndSaveStatus(AvailableLatestVersion, "", Settings.Startup.UpdateChannel);
if (isDownloadSuccessful) {
// 下载成功,提示用户准备安装
MessageBoxResult result = MessageBox.Show("更新已下载完成,点击确定后将关闭软件并安装新版本!", "安装更新", MessageBoxButton.OKCancel, MessageBoxImage.Information);
// 只有当用户点击确定按钮后才关闭软件
if (result == MessageBoxResult.OK) {
// 设置为用户主动退出,避免被看门狗判定为崩溃
App.IsAppExitByUser = true;
// 准备批处理脚本
2025-06-18 22:40:48 +08:00
AutoUpdateHelper.InstallNewVersionApp(AvailableLatestVersion, false);
// 关闭软件,让安装程序接管
Application.Current.Shutdown();
} else {
LogHelper.WriteLogToFile("AutoUpdate | User cancelled update installation");
}
} else {
// 下载失败
MessageBox.Show("更新下载失败,请检查网络连接后重试。", "下载失败", MessageBoxButton.OK, MessageBoxImage.Error);
}
break;
case HasNewUpdateWindow.UpdateResult.UpdateLater:
// 稍后更新:静默下载,在软件关闭时自动安装
LogHelper.WriteLogToFile("AutoUpdate | User chose to update later");
// 不管设置如何,都进行下载
2025-06-29 11:56:38 +08:00
isDownloadSuccessful = await AutoUpdateHelper.DownloadSetupFileAndSaveStatus(AvailableLatestVersion, "", Settings.Startup.UpdateChannel);
if (isDownloadSuccessful) {
LogHelper.WriteLogToFile("AutoUpdate | Update downloaded successfully, will install when application closes");
// 设置标志,在应用程序关闭时安装
Settings.Startup.IsAutoUpdate = true;
Settings.Startup.IsAutoUpdateWithSilence = true;
// 启动检查定时器
timerCheckAutoUpdateWithSilence.Start();
// 通知用户
MessageBox.Show("更新已下载完成,将在软件关闭时自动安装。", "更新已准备就绪", MessageBoxButton.OK, MessageBoxImage.Information);
} else {
LogHelper.WriteLogToFile("AutoUpdate | Update download failed", LogHelper.LogType.Error);
MessageBox.Show("更新下载失败,请检查网络连接后重试。", "下载失败", MessageBoxButton.OK, MessageBoxImage.Error);
}
break;
case HasNewUpdateWindow.UpdateResult.SkipVersion:
// 跳过该版本:记录到设置中
LogHelper.WriteLogToFile($"AutoUpdate | User chose to skip version {AvailableLatestVersion}");
2025-06-29 11:56:38 +08:00
// 记录要跳过的版本号
Settings.Startup.SkippedVersion = AvailableLatestVersion;
// 保存设置到文件
SaveSettingsToFile();
// 通知用户
MessageBox.Show($"已设置跳过版本 {AvailableLatestVersion},在下次发布新版本之前不会再提示更新。",
"已跳过此版本",
MessageBoxButton.OK,
MessageBoxImage.Information);
break;
2025-05-25 09:29:48 +08:00
}
} else {
AutoUpdateHelper.DeleteUpdatesFolder();
}
}
2025-06-12 10:13:47 +08:00
// 新增:崩溃后操作设置按钮事件
private void RadioCrashAction_Checked(object sender, RoutedEventArgs e)
{
if (RadioCrashSilentRestart != null && RadioCrashSilentRestart.IsChecked == true)
{
App.CrashAction = App.CrashActionType.SilentRestart;
Settings.Startup.CrashAction = 0;
2025-06-12 10:13:47 +08:00
}
else if (RadioCrashNoAction != null && RadioCrashNoAction.IsChecked == true)
{
App.CrashAction = App.CrashActionType.NoAction;
Settings.Startup.CrashAction = 1;
2025-06-12 10:13:47 +08:00
}
2025-06-12 11:21:45 +08:00
SaveSettingsToFile();
// 强制同步全局变量,防止后台逻辑未及时感知
App.SyncCrashActionFromSettings();
2025-06-12 11:21:45 +08:00
}
2025-06-18 09:08:38 +08:00
// 添加一个辅助方法,根据当前编辑模式设置光标
private void SetCursorBasedOnEditingMode(InkCanvas canvas)
{
if (Settings.Canvas.IsShowCursor) {
canvas.UseCustomCursor = true;
canvas.ForceCursor = true;
// 根据编辑模式设置不同的光标
if (canvas.EditingMode == InkCanvasEditingMode.EraseByPoint) {
canvas.Cursor = Cursors.Cross;
} else if (canvas.EditingMode == InkCanvasEditingMode.Ink) {
var sri = Application.GetResourceStream(new Uri("Resources/Cursors/Pen.cur", UriKind.Relative));
if (sri != null)
canvas.Cursor = new Cursor(sri.Stream);
} else if (canvas.EditingMode == InkCanvasEditingMode.Select) {
canvas.Cursor = Cursors.Cross;
}
2025-06-19 11:25:15 +08:00
// 确保光标可见,无论是鼠标、触控还是手写笔
2025-06-18 09:08:38 +08:00
System.Windows.Forms.Cursor.Show();
2025-06-19 11:25:15 +08:00
// 强制应用光标设置
canvas.ForceCursor = true;
// 确保手写笔模式下也能显示光标
if (Tablet.TabletDevices.Count > 0) {
foreach (TabletDevice device in Tablet.TabletDevices) {
if (device.Type == TabletDeviceType.Stylus) {
// 手写笔设备存在,强制显示光标
System.Windows.Forms.Cursor.Show();
break;
}
}
}
2025-06-18 09:08:38 +08:00
} else {
canvas.UseCustomCursor = false;
canvas.ForceCursor = false;
System.Windows.Forms.Cursor.Show();
}
}
2025-06-12 11:21:45 +08:00
// 鼠标输入
private void inkCanvas_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
2025-06-18 09:08:38 +08:00
// 使用辅助方法设置光标
SetCursorBasedOnEditingMode(inkCanvas);
2025-06-12 11:21:45 +08:00
}
// 手写笔输入
private void inkCanvas_StylusDown(object sender, StylusDownEventArgs e)
{
2025-06-18 09:08:38 +08:00
// 使用辅助方法设置光标
SetCursorBasedOnEditingMode(inkCanvas);
2025-06-12 11:21:45 +08:00
}
2025-06-12 22:48:25 +08:00
// 触摸输入,不隐藏光标
2025-06-12 11:21:45 +08:00
private void inkCanvas_TouchDown(object sender, TouchEventArgs e)
{
2025-06-18 09:08:38 +08:00
// 使用辅助方法设置光标
SetCursorBasedOnEditingMode(inkCanvas);
}
// 触摸结束,恢复光标
private void inkCanvas_TouchUp(object sender, TouchEventArgs e)
{
// 使用辅助方法设置光标
SetCursorBasedOnEditingMode(inkCanvas);
2025-06-18 15:10:33 +08:00
// 确保光标可见
if (Settings.Canvas.IsShowCursor) {
inkCanvas.ForceCursor = true;
inkCanvas.UseCustomCursor = true;
System.Windows.Forms.Cursor.Show();
}
2025-06-18 09:08:38 +08:00
}
#endregion Definations and Loading
#region Navigation Sidebar Methods
// 侧边栏导航按钮事件处理
private void NavStartup_Click(object sender, RoutedEventArgs e)
{
// 切换到启动设置页面
ShowSettingsSection("startup");
}
private void NavCanvas_Click(object sender, RoutedEventArgs e)
{
// 切换到画布设置页面
ShowSettingsSection("canvas");
}
private void NavGesture_Click(object sender, RoutedEventArgs e)
{
// 切换到手势设置页面
ShowSettingsSection("gesture");
}
private void NavInkRecognition_Click(object sender, RoutedEventArgs e)
{
// 切换到墨迹识别设置页面
ShowSettingsSection("inkrecognition");
}
private void NavCrashAction_Click(object sender, RoutedEventArgs e)
{
// 切换到崩溃处理设置页面
ShowSettingsSection("crashaction");
}
private void NavPPT_Click(object sender, RoutedEventArgs e)
{
// 切换到PPT设置页面
ShowSettingsSection("ppt");
}
private void NavAdvanced_Click(object sender, RoutedEventArgs e)
{
// 切换到高级设置页面
ShowSettingsSection("advanced");
}
private void NavAutomation_Click(object sender, RoutedEventArgs e)
{
// 切换到自动化设置页面
ShowSettingsSection("automation");
}
private void NavRandomWindow_Click(object sender, RoutedEventArgs e)
{
// 切换到随机窗口设置页面
ShowSettingsSection("randomwindow");
}
private void NavAbout_Click(object sender, RoutedEventArgs e)
{
// 切换到关于页面
ShowSettingsSection("about");
}
// 新增:个性化设置
private void NavTheme_Click(object sender, RoutedEventArgs e)
{
// 切换到个性化设置页面
ShowSettingsSection("theme");
}
// 新增:快捷键设置
private void NavShortcuts_Click(object sender, RoutedEventArgs e)
{
// 切换到快捷键设置页面
ShowSettingsSection("shortcuts");
// 如果设置部分尚未快捷键
MessageBox.Show("设置功能正在开发中", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
}
private void BtnCloseSettings_Click(object sender, RoutedEventArgs e)
{
// 关闭设置面板
BorderSettings.Visibility = Visibility.Collapsed;
2025-06-19 14:30:24 +08:00
// 设置蒙版为不可点击,并清除背景
2025-06-18 09:08:38 +08:00
BorderSettingsMask.IsHitTestVisible = false;
2025-06-19 14:30:24 +08:00
BorderSettingsMask.Background = null; // 确保清除蒙层背景
2025-06-18 09:08:38 +08:00
}
// 新增:折叠侧边栏
private void CollapseNavSidebar_Click(object sender, RoutedEventArgs e)
{
// 折叠/展开侧边栏
var columnDefinitions = ((Grid)BorderSettings.Child).ColumnDefinitions;
if (columnDefinitions[0].Width.Value == 50)
2025-06-17 13:20:06 +08:00
{
2025-06-18 09:08:38 +08:00
// 折叠侧边栏
columnDefinitions[0].Width = new GridLength(0);
2025-06-17 13:20:06 +08:00
}
else
{
2025-06-18 09:08:38 +08:00
// 展开侧边栏
columnDefinitions[0].Width = new GridLength(50);
2025-06-13 11:43:50 +08:00
}
2025-06-12 11:21:45 +08:00
}
2025-06-18 09:08:38 +08:00
// 新增:显示侧边栏
private void ShowNavSidebar_Click(object sender, RoutedEventArgs e)
{
// 确保侧边栏展开
var columnDefinitions = ((Grid)BorderSettings.Child).ColumnDefinitions;
columnDefinitions[0].Width = new GridLength(50);
}
2025-06-12 11:21:45 +08:00
2025-06-18 09:08:38 +08:00
// 辅助方法:显示指定的设置部分
2025-07-15 21:10:49 +08:00
private async void ShowSettingsSection(string sectionTag)
2025-06-12 11:21:45 +08:00
{
2025-06-18 09:08:38 +08:00
// 显示设置面板
BorderSettings.Visibility = Visibility.Visible;
2025-06-19 14:32:16 +08:00
// 设置蒙版为可点击,并添加半透明背景
2025-06-18 09:08:38 +08:00
BorderSettingsMask.IsHitTestVisible = true;
2025-06-19 14:32:16 +08:00
BorderSettingsMask.Background = new SolidColorBrush(System.Windows.Media.Color.FromArgb(1, 0, 0, 0));
2025-06-18 09:08:38 +08:00
// 获取SettingsPanelScrollViewer中的所有GroupBox
var stackPanel = SettingsPanelScrollViewer.Content as StackPanel;
if (stackPanel == null) return;
2025-07-15 21:10:49 +08:00
// 确保所有GroupBox都是可见的
2025-06-18 09:08:38 +08:00
foreach (var child in stackPanel.Children)
{
if (child is GroupBox groupBox)
{
2025-07-15 21:10:49 +08:00
groupBox.Visibility = Visibility.Visible;
2025-06-18 09:08:38 +08:00
}
}
2025-07-15 21:10:49 +08:00
// 确保UI完全更新
await Dispatcher.InvokeAsync(() => {}, System.Windows.Threading.DispatcherPriority.Render);
// 根据传入的sectionTag滚动到相应的设置部分
GroupBox targetGroupBox = null;
2025-06-18 09:08:38 +08:00
switch (sectionTag.ToLower())
{
case "startup":
2025-07-15 21:10:49 +08:00
targetGroupBox = FindGroupBoxByHeader(stackPanel, "启动");
2025-06-18 09:08:38 +08:00
break;
case "canvas":
2025-07-15 21:10:49 +08:00
targetGroupBox = FindGroupBoxByHeader(stackPanel, "画板和墨迹");
2025-06-18 09:08:38 +08:00
break;
case "gesture":
2025-07-15 21:10:49 +08:00
targetGroupBox = FindGroupBoxByHeader(stackPanel, "手势");
2025-06-18 09:08:38 +08:00
break;
case "inkrecognition":
2025-07-15 21:10:49 +08:00
targetGroupBox = GroupBoxInkRecognition;
2025-06-18 09:08:38 +08:00
break;
case "crashaction":
2025-07-15 21:10:49 +08:00
targetGroupBox = FindGroupBoxByHeader(stackPanel, "崩溃后操作");
2025-06-18 09:08:38 +08:00
break;
case "ppt":
2025-07-15 21:10:49 +08:00
targetGroupBox = FindGroupBoxByHeader(stackPanel, "PPT联动");
2025-06-18 09:08:38 +08:00
break;
case "advanced":
2025-07-15 21:10:49 +08:00
targetGroupBox = FindGroupBoxByHeader(stackPanel, "高级设置");
2025-06-18 09:08:38 +08:00
break;
case "automation":
2025-07-15 21:10:49 +08:00
targetGroupBox = FindGroupBoxByHeader(stackPanel, "自动化");
2025-06-18 09:08:38 +08:00
break;
case "randomwindow":
2025-07-15 21:10:49 +08:00
targetGroupBox = GroupBoxRandWindow;
2025-06-18 09:08:38 +08:00
break;
case "theme":
2025-07-15 21:10:49 +08:00
targetGroupBox = GroupBoxAppearanceNewUI;
2025-06-18 09:08:38 +08:00
break;
case "shortcuts":
// 快捷键设置部分可能尚未实现
2025-07-15 21:10:49 +08:00
targetGroupBox = FindGroupBoxByHeader(stackPanel, "快捷键");
2025-06-18 09:08:38 +08:00
break;
case "about":
2025-07-15 21:10:49 +08:00
targetGroupBox = FindGroupBoxByHeader(stackPanel, "关于");
2025-06-18 09:08:38 +08:00
break;
default:
2025-07-15 21:10:49 +08:00
// 默认滚动到顶部
SettingsPanelScrollViewer.ScrollToTop();
return;
}
// 如果找到目标GroupBox,则滚动到它的位置
if (targetGroupBox != null)
{
// 使用动画平滑滚动到目标位置
ScrollToElement(targetGroupBox);
// 高亮显示当前选中的导航项
UpdateNavigationButtonState(sectionTag);
}
else
{
// 如果没有找到目标GroupBox,则滚动到顶部
SettingsPanelScrollViewer.ScrollToTop();
}
}
// 根据Header文本查找GroupBox
private GroupBox FindGroupBoxByHeader(StackPanel parent, string headerText)
{
foreach (var child in parent.Children)
{
if (child is GroupBox groupBox)
{
// 查找GroupBox的Header
if (groupBox.Header is TextBlock headerTextBlock &&
headerTextBlock.Text != null &&
headerTextBlock.Text.Contains(headerText))
{
return groupBox;
}
}
}
return null;
}
// 平滑滚动到指定元素
private async void ScrollToElement(FrameworkElement element)
{
if (element == null || SettingsPanelScrollViewer == null) return;
try
{
// 暂时禁用滚动事件处理
SettingsPanelScrollViewer.ScrollChanged -= SettingsPanelScrollViewer_ScrollChanged;
// 记录当前滚动位置
double originalOffset = SettingsPanelScrollViewer.VerticalOffset;
// 将ScrollViewer内部的位置信息重置到顶部(不会触发视觉更新)
SettingsPanelScrollViewer.ScrollToHome();
// 使用Dispatcher进行延迟处理,确保布局更新
await Dispatcher.InvokeAsync(() => {
try
{
// 强制更新布局
SettingsPanelScrollViewer.UpdateLayout();
// 获取元素相对于顶部的准确位置
Point elementPosition = element.TransformToAncestor(SettingsPanelScrollViewer).Transform(new Point(0, 0));
// 计算目标位置,减去一些偏移,使元素不会贴在顶部
double targetPosition = elementPosition.Y - 20;
// 确保目标位置不小于0
targetPosition = Math.Max(0, targetPosition);
// 直接设置滚动位置,不使用动画
SettingsPanelScrollViewer.ScrollToVerticalOffset(targetPosition);
}
catch (Exception ex)
2025-06-18 09:08:38 +08:00
{
2025-07-15 21:10:49 +08:00
// 如果出现异常,恢复到原来的滚动位置
SettingsPanelScrollViewer.ScrollToVerticalOffset(originalOffset);
2025-06-18 09:08:38 +08:00
}
2025-07-15 21:10:49 +08:00
finally
{
// 重新启用滚动事件处理
SettingsPanelScrollViewer.ScrollChanged += SettingsPanelScrollViewer_ScrollChanged;
}
}, System.Windows.Threading.DispatcherPriority.Render);
}
catch (Exception)
{
// 确保在异常情况下也重新启用滚动事件处理
SettingsPanelScrollViewer.ScrollChanged += SettingsPanelScrollViewer_ScrollChanged;
}
}
// 滚动条变化事件处理
private void SettingsPanelScrollViewer_ScrollChanged(object sender, System.Windows.Controls.ScrollChangedEventArgs e)
{
// 可以在这里添加滚动事件的处理逻辑,如果需要的话
}
// 更新导航按钮状态
private void UpdateNavigationButtonState(string activeTag)
{
// 清除所有导航按钮的Tag属性
ClearAllNavButtonTags();
// 设置当前活动按钮的Tag属性
switch (activeTag.ToLower())
{
case "startup":
SetNavButtonTag("startup");
break;
case "canvas":
SetNavButtonTag("canvas");
break;
case "gesture":
SetNavButtonTag("gesture");
break;
case "inkrecognition":
SetNavButtonTag("inkrecognition");
break;
case "crashaction":
SetNavButtonTag("crashaction");
break;
case "ppt":
SetNavButtonTag("ppt");
break;
case "advanced":
SetNavButtonTag("advanced");
break;
case "automation":
SetNavButtonTag("automation");
break;
case "randomwindow":
SetNavButtonTag("randomwindow");
break;
case "theme":
SetNavButtonTag("theme");
2025-06-18 09:08:38 +08:00
break;
2025-07-15 21:10:49 +08:00
case "shortcuts":
SetNavButtonTag("shortcuts");
break;
case "about":
SetNavButtonTag("about");
break;
}
}
// 清除所有导航按钮的Tag属性
private void ClearAllNavButtonTags()
{
var grid = BorderSettings.Child as Grid;
if (grid == null) return;
var navSidebar = grid.Children[0] as Border;
if (navSidebar == null) return;
var navGrid = navSidebar.Child as Grid;
if (navGrid == null) return;
var scrollViewer = navGrid.Children[1] as ScrollViewer;
if (scrollViewer == null) return;
var stackPanel = scrollViewer.Content as StackPanel;
if (stackPanel == null) return;
foreach (var child in stackPanel.Children)
{
if (child is Button button)
{
button.Tag = null;
}
2025-06-18 09:08:38 +08:00
}
2025-07-15 21:10:49 +08:00
}
// 设置导航按钮的Tag属性
private void SetNavButtonTag(string tag)
{
var grid = BorderSettings.Child as Grid;
if (grid == null) return;
2025-06-18 09:08:38 +08:00
2025-07-15 21:10:49 +08:00
var navSidebar = grid.Children[0] as Border;
if (navSidebar == null) return;
var navGrid = navSidebar.Child as Grid;
if (navGrid == null) return;
var scrollViewer = navGrid.Children[1] as ScrollViewer;
if (scrollViewer == null) return;
var stackPanel = scrollViewer.Content as StackPanel;
if (stackPanel == null) return;
foreach (var child in stackPanel.Children)
{
if (child is Button button)
{
// 检查按钮的ToolTip属性,根据tag设置对应的按钮
string buttonTag = button.Tag as string;
// 如果按钮的Tag与要设置的tag匹配,则设置Tag
if (buttonTag != null && buttonTag.ToLower() == tag.ToLower())
{
button.Tag = tag;
return;
}
}
}
2025-06-18 09:08:38 +08:00
}
// 根据Header文本查找并显示GroupBox
private void ShowGroupBoxByHeader(StackPanel parent, string headerText)
{
foreach (var child in parent.Children)
{
if (child is GroupBox groupBox)
{
// 查找GroupBox的Header
if (groupBox.Header is TextBlock headerTextBlock &&
headerTextBlock.Text != null &&
headerTextBlock.Text.Contains(headerText))
{
groupBox.Visibility = Visibility.Visible;
return;
}
}
2025-06-13 11:43:50 +08:00
}
2025-06-12 10:13:47 +08:00
}
2025-06-18 09:08:38 +08:00
#endregion Navigation Sidebar Methods
2025-05-25 09:29:48 +08:00
}
}