From 6802476afa753c58717052e5f5daaff43698e63b Mon Sep 17 00:00:00 2001 From: CJKmkp <2564608840@qq.com> Date: Sat, 29 Nov 2025 16:27:35 +0800 Subject: [PATCH] =?UTF-8?q?improve:=E8=AE=A1=E6=97=B6=E5=99=A8UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将计时器窗口整合至主窗口,优化全屏计时逻辑 --- Ink Canvas/MainWindow.xaml | 24 + Ink Canvas/MainWindow.xaml.cs | 96 +++ .../MainWindow_cs/MW_FloatingBarIcons.cs | 37 +- .../Windows/CountdownTimerWindow.xaml.cs | 9 +- Ink Canvas/Windows/FullscreenTimerWindow.xaml | 4 +- .../Windows/FullscreenTimerWindow.xaml.cs | 78 +- Ink Canvas/Windows/MinimizedTimerControl.xaml | 124 +++ .../Windows/MinimizedTimerControl.xaml.cs | 471 +++++++++++ Ink Canvas/Windows/MinimizedTimerWindow.xaml | 4 +- .../Windows/MinimizedTimerWindow.xaml.cs | 68 +- ...tyleTimerWindow.xaml => TimerControl.xaml} | 784 +++++++++++------- ...yleTimerWindow.cs => TimerControl.xaml.cs} | 513 ++++++------ 12 files changed, 1581 insertions(+), 631 deletions(-) create mode 100644 Ink Canvas/Windows/MinimizedTimerControl.xaml create mode 100644 Ink Canvas/Windows/MinimizedTimerControl.xaml.cs rename Ink Canvas/Windows/{NewStyleTimerWindow.xaml => TimerControl.xaml} (55%) rename Ink Canvas/Windows/{NewStyleTimerWindow.cs => TimerControl.xaml.cs} (79%) diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml index daf5c125..75494a41 100644 --- a/Ink Canvas/MainWindow.xaml +++ b/Ink Canvas/MainWindow.xaml @@ -7,6 +7,7 @@ xmlns:c="clr-namespace:Ink_Canvas.Converter" xmlns:Controls="http://schemas.microsoft.com/netfx/2009/xaml/presentation" xmlns:controls="clr-namespace:Ink_Canvas.Controls" + xmlns:Windows="clr-namespace:Ink_Canvas.Windows" mc:Ignorable="d" AllowsTransparency="True" WindowStyle="None" @@ -37,6 +38,8 @@ + + @@ -9950,6 +9953,27 @@ + + + + + + + + diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs index 27fa6bf1..1b0e8887 100644 --- a/Ink Canvas/MainWindow.xaml.cs +++ b/Ink Canvas/MainWindow.xaml.cs @@ -268,6 +268,74 @@ namespace Ink_Canvas // 为滑块控件添加触摸事件支持 AddTouchSupportToSliders(); + + // 初始化计时器控件事件 + Dispatcher.BeginInvoke(new Action(() => + { + if (TimerControl != null) + { + TimerControl.ShowMinimizedRequested += TimerControl_ShowMinimizedRequested; + TimerControl.HideMinimizedRequested += TimerControl_HideMinimizedRequested; + } + + if (MinimizedTimerControl != null && TimerControl != null) + { + MinimizedTimerControl.SetParentControl(TimerControl); + } + }), DispatcherPriority.Loaded); + } + + private void TimerControl_ShowMinimizedRequested(object sender, EventArgs e) + { + var timerContainer = FindName("TimerContainer") as FrameworkElement; + var minimizedContainer = FindName("MinimizedTimerContainer") as FrameworkElement; + + if (timerContainer != null && minimizedContainer != null) + { + double x = 0, y = 0; + + if (timerContainer.HorizontalAlignment == HorizontalAlignment.Center && + timerContainer.VerticalAlignment == VerticalAlignment.Center) + { + var timerPoint = timerContainer.TransformToAncestor(this).Transform(new Point(0, 0)); + x = timerPoint.X; + y = timerPoint.Y; + } + else + { + var timerMargin = timerContainer.Margin; + x = double.IsNaN(timerMargin.Left) ? 0 : timerMargin.Left; + y = double.IsNaN(timerMargin.Top) ? 0 : timerMargin.Top; + } + + minimizedContainer.Margin = new Thickness(x, y, 0, 0); + minimizedContainer.HorizontalAlignment = HorizontalAlignment.Left; + minimizedContainer.VerticalAlignment = VerticalAlignment.Top; + + timerContainer.Margin = new Thickness(x, y, 0, 0); + timerContainer.HorizontalAlignment = HorizontalAlignment.Left; + timerContainer.VerticalAlignment = VerticalAlignment.Top; + + timerContainer.Visibility = Visibility.Collapsed; + minimizedContainer.Visibility = Visibility.Visible; + } + } + + private void TimerControl_HideMinimizedRequested(object sender, EventArgs e) + { + var timerContainer = FindName("TimerContainer") as FrameworkElement; + var minimizedContainer = FindName("MinimizedTimerContainer") as FrameworkElement; + + if (timerContainer != null && minimizedContainer != null) + { + minimizedContainer.Visibility = Visibility.Collapsed; + timerContainer.Visibility = Visibility.Visible; + + if (TimerControl != null) + { + TimerControl.UpdateActivityTime(); + } + } } @@ -615,6 +683,34 @@ namespace Ink_Canvas } }), DispatcherPriority.Loaded); } + + // 初始化计时器控件关联 + Dispatcher.BeginInvoke(new Action(() => + { + if (TimerControl != null && MinimizedTimerControl != null) + { + MinimizedTimerControl.SetParentControl(TimerControl); + + TimerControl.ShowMinimizedRequested += (s, args) => + { + if (TimerContainer != null && MinimizedTimerContainer != null && MinimizedTimerControl != null) + { + TimerContainer.Visibility = Visibility.Collapsed; + MinimizedTimerContainer.Visibility = Visibility.Visible; + MinimizedTimerControl.Visibility = Visibility.Visible; + } + }; + + TimerControl.HideMinimizedRequested += (s, args) => + { + if (MinimizedTimerContainer != null && MinimizedTimerControl != null) + { + MinimizedTimerContainer.Visibility = Visibility.Collapsed; + MinimizedTimerControl.Visibility = Visibility.Collapsed; + } + }; + } + }), DispatcherPriority.Loaded); } private void SystemEventsOnDisplaySettingsChanged(object sender, EventArgs e) diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs index 5e954079..1aec6e11 100644 --- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs +++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs @@ -1051,17 +1051,38 @@ namespace Ink_Canvas AnimationsHelper.HideWithSlideAndFade(BoardBorderTools); AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel); - // 参考老计时器的窗口置顶功能:在白板模式下停止窗口置顶 - if (currentMode == 1) // 白板模式 + if (Settings.RandSettings?.UseNewStyleUI == true) { - Topmost = false; + if (TimerContainer != null && TimerControl != null) + { + TimerContainer.Visibility = Visibility.Visible; + if (MinimizedTimerContainer != null) + { + MinimizedTimerContainer.Visibility = Visibility.Collapsed; + } + TimerControl.CloseRequested += (s, args) => + { + TimerContainer.Visibility = Visibility.Collapsed; + if (MinimizedTimerContainer != null) + { + MinimizedTimerContainer.Visibility = Visibility.Collapsed; + } + }; + } } - - var timerWindow = CountdownTimerWindow.CreateTimerWindow(); - timerWindow.Show(); - if (currentMode == 1) // 白板模式 + else { - timerWindow.Topmost = true; + if (currentMode == 1) + { + Topmost = false; + } + + var timerWindow = CountdownTimerWindow.CreateTimerWindow(); + timerWindow.Show(); + if (currentMode == 1) + { + timerWindow.Topmost = true; + } } } diff --git a/Ink Canvas/Windows/CountdownTimerWindow.xaml.cs b/Ink Canvas/Windows/CountdownTimerWindow.xaml.cs index a4d1cbae..1fd31fd5 100644 --- a/Ink Canvas/Windows/CountdownTimerWindow.xaml.cs +++ b/Ink Canvas/Windows/CountdownTimerWindow.xaml.cs @@ -29,14 +29,7 @@ namespace Ink_Canvas public static Window CreateTimerWindow() { - if (MainWindow.Settings.RandSettings?.UseNewStyleUI == true) - { - return new NewStyleTimerWindow(); - } - else - { - return new CountdownTimerWindow(); - } + return new CountdownTimerWindow(); } private void Timer_Elapsed(object sender, ElapsedEventArgs e) diff --git a/Ink Canvas/Windows/FullscreenTimerWindow.xaml b/Ink Canvas/Windows/FullscreenTimerWindow.xaml index 115730bf..fda1bb4d 100644 --- a/Ink Canvas/Windows/FullscreenTimerWindow.xaml +++ b/Ink Canvas/Windows/FullscreenTimerWindow.xaml @@ -1,9 +1,9 @@ - /// 全屏计时器窗口 /// public partial class FullscreenTimerWindow : Window { - private NewStyleTimerWindow parentWindow; + private TimerControl parentControl; private System.Timers.Timer updateTimer; + private Visibility previousTimerContainerVisibility = Visibility.Visible; - public FullscreenTimerWindow(NewStyleTimerWindow parent) + public FullscreenTimerWindow(TimerControl parent) { InitializeComponent(); - parentWindow = parent; + parentControl = parent; - // 设置窗口位置和大小 this.Left = 0; this.Top = 0; this.Width = SystemParameters.PrimaryScreenWidth; this.Height = SystemParameters.PrimaryScreenHeight; - // 启动更新定时器 updateTimer = new System.Timers.Timer(100); updateTimer.Elapsed += UpdateTimer_Elapsed; updateTimer.Start(); - parentWindow.TimerCompleted += ParentWindow_TimerCompleted; + parentControl.TimerCompleted += ParentWindow_TimerCompleted; + + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow != null) + { + mainWindow.PauseTopmostMaintenance(); + + var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement; + if (timerContainer != null) + { + previousTimerContainerVisibility = timerContainer.Visibility; + timerContainer.Visibility = Visibility.Collapsed; + } + } // 确保窗口置顶 Loaded += FullscreenTimerWindow_Loaded; @@ -97,7 +109,7 @@ namespace Ink_Canvas private void UpdateTimer_Elapsed(object sender, ElapsedEventArgs e) { - if (parentWindow != null) + if (parentControl != null) { Application.Current.Dispatcher.Invoke(() => { @@ -114,16 +126,16 @@ namespace Ink_Canvas private bool ShouldCloseWindow() { - if (parentWindow == null) return true; + if (parentControl == null) return true; if (MainWindow.Settings.RandSettings?.EnableOvertimeCountUp == true) { - if (parentWindow.IsTimerRunning) + if (parentControl.IsTimerRunning) { return false; } - var remainingTime = parentWindow.GetRemainingTime(); + var remainingTime = parentControl.GetRemainingTime(); if (remainingTime.HasValue && remainingTime.Value.TotalSeconds < 0) { return false; @@ -133,16 +145,15 @@ namespace Ink_Canvas } else { - return !parentWindow.IsTimerRunning; + return !parentControl.IsTimerRunning; } } private void UpdateTimeDisplay() { - if (parentWindow == null) return; + if (parentControl == null) return; - // 获取剩余时间 - var remainingTime = parentWindow.GetRemainingTime(); + var remainingTime = parentControl.GetRemainingTime(); if (remainingTime.HasValue) { var timeSpan = remainingTime.Value; @@ -153,10 +164,10 @@ namespace Ink_Canvas if (isOvertimeMode) { - var totalTimeSpan = parentWindow.GetTotalTimeSpan(); + var totalTimeSpan = parentControl.GetTotalTimeSpan(); if (totalTimeSpan.HasValue) { - var elapsedTime = parentWindow.GetElapsedTime(); + var elapsedTime = parentControl.GetElapsedTime(); if (elapsedTime.HasValue) { var overtimeSpan = elapsedTime.Value - totalTimeSpan.Value; @@ -188,11 +199,9 @@ namespace Ink_Canvas SetDigitDisplay("FullHour1Display", Math.Abs(hours / 10) % 10, shouldShowRed); SetDigitDisplay("FullHour2Display", (hours % 10 + 10) % 10, shouldShowRed); - // 更新分钟显示 SetDigitDisplay("FullMinute1Display", minutes / 10, shouldShowRed); SetDigitDisplay("FullMinute2Display", minutes % 10, shouldShowRed); - // 更新秒显示 SetDigitDisplay("FullSecond1Display", seconds / 10, shouldShowRed); SetDigitDisplay("FullSecond2Display", seconds % 10, shouldShowRed); @@ -283,23 +292,32 @@ namespace Ink_Canvas private void ExitFullscreen() { - // 恢复主窗口 - if (parentWindow != null) - { - // 清除全屏模式标志 - parentWindow.SetFullscreenMode(false); - parentWindow.Show(); - parentWindow.Activate(); - parentWindow.WindowState = WindowState.Normal; - } this.Close(); } protected override void OnClosed(EventArgs e) { - if (parentWindow != null) + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow != null) { - parentWindow.TimerCompleted -= ParentWindow_TimerCompleted; + mainWindow.ResumeTopmostMaintenance(); + + var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement; + if (timerContainer != null && previousTimerContainerVisibility == Visibility.Visible) + { + timerContainer.Visibility = Visibility.Visible; + + // 重置5秒最小化计时 + if (parentControl != null) + { + parentControl.UpdateActivityTime(); + } + } + } + + if (parentControl != null) + { + parentControl.TimerCompleted -= ParentWindow_TimerCompleted; } // 清理资源 diff --git a/Ink Canvas/Windows/MinimizedTimerControl.xaml b/Ink Canvas/Windows/MinimizedTimerControl.xaml new file mode 100644 index 00000000..59a2ff80 --- /dev/null +++ b/Ink Canvas/Windows/MinimizedTimerControl.xaml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ink Canvas/Windows/MinimizedTimerControl.xaml.cs b/Ink Canvas/Windows/MinimizedTimerControl.xaml.cs new file mode 100644 index 00000000..7d92fb85 --- /dev/null +++ b/Ink Canvas/Windows/MinimizedTimerControl.xaml.cs @@ -0,0 +1,471 @@ +using System; +using System.Timers; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Shapes; + +namespace Ink_Canvas.Windows +{ + /// + /// 最小化计时器窗口 + /// + public partial class MinimizedTimerControl : UserControl + { + private TimerControl parentControl; + private System.Timers.Timer updateTimer; + + public MinimizedTimerControl() + { + InitializeComponent(); + + updateTimer = new System.Timers.Timer(100); + updateTimer.Elapsed += UpdateTimer_Elapsed; + updateTimer.Start(); + + ApplyTheme(); + + Unloaded += MinimizedTimerControl_Unloaded; + } + + private void MinimizedTimerControl_Unloaded(object sender, RoutedEventArgs e) + { + if (parentControl != null) + { + parentControl.TimerCompleted -= ParentControl_TimerCompleted; + } + + if (updateTimer != null) + { + updateTimer.Stop(); + updateTimer.Dispose(); + } + } + + public void SetParentControl(TimerControl parent) + { + if (parentControl != null) + { + parentControl.TimerCompleted -= ParentControl_TimerCompleted; + } + + parentControl = parent; + + if (parentControl != null) + { + parentControl.TimerCompleted += ParentControl_TimerCompleted; + UpdateTimeDisplay(); + } + } + + private void UpdateTimer_Elapsed(object sender, ElapsedEventArgs e) + { + if (parentControl != null) + { + Application.Current.Dispatcher.Invoke(() => + { + if (this.Visibility != Visibility.Visible) + { + return; + } + + if (ShouldHide()) + { + this.Visibility = Visibility.Collapsed; + var parent = this.Parent as FrameworkElement; + if (parent != null) + { + parent.Visibility = Visibility.Collapsed; + } + return; + } + + UpdateTimeDisplay(); + }); + } + } + + private bool ShouldHide() + { + if (parentControl == null) return true; + + if (parentControl.IsFullscreenWindowOpen) + { + return true; + } + + if (MainWindow.Settings.RandSettings?.EnableOvertimeCountUp == true) + { + if (parentControl.IsTimerRunning) + { + return false; + } + + var remainingTime = parentControl.GetRemainingTime(); + if (remainingTime.HasValue && remainingTime.Value.TotalSeconds < 0) + { + return false; + } + + return true; + } + else + { + return !parentControl.IsTimerRunning; + } + } + + private void UpdateTimeDisplay() + { + if (parentControl == null) return; + + var remainingTime = parentControl.GetRemainingTime(); + if (remainingTime.HasValue) + { + var timeSpan = remainingTime.Value; + bool isOvertimeMode = timeSpan.TotalSeconds < 0; + bool shouldShowRed = isOvertimeMode && MainWindow.Settings.RandSettings?.EnableOvertimeRedText == true; + + int hours, minutes, seconds; + + if (isOvertimeMode) + { + var totalTimeSpan = parentControl.GetTotalTimeSpan(); + if (totalTimeSpan.HasValue) + { + var elapsedTime = parentControl.GetElapsedTime(); + if (elapsedTime.HasValue) + { + var overtimeSpan = elapsedTime.Value - totalTimeSpan.Value; + hours = (int)overtimeSpan.TotalHours; + minutes = overtimeSpan.Minutes; + seconds = overtimeSpan.Seconds; + } + else + { + hours = 0; + minutes = 0; + seconds = 0; + } + } + else + { + hours = 0; + minutes = 0; + seconds = 0; + } + } + else + { + hours = (int)timeSpan.TotalHours; + minutes = timeSpan.Minutes; + seconds = timeSpan.Seconds; + } + + SetDigitDisplay("MinHour1Display", Math.Abs(hours / 10) % 10, shouldShowRed); + SetDigitDisplay("MinHour2Display", (hours % 10 + 10) % 10, shouldShowRed); + + SetDigitDisplay("MinMinute1Display", minutes / 10, shouldShowRed); + SetDigitDisplay("MinMinute2Display", minutes % 10, shouldShowRed); + + SetDigitDisplay("MinSecond1Display", seconds / 10, shouldShowRed); + SetDigitDisplay("MinSecond2Display", seconds % 10, shouldShowRed); + + SetColonDisplay(shouldShowRed); + } + } + + private void ParentControl_TimerCompleted(object sender, EventArgs e) + { + Application.Current.Dispatcher.Invoke(() => + { + Visibility = Visibility.Collapsed; + }); + } + + private void SetDigitDisplay(string pathName, int digit, bool isRed = false) + { + var path = this.FindName(pathName) as Path; + if (path != null) + { + string resourceKey = $"Digit{digit}"; + var geometry = this.FindResource(resourceKey) as Geometry; + if (geometry != null) + { + path.Data = geometry; + } + + if (isRed) + { + path.Fill = Brushes.Red; + } + else + { + var defaultBrush = this.FindResource("NewTimerWindowDigitForeground") as Brush; + if (defaultBrush != null) + { + path.Fill = defaultBrush; + } + else + { + bool isLightTheme = IsLightTheme(); + path.Fill = isLightTheme ? Brushes.Black : Brushes.White; + } + } + } + } + + private void SetColonDisplay(bool isRed = false) + { + var colon1 = this.FindName("MinColon1Display") as TextBlock; + var colon2 = this.FindName("MinColon2Display") as TextBlock; + + if (colon1 != null) + { + if (isRed) + { + colon1.Foreground = Brushes.Red; + } + else + { + var defaultBrush = this.FindResource("NewTimerWindowDigitForeground") as Brush; + if (defaultBrush != null) + { + colon1.Foreground = defaultBrush; + } + else + { + bool isLightTheme = IsLightTheme(); + colon1.Foreground = isLightTheme ? Brushes.Black : Brushes.White; + } + } + } + + if (colon2 != null) + { + if (isRed) + { + colon2.Foreground = Brushes.Red; + } + else + { + var defaultBrush = this.FindResource("NewTimerWindowDigitForeground") as Brush; + if (defaultBrush != null) + { + colon2.Foreground = defaultBrush; + } + else + { + bool isLightTheme = IsLightTheme(); + colon2.Foreground = isLightTheme ? Brushes.Black : Brushes.White; + } + } + } + } + + private void ApplyTheme() + { + try + { + bool isLightTheme = IsLightTheme(); + if (!isLightTheme) + { + SetDarkThemeBorder(); + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"应用主题时出错: {ex.Message}"); + } + } + + private bool IsLightTheme() + { + try + { + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow != null) + { + var currentModeField = mainWindow.GetType().GetField("currentMode", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + if (currentModeField != null) + { + var currentMode = currentModeField.GetValue(mainWindow); + return currentMode?.ToString() == "Light"; + } + } + } + catch + { + } + return true; + } + + private void SetDarkThemeBorder() + { + try + { + var border = this.FindName("MainBorder") as Border; + if (border != null) + { + border.BorderBrush = new SolidColorBrush(Color.FromRgb(64, 64, 64)); + } + } + catch + { + } + } + + private void CloseButton_Click(object sender, RoutedEventArgs e) + { + if (parentControl != null) + { + parentControl.StopTimer(); + } + Visibility = Visibility.Collapsed; + } + + private bool isDragging = false; + private bool isDragStarted = false; + private Point dragStartPoint; + private Point containerStartPosition; + private const double DragThreshold = 5.0; // 拖动阈值,像素 + + private void MainBorder_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + if (e.ClickCount == 2) + { + // 双击:恢复主窗口 + if (parentControl != null) + { + parentControl.UpdateActivityTime(); + + 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 (timerContainer != null && minimizedContainer != null) + { + timerContainer.Visibility = Visibility.Visible; + minimizedContainer.Visibility = Visibility.Collapsed; + } + } + } + e.Handled = true; + } + else if (e.ClickCount == 1) + { + // 单击:准备拖动或点击 + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow != null) + { + var minimizedContainer = mainWindow.FindName("MinimizedTimerContainer") as FrameworkElement; + if (minimizedContainer != null) + { + var point = e.GetPosition(minimizedContainer); + var mainWindowPoint = minimizedContainer.TransformToAncestor(mainWindow).Transform(point); + + // 初始化拖动状态,但不立即开始拖动 + isDragging = false; + isDragStarted = false; + dragStartPoint = mainWindowPoint; + + var margin = minimizedContainer.Margin; + containerStartPosition = new Point(margin.Left, margin.Top); + + if (double.IsNaN(containerStartPosition.X) || containerStartPosition.X < 0) containerStartPosition.X = 0; + if (double.IsNaN(containerStartPosition.Y) || containerStartPosition.Y < 0) containerStartPosition.Y = 0; + + // 捕获鼠标并订阅事件,等待判断是拖动还是点击 + minimizedContainer.CaptureMouse(); + minimizedContainer.MouseMove += MinimizedContainer_MouseMove; + minimizedContainer.MouseLeftButtonUp += MinimizedContainer_MouseLeftButtonUp; + e.Handled = true; + } + } + } + } + + private void MinimizedContainer_MouseMove(object sender, MouseEventArgs e) + { + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow == null) return; + + var minimizedContainer = mainWindow.FindName("MinimizedTimerContainer") as FrameworkElement; + if (minimizedContainer == null) return; + + var currentPoint = e.GetPosition(mainWindow); + var deltaX = currentPoint.X - dragStartPoint.X; + var deltaY = currentPoint.Y - dragStartPoint.Y; + var distance = Math.Sqrt(deltaX * deltaX + deltaY * deltaY); + + // 如果移动距离超过阈值,开始拖动 + if (!isDragStarted && distance > DragThreshold) + { + isDragStarted = true; + isDragging = true; + } + + // 如果已经开始拖动,更新位置 + if (isDragging) + { + var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement; + + var newX = containerStartPosition.X + deltaX; + var newY = containerStartPosition.Y + deltaY; + + if (newX < 0) newX = 0; + if (newY < 0) newY = 0; + + minimizedContainer.Margin = new Thickness(newX, newY, 0, 0); + minimizedContainer.HorizontalAlignment = HorizontalAlignment.Left; + minimizedContainer.VerticalAlignment = VerticalAlignment.Top; + + if (timerContainer != null) + { + timerContainer.Margin = new Thickness(newX, newY, 0, 0); + timerContainer.HorizontalAlignment = HorizontalAlignment.Left; + timerContainer.VerticalAlignment = VerticalAlignment.Top; + } + } + } + + private void MinimizedContainer_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow == null) return; + + var minimizedContainer = mainWindow.FindName("MinimizedTimerContainer") as FrameworkElement; + if (minimizedContainer != null) + { + minimizedContainer.ReleaseMouseCapture(); + minimizedContainer.MouseMove -= MinimizedContainer_MouseMove; + minimizedContainer.MouseLeftButtonUp -= MinimizedContainer_MouseLeftButtonUp; + } + + // 如果没有开始拖动(移动距离小于阈值),则视为单击,恢复主窗口 + if (!isDragStarted) + { + if (parentControl != null) + { + parentControl.UpdateActivityTime(); + + var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement; + if (timerContainer != null && minimizedContainer != null) + { + timerContainer.Visibility = Visibility.Visible; + minimizedContainer.Visibility = Visibility.Collapsed; + } + } + } + + isDragging = false; + isDragStarted = false; + } + + } +} + diff --git a/Ink Canvas/Windows/MinimizedTimerWindow.xaml b/Ink Canvas/Windows/MinimizedTimerWindow.xaml index ecd6e333..6693df4c 100644 --- a/Ink Canvas/Windows/MinimizedTimerWindow.xaml +++ b/Ink Canvas/Windows/MinimizedTimerWindow.xaml @@ -1,9 +1,9 @@ - - /// 最小化计时器窗口 - /// public partial class MinimizedTimerWindow : Window { - private NewStyleTimerWindow parentWindow; + private TimerControl parentControl; private System.Timers.Timer updateTimer; private bool isMouseOver = false; private bool isDragging = false; private Point lastMousePosition; - public MinimizedTimerWindow(NewStyleTimerWindow parent) + public MinimizedTimerWindow(TimerControl parent) { InitializeComponent(); - parentWindow = parent; + parentControl = parent; - // 设置窗口位置 - this.Left = parent.Left; - this.Top = parent.Top; + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow != null) + { + this.Left = mainWindow.Left; + this.Top = mainWindow.Top; + } - // 根据分辨率和DPI缩放窗口 ScaleWindowForResolution(); - // 启动更新定时器 - updateTimer = new System.Timers.Timer(100); // 100ms更新一次 + updateTimer = new System.Timers.Timer(100); updateTimer.Elapsed += UpdateTimer_Elapsed; updateTimer.Start(); - parentWindow.TimerCompleted += ParentWindow_TimerCompleted; + parentControl.TimerCompleted += ParentWindow_TimerCompleted; // 应用主题 ApplyTheme(); @@ -141,7 +139,7 @@ namespace Ink_Canvas private void UpdateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { - if (parentWindow != null) + if (parentControl != null) { Application.Current.Dispatcher.Invoke(() => { @@ -158,16 +156,16 @@ namespace Ink_Canvas private bool ShouldCloseWindow() { - if (parentWindow == null) return true; + if (parentControl == null) return true; if (MainWindow.Settings.RandSettings?.EnableOvertimeCountUp == true) { - if (parentWindow.IsTimerRunning) + if (parentControl.IsTimerRunning) { return false; } - var remainingTime = parentWindow.GetRemainingTime(); + var remainingTime = parentControl.GetRemainingTime(); if (remainingTime.HasValue && remainingTime.Value.TotalSeconds < 0) { return false; @@ -177,16 +175,15 @@ namespace Ink_Canvas } else { - return !parentWindow.IsTimerRunning; + return !parentControl.IsTimerRunning; } } private void UpdateTimeDisplay() { - if (parentWindow == null) return; + if (parentControl == null) return; - // 获取剩余时间 - var remainingTime = parentWindow.GetRemainingTime(); + var remainingTime = parentControl.GetRemainingTime(); if (remainingTime.HasValue) { var timeSpan = remainingTime.Value; @@ -197,10 +194,10 @@ namespace Ink_Canvas if (isOvertimeMode) { - var totalTimeSpan = parentWindow.GetTotalTimeSpan(); + var totalTimeSpan = parentControl.GetTotalTimeSpan(); if (totalTimeSpan.HasValue) { - var elapsedTime = parentWindow.GetElapsedTime(); + var elapsedTime = parentControl.GetElapsedTime(); if (elapsedTime.HasValue) { var overtimeSpan = elapsedTime.Value - totalTimeSpan.Value; @@ -232,11 +229,9 @@ namespace Ink_Canvas SetDigitDisplay("MinHour1Display", Math.Abs(hours / 10) % 10, shouldShowRed); SetDigitDisplay("MinHour2Display", (hours % 10 + 10) % 10, shouldShowRed); - // 更新分钟显示 SetDigitDisplay("MinMinute1Display", minutes / 10, shouldShowRed); SetDigitDisplay("MinMinute2Display", minutes % 10, shouldShowRed); - // 更新秒显示 SetDigitDisplay("MinSecond1Display", seconds / 10, shouldShowRed); SetDigitDisplay("MinSecond2Display", seconds % 10, shouldShowRed); @@ -424,18 +419,10 @@ namespace Ink_Canvas isDragging = false; this.ReleaseMouseCapture(); - // 如果点击时间很短,认为是单击,恢复主窗口 var clickDuration = DateTime.Now - lastClickTime; - if (clickDuration.TotalMilliseconds < 200) // 200ms内认为是单击 + if (clickDuration.TotalMilliseconds < 200) { - // 恢复主窗口 - if (parentWindow != null) - { - parentWindow.Show(); - parentWindow.Activate(); - parentWindow.WindowState = WindowState.Normal; - this.Close(); - } + this.Close(); } } } @@ -464,19 +451,18 @@ namespace Ink_Canvas private void CloseButton_Click(object sender, RoutedEventArgs e) { - // 停止计时器并关闭窗口 - if (parentWindow != null) + if (parentControl != null) { - parentWindow.StopTimer(); + parentControl.StopTimer(); } this.Close(); } protected override void OnClosed(EventArgs e) { - if (parentWindow != null) + if (parentControl != null) { - parentWindow.TimerCompleted -= ParentWindow_TimerCompleted; + parentControl.TimerCompleted -= ParentWindow_TimerCompleted; } // 清理资源 diff --git a/Ink Canvas/Windows/NewStyleTimerWindow.xaml b/Ink Canvas/Windows/TimerControl.xaml similarity index 55% rename from Ink Canvas/Windows/NewStyleTimerWindow.xaml rename to Ink Canvas/Windows/TimerControl.xaml index e23e1a8c..280c913c 100644 --- a/Ink Canvas/Windows/NewStyleTimerWindow.xaml +++ b/Ink Canvas/Windows/TimerControl.xaml @@ -1,32 +1,37 @@ - - - + + + + - + - + @@ -34,8 +39,16 @@ - - + + - + - + - - - - - - - - - - - - - - - + + + + - - - - - - - - + + + + + + + - - - - + + + + - - - - - + + + + + - - - - - - - - - - - - - - + + + + - - - - - - - - + + + + + + + - - - - + + + + - - - - - + + + + + - - - - - - - - - - - - - - + + + + - - - - - - - - + + + + + + + - - - - + + + + - @@ -619,9 +762,8 @@ - - - + + @@ -663,7 +805,7 @@ - + @@ -709,17 +851,29 @@ - - - + + - - - - - @@ -786,4 +961,5 @@ - \ No newline at end of file + + diff --git a/Ink Canvas/Windows/NewStyleTimerWindow.cs b/Ink Canvas/Windows/TimerControl.xaml.cs similarity index 79% rename from Ink Canvas/Windows/NewStyleTimerWindow.cs rename to Ink Canvas/Windows/TimerControl.xaml.cs index ff837f38..a290419c 100644 --- a/Ink Canvas/Windows/NewStyleTimerWindow.cs +++ b/Ink Canvas/Windows/TimerControl.xaml.cs @@ -6,14 +6,12 @@ using System.Timers; using System.Windows; using System.Windows.Controls; using System.Windows.Input; -using System.Windows.Interop; using System.Windows.Media; using System.Windows.Shapes; using Newtonsoft.Json; -using System.Runtime.InteropServices; using System.Windows.Threading; -namespace Ink_Canvas +namespace Ink_Canvas.Windows { /// /// 最近计时记录数据模型 @@ -31,12 +29,11 @@ namespace Ink_Canvas /// /// 新计时器UI风格的倒计时器窗口 /// - public partial class NewStyleTimerWindow : Window + public partial class TimerControl : UserControl { - public NewStyleTimerWindow() + public TimerControl() { InitializeComponent(); - AnimationsHelper.ShowWithSlideFromBottomAndFade(this, 0.25); timer.Elapsed += Timer_Elapsed; timer.Interval = 50; @@ -49,30 +46,29 @@ namespace Ink_Canvas hideTimer = new Timer(1000); // 每秒检查一次 hideTimer.Elapsed += HideTimer_Elapsed; lastActivityTime = DateTime.Now; - - // 添加窗口加载事件处理,确保置顶 - Loaded += TimerWindow_Loaded; - - // 暂停主窗口的置顶维护 - var mainWindow = Application.Current.MainWindow as MainWindow; - if (mainWindow != null) - { - mainWindow.PauseTopmostMaintenance(); - } - - // 窗口关闭时恢复主窗口的置顶维护 - Closing += TimerWindow_Closing; } - private void TimerWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) - { - // 恢复主窗口的置顶维护 - var mainWindow = Application.Current.MainWindow as MainWindow; - if (mainWindow != null) - { - mainWindow.ResumeTopmostMaintenance(); - } - } + #region 事件定义 + /// + /// 计时器完成事件 + /// + public event EventHandler TimerCompleted; + + /// + /// 关闭事件 - 通知主窗口隐藏容器 + /// + public event EventHandler CloseRequested; + + /// + /// 显示最小化视图事件 + /// + public event EventHandler ShowMinimizedRequested; + + /// + /// 隐藏最小化视图事件 + /// + public event EventHandler HideMinimizedRequested; + #endregion private void Timer_Elapsed(object sender, ElapsedEventArgs e) @@ -153,15 +149,23 @@ namespace Ink_Canvas int displayHours = totalHours; if (displayHours > 99) displayHours = 99; + if (displayHours < 0) displayHours = 0; bool shouldShowRed = MainWindow.Settings.RandSettings?.EnableOvertimeRedText == true; - SetDigitDisplay("Digit1Display", Math.Abs(displayHours / 10) % 10, shouldShowRed); - SetDigitDisplay("Digit2Display", (displayHours % 10 + 10) % 10, shouldShowRed); - SetDigitDisplay("Digit3Display", overtimeSpan.Minutes / 10, shouldShowRed); - SetDigitDisplay("Digit4Display", overtimeSpan.Minutes % 10, shouldShowRed); - SetDigitDisplay("Digit5Display", overtimeSpan.Seconds / 10, shouldShowRed); - SetDigitDisplay("Digit6Display", overtimeSpan.Seconds % 10, shouldShowRed); + int hoursTens = Math.Max(0, Math.Min(9, Math.Abs(displayHours / 10) % 10)); + int hoursOnes = Math.Max(0, Math.Min(9, (displayHours % 10 + 10) % 10)); + int minutesTens = Math.Max(0, Math.Min(9, Math.Abs(overtimeSpan.Minutes) / 10)); + int minutesOnes = Math.Max(0, Math.Min(9, Math.Abs(overtimeSpan.Minutes) % 10)); + int secondsTens = Math.Max(0, Math.Min(9, Math.Abs(overtimeSpan.Seconds) / 10)); + int secondsOnes = Math.Max(0, Math.Min(9, Math.Abs(overtimeSpan.Seconds) % 10)); + + SetDigitDisplay("Digit1Display", hoursTens, shouldShowRed); + SetDigitDisplay("Digit2Display", hoursOnes, shouldShowRed); + SetDigitDisplay("Digit3Display", minutesTens, shouldShowRed); + SetDigitDisplay("Digit4Display", minutesOnes, shouldShowRed); + SetDigitDisplay("Digit5Display", secondsTens, shouldShowRed); + SetDigitDisplay("Digit6Display", secondsOnes, shouldShowRed); SetColonDisplay(shouldShowRed); } @@ -186,11 +190,7 @@ namespace Ink_Canvas Timer timer = new Timer(); private Timer hideTimer; - private MinimizedTimerWindow minimizedWindow; - private DateTime lastActivityTime; - private bool isFullscreenMode = false; - private FullscreenTimerWindow fullscreenWindow; - public event EventHandler TimerCompleted; + private DateTime lastActivityTime; public TimeSpan? GetTotalTimeSpan() { return new TimeSpan(hour, minute, second); @@ -340,47 +340,6 @@ namespace Ink_Canvas SetColonDisplay(false); } - private void HideTimer_Elapsed(object sender, ElapsedEventArgs e) - { - Application.Current.Dispatcher.Invoke(() => - { - // 只有在计时器运行时且不在全屏模式下才检查自动隐藏 - if (isTimerRunning && !isPaused && !isFullscreenMode) - { - var timeSinceLastActivity = DateTime.Now - lastActivityTime; - if (timeSinceLastActivity.TotalSeconds >= 5) - { - ShowMinimizedWindow(); - } - } - }); - } - - private void ShowMinimizedWindow() - { - if (minimizedWindow == null || !minimizedWindow.IsVisible) - { - minimizedWindow = new MinimizedTimerWindow(this); - minimizedWindow.Show(); - - // 确保最小化窗口也置顶(窗口加载时会自动应用) - minimizedWindow.Topmost = true; - - // 隐藏主窗口 - this.Hide(); - } - } - - public void UpdateActivityTime() - { - lastActivityTime = DateTime.Now; - } - - public void SetFullscreenMode(bool isFullscreen) - { - isFullscreenMode = isFullscreen; - } - // 更新剩余时间 private void UpdateRemainingTime() { @@ -471,15 +430,6 @@ namespace Ink_Canvas StartPauseIcon.Data = Geometry.Parse(PlayIconData); } - private void Window_MouseMove(object sender, MouseEventArgs e) - { - UpdateActivityTime(); - } - - private void Window_MouseEnter(object sender, MouseEventArgs e) - { - UpdateActivityTime(); - } /// /// 根据数字值设置SVG数字显示 @@ -492,6 +442,8 @@ namespace Ink_Canvas var path = this.FindName(pathName) as System.Windows.Shapes.Path; if (path != null) { + digit = Math.Max(0, Math.Min(9, digit)); + string resourceKey = $"Digit{digit}"; var geometry = this.FindResource(resourceKey) as Geometry; if (geometry != null) @@ -572,6 +524,7 @@ namespace Ink_Canvas private void Digit1Plus_Click(object sender, RoutedEventArgs e) { if (isTimerRunning) return; + UpdateActivityTime(); int currentHour = hour; int hourTens = currentHour / 10; int hourOnes = currentHour % 10; @@ -586,6 +539,7 @@ namespace Ink_Canvas private void Digit1Minus_Click(object sender, RoutedEventArgs e) { if (isTimerRunning) return; + UpdateActivityTime(); int currentHour = hour; int hourTens = currentHour / 10; int hourOnes = currentHour % 10; @@ -601,6 +555,7 @@ namespace Ink_Canvas private void Digit2Plus_Click(object sender, RoutedEventArgs e) { if (isTimerRunning) return; + UpdateActivityTime(); int currentHour = hour; int hourTens = currentHour / 10; int hourOnes = currentHour % 10; @@ -620,6 +575,7 @@ namespace Ink_Canvas private void Digit2Minus_Click(object sender, RoutedEventArgs e) { if (isTimerRunning) return; + UpdateActivityTime(); int currentHour = hour; int hourTens = currentHour / 10; int hourOnes = currentHour % 10; @@ -640,6 +596,7 @@ namespace Ink_Canvas private void Digit3Plus_Click(object sender, RoutedEventArgs e) { if (isTimerRunning) return; + UpdateActivityTime(); int currentMinute = minute; int minuteTens = currentMinute / 10; int minuteOnes = currentMinute % 10; @@ -654,6 +611,7 @@ namespace Ink_Canvas private void Digit3Minus_Click(object sender, RoutedEventArgs e) { if (isTimerRunning) return; + UpdateActivityTime(); int currentMinute = minute; int minuteTens = currentMinute / 10; int minuteOnes = currentMinute % 10; @@ -669,6 +627,7 @@ namespace Ink_Canvas private void Digit4Plus_Click(object sender, RoutedEventArgs e) { if (isTimerRunning) return; + UpdateActivityTime(); int currentMinute = minute; int minuteTens = currentMinute / 10; int minuteOnes = currentMinute % 10; @@ -688,6 +647,7 @@ namespace Ink_Canvas private void Digit4Minus_Click(object sender, RoutedEventArgs e) { if (isTimerRunning) return; + UpdateActivityTime(); int currentMinute = minute; int minuteTens = currentMinute / 10; int minuteOnes = currentMinute % 10; @@ -708,6 +668,7 @@ namespace Ink_Canvas private void Digit5Plus_Click(object sender, RoutedEventArgs e) { if (isTimerRunning) return; + UpdateActivityTime(); int currentSecond = second; int secondTens = currentSecond / 10; int secondOnes = currentSecond % 10; @@ -722,6 +683,7 @@ namespace Ink_Canvas private void Digit5Minus_Click(object sender, RoutedEventArgs e) { if (isTimerRunning) return; + UpdateActivityTime(); int currentSecond = second; int secondTens = currentSecond / 10; int secondOnes = currentSecond % 10; @@ -737,6 +699,7 @@ namespace Ink_Canvas private void Digit6Plus_Click(object sender, RoutedEventArgs e) { if (isTimerRunning) return; + UpdateActivityTime(); int currentSecond = second; int secondTens = currentSecond / 10; int secondOnes = currentSecond % 10; @@ -756,6 +719,7 @@ namespace Ink_Canvas private void Digit6Minus_Click(object sender, RoutedEventArgs e) { if (isTimerRunning) return; + UpdateActivityTime(); int currentSecond = second; int secondTens = currentSecond / 10; int secondOnes = currentSecond % 10; @@ -778,6 +742,7 @@ namespace Ink_Canvas private void StartPause_Click(object sender, RoutedEventArgs e) { + UpdateActivityTime(); if (isPaused && isTimerRunning) { // 继续计时 @@ -814,9 +779,6 @@ namespace Ink_Canvas // 启动隐藏定时器 hideTimer.Start(); - // 确保计时器窗口置顶 - ApplyTimerWindowTopmost(); - // 保存到最近计时记录 SaveRecentTimer(); @@ -830,16 +792,31 @@ namespace Ink_Canvas private void Reset_Click(object sender, RoutedEventArgs e) { + UpdateActivityTime(); + if (isTimerRunning) { + // 停止计时器 timer.Stop(); isTimerRunning = false; + isPaused = false; + + if (hideTimer != null) + { + hideTimer.Stop(); + } } - isPaused = false; - isOvertimeMode = false; UpdateDigitDisplays(); - StartPauseIcon.Data = Geometry.Parse(PlayIconData); + SetColonDisplay(false); + + if (StartPauseIcon != null) + { + StartPauseIcon.Data = Geometry.Parse(PlayIconData); + } + + isOvertimeMode = false; + hasPlayedProgressiveReminder = false; // 禁用全屏按钮 if (FullscreenBtn != null) @@ -914,36 +891,15 @@ namespace Ink_Canvas } } - private void Window_Loaded(object sender, RoutedEventArgs e) - { - // 窗口加载时的初始化 - } - - private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) - { - isTimerRunning = false; - - // 恢复主窗口的置顶维护 - var mainWindow = Application.Current.MainWindow as MainWindow; - if (mainWindow != null) - { - mainWindow.ResumeTopmostMaintenance(); - } - } - private void CloseButton_Click(object sender, RoutedEventArgs e) { - Close(); - } - - private void WindowDragMove(object sender, MouseEventArgs e) - { - if (e.LeftButton == MouseButtonState.Pressed) - DragMove(); + StopTimer(); + CloseRequested?.Invoke(this, EventArgs.Empty); } private void CommonTab_Click(object sender, RoutedEventArgs e) { + UpdateActivityTime(); CommonTimersGrid.Visibility = Visibility.Visible; RecentTimersGrid.Visibility = Visibility.Collapsed; @@ -978,6 +934,7 @@ namespace Ink_Canvas private void RecentTab_Click(object sender, RoutedEventArgs e) { + UpdateActivityTime(); CommonTimersGrid.Visibility = Visibility.Collapsed; RecentTimersGrid.Visibility = Visibility.Visible; @@ -1014,36 +971,42 @@ namespace Ink_Canvas private void Common5Min_Click(object sender, RoutedEventArgs e) { if (isTimerRunning && !isPaused) return; + UpdateActivityTime(); SetQuickTime(0, 5, 0); } private void Common10Min_Click(object sender, RoutedEventArgs e) { if (isTimerRunning && !isPaused) return; + UpdateActivityTime(); SetQuickTime(0, 10, 0); } private void Common15Min_Click(object sender, RoutedEventArgs e) { if (isTimerRunning && !isPaused) return; + UpdateActivityTime(); SetQuickTime(0, 15, 0); } private void Common30Min_Click(object sender, RoutedEventArgs e) { if (isTimerRunning && !isPaused) return; + UpdateActivityTime(); SetQuickTime(0, 30, 0); } private void Common45Min_Click(object sender, RoutedEventArgs e) { if (isTimerRunning && !isPaused) return; + UpdateActivityTime(); SetQuickTime(0, 45, 0); } private void Common60Min_Click(object sender, RoutedEventArgs e) { if (isTimerRunning && !isPaused) return; + UpdateActivityTime(); SetQuickTime(1, 0, 0); } @@ -1051,36 +1014,42 @@ namespace Ink_Canvas private void RecentTimer1_Click(object sender, RoutedEventArgs e) { if ((isTimerRunning && !isPaused) || recentTimer1 == "--:--") return; + UpdateActivityTime(); ApplyRecentTimer(recentTimer1); } private void RecentTimer2_Click(object sender, RoutedEventArgs e) { if ((isTimerRunning && !isPaused) || recentTimer2 == "--:--") return; + UpdateActivityTime(); ApplyRecentTimer(recentTimer2); } private void RecentTimer3_Click(object sender, RoutedEventArgs e) { if ((isTimerRunning && !isPaused) || recentTimer3 == "--:--") return; + UpdateActivityTime(); ApplyRecentTimer(recentTimer3); } private void RecentTimer4_Click(object sender, RoutedEventArgs e) { if ((isTimerRunning && !isPaused) || recentTimer4 == "--:--") return; + UpdateActivityTime(); ApplyRecentTimer(recentTimer4); } private void RecentTimer5_Click(object sender, RoutedEventArgs e) { if ((isTimerRunning && !isPaused) || recentTimer5 == "--:--") return; + UpdateActivityTime(); ApplyRecentTimer(recentTimer5); } private void RecentTimer6_Click(object sender, RoutedEventArgs e) { if ((isTimerRunning && !isPaused) || recentTimer6 == "--:--") return; + UpdateActivityTime(); ApplyRecentTimer(recentTimer6); } @@ -1220,16 +1189,22 @@ namespace Ink_Canvas { try { - RecentTimer1Text.Text = recentTimer1; - RecentTimer2Text.Text = recentTimer2; - RecentTimer3Text.Text = recentTimer3; - RecentTimer4Text.Text = recentTimer4; - RecentTimer5Text.Text = recentTimer5; - RecentTimer6Text.Text = recentTimer6; + var timer1Text = this.FindName("RecentTimer1Text") as TextBlock; + var timer2Text = this.FindName("RecentTimer2Text") as TextBlock; + var timer3Text = this.FindName("RecentTimer3Text") as TextBlock; + var timer4Text = this.FindName("RecentTimer4Text") as TextBlock; + var timer5Text = this.FindName("RecentTimer5Text") as TextBlock; + var timer6Text = this.FindName("RecentTimer6Text") as TextBlock; + + if (timer1Text != null) timer1Text.Text = recentTimer1; + if (timer2Text != null) timer2Text.Text = recentTimer2; + if (timer3Text != null) timer3Text.Text = recentTimer3; + if (timer4Text != null) timer4Text.Text = recentTimer4; + if (timer5Text != null) timer5Text.Text = recentTimer5; + if (timer6Text != null) timer6Text.Text = recentTimer6; } catch { - // 如果UI元素还未初始化,忽略错误 } } @@ -1335,136 +1310,202 @@ namespace Ink_Canvas } } + private FullscreenTimerWindow fullscreenWindow; + + public bool IsFullscreenWindowOpen => fullscreenWindow != null && fullscreenWindow.IsVisible; + private void Fullscreen_Click(object sender, RoutedEventArgs e) { - if (!isTimerRunning) + if (fullscreenWindow != null && fullscreenWindow.IsVisible) { + fullscreenWindow.Close(); + fullscreenWindow = null; return; } - ShowFullscreenTimer(); + + if (isTimerRunning && !isPaused) + { + fullscreenWindow = new FullscreenTimerWindow(this); + fullscreenWindow.Closed += (s, args) => { fullscreenWindow = null; }; + fullscreenWindow.Show(); + HideMinimizedRequested?.Invoke(this, EventArgs.Empty); + } } - - private void ShowFullscreenTimer() + + private void MainBorder_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { - // 设置全屏模式标志 - isFullscreenMode = true; + UpdateActivityTime(); + if (e.ClickCount == 1) + { + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow != null) + { + var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement; + if (timerContainer != null) + { + var point = e.GetPosition(timerContainer); + var mainWindowPoint = timerContainer.TransformToAncestor(mainWindow).Transform(point); + DragTimerContainer(mainWindow, mainWindowPoint, e); + } + } + } + } + + private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + UpdateActivityTime(); + if (e.ClickCount == 1) + { + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow != null) + { + var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement; + if (timerContainer != null) + { + var point = e.GetPosition(timerContainer); + var mainWindowPoint = timerContainer.TransformToAncestor(mainWindow).Transform(point); + DragTimerContainer(mainWindow, mainWindowPoint, e); + } + } + } + } + + private bool isDragging = false; + private Point dragStartPoint; + private Point containerStartPosition; + + private void DragTimerContainer(MainWindow mainWindow, Point startPoint, MouseButtonEventArgs e) + { + var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement; + if (timerContainer == null) return; - // 创建全屏计时器窗口 - fullscreenWindow = new FullscreenTimerWindow(this); - fullscreenWindow.Show(); + isDragging = true; + dragStartPoint = startPoint; - // 确保全屏窗口也置顶(窗口加载时会自动应用) - fullscreenWindow.Topmost = true; + if (timerContainer.HorizontalAlignment == HorizontalAlignment.Center || + timerContainer.VerticalAlignment == VerticalAlignment.Center) + { + var timerPoint = timerContainer.TransformToAncestor(mainWindow).Transform(new Point(0, 0)); + containerStartPosition = new Point(timerPoint.X, timerPoint.Y); + + timerContainer.Margin = new Thickness(containerStartPosition.X, containerStartPosition.Y, 0, 0); + timerContainer.HorizontalAlignment = HorizontalAlignment.Left; + timerContainer.VerticalAlignment = VerticalAlignment.Top; + } + else + { + var margin = timerContainer.Margin; + containerStartPosition = new Point(margin.Left, margin.Top); + + if (double.IsNaN(containerStartPosition.X) || containerStartPosition.X < 0) containerStartPosition.X = 0; + if (double.IsNaN(containerStartPosition.Y) || containerStartPosition.Y < 0) containerStartPosition.Y = 0; + } - // 隐藏主窗口 - this.Hide(); + timerContainer.CaptureMouse(); + timerContainer.MouseMove += TimerContainer_MouseMove; + timerContainer.MouseLeftButtonUp += TimerContainer_MouseLeftButtonUp; + e.Handled = true; + } + + private void TimerContainer_MouseMove(object sender, MouseEventArgs e) + { + if (!isDragging) return; + + UpdateActivityTime(); + + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow == null) return; + + var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement; + var minimizedContainer = mainWindow.FindName("MinimizedTimerContainer") as FrameworkElement; + if (timerContainer == null) return; + + var currentPoint = e.GetPosition(mainWindow); + var deltaX = currentPoint.X - dragStartPoint.X; + var deltaY = currentPoint.Y - dragStartPoint.Y; + + var newX = containerStartPosition.X + deltaX; + var newY = containerStartPosition.Y + deltaY; + + if (newX < 0) newX = 0; + if (newY < 0) newY = 0; + + timerContainer.Margin = new Thickness(newX, newY, 0, 0); + timerContainer.HorizontalAlignment = HorizontalAlignment.Left; + timerContainer.VerticalAlignment = VerticalAlignment.Top; + + if (minimizedContainer != null && minimizedContainer.Visibility == Visibility.Visible) + { + minimizedContainer.Margin = new Thickness(newX, newY, 0, 0); + minimizedContainer.HorizontalAlignment = HorizontalAlignment.Left; + minimizedContainer.VerticalAlignment = VerticalAlignment.Top; + } + } + + private void TimerContainer_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + if (!isDragging) return; + + isDragging = false; + + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow == null) return; + + var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement; + if (timerContainer != null) + { + timerContainer.ReleaseMouseCapture(); + timerContainer.MouseMove -= TimerContainer_MouseMove; + timerContainer.MouseLeftButtonUp -= TimerContainer_MouseLeftButtonUp; + } } private void HandleTimerCompletion() { - if (minimizedWindow != null) - { - minimizedWindow.Close(); - minimizedWindow = null; - this.Show(); - this.Activate(); - this.WindowState = WindowState.Normal; - // 重新应用置顶 - ApplyTimerWindowTopmost(); - } - else if (fullscreenWindow != null) - { - fullscreenWindow.Close(); - fullscreenWindow = null; - isFullscreenMode = false; - this.Show(); - this.Activate(); - this.WindowState = WindowState.Normal; - // 重新应用置顶 - ApplyTimerWindowTopmost(); - } } - - #region Win32 API 声明和置顶管理 - [DllImport("user32.dll")] - private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); - - [DllImport("user32.dll")] - private static extern int GetWindowLong(IntPtr hWnd, int nIndex); - - [DllImport("user32.dll")] - private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); - - [DllImport("user32.dll")] - private static extern bool IsWindow(IntPtr hWnd); - - [DllImport("user32.dll")] - private static extern bool IsWindowVisible(IntPtr hWnd); - - [DllImport("user32.dll")] - private static extern bool IsIconic(IntPtr hWnd); - - [DllImport("user32.dll")] - private static extern IntPtr GetForegroundWindow(); - - [DllImport("user32.dll")] - private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); - - [DllImport("kernel32.dll")] - private static extern uint GetCurrentProcessId(); - - private const int GWL_EXSTYLE = -20; - private const int WS_EX_TOPMOST = 0x00000008; - private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); - private static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2); - private const uint SWP_NOMOVE = 0x0002; - private const uint SWP_NOSIZE = 0x0001; - private const uint SWP_NOACTIVATE = 0x0010; - private const uint SWP_SHOWWINDOW = 0x0040; - private const uint SWP_NOOWNERZORDER = 0x0200; - - /// - /// 应用计时器窗口置顶 - /// - private void ApplyTimerWindowTopmost() + + private void HideTimer_Elapsed(object sender, ElapsedEventArgs e) { - try + if (!isTimerRunning || isPaused) return; + + Application.Current.Dispatcher.Invoke(() => { - var hwnd = new WindowInteropHelper(this).Handle; - if (hwnd == IntPtr.Zero) return; - - // 设置WPF的Topmost属性 - Topmost = true; - - // 使用Win32 API强制置顶 - // 1. 设置窗口样式为置顶 - int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE); - SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST); - - // 2. 使用SetWindowPos确保窗口在最顶层 - // 使用HWND_TOPMOST确保窗口始终在所有其他窗口之上,包括主窗口 - SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW); - - LogHelper.WriteLogToFile("计时器窗口已应用置顶", LogHelper.LogType.Trace); - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"应用计时器窗口置顶失败: {ex.Message}", LogHelper.LogType.Error); - } + var timeSinceLastActivity = DateTime.Now - lastActivityTime; + + if (timeSinceLastActivity.TotalSeconds >= 5) + { + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow != null) + { + var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement; + if (timerContainer != null && timerContainer.Visibility == Visibility.Visible) + { + ShowMinimizedRequested?.Invoke(this, EventArgs.Empty); + } + } + } + }); } - - /// - /// 窗口加载事件处理,确保置顶 - /// - private void TimerWindow_Loaded(object sender, RoutedEventArgs e) + + public void UpdateActivityTime() { - // 使用延迟确保窗口完全加载后再应用置顶 - Dispatcher.BeginInvoke(new Action(() => + lastActivityTime = DateTime.Now; + + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow != null) { - ApplyTimerWindowTopmost(); - }), DispatcherPriority.Loaded); + var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement; + var minimizedContainer = mainWindow.FindName("MinimizedTimerContainer") as FrameworkElement; + + if (timerContainer != null && minimizedContainer != null) + { + if (timerContainer.Visibility == Visibility.Collapsed && minimizedContainer.Visibility == Visibility.Visible) + { + HideMinimizedRequested?.Invoke(this, EventArgs.Empty); + } + } + } } - #endregion + } }