2025-12-20 13:56:46 +08:00
|
|
|
|
using iNKORE.UI.WPF.Modern;
|
|
|
|
|
|
using Microsoft.Win32;
|
2025-11-29 16:27:35 +08:00
|
|
|
|
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();
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
updateTimer = new System.Timers.Timer(100);
|
|
|
|
|
|
updateTimer.Elapsed += UpdateTimer_Elapsed;
|
|
|
|
|
|
updateTimer.Start();
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
ApplyTheme();
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 23:11:01 +08:00
|
|
|
|
// 监听主题变化事件
|
|
|
|
|
|
SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-12-27 17:58:53 +08:00
|
|
|
|
// 监听分辨率变化事件
|
|
|
|
|
|
SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
|
|
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
Unloaded += MinimizedTimerControl_Unloaded;
|
2025-12-27 17:58:53 +08:00
|
|
|
|
|
|
|
|
|
|
// 监听加载事件,设置UI大小
|
|
|
|
|
|
Loaded += MinimizedTimerControl_Loaded;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 分辨率变化时重新计算大小
|
|
|
|
|
|
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
UpdateMinimizedTimerControlSize();
|
|
|
|
|
|
}), System.Windows.Threading.DispatcherPriority.Loaded);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void MainWindow_DpiChanged(object sender, DpiChangedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// DPI变化时重新计算大小
|
|
|
|
|
|
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
UpdateMinimizedTimerControlSize();
|
|
|
|
|
|
}), System.Windows.Threading.DispatcherPriority.Loaded);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void MinimizedTimerControl_Loaded(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 根据DPI和分辨率限制UI大小为屏幕的35%
|
|
|
|
|
|
UpdateMinimizedTimerControlSize();
|
|
|
|
|
|
|
|
|
|
|
|
// 监听DPI变化事件(通过主窗口)
|
|
|
|
|
|
var mainWindow = Application.Current.MainWindow as MainWindow;
|
|
|
|
|
|
if (mainWindow != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
mainWindow.DpiChanged += MainWindow_DpiChanged;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 根据DPI和分辨率更新最小化计时器控件大小,限制在屏幕大小的35%
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void UpdateMinimizedTimerControlSize()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 获取主窗口
|
|
|
|
|
|
var mainWindow = Application.Current.MainWindow as MainWindow;
|
|
|
|
|
|
if (mainWindow == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 获取DPI缩放因子
|
|
|
|
|
|
var source = PresentationSource.FromVisual(mainWindow);
|
|
|
|
|
|
double dpiScaleX = 1.0, dpiScaleY = 1.0;
|
|
|
|
|
|
if (source != null && source.CompositionTarget != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var transform = source.CompositionTarget.TransformToDevice;
|
|
|
|
|
|
dpiScaleX = transform.M11;
|
|
|
|
|
|
dpiScaleY = transform.M22;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取屏幕工作区域大小(考虑DPI)
|
|
|
|
|
|
double screenWidth = SystemParameters.WorkArea.Width / dpiScaleX;
|
|
|
|
|
|
double screenHeight = SystemParameters.WorkArea.Height / dpiScaleY;
|
|
|
|
|
|
|
|
|
|
|
|
// 计算最大尺寸(屏幕的35%)
|
|
|
|
|
|
double maxWidth = screenWidth * 0.35;
|
|
|
|
|
|
double maxHeight = screenHeight * 0.35;
|
|
|
|
|
|
|
|
|
|
|
|
// 保持宽高比(基于原始设计尺寸 600x200,宽高比约为 3:1)
|
|
|
|
|
|
double aspectRatio = 600.0 / 200.0;
|
|
|
|
|
|
double calculatedWidth = maxWidth;
|
|
|
|
|
|
double calculatedHeight = calculatedWidth / aspectRatio;
|
|
|
|
|
|
|
|
|
|
|
|
// 如果计算出的高度超过最大高度,则按高度计算
|
|
|
|
|
|
if (calculatedHeight > maxHeight)
|
|
|
|
|
|
{
|
|
|
|
|
|
calculatedHeight = maxHeight;
|
|
|
|
|
|
calculatedWidth = calculatedHeight * aspectRatio;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算缩放比例(基于原始尺寸600x200)
|
|
|
|
|
|
double originalWidth = 600.0;
|
|
|
|
|
|
double originalHeight = 200.0;
|
|
|
|
|
|
double scaleX = calculatedWidth / originalWidth;
|
|
|
|
|
|
double scaleY = calculatedHeight / originalHeight;
|
|
|
|
|
|
double scale = Math.Min(scaleX, scaleY); // 使用较小的缩放比例以保持比例
|
|
|
|
|
|
|
|
|
|
|
|
// 查找父容器(MinimizedTimerContainer)
|
|
|
|
|
|
var parent = this.Parent as FrameworkElement;
|
|
|
|
|
|
if (parent == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果直接父元素不是FrameworkElement,尝试查找Border
|
|
|
|
|
|
var visualParent = System.Windows.Media.VisualTreeHelper.GetParent(this);
|
|
|
|
|
|
while (visualParent != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (visualParent is FrameworkElement fe && fe.Name == "MinimizedTimerContainer")
|
|
|
|
|
|
{
|
|
|
|
|
|
parent = fe;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
visualParent = System.Windows.Media.VisualTreeHelper.GetParent(visualParent);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (parent != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 设置父容器大小
|
|
|
|
|
|
parent.Width = calculatedWidth;
|
|
|
|
|
|
parent.Height = calculatedHeight;
|
|
|
|
|
|
|
|
|
|
|
|
// 更新数字显示(Path元素)的大小 - 原始尺寸72x72
|
|
|
|
|
|
double digitSize = 72.0 * scale;
|
|
|
|
|
|
UpdateElementSize("MinHour1Display", digitSize, digitSize);
|
|
|
|
|
|
UpdateElementSize("MinHour2Display", digitSize, digitSize);
|
|
|
|
|
|
UpdateElementSize("MinMinute1Display", digitSize, digitSize);
|
|
|
|
|
|
UpdateElementSize("MinMinute2Display", digitSize, digitSize);
|
|
|
|
|
|
UpdateElementSize("MinSecond1Display", digitSize, digitSize);
|
|
|
|
|
|
UpdateElementSize("MinSecond2Display", digitSize, digitSize);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新冒号字体大小 - 原始尺寸48
|
|
|
|
|
|
double colonFontSize = 48.0 * scale;
|
|
|
|
|
|
UpdateTextBlockFontSize("MinColon1Display", colonFontSize);
|
|
|
|
|
|
UpdateTextBlockFontSize("MinColon2Display", colonFontSize);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新关闭按钮大小 - 原始尺寸24x24
|
|
|
|
|
|
double closeButtonSize = 24.0 * scale;
|
|
|
|
|
|
UpdateElementSize("CloseButton", closeButtonSize, closeButtonSize);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新关闭按钮字体大小 - 原始尺寸12
|
|
|
|
|
|
double closeButtonFontSize = 12.0 * scale;
|
|
|
|
|
|
var closeButton = this.FindName("CloseButton") as System.Windows.Controls.Button;
|
|
|
|
|
|
if (closeButton != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var textBlock = closeButton.Content as System.Windows.Controls.TextBlock;
|
|
|
|
|
|
if (textBlock != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
textBlock.FontSize = closeButtonFontSize;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新Margin - 原始Margin是12,需要按比例缩放
|
|
|
|
|
|
double marginSize = 12.0 * scale;
|
|
|
|
|
|
UpdateElementMargin("MinHour1Display", new Thickness(0, 0, marginSize, 0));
|
|
|
|
|
|
UpdateElementMargin("MinHour2Display", new Thickness(0, 0, marginSize, 0));
|
|
|
|
|
|
UpdateElementMargin("MinColon1Display", new Thickness(0, 0, marginSize, 0));
|
|
|
|
|
|
UpdateElementMargin("MinMinute1Display", new Thickness(0, 0, marginSize, 0));
|
|
|
|
|
|
UpdateElementMargin("MinMinute2Display", new Thickness(0, 0, marginSize, 0));
|
|
|
|
|
|
UpdateElementMargin("MinColon2Display", new Thickness(0, 0, marginSize, 0));
|
|
|
|
|
|
UpdateElementMargin("MinSecond1Display", new Thickness(0, 0, marginSize, 0));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"更新最小化计时器控件大小失败: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 更新元素的大小
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void UpdateElementSize(string elementName, double width, double height)
|
|
|
|
|
|
{
|
|
|
|
|
|
var element = this.FindName(elementName) as FrameworkElement;
|
|
|
|
|
|
if (element != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
element.Width = width;
|
|
|
|
|
|
element.Height = height;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 更新TextBlock的字体大小
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void UpdateTextBlockFontSize(string elementName, double fontSize)
|
|
|
|
|
|
{
|
|
|
|
|
|
var textBlock = this.FindName(elementName) as System.Windows.Controls.TextBlock;
|
|
|
|
|
|
if (textBlock != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
textBlock.FontSize = fontSize;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 更新元素的Margin
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void UpdateElementMargin(string elementName, Thickness margin)
|
|
|
|
|
|
{
|
|
|
|
|
|
var element = this.FindName(elementName) as FrameworkElement;
|
|
|
|
|
|
if (element != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
element.Margin = margin;
|
|
|
|
|
|
}
|
2025-11-29 16:27:35 +08:00
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
private void MinimizedTimerControl_Unloaded(object sender, RoutedEventArgs e)
|
|
|
|
|
|
{
|
2025-11-29 23:11:01 +08:00
|
|
|
|
// 取消订阅主题变化事件
|
|
|
|
|
|
SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged;
|
2025-12-27 17:58:53 +08:00
|
|
|
|
SystemEvents.DisplaySettingsChanged -= SystemEvents_DisplaySettingsChanged;
|
|
|
|
|
|
|
|
|
|
|
|
// 取消订阅DPI变化事件
|
|
|
|
|
|
var mainWindow = Application.Current.MainWindow as MainWindow;
|
|
|
|
|
|
if (mainWindow != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
mainWindow.DpiChanged -= MainWindow_DpiChanged;
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
if (parentControl != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
parentControl.TimerCompleted -= ParentControl_TimerCompleted;
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
if (updateTimer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
updateTimer.Stop();
|
|
|
|
|
|
updateTimer.Dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 23:11:01 +08:00
|
|
|
|
private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 当主题变化时,重新应用主题
|
|
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
RefreshTheme();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 23:11:01 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 刷新主题
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void RefreshTheme()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 重新应用主题
|
|
|
|
|
|
ApplyTheme();
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 23:11:01 +08:00
|
|
|
|
// 强制刷新UI
|
|
|
|
|
|
InvalidateVisual();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"刷新最小化计时器窗口主题出错: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-29 16:27:35 +08:00
|
|
|
|
|
|
|
|
|
|
public void SetParentControl(TimerControl parent)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (parentControl != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
parentControl.TimerCompleted -= ParentControl_TimerCompleted;
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
parentControl = parent;
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
if (ShouldHide())
|
|
|
|
|
|
{
|
|
|
|
|
|
this.Visibility = Visibility.Collapsed;
|
|
|
|
|
|
var parent = this.Parent as FrameworkElement;
|
|
|
|
|
|
if (parent != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
parent.Visibility = Visibility.Collapsed;
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
UpdateTimeDisplay();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
private bool ShouldHide()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (parentControl == null) return true;
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
if (parentControl.IsFullscreenWindowOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
if (MainWindow.Settings.RandSettings?.EnableOvertimeCountUp == true)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (parentControl.IsTimerRunning)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
var remainingTime = parentControl.GetRemainingTime();
|
|
|
|
|
|
if (remainingTime.HasValue && remainingTime.Value.TotalSeconds < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
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);
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
SetDigitDisplay("MinMinute1Display", minutes / 10, shouldShowRed);
|
|
|
|
|
|
SetDigitDisplay("MinMinute2Display", minutes % 10, shouldShowRed);
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
SetDigitDisplay("MinSecond1Display", seconds / 10, shouldShowRed);
|
|
|
|
|
|
SetDigitDisplay("MinSecond2Display", seconds % 10, shouldShowRed);
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
SetColonDisplay(shouldShowRed);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
if (isRed)
|
|
|
|
|
|
{
|
|
|
|
|
|
path.Fill = Brushes.Red;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-11-29 23:11:01 +08:00
|
|
|
|
var defaultBrush = this.TryFindResource("NewTimerWindowDigitForeground") as Brush;
|
2025-11-29 16:27:35 +08:00
|
|
|
|
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;
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
if (colon1 != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isRed)
|
|
|
|
|
|
{
|
|
|
|
|
|
colon1.Foreground = Brushes.Red;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-11-29 23:11:01 +08:00
|
|
|
|
var defaultBrush = this.TryFindResource("NewTimerWindowDigitForeground") as Brush;
|
2025-11-29 16:27:35 +08:00
|
|
|
|
if (defaultBrush != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
colon1.Foreground = defaultBrush;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
bool isLightTheme = IsLightTheme();
|
|
|
|
|
|
colon1.Foreground = isLightTheme ? Brushes.Black : Brushes.White;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
if (colon2 != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isRed)
|
|
|
|
|
|
{
|
|
|
|
|
|
colon2.Foreground = Brushes.Red;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-11-29 23:11:01 +08:00
|
|
|
|
var defaultBrush = this.TryFindResource("NewTimerWindowDigitForeground") as Brush;
|
2025-11-29 16:27:35 +08:00
|
|
|
|
if (defaultBrush != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
colon2.Foreground = defaultBrush;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
bool isLightTheme = IsLightTheme();
|
|
|
|
|
|
colon2.Foreground = isLightTheme ? Brushes.Black : Brushes.White;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ApplyTheme()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-11-29 23:11:01 +08:00
|
|
|
|
if (MainWindow.Settings != null)
|
2025-11-29 16:27:35 +08:00
|
|
|
|
{
|
2025-11-29 23:11:01 +08:00
|
|
|
|
ApplyTheme(MainWindow.Settings);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
bool isLightTheme = IsLightTheme();
|
|
|
|
|
|
if (!isLightTheme)
|
|
|
|
|
|
{
|
|
|
|
|
|
SetDarkThemeBorder();
|
|
|
|
|
|
}
|
2025-11-29 16:27:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"应用主题时出错: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 23:11:01 +08:00
|
|
|
|
private void ApplyTheme(Settings settings)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (settings.Appearance.Theme == 0) // 浅色主题
|
|
|
|
|
|
{
|
|
|
|
|
|
ThemeManager.SetRequestedTheme(this, ElementTheme.Light);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (settings.Appearance.Theme == 1) // 深色主题
|
|
|
|
|
|
{
|
|
|
|
|
|
ThemeManager.SetRequestedTheme(this, ElementTheme.Dark);
|
|
|
|
|
|
SetDarkThemeBorder();
|
|
|
|
|
|
}
|
|
|
|
|
|
else // 跟随系统主题
|
|
|
|
|
|
{
|
|
|
|
|
|
bool isSystemLight = IsSystemThemeLight();
|
|
|
|
|
|
if (isSystemLight)
|
|
|
|
|
|
{
|
|
|
|
|
|
ThemeManager.SetRequestedTheme(this, ElementTheme.Light);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
ThemeManager.SetRequestedTheme(this, ElementTheme.Dark);
|
|
|
|
|
|
SetDarkThemeBorder();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 23:11:01 +08:00
|
|
|
|
// 刷新数字和冒号显示的颜色
|
|
|
|
|
|
if (parentControl != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
UpdateTimeDisplay();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"应用最小化计时器窗口主题出错: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 23:11:01 +08:00
|
|
|
|
private bool IsSystemThemeLight()
|
|
|
|
|
|
{
|
|
|
|
|
|
var light = false;
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var registryKey = Microsoft.Win32.Registry.CurrentUser;
|
|
|
|
|
|
var themeKey = registryKey.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
|
|
|
|
|
|
if (themeKey != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var value = themeKey.GetValue("AppsUseLightTheme");
|
|
|
|
|
|
if (value != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
light = (int)value == 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
themeKey.Close();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果读取注册表失败,默认为浅色主题
|
|
|
|
|
|
light = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
return light;
|
|
|
|
|
|
}
|
2025-11-29 16:27:35 +08:00
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
private bool isDragging = false;
|
|
|
|
|
|
private bool isDragStarted = false;
|
|
|
|
|
|
private Point dragStartPoint;
|
|
|
|
|
|
private Point containerStartPosition;
|
|
|
|
|
|
private const double DragThreshold = 5.0; // 拖动阈值,像素
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
private void MainBorder_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (e.ClickCount == 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 双击:恢复主窗口
|
|
|
|
|
|
if (parentControl != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
parentControl.UpdateActivityTime();
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
var mainWindow = Application.Current.MainWindow as MainWindow;
|
|
|
|
|
|
if (mainWindow != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement;
|
|
|
|
|
|
var minimizedContainer = mainWindow.FindName("MinimizedTimerContainer") as FrameworkElement;
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
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);
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
// 初始化拖动状态,但不立即开始拖动
|
|
|
|
|
|
isDragging = false;
|
|
|
|
|
|
isDragStarted = false;
|
|
|
|
|
|
dragStartPoint = mainWindowPoint;
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
var margin = minimizedContainer.Margin;
|
|
|
|
|
|
containerStartPosition = new Point(margin.Left, margin.Top);
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
if (double.IsNaN(containerStartPosition.X) || containerStartPosition.X < 0) containerStartPosition.X = 0;
|
|
|
|
|
|
if (double.IsNaN(containerStartPosition.Y) || containerStartPosition.Y < 0) containerStartPosition.Y = 0;
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
// 捕获鼠标并订阅事件,等待判断是拖动还是点击
|
|
|
|
|
|
minimizedContainer.CaptureMouse();
|
|
|
|
|
|
minimizedContainer.MouseMove += MinimizedContainer_MouseMove;
|
|
|
|
|
|
minimizedContainer.MouseLeftButtonUp += MinimizedContainer_MouseLeftButtonUp;
|
|
|
|
|
|
e.Handled = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
private void MinimizedContainer_MouseMove(object sender, MouseEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
var mainWindow = Application.Current.MainWindow as MainWindow;
|
|
|
|
|
|
if (mainWindow == null) return;
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
var minimizedContainer = mainWindow.FindName("MinimizedTimerContainer") as FrameworkElement;
|
|
|
|
|
|
if (minimizedContainer == null) return;
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
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);
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
// 如果移动距离超过阈值,开始拖动
|
|
|
|
|
|
if (!isDragStarted && distance > DragThreshold)
|
|
|
|
|
|
{
|
|
|
|
|
|
isDragStarted = true;
|
|
|
|
|
|
isDragging = true;
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
// 如果已经开始拖动,更新位置
|
|
|
|
|
|
if (isDragging)
|
|
|
|
|
|
{
|
|
|
|
|
|
var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement;
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
var newX = containerStartPosition.X + deltaX;
|
|
|
|
|
|
var newY = containerStartPosition.Y + deltaY;
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
if (newX < 0) newX = 0;
|
|
|
|
|
|
if (newY < 0) newY = 0;
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
minimizedContainer.Margin = new Thickness(newX, newY, 0, 0);
|
|
|
|
|
|
minimizedContainer.HorizontalAlignment = HorizontalAlignment.Left;
|
|
|
|
|
|
minimizedContainer.VerticalAlignment = VerticalAlignment.Top;
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
if (timerContainer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
timerContainer.Margin = new Thickness(newX, newY, 0, 0);
|
|
|
|
|
|
timerContainer.HorizontalAlignment = HorizontalAlignment.Left;
|
|
|
|
|
|
timerContainer.VerticalAlignment = VerticalAlignment.Top;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
private void MinimizedContainer_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
var mainWindow = Application.Current.MainWindow as MainWindow;
|
|
|
|
|
|
if (mainWindow == null) return;
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
var minimizedContainer = mainWindow.FindName("MinimizedTimerContainer") as FrameworkElement;
|
|
|
|
|
|
if (minimizedContainer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
minimizedContainer.ReleaseMouseCapture();
|
|
|
|
|
|
minimizedContainer.MouseMove -= MinimizedContainer_MouseMove;
|
|
|
|
|
|
minimizedContainer.MouseLeftButtonUp -= MinimizedContainer_MouseLeftButtonUp;
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
// 如果没有开始拖动(移动距离小于阈值),则视为单击,恢复主窗口
|
|
|
|
|
|
if (!isDragStarted)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (parentControl != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
parentControl.UpdateActivityTime();
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement;
|
|
|
|
|
|
if (timerContainer != null && minimizedContainer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
timerContainer.Visibility = Visibility.Visible;
|
|
|
|
|
|
minimizedContainer.Visibility = Visibility.Collapsed;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-20 13:56:46 +08:00
|
|
|
|
|
2025-11-29 16:27:35 +08:00
|
|
|
|
isDragging = false;
|
|
|
|
|
|
isDragStarted = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-29 23:11:01 +08:00
|
|
|
|
|