improve:计时器UI

将计时器窗口整合至主窗口,优化全屏计时逻辑
This commit is contained in:
2025-11-29 16:27:35 +08:00
parent a0539dce9b
commit 6802476afa
12 changed files with 1581 additions and 631 deletions
+24
View File
@@ -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 @@
<!-- 合并新橡皮擦资源 -->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MainWindow_cs/MW_Eraser.xaml"/>
<ResourceDictionary Source="Resources/Styles/Light.xaml"/>
<ResourceDictionary Source="Resources/Styles/Dark.xaml"/>
</ResourceDictionary.MergedDictionaries>
<c:IsEnabledToOpacityConverter x:Key="IsEnabledToOpacityConverter" />
@@ -9950,6 +9953,27 @@
</ui:SimpleStackPanel>
</Border>
</Viewbox>
<Border x:Name="TimerContainer"
Visibility="Collapsed"
Panel.ZIndex="998"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="900"
Height="500">
<Windows:TimerControl x:Name="TimerControl"/>
</Border>
<Border x:Name="MinimizedTimerContainer"
Visibility="Collapsed"
Panel.ZIndex="997"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="20,20,0,0"
Width="600"
Height="200">
<Windows:MinimizedTimerControl x:Name="MinimizedTimerControl"/>
</Border>
</Grid>
</Window>
+96
View File
@@ -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)
@@ -1051,19 +1051,40 @@ namespace Ink_Canvas
AnimationsHelper.HideWithSlideAndFade(BoardBorderTools);
AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel);
// 参考老计时器的窗口置顶功能:在白板模式下停止窗口置顶
if (currentMode == 1) // 白板模式
if (Settings.RandSettings?.UseNewStyleUI == true)
{
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;
}
};
}
}
else
{
if (currentMode == 1)
{
Topmost = false;
}
var timerWindow = CountdownTimerWindow.CreateTimerWindow();
timerWindow.Show();
if (currentMode == 1) // 白板模式
if (currentMode == 1)
{
timerWindow.Topmost = true;
}
}
}
private void OperatingGuideWindowIcon_MouseUp(object sender, MouseButtonEventArgs e)
{
@@ -28,16 +28,9 @@ namespace Ink_Canvas
}
public static Window CreateTimerWindow()
{
if (MainWindow.Settings.RandSettings?.UseNewStyleUI == true)
{
return new NewStyleTimerWindow();
}
else
{
return new CountdownTimerWindow();
}
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
@@ -1,9 +1,9 @@
<Window x:Class="Ink_Canvas.FullscreenTimerWindow"
<Window x:Class="Ink_Canvas.Windows.FullscreenTimerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Ink_Canvas"
xmlns:local="clr-namespace:Ink_Canvas.Windows"
Topmost="True" Background="Black"
mc:Ignorable="d" WindowStyle="None" AllowsTransparency="False"
WindowState="Maximized" WindowStartupLocation="Manual"
@@ -8,33 +8,45 @@ using System.Windows.Media;
using System.Windows.Shapes;
using System.Timers;
namespace Ink_Canvas
namespace Ink_Canvas.Windows
{
/// <summary>
/// 全屏计时器窗口
/// </summary>
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;
}
// 清理资源
@@ -0,0 +1,124 @@
<UserControl x:Class="Ink_Canvas.Windows.MinimizedTimerControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="200" d:DesignWidth="600">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="DigitResources.xaml" />
<ResourceDictionary Source="/Resources/Styles/Light.xaml" />
<ResourceDictionary Source="/Resources/Styles/Dark.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Border x:Name="MainBorder" Background="{DynamicResource NewTimerWindowBackground}"
CornerRadius="15"
BorderThickness="1"
BorderBrush="{DynamicResource NewTimerWindowBorderBrush}"
Margin="0"
UseLayoutRounding="True"
SnapsToDevicePixels="True"
MouseLeftButtonDown="MainBorder_MouseLeftButtonDown"
Cursor="Hand">
<Grid>
<!-- 时间显示 -->
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20,20,20,20">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<!-- 小时 -->
<Path x:Name="MinHour1Display" Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="72" Height="72"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Margin="0,0,12,0"/>
<Path x:Name="MinHour2Display" Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="72" Height="72"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Margin="0,0,12,0"/>
<!-- 冒号 -->
<TextBlock x:Name="MinColon1Display" Text=":" FontSize="48" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowDigitForeground}"
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="0,0,12,0"/>
<!-- 分钟 -->
<Path x:Name="MinMinute1Display" Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="72" Height="72"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Margin="0,0,12,0"/>
<Path x:Name="MinMinute2Display" Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="72" Height="72"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Margin="0,0,12,0"/>
<!-- 冒号 -->
<TextBlock x:Name="MinColon2Display" Text=":" FontSize="48" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowDigitForeground}"
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="0,0,12,0"/>
<!-- 秒 -->
<Path x:Name="MinSecond1Display" Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="72" Height="72"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Margin="0,0,12,0"/>
<Path x:Name="MinSecond2Display" Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="72" Height="72"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Margin="0,0,0,0"/>
</StackPanel>
</Grid>
<!-- 关闭按钮 -->
<Button x:Name="CloseButton"
Width="24" Height="24"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="0,8,8,0"
Background="Transparent"
BorderThickness="0"
Click="CloseButton_Click"
Cursor="Hand"
Opacity="0.7">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="12">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#E81123"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
<TextBlock Text="✕" FontSize="12" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Button>
</Grid>
</Border>
</UserControl>
@@ -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
{
/// <summary>
/// 最小化计时器窗口
/// </summary>
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;
}
}
}
+2 -2
View File
@@ -1,9 +1,9 @@
<Window x:Class="Ink_Canvas.MinimizedTimerWindow"
<Window x:Class="Ink_Canvas.Windows.MinimizedTimerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Ink_Canvas"
xmlns:local="clr-namespace:Ink_Canvas.Windows"
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
Topmost="True" Background="Transparent"
mc:Ignorable="d" WindowStyle="None" AllowsTransparency="True"
+26 -40
View File
@@ -8,37 +8,35 @@ using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Media.Animation;
namespace Ink_Canvas
namespace Ink_Canvas.Windows
{
/// <summary>
/// 最小化计时器窗口
/// </summary>
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,21 +419,13 @@ 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();
}
}
}
}
private DateTime lastClickTime = DateTime.Now;
@@ -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;
}
// 清理资源
@@ -1,32 +1,37 @@
<Window x:Class="Ink_Canvas.NewStyleTimerWindow"
<UserControl x:Class="Ink_Canvas.Windows.TimerControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Ink_Canvas"
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:controls="clr-namespace:Ink_Canvas.Windows.Controls"
Topmost="True" Background="Transparent"
mc:Ignorable="d" WindowStyle="None" AllowsTransparency="True"
ResizeMode="CanMinimize"
Loaded="Window_Loaded" Closing="Window_Closing" WindowStartupLocation="CenterScreen"
MouseMove="Window_MouseMove" MouseEnter="Window_MouseEnter"
Title="Ink Canvas 画板 - 计时器" Height="450" Width="900">
<Window.Resources>
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="900">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Controls/WinUI3CloseButton.xaml" />
<ResourceDictionary Source="DigitResources.xaml" />
<ResourceDictionary Source="/Resources/Styles/Light.xaml" />
<ResourceDictionary Source="/Resources/Styles/Dark.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
</UserControl.Resources>
<Border Background="{DynamicResource NewTimerWindowBackground}" CornerRadius="15" BorderThickness="1" BorderBrush="{DynamicResource NewTimerWindowBorderBrush}" Margin="10" x:Name="MainBorder" MouseLeftButtonDown="WindowDragMove">
<Border Background="{DynamicResource NewTimerWindowBackground}"
CornerRadius="15"
BorderThickness="1"
BorderBrush="{DynamicResource NewTimerWindowBorderBrush}"
Margin="10"
x:Name="MainBorder"
MouseLeftButtonDown="MainBorder_MouseLeftButtonDown">
<Grid>
<controls:WinUI3CloseButton x:Name="CloseButton"
HorizontalAlignment="Right" VerticalAlignment="Top"
Margin="0,0,0,0" Cursor="Hand" Click="CloseButton_Click"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="0,0,0,0"
Cursor="Hand"
Click="CloseButton_Click"
Content="✕"/>
<!-- 主要内容区域 -->
<Grid>
@@ -34,8 +39,16 @@
<Viewbox x:Name="MainViewController" Margin="20,20,20,20">
<Grid Height="400" Width="900">
<!-- 顶部标题栏 -->
<Grid Height="50" Background="{DynamicResource NewTimerWindowBackground}" x:Name="TitleBar" VerticalAlignment="Top" MouseLeftButtonDown="WindowDragMove" Margin="0,0,450,0">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="22,0,0,0">
<Grid Height="50"
Background="{DynamicResource NewTimerWindowBackground}"
x:Name="TitleBar"
VerticalAlignment="Top"
Margin="0,0,450,0"
MouseLeftButtonDown="TitleBar_MouseLeftButtonDown">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="22,0,0,0">
<!-- 计时器图标 -->
<Path Data="M5 13a7 7 0 1 0 14 0a7 7 0 0 0 -14 0z M14.5 10.5l-2.5 2.5 M17 8l1 -1 M14 3h-4"
Stroke="{DynamicResource NewTimerWindowTitleForeground}"
@@ -46,32 +59,53 @@
Stretch="Uniform"
Margin="0,0,8,0"/>
<!-- 计时文字 -->
<TextBlock Text="计时" FontSize="28" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowTitleForeground}" x:Name="TitleText"/>
<TextBlock Text="计时"
FontSize="28"
FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowTitleForeground}"
x:Name="TitleText"/>
</StackPanel>
</Grid>
<!-- 主要内容区域 - 分为左右两部分 -->
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Center"
x:Name="MainContentGrid" Margin="0,-25,0,25">
<Grid HorizontalAlignment="Stretch"
VerticalAlignment="Center"
x:Name="MainContentGrid"
Margin="0,-25,0,25">
<!-- 左侧:6位数字显示区域 -->
<Grid HorizontalAlignment="Left" VerticalAlignment="Center"
x:Name="MainDisplayGrid" Width="500" Margin="-10,0,0,0">
<Grid HorizontalAlignment="Left"
VerticalAlignment="Center"
x:Name="MainDisplayGrid"
Width="500"
Margin="-10,0,0,0">
<!-- 6位数字水平排列 -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
x:Name="DigitsPanel">
<!-- 小时组(十位和个位) -->
<Grid Margin="0,0,20,0" HorizontalAlignment="Center" Width="120">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Grid Margin="0,0,20,0"
HorizontalAlignment="Center"
Width="120">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<!-- 第1位数字(小时十位) -->
<Grid Margin="0,0,15,0">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center">
<!-- 上方+按钮 -->
<Button x:Name="Digit1PlusBtn" Width="40" Height="40" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit1Plus_Click" Cursor="Hand" Margin="0,0,0,15" HorizontalAlignment="Center">
<Button x:Name="Digit1PlusBtn"
Width="40" Height="40"
Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0"
Click="Digit1Plus_Click"
Cursor="Hand"
Margin="0,0,0,15"
HorizontalAlignment="Center">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border Background="{TemplateBinding Background}"
CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
@@ -86,7 +120,8 @@
Stretch="Uniform"/>
</Button>
<!-- 数字显示 -->
<Path x:Name="Digit1Display" Data="{StaticResource Digit0}"
<Path x:Name="Digit1Display"
Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="48" Height="48"
HorizontalAlignment="Center"
@@ -94,12 +129,19 @@
Stretch="Uniform"
Margin="0,0,0,15"/>
<!-- 下方-按钮 -->
<Button x:Name="Digit1MinusBtn" Width="40" Height="40" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit1Minus_Click" Cursor="Hand" HorizontalAlignment="Center">
<Button x:Name="Digit1MinusBtn"
Width="40" Height="40"
Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0"
Click="Digit1Minus_Click"
Cursor="Hand"
HorizontalAlignment="Center">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border Background="{TemplateBinding Background}"
CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
@@ -115,17 +157,25 @@
</Button>
</StackPanel>
</Grid>
<!-- 第2位数字(小时个位) -->
<Grid>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center">
<!-- 上方+按钮 -->
<Button x:Name="Digit2PlusBtn" Width="40" Height="40" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit2Plus_Click" Cursor="Hand" Margin="0,0,0,15" HorizontalAlignment="Center">
<Button x:Name="Digit2PlusBtn"
Width="40" Height="40"
Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0"
Click="Digit2Plus_Click"
Cursor="Hand"
Margin="0,0,0,15"
HorizontalAlignment="Center">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border Background="{TemplateBinding Background}"
CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
@@ -140,7 +190,8 @@
Stretch="Uniform"/>
</Button>
<!-- 数字显示 -->
<Path x:Name="Digit2Display" Data="{StaticResource Digit0}"
<Path x:Name="Digit2Display"
Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="48" Height="48"
HorizontalAlignment="Center"
@@ -148,12 +199,19 @@
Stretch="Uniform"
Margin="0,0,0,15"/>
<!-- 下方-按钮 -->
<Button x:Name="Digit2MinusBtn" Width="40" Height="40" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit2Minus_Click" Cursor="Hand" HorizontalAlignment="Center">
<Button x:Name="Digit2MinusBtn"
Width="40" Height="40"
Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0"
Click="Digit2Minus_Click"
Cursor="Hand"
HorizontalAlignment="Center">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border Background="{TemplateBinding Background}"
CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
@@ -171,26 +229,40 @@
</Grid>
</StackPanel>
</Grid>
<!-- 冒号分隔符 -->
<TextBlock x:Name="Colon1Display" Text=":" FontSize="48" FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center"
<TextBlock x:Name="Colon1Display"
Text=":"
FontSize="48"
FontWeight="Bold"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{DynamicResource NewTimerWindowDigitForeground}"
Margin="-20,0,0,0"/>
<!-- 分钟组(十位和个位) -->
<Grid Margin="0,0,20,0" HorizontalAlignment="Center" Width="120">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Grid Margin="0,0,20,0"
HorizontalAlignment="Center"
Width="120">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<!-- 第3位数字(分钟十位) -->
<Grid Margin="0,0,15,0">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center">
<!-- 上方+按钮 -->
<Button x:Name="Digit3PlusBtn" Width="40" Height="40" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit3Plus_Click" Cursor="Hand" Margin="0,0,0,15" HorizontalAlignment="Center">
<Button x:Name="Digit3PlusBtn"
Width="40" Height="40"
Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0"
Click="Digit3Plus_Click"
Cursor="Hand"
Margin="0,0,0,15"
HorizontalAlignment="Center">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border Background="{TemplateBinding Background}"
CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
@@ -205,7 +277,8 @@
Stretch="Uniform"/>
</Button>
<!-- 数字显示 -->
<Path x:Name="Digit3Display" Data="{StaticResource Digit0}"
<Path x:Name="Digit3Display"
Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="48" Height="48"
HorizontalAlignment="Center"
@@ -213,12 +286,19 @@
Stretch="Uniform"
Margin="0,0,0,15"/>
<!-- 下方-按钮 -->
<Button x:Name="Digit3MinusBtn" Width="40" Height="40" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit3Minus_Click" Cursor="Hand" HorizontalAlignment="Center">
<Button x:Name="Digit3MinusBtn"
Width="40" Height="40"
Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0"
Click="Digit3Minus_Click"
Cursor="Hand"
HorizontalAlignment="Center">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border Background="{TemplateBinding Background}"
CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
@@ -234,17 +314,25 @@
</Button>
</StackPanel>
</Grid>
<!-- 第4位数字(分钟个位) -->
<Grid>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center">
<!-- 上方+按钮 -->
<Button x:Name="Digit4PlusBtn" Width="40" Height="40" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit4Plus_Click" Cursor="Hand" Margin="0,0,0,15" HorizontalAlignment="Center">
<Button x:Name="Digit4PlusBtn"
Width="40" Height="40"
Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0"
Click="Digit4Plus_Click"
Cursor="Hand"
Margin="0,0,0,15"
HorizontalAlignment="Center">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border Background="{TemplateBinding Background}"
CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
@@ -259,7 +347,8 @@
Stretch="Uniform"/>
</Button>
<!-- 数字显示 -->
<Path x:Name="Digit4Display" Data="{StaticResource Digit0}"
<Path x:Name="Digit4Display"
Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="48" Height="48"
HorizontalAlignment="Center"
@@ -267,12 +356,19 @@
Stretch="Uniform"
Margin="0,0,0,15"/>
<!-- 下方-按钮 -->
<Button x:Name="Digit4MinusBtn" Width="40" Height="40" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit4Minus_Click" Cursor="Hand" HorizontalAlignment="Center">
<Button x:Name="Digit4MinusBtn"
Width="40" Height="40"
Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0"
Click="Digit4Minus_Click"
Cursor="Hand"
HorizontalAlignment="Center">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border Background="{TemplateBinding Background}"
CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
@@ -290,26 +386,38 @@
</Grid>
</StackPanel>
</Grid>
<!-- 冒号分隔符 -->
<TextBlock x:Name="Colon2Display" Text=":" FontSize="48" FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center"
<TextBlock x:Name="Colon2Display"
Text=":"
FontSize="48"
FontWeight="Bold"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{DynamicResource NewTimerWindowDigitForeground}"
Margin="-20,0,0,0"/>
<!-- 秒组(十位和个位) -->
<Grid Width="120">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<!-- 第5位数字(秒十位) -->
<Grid Margin="0,0,15,0">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center">
<!-- 上方+按钮 -->
<Button x:Name="Digit5PlusBtn" Width="40" Height="40" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit5Plus_Click" Cursor="Hand" Margin="0,0,0,15" HorizontalAlignment="Center">
<Button x:Name="Digit5PlusBtn"
Width="40" Height="40"
Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0"
Click="Digit5Plus_Click"
Cursor="Hand"
Margin="0,0,0,15"
HorizontalAlignment="Center">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border Background="{TemplateBinding Background}"
CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
@@ -324,7 +432,8 @@
Stretch="Uniform"/>
</Button>
<!-- 数字显示 -->
<Path x:Name="Digit5Display" Data="{StaticResource Digit0}"
<Path x:Name="Digit5Display"
Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="48" Height="48"
HorizontalAlignment="Center"
@@ -332,12 +441,19 @@
Stretch="Uniform"
Margin="0,0,0,15"/>
<!-- 下方-按钮 -->
<Button x:Name="Digit5MinusBtn" Width="40" Height="40" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit5Minus_Click" Cursor="Hand" HorizontalAlignment="Center">
<Button x:Name="Digit5MinusBtn"
Width="40" Height="40"
Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0"
Click="Digit5Minus_Click"
Cursor="Hand"
HorizontalAlignment="Center">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border Background="{TemplateBinding Background}"
CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
@@ -353,17 +469,25 @@
</Button>
</StackPanel>
</Grid>
<!-- 第6位数字(秒个位) -->
<Grid>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center">
<!-- 上方+按钮 -->
<Button x:Name="Digit6PlusBtn" Width="40" Height="40" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit6Plus_Click" Cursor="Hand" Margin="0,0,0,15" HorizontalAlignment="Center">
<Button x:Name="Digit6PlusBtn"
Width="40" Height="40"
Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0"
Click="Digit6Plus_Click"
Cursor="Hand"
Margin="0,0,0,15"
HorizontalAlignment="Center">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border Background="{TemplateBinding Background}"
CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
@@ -378,7 +502,8 @@
Stretch="Uniform"/>
</Button>
<!-- 数字显示 -->
<Path x:Name="Digit6Display" Data="{StaticResource Digit0}"
<Path x:Name="Digit6Display"
Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="48" Height="48"
HorizontalAlignment="Center"
@@ -386,12 +511,19 @@
Stretch="Uniform"
Margin="0,0,0,15"/>
<!-- 下方-按钮 -->
<Button x:Name="Digit6MinusBtn" Width="40" Height="40" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit6Minus_Click" Cursor="Hand" HorizontalAlignment="Center">
<Button x:Name="Digit6MinusBtn"
Width="40" Height="40"
Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0"
Click="Digit6Minus_Click"
Cursor="Hand"
HorizontalAlignment="Center">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border Background="{TemplateBinding Background}"
CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
@@ -411,16 +543,22 @@
</Grid>
</StackPanel>
</Grid>
<!-- 分割线 -->
<Border Width="2" Background="{DynamicResource NewTimerWindowButtonForeground}"
Opacity="0.3" HorizontalAlignment="Left" VerticalAlignment="Stretch"
<Border Width="2"
Background="{DynamicResource NewTimerWindowButtonForeground}"
Opacity="0.3"
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
Margin="465,0,0,0"/>
<!-- 右侧:快捷选项区域 -->
<Grid HorizontalAlignment="Left" VerticalAlignment="Center"
x:Name="QuickOptionsGrid" Width="400" Margin="470,0,0,0" Height="200">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<Grid HorizontalAlignment="Left"
VerticalAlignment="Center"
x:Name="QuickOptionsGrid"
Width="400"
Margin="470,0,0,0"
Height="200">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center">
<!-- Segmented Control -->
<Grid Margin="0,0,0,20">
<Border Background="{DynamicResource NewTimerWindowButtonBackground}"
@@ -437,7 +575,6 @@
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="0,0,0,0"/>
<!-- 按钮容器 -->
<Grid>
<Button x:Name="CommonTabBtn"
@@ -447,7 +584,10 @@
Click="CommonTab_Click"
Cursor="Hand"
HorizontalAlignment="Left">
<TextBlock x:Name="CommonTabText" Text="常用" FontSize="16" FontWeight="Bold"
<TextBlock x:Name="CommonTabText"
Text="常用"
FontSize="16"
FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</Button>
<Button x:Name="RecentTabBtn"
@@ -457,14 +597,17 @@
Click="RecentTab_Click"
Cursor="Hand"
HorizontalAlignment="Right">
<TextBlock x:Name="RecentTabText" Text="最近" FontSize="16" FontWeight="Normal"
Foreground="{DynamicResource NewTimerWindowButtonForeground}" Opacity="0.6"/>
<TextBlock x:Name="RecentTabText"
Text="最近"
FontSize="16"
FontWeight="Normal"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"
Opacity="0.6"/>
</Button>
</Grid>
</Grid>
</Border>
</Grid>
<!-- 常用计时区域 -->
<Grid x:Name="CommonTimersGrid" Visibility="Visible">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
@@ -621,7 +764,6 @@
</StackPanel>
</StackPanel>
</Grid>
<!-- 最近计时区域 -->
<Grid x:Name="RecentTimersGrid" Visibility="Collapsed">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
@@ -709,17 +851,29 @@
</StackPanel>
</Grid>
</Grid>
<!-- 底部控制按钮区域 -->
<Grid HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,20">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Grid HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Margin="0,0,0,20">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<!-- 全屏按钮 -->
<Button x:Name="FullscreenBtn" Width="80" Height="40" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Fullscreen_Click" Cursor="Hand" Margin="0,0,30,0" IsEnabled="False">
<Button x:Name="FullscreenBtn"
Width="80" Height="40"
Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0"
Click="Fullscreen_Click"
Cursor="Hand"
Margin="0,0,30,0"
IsEnabled="False">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border x:Name="border" Background="{TemplateBinding Background}" CornerRadius="8" Opacity="1">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border x:Name="border"
Background="{TemplateBinding Background}"
CornerRadius="8"
Opacity="1">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
@@ -728,7 +882,8 @@
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<Path Data="M4 8v-2a2 2 0 0 1 2 -2h2 M4 16v2a2 2 0 0 0 2 2h2 M16 4h2a2 2 0 0 1 2 2v2 M16 20h2a2 2 0 0 0 2 -2v-2"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
@@ -737,37 +892,55 @@
Width="20" Height="20"
Stretch="Uniform"
Margin="0,0,5,0"/>
<TextBlock Text="全屏" FontSize="16" Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
<TextBlock Text="全屏"
FontSize="16"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</StackPanel>
</Button>
<!-- 开始/暂停按钮 -->
<Button x:Name="StartPauseBtn" Width="80" Height="80" Background="{DynamicResource NewTimerWindowPrimaryButtonBackground}"
BorderThickness="0" Click="StartPause_Click" Cursor="Hand" Margin="0,0,30,0">
<Button x:Name="StartPauseBtn"
Width="80" Height="80"
Background="{DynamicResource NewTimerWindowPrimaryButtonBackground}"
BorderThickness="0"
Click="StartPause_Click"
Cursor="Hand"
Margin="0,0,30,0">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="40">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border Background="{TemplateBinding Background}"
CornerRadius="40">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<Path x:Name="StartPauseIcon" Data="M6.5 4.00004V20C6.49995 20.178 6.54737 20.3527 6.63738 20.5062C6.72739 20.6597 6.85672 20.7864 7.01202 20.8732C7.16733 20.96 7.34299 21.0038 7.52088 21.0001C7.69878 20.9964 7.87245 20.9453 8.024 20.852L21.024 12.852C21.1696 12.7626 21.2898 12.6373 21.3733 12.4881C21.4567 12.339 21.5005 12.1709 21.5005 12C21.5005 11.8291 21.4567 11.6611 21.3733 11.512C21.2898 11.3628 21.1696 11.2375 21.024 11.148L8.024 3.14804C7.87245 3.0548 7.69878 3.00369 7.52088 2.99997C7.34299 2.99626 7.16733 3.04007 7.01202 3.1269C6.85672 3.21372 6.72739 3.34042 6.63738 3.4939C6.54737 3.64739 6.49995 3.82211 6.5 4.00004Z"
<Path x:Name="StartPauseIcon"
Data="M6.5 4.00004V20C6.49995 20.178 6.54737 20.3527 6.63738 20.5062C6.72739 20.6597 6.85672 20.7864 7.01202 20.8732C7.16733 20.96 7.34299 21.0038 7.52088 21.0001C7.69878 20.9964 7.87245 20.9453 8.024 20.852L21.024 12.852C21.1696 12.7626 21.2898 12.6373 21.3733 12.4881C21.4567 12.339 21.5005 12.1709 21.5005 12C21.5005 11.8291 21.4567 11.6611 21.3733 11.512C21.2898 11.3628 21.1696 11.2375 21.024 11.148L8.024 3.14804C7.87245 3.0548 7.69878 3.00369 7.52088 2.99997C7.34299 2.99626 7.16733 3.04007 7.01202 3.1269C6.85672 3.21372 6.72739 3.34042 6.63738 3.4939C6.54737 3.64739 6.49995 3.82211 6.5 4.00004Z"
Fill="{DynamicResource NewTimerWindowPrimaryButtonForeground}"
Width="24" Height="24" Margin="2,0,0,0"
HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="Fill"/>
Width="24" Height="24"
Margin="2,0,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Fill"/>
</Button>
<!-- 重置按钮 -->
<Button x:Name="ResetBtn" Width="80" Height="40" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Reset_Click" Cursor="Hand">
<Button x:Name="ResetBtn"
Width="80" Height="40"
Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0"
Click="Reset_Click"
Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="8">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Border Background="{TemplateBinding Background}"
CornerRadius="8">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<Path Data="M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4 M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
@@ -776,7 +949,9 @@
Width="20" Height="20"
Stretch="Uniform"
Margin="0,0,5,0"/>
<TextBlock Text="重置" FontSize="16" Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
<TextBlock Text="重置"
FontSize="16"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</StackPanel>
</Button>
</StackPanel>
@@ -786,4 +961,5 @@
</Grid>
</Grid>
</Border>
</Window>
</UserControl>
@@ -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
{
/// <summary>
/// 最近计时记录数据模型
@@ -31,12 +29,11 @@ namespace Ink_Canvas
/// <summary>
/// 新计时器UI风格的倒计时器窗口
/// </summary>
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;
}
#region
/// <summary>
/// 计时器完成事件
/// </summary>
public event EventHandler TimerCompleted;
private void TimerWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// 恢复主窗口的置顶维护
var mainWindow = Application.Current.MainWindow as MainWindow;
if (mainWindow != null)
{
mainWindow.ResumeTopmostMaintenance();
}
}
/// <summary>
/// 关闭事件 - 通知主窗口隐藏容器
/// </summary>
public event EventHandler CloseRequested;
/// <summary>
/// 显示最小化视图事件
/// </summary>
public event EventHandler ShowMinimizedRequested;
/// <summary>
/// 隐藏最小化视图事件
/// </summary>
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;
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();
}
/// <summary>
/// 根据数字值设置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();
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);
}
}
}
}
// 创建全屏计时器窗口
fullscreenWindow = new FullscreenTimerWindow(this);
fullscreenWindow.Show();
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);
}
}
}
}
// 确保全屏窗口也置顶(窗口加载时会自动应用)
fullscreenWindow.Topmost = true;
private bool isDragging = false;
private Point dragStartPoint;
private Point containerStartPosition;
// 隐藏主窗口
this.Hide();
private void DragTimerContainer(MainWindow mainWindow, Point startPoint, MouseButtonEventArgs e)
{
var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement;
if (timerContainer == null) return;
isDragging = true;
dragStartPoint = startPoint;
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;
}
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)
private void HideTimer_Elapsed(object sender, ElapsedEventArgs e)
{
fullscreenWindow.Close();
fullscreenWindow = null;
isFullscreenMode = false;
this.Show();
this.Activate();
this.WindowState = WindowState.Normal;
// 重新应用置顶
ApplyTimerWindowTopmost();
if (!isTimerRunning || isPaused) return;
Application.Current.Dispatcher.Invoke(() =>
{
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);
}
}
}
});
}
public void UpdateActivityTime()
{
lastActivityTime = DateTime.Now;
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)
{
if (timerContainer.Visibility == Visibility.Collapsed && minimizedContainer.Visibility == Visibility.Visible)
{
HideMinimizedRequested?.Invoke(this, EventArgs.Empty);
}
}
}
}
#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;
/// <summary>
/// 应用计时器窗口置顶
/// </summary>
private void ApplyTimerWindowTopmost()
{
try
{
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);
}
}
/// <summary>
/// 窗口加载事件处理,确保置顶
/// </summary>
private void TimerWindow_Loaded(object sender, RoutedEventArgs e)
{
// 使用延迟确保窗口完全加载后再应用置顶
Dispatcher.BeginInvoke(new Action(() =>
{
ApplyTimerWindowTopmost();
}), DispatcherPriority.Loaded);
}
#endregion
}
}