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 @@
-
-
-
+
+
-
+
-
-
+
+
@@ -728,7 +882,8 @@
-
+
-
+
-
-
+
-
-
+
+
-
+
-
-
+
-
-
+
+
-
+
-
+
@@ -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
+
}
}