Merge pull request #266 from InkCanvasForClass/beta

ICC CE 1.7.14.0
This commit is contained in:
CJK_mkp
2025-10-18 19:06:17 +08:00
committed by GitHub
61 changed files with 4632 additions and 1206 deletions
+427 -3
View File
@@ -1,4 +1,428 @@
obj/
bin/
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
*.env
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
[Dd]ebug/x64/
[Dd]ebugPublic/x64/
[Rr]elease/x64/
[Rr]eleases/x64/
bin/x64/
obj/x64/
[Dd]ebug/x86/
[Dd]ebugPublic/x86/
[Rr]elease/x86/
[Rr]eleases/x86/
bin/x86/
obj/x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
[Aa][Rr][Mm]64[Ee][Cc]/
bld/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
# Build results on 'Bin' directories
**/[Bb]in/*
# Uncomment if you have tasks that rely on *.refresh files to move binaries
# (https://github.com/github/gitignore/pull/3736)
#!**/[Bb]in/*.refresh
# Visual Studio 2015/2017 cache/options directory
.vs/
/Ink Canvas/obj
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
*.trx
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Approval Tests result files
*.received.*
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.idb
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
# but not Directory.Build.rsp, as it configures directory-level build defaults
!Directory.Build.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
**/.paket/paket.exe
paket-files/
# FAKE - F# Make
**/.fake/
# CodeRush personal settings
**/.cr/personal
# Python Tools for Visual Studio (PTVS)
**/__pycache__/
*.pyc
# Cake - Uncomment if you are using it
#tools/**
#!tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
MSBuild_Logs/
# AWS SAM Build and Temporary Artifacts folder
.aws-sam
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
**/.mfractor/
# Local History for Visual Studio
**/.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
**/.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
+1 -1
View File
@@ -1 +1 @@
1.7.13.0
1.7.14.0
-6
View File
@@ -1,6 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/PencilsConfiguration/ActualSeverity/@EntryValue">WARNING</s:String>
<s:String x:Key="/Default/Environment/Hierarchy/Build/BuildTool/CustomBuildToolPath/@EntryValue">C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\amd64\MSBuild.exe</s:String>
<s:Int64 x:Key="/Default/Environment/Hierarchy/Build/BuildTool/MsbuildVersion/@EntryValue">1114112</s:Int64>
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=InkCanvasForClass_002FProperties_002FResources/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/ResxEditorPersonal/Initialized/@EntryValue">True</s:Boolean></wpf:ResourceDictionary>
+1 -1
View File
@@ -232,7 +232,7 @@
ContextMenu="{StaticResource SysTrayMenu}"
IconSource="/Resources/icc.ico"/>
<ResourceDictionary.MergedDictionaries>
<ui:ThemeResources RequestedTheme="Light"/>
<ui:ThemeResources/>
<ui:XamlControlsResources />
<ResourceDictionary Source="Resources/SeewoImageDictionary.xaml"/>
<ResourceDictionary Source="Resources/DrawShapeImageDictionary.xaml"/>
+28 -3
View File
@@ -41,6 +41,8 @@ namespace Ink_Canvas
private static Process watchdogProcess;
// 新增:标记是否为软件内主动退出
public static bool IsAppExitByUser;
// 新增:标记是否启用了UIA置顶功能
public static bool IsUIAccessTopMostEnabled;
// 新增:退出信号文件路径
private static string watchdogExitSignalFile = Path.Combine(Path.GetTempPath(), "icc_watchdog_exit_" + Process.GetCurrentProcess().Id + ".flag");
// 新增:崩溃日志文件路径
@@ -629,7 +631,7 @@ namespace Ink_Canvas
LogHelper.WriteLogToFile("App | 检测到最终应用启动(更新后的应用)");
}
// 在应用启动时自动释放IACore相关DLL
// 释放IACore相关DLL
if (_isSplashScreenShown)
{
SetSplashMessage("正在初始化组件...");
@@ -645,6 +647,22 @@ namespace Ink_Canvas
LogHelper.WriteLogToFile($"释放IACore DLL时出错: {ex.Message}", LogHelper.LogType.Error);
}
// 释放UIAccess DLL
if (_isSplashScreenShown)
{
SetSplashMessage("正在初始化组件...");
SetSplashProgress(50);
await Task.Delay(300);
}
try
{
UIAccessDllExtractor.ExtractUIAccessDlls();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"释放UIAccess DLL时出错: {ex.Message}", LogHelper.LogType.Error);
}
// 记录应用启动(设备标识符)
if (_isSplashScreenShown)
{
@@ -1055,7 +1073,15 @@ namespace Ink_Canvas
Thread.Sleep(2000);
}
// 主进程异常退出,自动重启前判断崩溃后操作
SyncCrashActionFromSettings(); // 新增:同步设置
SyncCrashActionFromSettings(); // 同步设置
if (IsUIAccessTopMostEnabled)
{
string exePath = Process.GetCurrentProcess().MainModule.FileName;
Process.Start(exePath);
Environment.Exit(0);
}
if (CrashAction == CrashActionType.SilentRestart)
{
StartupCount.Increment();
@@ -1068,7 +1094,6 @@ namespace Ink_Canvas
string exePath = Process.GetCurrentProcess().MainModule.FileName;
Process.Start(exePath);
}
// CrashActionType.NoAction 时不重启,直接退出
}
catch { }
Environment.Exit(0);
+2 -2
View File
@@ -49,5 +49,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.7.13.0")]
[assembly: AssemblyFileVersion("1.7.13.0")]
[assembly: AssemblyVersion("1.7.14.0")]
[assembly: AssemblyFileVersion("1.7.14.0")]
-176
View File
@@ -1,176 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>Obsolete, use UnmanagedWinX86Assemblies instead</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="UnmanagedWinX86Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged X86 (32 bit) assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>Obsolete, use UnmanagedWinX64Assemblies instead.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="UnmanagedWinX64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged X64 (64 bit) assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="UnmanagedWinArm64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged Arm64 (64 bit) assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeReferences" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if runtime assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UseRuntimeReferencePaths" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls whether the runtime assemblies are embedded with their full path or only with their assembly name.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCompression" type="xs:boolean">
<xs:annotation>
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCleanup" type="xs:boolean">
<xs:annotation>
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableEventSubscription" type="xs:boolean">
<xs:annotation>
<xs:documentation>The attach method no longer subscribes to the `AppDomain.AssemblyResolve` (.NET 4.x) and `AssemblyLoadContext.Resolving` (.NET 6.0+) events.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>Obsolete, use UnmanagedWinX86Assemblies instead</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UnmanagedWinX86Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged X86 (32 bit) assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>Obsolete, use UnmanagedWinX64Assemblies instead</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UnmanagedWinX64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged X64 (64 bit) assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UnmanagedWinArm64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged Arm64 (64 bit) assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
+23
View File
@@ -112,4 +112,27 @@ namespace Ink_Canvas.Converter
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); }
}
public class InverseBooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((bool)value)
{
return Visibility.Collapsed;
}
return Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((bool)value)
{
return Visibility.Collapsed;
}
return Visibility.Visible;
}
}
}
+2 -2
View File
@@ -865,7 +865,7 @@ namespace Ink_Canvas.Helpers
{
// 检查当前是否处于鼠标模式
bool isMouseMode = IsInSelectMode();
if (isMouseMode)
{
// 鼠标模式下,根据设置决定是否启用快捷键
@@ -874,7 +874,7 @@ namespace Ink_Canvas.Helpers
else
{
// 非鼠标模式下,需要检查焦点和屏幕位置
// 策略1:鼠标在窗口上时启用热键(最高优先级)
if (_isMouseOverWindow)
{
+1 -1
View File
@@ -162,7 +162,7 @@ namespace Ink_Canvas.Helpers
}
/// <summary>
/// 强制保存指定页面的墨迹(忽略锁定状态)
/// 强制保存指定页面的墨迹
/// </summary>
public void ForceSaveSlideStrokes(int slideIndex, StrokeCollection strokes)
{
+16 -5
View File
@@ -678,14 +678,25 @@ namespace Ink_Canvas.Helpers
{
try
{
if (!IsConnected || !IsInSlideShow || PPTApplication == null) return false;
if (!IsConnected || PPTApplication == null) return false;
if (!Marshal.IsComObject(PPTApplication)) return false;
var slideShowWindow = PPTApplication.SlideShowWindows[1];
if (slideShowWindow?.View != null)
if (IsInSlideShow && PPTApplication.SlideShowWindows.Count >= 1)
{
slideShowWindow.View.GotoSlide(slideNumber);
return true;
var slideShowWindow = PPTApplication.SlideShowWindows[1];
if (slideShowWindow?.View != null)
{
slideShowWindow.View.GotoSlide(slideNumber);
return true;
}
}
else if (CurrentPresentation != null)
{
if (CurrentPresentation.Windows?.Count >= 1)
{
CurrentPresentation.Windows[1].View.GotoSlide(slideNumber);
return true;
}
}
return false;
}
+165
View File
@@ -0,0 +1,165 @@
using System;
using System.IO;
using System.Reflection;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// UIAccess DLL释放器
/// </summary>
public static class UIAccessDllExtractor
{
private static readonly string[] RequiredDlls = {
"UIAccessDLL_x64.dll",
"UIAccessDLL_x86.dll"
};
/// <summary>
/// 在应用启动时释放UIAccess相关DLL
/// </summary>
public static void ExtractUIAccessDlls()
{
try
{
string appDirectory = AppDomain.CurrentDomain.BaseDirectory;
LogHelper.WriteLogToFile("开始检查并释放UIAccess相关DLL文件");
foreach (string dllName in RequiredDlls)
{
string targetPath = Path.Combine(appDirectory, dllName);
// 检查文件是否已存在且有效
if (File.Exists(targetPath) && IsValidDll(targetPath))
{
LogHelper.WriteLogToFile($"{dllName} 已存在且有效,跳过释放");
continue;
}
// 从嵌入资源中释放DLL
if (ExtractDllFromResource(dllName, targetPath))
{
LogHelper.WriteLogToFile($"成功释放 {dllName} 到 {targetPath}");
}
else
{
LogHelper.WriteLogToFile($"警告:无法释放 {dllName},可能影响UIA置顶功能", LogHelper.LogType.Warning);
}
}
LogHelper.WriteLogToFile("UIAccess DLL释放检查完成");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"释放UIAccess DLL时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 从嵌入资源中提取DLL文件
/// </summary>
private static bool ExtractDllFromResource(string dllName, string targetPath)
{
try
{
Assembly assembly = Assembly.GetExecutingAssembly();
string resourceName = $"Ink_Canvas.{dllName}";
using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName))
{
if (resourceStream == null)
{
LogHelper.WriteLogToFile($"未找到嵌入资源: {resourceName}", LogHelper.LogType.Warning);
return false;
}
// 确保目标目录存在
string targetDirectory = Path.GetDirectoryName(targetPath);
if (!Directory.Exists(targetDirectory))
{
Directory.CreateDirectory(targetDirectory);
}
// 写入文件
using (FileStream fileStream = new FileStream(targetPath, FileMode.Create, FileAccess.Write))
{
resourceStream.CopyTo(fileStream);
}
return true;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"从资源提取 {dllName} 失败: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 检查DLL文件是否有效
/// </summary>
private static bool IsValidDll(string filePath)
{
try
{
if (!File.Exists(filePath))
return false;
FileInfo fileInfo = new FileInfo(filePath);
// 检查文件大小(空文件或过小的文件可能无效)
if (fileInfo.Length < 1024) // 小于1KB可能无效
return false;
// 简单检查PE头(DLL文件应该以MZ开头)
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[2];
if (fs.Read(buffer, 0, 2) == 2)
{
return buffer[0] == 0x4D && buffer[1] == 0x5A; // "MZ"
}
}
return false;
}
catch
{
return false;
}
}
/// <summary>
/// 清理释放的DLL文件(可选,在应用退出时调用)
/// </summary>
public static void CleanupExtractedDlls()
{
try
{
string appDirectory = AppDomain.CurrentDomain.BaseDirectory;
foreach (string dllName in RequiredDlls)
{
string filePath = Path.Combine(appDirectory, dllName);
if (File.Exists(filePath))
{
try
{
File.Delete(filePath);
LogHelper.WriteLogToFile($"已清理 {dllName}");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理 {dllName} 失败: {ex.Message}", LogHelper.LogType.Warning);
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理UIAccess DLL时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
}
}
+7
View File
@@ -192,11 +192,14 @@
</ItemGroup>
<ItemGroup>
<None Include="Resources\TimerDownNotice.wav" />
<None Include="Resources\ProgressiveAudio.wav" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\IACore\IACore.dll" />
<EmbeddedResource Include="Resources\IACore\IALoader.dll" />
<EmbeddedResource Include="Resources\IACore\IAWinFX.dll" />
<EmbeddedResource Include="UIAccessDLL_x64.dll" />
<EmbeddedResource Include="UIAccessDLL_x86.dll" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\Cursors\Cursor.cur" />
@@ -243,6 +246,10 @@
<Resource Include="Resources\Icons-png\undo.png" />
<Resource Include="Resources\Icons-png\minimize.png" />
<Resource Include="Resources\Icons-png\penUpright.png" />
<Resource Include="Resources\new-icons\multi-touch_white.png" />
<Resource Include="Resources\new-icons\hand-move_white.png" />
<Resource Include="Resources\new-icons\zoom_white.png" />
<Resource Include="Resources\new-icons\rotate_white.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\Icons-png\twoFingelMove-Blue.png" />
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_LastSelectedProfileId>D:\vs\ica\Ink Canvas\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
</PropertyGroup>
</Project>
+75 -12
View File
@@ -40,6 +40,7 @@
<c:IsEnabledToOpacityConverter x:Key="IsEnabledToOpacityConverter" />
<c:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<c:InverseBooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter" />
<c:IntNumberToString x:Key="IntNumberToString" />
<c:IntNumberToString2 x:Key="IntNumberToString2" />
@@ -609,6 +610,14 @@
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchAlwaysOnTop_Toggled" />
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Name="UIAccessTopMostPanel" Visibility="Collapsed">
<TextBlock Foreground="#fafafa" Text="UIA置顶" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchUIAccessTopMost"
IsOn="False" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchUIAccessTopMost_Toggled" />
</ui:SimpleStackPanel>
<TextBlock Name="UIAccessTopMostDescription" Text="# 开启UIA置顶后,软件自动重启置顶,关闭此功能需要完全关闭软件后再手动启动,无法使用重启来关闭此功能" TextWrapping="Wrap" Foreground="#a1a1aa" Visibility="Collapsed" />
<ui:ToggleSwitch OnContent="" OffContent=""
Name="ToggleSwitchIsAutoUpdate" Header="自动检查更新"
FontFamily="Microsoft YaHei UI"
@@ -631,6 +640,13 @@
<TextBlock Text="# 稳定版提供可靠更新,测试版提供新功能抢先体验" TextWrapping="Wrap" Foreground="#a1a1aa" />
</ui:SimpleStackPanel>
<!-- 手动更新按钮 -->
<Button x:Name="ManualUpdateButton" Content="手动更新" Margin="0,8,0,0"
Width="120" HorizontalAlignment="Left" Click="ManualUpdateButton_Click"
Visibility="{Binding ElementName=ToggleSwitchIsAutoUpdate, Path=IsOn, Converter={StaticResource InverseBooleanToVisibilityConverter}}"/>
<TextBlock Text="# 点击后立即检查并下载最新版本"
TextWrapping="Wrap" Foreground="#a1a1aa"
Visibility="{Binding ElementName=ToggleSwitchIsAutoUpdate, Path=IsOn, Converter={StaticResource InverseBooleanToVisibilityConverter}}"/>
<!-- 版本修复按钮 -->
<Button x:Name="FixVersionButton" Content="版本修复" Margin="0,8,0,0"
Width="120" HorizontalAlignment="Left" Click="FixVersionButton_Click"/>
@@ -2013,7 +2029,7 @@
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchNotifyPreviousPage_Toggled" />
</ui:SimpleStackPanel>
<TextBlock Text="#开启后会记录上次播放的页数,点击“是”后会在进入放映状态时自动跳转"
<TextBlock Text="#开启后会记录上次播放的页数,点击“是”后会自动跳转"
TextWrapping="Wrap" Foreground="#a1a1aa" />
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="进入放映时回到首页" VerticalAlignment="Center"
@@ -3297,13 +3313,31 @@
Toggled="ToggleSwitchUseLegacyTimerUI_Toggled" />
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="启用仿希沃UI"
<TextBlock Foreground="#fafafa" Text="新计时器UI"
VerticalAlignment="Center" FontSize="14" Margin="0,0,16,0" />
<ui:ToggleSwitch OnContent="" OffContent=""
Name="ToggleSwitchUseSeewoStyleUI"
Name="ToggleSwitchUseNewStyleUI"
IsOn="False" FontFamily="Microsoft YaHei UI"
FontWeight="Bold"
Toggled="ToggleSwitchUseSeewoStyleUI_Toggled" />
Toggled="ToggleSwitchUseNewStyleUI_Toggled" />
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="启用正计时"
VerticalAlignment="Center" FontSize="14" Margin="0,0,16,0" />
<ui:ToggleSwitch OnContent="" OffContent=""
Name="ToggleSwitchEnableOvertimeCountUp"
IsOn="False" FontFamily="Microsoft YaHei UI"
FontWeight="Bold"
Toggled="ToggleSwitchEnableOvertimeCountUp_Toggled" />
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="超时醒目数字"
VerticalAlignment="Center" FontSize="14" Margin="0,0,16,0" />
<ui:ToggleSwitch OnContent="" OffContent=""
Name="ToggleSwitchEnableOvertimeRedText"
IsOn="True" FontFamily="Microsoft YaHei UI"
FontWeight="Bold"
Toggled="ToggleSwitchEnableOvertimeRedText_Toggled" />
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="计时器提醒音量" VerticalAlignment="Center"
@@ -3325,6 +3359,35 @@
<Button Name="ButtonResetTimerSound" Content="重置" FontFamily="Microsoft YaHei UI"
Click="ButtonResetTimerSound_Click" Padding="10,3" Margin="5,0,0,0"/>
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,5,0,0">
<TextBlock Foreground="#fafafa" Text="渐进提醒" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<ui:ToggleSwitch OnContent="" OffContent=""
Name="ToggleSwitchEnableProgressiveReminder"
IsOn="False" FontFamily="Microsoft YaHei UI"
FontWeight="Bold"
Toggled="ToggleSwitchEnableProgressiveReminder_Toggled" />
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,5,0,0">
<TextBlock Foreground="#fafafa" Text="渐进提醒音量" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<Slider x:Name="ProgressiveReminderVolumeSlider" Minimum="0"
Maximum="1" Width="168" FontFamily="Microsoft YaHei UI"
ValueChanged="ProgressiveReminderVolumeSlider_ValueChanged"
FontSize="20" IsSnapToTickEnabled="True" Value="1" TickFrequency="0.1"
TickPlacement="None" AutoToolTipPlacement="None" />
<TextBlock VerticalAlignment="Center" Margin="12,0,16,0" FontSize="14"
FontFamily="Consolas"
Text="{Binding ElementName=ProgressiveReminderVolumeSlider, Path=Value, StringFormat={}{0:P0}}" />
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,5,0,0">
<TextBlock Foreground="#fafafa" Text="自定义渐进提醒音频:" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<Button Name="ButtonSelectCustomProgressiveReminderSound" Content="选择文件" FontFamily="Microsoft YaHei UI"
Click="ButtonSelectCustomProgressiveReminderSound_Click" Padding="10,3"/>
<Button Name="ButtonResetProgressiveReminderSound" Content="重置" FontFamily="Microsoft YaHei UI"
Click="ButtonResetProgressiveReminderSound_Click" Padding="10,3" Margin="5,0,0,0"/>
</ui:SimpleStackPanel>
</ui:SimpleStackPanel>
</GroupBox>
<GroupBox>
@@ -4418,7 +4481,7 @@
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="0,3,0,0">
<Image Source="/Resources/new-icons/multi-touch.png"
<Image Source="{DynamicResource MultiTouchIcon}"
RenderOptions.BitmapScalingMode="HighQuality"
Height="16"
Width="16" />
@@ -4449,7 +4512,7 @@
Orientation="Horizontal" Spacing="4"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<Image Source="/Resources/new-icons/hand-move.png"
<Image Source="{DynamicResource HandMoveIcon}"
RenderOptions.BitmapScalingMode="HighQuality"
Height="16"
Width="16" />
@@ -4480,7 +4543,7 @@
Orientation="Horizontal" Spacing="4"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<Image Source="/Resources/new-icons/zoom.png"
<Image Source="{DynamicResource ZoomIcon}"
RenderOptions.BitmapScalingMode="HighQuality"
Height="16"
Width="16" />
@@ -4509,7 +4572,7 @@
Orientation="Horizontal" Spacing="4"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<Image Source="/Resources/new-icons/rotate.png"
<Image Source="{DynamicResource RotateIcon}"
RenderOptions.BitmapScalingMode="HighQuality"
Height="16"
Width="16" />
@@ -9335,7 +9398,7 @@
</Border>
<ui:SimpleStackPanel Orientation="Horizontal" Spacing="4" VerticalAlignment="Center"
HorizontalAlignment="Center" Margin="0,3,0,0">
<Image Source="/Resources/new-icons/multi-touch.png"
<Image Source="{DynamicResource MultiTouchIcon}"
RenderOptions.BitmapScalingMode="HighQuality" Height="16" Width="16" />
<Label Content="多指书写" FontSize="10" VerticalAlignment="Center" />
<Viewbox Width="36" Height="18" Margin="4,0,0,0">
@@ -9359,7 +9422,7 @@
<ui:SimpleStackPanel Opacity="1" x:Name="TwoFingerGestureSimpleStackPanel"
Orientation="Horizontal" Spacing="4" VerticalAlignment="Center"
HorizontalAlignment="Center">
<Image Source="/Resources/new-icons/hand-move.png"
<Image Source="{DynamicResource HandMoveIcon}"
RenderOptions.BitmapScalingMode="HighQuality" Height="16" Width="16" />
<Label Content="双指移动" FontSize="10" VerticalAlignment="Center" />
<Viewbox Width="36" Height="18" Margin="4,0,0,0">
@@ -9384,7 +9447,7 @@
Opacity="{Binding ElementName=TwoFingerGestureSimpleStackPanel, Path=Opacity}"
Orientation="Horizontal" Spacing="4" VerticalAlignment="Center"
HorizontalAlignment="Center">
<Image Source="/Resources/new-icons/zoom.png"
<Image Source="{DynamicResource ZoomIcon}"
RenderOptions.BitmapScalingMode="HighQuality" Height="16" Width="16" />
<Label Content="双指缩放" FontSize="10" VerticalAlignment="Center" />
<Viewbox Width="36" Height="18" Margin="4,0,0,0">
@@ -9409,7 +9472,7 @@
Opacity="{Binding ElementName=TwoFingerGestureSimpleStackPanel, Path=Opacity}"
Orientation="Horizontal" Spacing="4" VerticalAlignment="Center"
HorizontalAlignment="Center">
<Image Source="/Resources/new-icons/rotate.png"
<Image Source="{DynamicResource RotateIcon}"
RenderOptions.BitmapScalingMode="HighQuality" Height="16" Width="16" />
<Label Content="双指旋转" FontSize="10" VerticalAlignment="Center" />
<Viewbox Width="36" Height="18" Margin="4,0,0,0">
+139 -11
View File
@@ -12,6 +12,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
@@ -38,6 +39,12 @@ namespace Ink_Canvas
{
public partial class MainWindow : Window
{
[DllImport("UIAccessDLL_x86.dll", EntryPoint = "PrepareUIAccess", CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 PrepareUIAccessX86();
[DllImport("UIAccessDLL_x64.dll", EntryPoint = "PrepareUIAccess", CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 PrepareUIAccessX64();
// 每一页一个Canvas对象
private List<System.Windows.Controls.Canvas> whiteboardPages = new List<System.Windows.Controls.Canvas>();
private int currentPageIndex;
@@ -55,6 +62,7 @@ namespace Ink_Canvas
// 设置面板相关状态
private bool userChangedNoFocusModeInSettings;
private bool isTemporarilyDisablingNoFocusMode = false;
@@ -550,6 +558,12 @@ namespace Ink_Canvas
ToggleSwitchAlwaysOnTop.IsOn = Settings.Advanced.IsAlwaysOnTop;
ApplyAlwaysOnTop();
// 初始化UIA置顶开关
ToggleSwitchUIAccessTopMost.IsOn = Settings.Advanced.EnableUIAccessTopMost;
UpdateUIAccessTopMostVisibility();
App.IsUIAccessTopMostEnabled = Settings.Advanced.EnableUIAccessTopMost;
// 初始化剪贴板监控
InitializeClipboardMonitoring();
@@ -787,7 +801,7 @@ namespace Ink_Canvas
}
}
// 辅助方法:使用多线路组下载更新
// 使用多线路组下载更新
private async Task<bool> DownloadUpdateWithFallback(string version, AutoUpdateHelper.UpdateLineGroup primaryGroup, UpdateChannel channel)
{
try
@@ -832,12 +846,14 @@ namespace Ink_Canvas
// 声明下载状态变量,用于整个方法
bool isDownloadSuccessful = false;
bool hasValidLineGroup = lineGroup != null;
if (AvailableLatestVersion != null)
{
// 检测到新版本,停止重试定时器
timerCheckAutoUpdateRetry.Stop();
updateCheckRetryCount = 0;
// 检测到新版本
LogHelper.WriteLogToFile($"AutoUpdate | New version available: {AvailableLatestVersion}");
@@ -1001,17 +1017,25 @@ namespace Ink_Canvas
break;
}
}
else if (hasValidLineGroup)
{
LogHelper.WriteLogToFile("AutoUpdate | Current version is already the latest, no retry needed");
// 停止重试定时器
timerCheckAutoUpdateRetry.Stop();
updateCheckRetryCount = 0;
}
else
{
// 检查更新失败,启动重试定时器
LogHelper.WriteLogToFile("AutoUpdate | Update check failed, starting retry timer");
// 重置重试计数
updateCheckRetryCount = 0;
// 启动重试定时器,10分钟后重新检查
timerCheckAutoUpdateRetry.Start();
// 清理更新文件夹
AutoUpdateHelper.DeleteUpdatesFolder();
}
@@ -1194,14 +1218,14 @@ namespace Ink_Canvas
RefreshDeviceInfo();
}
// 新增:个性化设置
// 个性化设置
private void NavTheme_Click(object sender, RoutedEventArgs e)
{
// 切换到个性化设置页面
ShowSettingsSection("theme");
}
// 新增:快捷键设置
// 快捷键设置
private void NavShortcuts_Click(object sender, RoutedEventArgs e)
{
OpenHotkeySettingsWindow();
@@ -1298,7 +1322,7 @@ namespace Ink_Canvas
}
}
// 新增:折叠侧边栏
// 折叠侧边栏
private void CollapseNavSidebar_Click(object sender, RoutedEventArgs e)
{
// 折叠/展开侧边栏
@@ -1315,7 +1339,7 @@ namespace Ink_Canvas
}
}
// 新增:显示侧边栏
// 显示侧边栏
private void ShowNavSidebar_Click(object sender, RoutedEventArgs e)
{
// 确保侧边栏展开
@@ -1323,7 +1347,7 @@ namespace Ink_Canvas
columnDefinitions[0].Width = new GridLength(50);
}
// 辅助方法:显示指定的设置部分
// 显示指定的设置部分
private async void ShowSettingsSection(string sectionTag)
{
// 显示设置面板
@@ -1816,7 +1840,11 @@ namespace Ink_Canvas
{
var hwnd = new WindowInteropHelper(this).Handle;
int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
if (Settings.Advanced.IsNoFocusMode)
bool shouldBeNoFocus = isTemporarilyDisablingNoFocusMode ?
false : Settings.Advanced.IsNoFocusMode;
if (shouldBeNoFocus)
{
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_NOACTIVATE);
}
@@ -1998,6 +2026,12 @@ namespace Ink_Canvas
var toggle = sender as ToggleSwitch;
Settings.Advanced.IsNoFocusMode = toggle != null && toggle.IsOn;
SaveSettingsToFile();
if (isTemporarilyDisablingNoFocusMode)
{
isTemporarilyDisablingNoFocusMode = false;
}
ApplyNoFocusMode();
// 如果启用了窗口置顶,需要重新应用置顶设置以处理无焦点模式的变化
@@ -2020,6 +2054,21 @@ namespace Ink_Canvas
Settings.Advanced.IsAlwaysOnTop = toggle != null && toggle.IsOn;
SaveSettingsToFile();
ApplyAlwaysOnTop();
UpdateUIAccessTopMostVisibility();
}
private void ToggleSwitchUIAccessTopMost_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
var toggle = sender as ToggleSwitch;
bool newValue = toggle != null && toggle.IsOn;
Settings.Advanced.EnableUIAccessTopMost = newValue;
SaveSettingsToFile();
ApplyUIAccessTopMost();
App.IsUIAccessTopMostEnabled = newValue;
}
private void Window_Activated(object sender, EventArgs e)
@@ -2449,6 +2498,8 @@ namespace Ink_Canvas
SideControlMinimumAutomationSlider,
RandWindowOnceCloseLatencySlider,
RandWindowOnceMaxStudentsSlider,
TimerVolumeSlider,
ProgressiveReminderVolumeSlider,
BoardInkWidthSlider,
BoardInkAlphaSlider,
BoardHighlighterWidthSlider,
@@ -2911,5 +2962,82 @@ namespace Ink_Canvas
}
#endregion
#region UIA置顶功能
/// <summary>
/// 更新UIA置顶开关的可见性
/// </summary>
private void UpdateUIAccessTopMostVisibility()
{
try
{
var visibility = Settings.Advanced.IsAlwaysOnTop ? Visibility.Visible : Visibility.Collapsed;
if (UIAccessTopMostPanel != null)
{
UIAccessTopMostPanel.Visibility = visibility;
}
if (UIAccessTopMostDescription != null)
{
UIAccessTopMostDescription.Visibility = visibility;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新UIA置顶开关可见性时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 应用UIA置顶功能
/// </summary>
private void ApplyUIAccessTopMost()
{
try
{
if (Settings.Advanced.EnableUIAccessTopMost && Settings.Advanced.IsAlwaysOnTop)
{
// 检查是否以管理员权限运行
var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
if (principal.IsInRole(WindowsBuiltInRole.Administrator))
{
try
{
// 调用UIAccess DLL
if (Environment.Is64BitProcess)
{
PrepareUIAccessX64();
}
else
{
PrepareUIAccessX86();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启用UIA置顶功能时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
else
{
LogHelper.WriteLogToFile("UIA置顶功能需要管理员权限", LogHelper.LogType.Warning);
}
}
else
{
LogHelper.WriteLogToFile("UIA置顶功能已禁用", LogHelper.LogType.Trace);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"应用UIA置顶功能时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
}
}
+14 -14
View File
@@ -74,7 +74,7 @@ namespace Ink_Canvas
// 强制刷新UI
window.InvalidateVisual();
// 通知其他窗口刷新主题
RefreshOtherWindowsTheme();
}
@@ -118,7 +118,7 @@ namespace Ink_Canvas
// 强制刷新UI
window.InvalidateVisual();
// 通知其他窗口刷新主题
RefreshOtherWindowsTheme();
}
@@ -184,18 +184,18 @@ namespace Ink_Canvas
// 根据主题设置高光颜色
Color highlightBackgroundColor;
Color highlightBarColor;
bool isDarkTheme = Settings.Appearance.Theme == 1 ||
bool isDarkTheme = Settings.Appearance.Theme == 1 ||
(Settings.Appearance.Theme == 2 && !IsSystemThemeLight());
if (isDarkTheme)
{
highlightBackgroundColor = Color.FromArgb(21, 102, 204, 255);
highlightBarColor = Color.FromRgb(102, 204, 255);
highlightBackgroundColor = Color.FromArgb(21, 102, 204, 255);
highlightBarColor = Color.FromRgb(102, 204, 255);
}
else
{
highlightBackgroundColor = Color.FromArgb(21, 59, 130, 246);
highlightBarColor = Color.FromRgb(37, 99, 235);
highlightBackgroundColor = Color.FromArgb(21, 59, 130, 246);
highlightBarColor = Color.FromRgb(37, 99, 235);
}
// 设置高光背景颜色
@@ -224,16 +224,16 @@ namespace Ink_Canvas
{
// 根据主题选择高光颜色
Color selectedColor;
bool isDarkTheme = Settings.Appearance.Theme == 1 ||
bool isDarkTheme = Settings.Appearance.Theme == 1 ||
(Settings.Appearance.Theme == 2 && !IsSystemThemeLight());
if (isDarkTheme)
{
selectedColor = Color.FromRgb(102, 204, 255);
selectedColor = Color.FromRgb(102, 204, 255);
}
else
{
selectedColor = Color.FromRgb(30, 58, 138);
selectedColor = Color.FromRgb(30, 58, 138);
}
// 根据当前模式设置按钮颜色
@@ -376,7 +376,7 @@ namespace Ink_Canvas
{
// 强制刷新墨迹选中栏的视觉状态
BorderStrokeSelectionControl.InvalidateVisual();
// 刷新墨迹选中栏内的所有图标
var viewbox = BorderStrokeSelectionControl.Child as Viewbox;
if (viewbox?.Child is ui.SimpleStackPanel stackPanel)
@@ -434,7 +434,7 @@ namespace Ink_Canvas
{
// 强制刷新图片选中栏的视觉状态
BorderImageSelectionControl.InvalidateVisual();
// 刷新图片选中栏内的所有图标
var viewbox = BorderImageSelectionControl.Child as Viewbox;
if (viewbox?.Child is ui.SimpleStackPanel stackPanel)
+16 -5
View File
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@@ -120,15 +121,25 @@ namespace Ink_Canvas
_currentCommitType = CommitReason.ClearingCanvas;
if (isErasedByCode) _currentCommitType = CommitReason.CodeInput;
// 只清除笔画,不清除图片元素
// 图片元素的清除由调用方决定
inkCanvas.Strokes.Clear();
// 执行内存清理
PerformLightweightMemoryCleanup();
_currentCommitType = CommitReason.UserInput;
}
/// <summary>
/// 执行内存清理
/// </summary>
private void PerformLightweightMemoryCleanup()
{
Task.Run(() =>
{
GC.Collect();
});
}
// 恢复每页白板图片信息
private void RestoreStrokes(bool isBackupMain = false)
{
@@ -418,7 +429,7 @@ namespace Ink_Canvas
// 获取主题颜色资源
var iconForegroundBrush = Application.Current.FindResource("IconForeground") as SolidColorBrush;
// 设置下一页按钮颜色
if (iconForegroundBrush != null)
{
+4 -1
View File
@@ -18,7 +18,10 @@ namespace Ink_Canvas
private void ColorSwitchCheck()
{
HideSubPanels("color");
if (penType != 1)
{
HideSubPanels("color");
}
if (GridTransparencyFakeBackground.Background == Brushes.Transparent)
{
if (currentMode == 1)
+19 -29
View File
@@ -383,7 +383,7 @@ namespace Ink_Canvas
var slideAnimation = new DoubleAnimation
{
From = 0, // 滑动距离
To = BorderSettings.RenderTransform.Value.OffsetX - 440,
To = BorderSettings.RenderTransform.Value.OffsetX - 490,
Duration = TimeSpan.FromSeconds(0.6)
};
slideAnimation.EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut };
@@ -396,18 +396,13 @@ namespace Ink_Canvas
{
BorderSettings.Visibility = Visibility.Collapsed;
isOpeningOrHidingSettingsPane = false;
// 在设置面板完全关闭后,根据情况恢复无焦点模式状态
if (!userChangedNoFocusModeInSettings && wasNoFocusModeBeforeSettings)
if (isTemporarilyDisablingNoFocusMode)
{
// 如果用户没有在设置中修改无焦点模式,则恢复之前的状态
Settings.Advanced.IsNoFocusMode = true;
ToggleSwitchNoFocusMode.IsOn = true; // 同步更新设置面板中的开关状态
isTemporarilyDisablingNoFocusMode = false;
ApplyNoFocusMode();
}
// 如果用户在设置中修改了无焦点模式,则保持用户的修改
};
BorderSettings.Visibility = Visibility.Visible;
BorderSettings.RenderTransform = new TranslateTransform();
isOpeningOrHidingSettingsPane = true;
@@ -477,9 +472,9 @@ namespace Ink_Canvas
// 根据主题选择高光颜色
Color highlightColor;
bool isDarkTheme = Settings.Appearance.Theme == 1 ||
bool isDarkTheme = Settings.Appearance.Theme == 1 ||
(Settings.Appearance.Theme == 2 && !IsSystemThemeLight());
if (isDarkTheme)
{
highlightColor = Color.FromRgb(102, 204, 255); // #66ccff for dark theme
@@ -929,7 +924,7 @@ namespace Ink_Canvas
#region
/// <summary>
/// 浮動工具欄的"套索選"按鈕事件,重定向到舊UI的<c>BtnSelect_Click</c>方法
/// 浮動工具欄的"套索選"按鈕事件,重定向到舊UI的<c>BtnSelect_Click</c>方法
/// </summary>
/// <param name="sender">sender</param>
/// <param name="e">MouseButtonEventArgs</param>
@@ -2708,11 +2703,9 @@ namespace Ink_Canvas
// 如果当前在设置面板中,需要先恢复无焦点模式状态
if (BorderSettings.Visibility == Visibility.Visible)
{
// 如果用户没有在设置中修改无焦点模式,则恢复之前的状态
if (!userChangedNoFocusModeInSettings && wasNoFocusModeBeforeSettings)
if (isTemporarilyDisablingNoFocusMode)
{
Settings.Advanced.IsNoFocusMode = true;
ToggleSwitchNoFocusMode.IsOn = true;
isTemporarilyDisablingNoFocusMode = false;
ApplyNoFocusMode();
}
SaveSettingsToFile();
@@ -2727,11 +2720,9 @@ namespace Ink_Canvas
{
if (BorderSettings.Visibility == Visibility.Visible)
{
// 如果用户没有在设置中修改无焦点模式,则恢复之前的状态
if (!userChangedNoFocusModeInSettings && wasNoFocusModeBeforeSettings)
if (isTemporarilyDisablingNoFocusMode)
{
Settings.Advanced.IsNoFocusMode = true;
ToggleSwitchNoFocusMode.IsOn = true;
isTemporarilyDisablingNoFocusMode = false;
ApplyNoFocusMode();
}
SaveSettingsToFile();
@@ -2777,12 +2768,12 @@ namespace Ink_Canvas
}
else
{
// 临时禁用无焦点模式以避免下拉选项被遮挡
BorderSettings.Visibility = Visibility.Visible;
wasNoFocusModeBeforeSettings = Settings.Advanced.IsNoFocusMode;
userChangedNoFocusModeInSettings = false; // 重置用户修改标志
if (wasNoFocusModeBeforeSettings)
{
Settings.Advanced.IsNoFocusMode = false;
isTemporarilyDisablingNoFocusMode = true;
ApplyNoFocusMode();
}
@@ -2795,7 +2786,7 @@ namespace Ink_Canvas
// 滑动动画
var slideAnimation = new DoubleAnimation
{
From = BorderSettings.RenderTransform.Value.OffsetX - 440, // 滑动距离
From = BorderSettings.RenderTransform.Value.OffsetX - 490, // 滑动距离
To = 0,
Duration = TimeSpan.FromSeconds(0.6)
};
@@ -2807,7 +2798,6 @@ namespace Ink_Canvas
sb.Completed += (s, _) => { isOpeningOrHidingSettingsPane = false; };
BorderSettings.Visibility = Visibility.Visible;
BorderSettings.RenderTransform = new TranslateTransform();
isOpeningOrHidingSettingsPane = true;
@@ -3717,18 +3707,18 @@ namespace Ink_Canvas
// 根据主题设置高光颜色
Color highlightBackgroundColor;
Color highlightBarColor;
bool isDarkTheme = Settings.Appearance.Theme == 1 ||
bool isDarkTheme = Settings.Appearance.Theme == 1 ||
(Settings.Appearance.Theme == 2 && !IsSystemThemeLight());
if (isDarkTheme)
{
highlightBackgroundColor = Color.FromArgb(21, 102, 204, 255);
highlightBarColor = Color.FromRgb(102, 204, 255);
highlightBackgroundColor = Color.FromArgb(21, 102, 204, 255);
highlightBarColor = Color.FromRgb(102, 204, 255);
}
else
{
highlightBackgroundColor = Color.FromArgb(21, 59, 130, 246);
highlightBarColor = Color.FromRgb(37, 99, 235);
highlightBackgroundColor = Color.FromArgb(21, 59, 130, 246);
highlightBarColor = Color.FromRgb(37, 99, 235);
}
// 设置高光背景颜色
+180 -65
View File
@@ -11,6 +11,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Media;
using System.Windows.Threading;
using Application = System.Windows.Application;
@@ -77,7 +78,7 @@ namespace Ink_Canvas
#region PPT State Management
private bool wasFloatingBarFoldedWhenEnterSlideShow;
private bool isEnteredSlideShowEndEvent; //防止重复调用本函数导致墨迹保存失效
private bool isEnteredSlideShowEndEvent;
private bool isPresentationHaveBlackSpace;
// 长按翻页相关字段
@@ -104,10 +105,11 @@ namespace Ink_Canvas
#region PPT Managers
private PPTManager _pptManager;
private MultiPPTInkManager _multiPPTInkManager;
private PPTInkManager _singlePPTInkManager;
private PPTUIManager _pptUIManager;
/// <summary>
/// 获取PPT管理器实例(供UI管理器使用)
/// 获取PPT管理器实例
/// </summary>
public PPTManager PPTManager => _pptManager;
#endregion
@@ -133,11 +135,19 @@ namespace Ink_Canvas
_pptManager.PresentationClose += OnPPTPresentationClose;
_pptManager.SlideShowStateChanged += OnPPTSlideShowStateChanged;
// 初始化多PPT墨迹管理器
_multiPPTInkManager = new MultiPPTInkManager();
_multiPPTInkManager.IsAutoSaveEnabled = Settings.PowerPointSettings.IsAutoSaveStrokesInPowerPoint;
_multiPPTInkManager.AutoSaveLocation = Settings.Automation.AutoSavedStrokesLocation;
_multiPPTInkManager.PPTManager = _pptManager;
if (Settings.PowerPointSettings.IsSupportWPS)
{
_singlePPTInkManager = new PPTInkManager();
_singlePPTInkManager.IsAutoSaveEnabled = Settings.PowerPointSettings.IsAutoSaveStrokesInPowerPoint;
_singlePPTInkManager.AutoSaveLocation = Settings.Automation.AutoSavedStrokesLocation;
}
else
{
_multiPPTInkManager = new MultiPPTInkManager();
_multiPPTInkManager.IsAutoSaveEnabled = Settings.PowerPointSettings.IsAutoSaveStrokesInPowerPoint;
_multiPPTInkManager.AutoSaveLocation = Settings.Automation.AutoSavedStrokesLocation;
_multiPPTInkManager.PPTManager = _pptManager;
}
// 初始化UI管理器
_pptUIManager = new PPTUIManager(this);
@@ -421,10 +431,12 @@ namespace Ink_Canvas
{
_pptManager?.Dispose();
_multiPPTInkManager?.Dispose();
_singlePPTInkManager?.Dispose();
_longPressTimer?.Stop();
_longPressTimer = null;
_pptManager = null;
_multiPPTInkManager = null;
_singlePPTInkManager = null;
_pptUIManager = null;
// 清理PowerPoint进程守护
@@ -509,8 +521,14 @@ namespace Ink_Canvas
else
{
LogHelper.WriteLogToFile("PPT连接已断开", LogHelper.LogType.Event);
// 清理墨迹管理器
_multiPPTInkManager?.ClearAllStrokes();
if (Settings.PowerPointSettings.IsSupportWPS)
{
_singlePPTInkManager?.ClearAllStrokes();
}
else
{
_multiPPTInkManager?.ClearAllStrokes();
}
}
});
}
@@ -535,8 +553,14 @@ namespace Ink_Canvas
TimeMachineHistories[0] = null;
}
// 初始化多PPT墨迹管理器
_multiPPTInkManager?.InitializePresentation(pres);
if (Settings.PowerPointSettings.IsSupportWPS)
{
_singlePPTInkManager?.InitializePresentation(pres);
}
else
{
_multiPPTInkManager?.InitializePresentation(pres);
}
// 处理跳转到首页或上次播放页的逻辑
HandlePresentationOpenNavigation(pres);
@@ -570,11 +594,15 @@ namespace Ink_Canvas
{
Application.Current.Dispatcher.InvokeAsync(() =>
{
// 保存所有墨迹
_multiPPTInkManager?.SaveAllStrokesToFile(pres);
// 移除演示文稿管理器
_multiPPTInkManager?.RemovePresentation(pres);
if (Settings.PowerPointSettings.IsSupportWPS)
{
_singlePPTInkManager?.SaveAllStrokesToFile(pres);
}
else
{
_multiPPTInkManager?.SaveAllStrokesToFile(pres);
_multiPPTInkManager?.RemovePresentation(pres);
}
_pptUIManager?.UpdateConnectionStatus(false);
});
@@ -615,7 +643,7 @@ namespace Ink_Canvas
}
}
private async void OnPPTSlideShowBegin(SlideShowWindow wn)
private void OnPPTSlideShowBegin(SlideShowWindow wn)
{
try
{
@@ -629,22 +657,26 @@ namespace Ink_Canvas
}
else
{
// 如果关闭了PPT自动收纳功能,但用户当前在收纳模式下,进入PPT时取消收纳以提供更好的使用体验
if (isFloatingBarFolded)
{
await UnFoldFloatingBar(new object());
UnFoldFloatingBar(new object());
}
}
isStopInkReplay = true;
await Application.Current.Dispatcher.InvokeAsync(() =>
Application.Current.Dispatcher.Invoke(() =>
{
// 获取当前活跃的演示文稿并切换到对应的墨迹管理器
var activePresentation = _pptManager?.GetCurrentActivePresentation();
if (activePresentation != null)
{
_multiPPTInkManager?.SwitchToPresentation(activePresentation);
if (Settings.PowerPointSettings.IsSupportWPS)
{
}
else
{
_multiPPTInkManager?.SwitchToPresentation(activePresentation);
}
}
// 处理跳转到首页或上次播放位置
@@ -720,6 +752,22 @@ namespace Ink_Canvas
{
UpdateCurrentToolMode("pen");
SetFloatingBarHighlightPosition("pen");
if (Settings.Appearance.IsShowQuickColorPalette && QuickColorPalettePanel != null && QuickColorPaletteSingleRowPanel != null)
{
// 根据显示模式选择显示哪个面板
if (Settings.Appearance.QuickColorPaletteDisplayMode == 0)
{
// 单行显示模式
QuickColorPalettePanel.Visibility = Visibility.Collapsed;
QuickColorPaletteSingleRowPanel.Visibility = Visibility.Visible;
}
else
{
// 双行显示模式
QuickColorPalettePanel.Visibility = Visibility.Visible;
QuickColorPaletteSingleRowPanel.Visibility = Visibility.Collapsed;
}
}
}
}
catch (Exception ex)
@@ -737,14 +785,7 @@ namespace Ink_Canvas
if (!isFloatingBarFolded)
{
new Thread(() =>
{
Thread.Sleep(100);
Application.Current.Dispatcher.Invoke(() =>
{
ViewboxFloatingBarMarginAnimation(60);
});
}).Start();
ViewboxFloatingBarMarginAnimation(60);
}
}
catch (Exception ex)
@@ -759,11 +800,16 @@ namespace Ink_Canvas
{
Application.Current.Dispatcher.InvokeAsync(() =>
{
// 获取当前活跃的演示文稿并确保切换到正确的墨迹管理器
var activePresentation = _pptManager?.GetCurrentActivePresentation();
if (activePresentation != null)
{
_multiPPTInkManager?.SwitchToPresentation(activePresentation);
if (Settings.PowerPointSettings.IsSupportWPS)
{
}
else
{
_multiPPTInkManager?.SwitchToPresentation(activePresentation);
}
}
var currentSlide = _pptManager?.GetCurrentSlideNumber() ?? 0;
@@ -784,7 +830,6 @@ namespace Ink_Canvas
{
try
{
// 处理浮动栏状态:根据"退出PPT放映后自动恢复浮动栏状态"设置决定是否恢复
if (Settings.Automation.IsAutoFoldAfterPPTSlideShow)
{
if (wasFloatingBarFoldedWhenEnterSlideShow)
@@ -807,7 +852,6 @@ namespace Ink_Canvas
}
else
{
// 如果两个功能都关闭,确保浮动栏展开
if (isFloatingBarFolded)
{
await UnFoldFloatingBar(new object());
@@ -818,8 +862,14 @@ namespace Ink_Canvas
if (isEnteredSlideShowEndEvent) return;
isEnteredSlideShowEndEvent = true;
// 保存所有墨迹
_multiPPTInkManager?.SaveAllStrokesToFile(pres);
if (Settings.PowerPointSettings.IsSupportWPS)
{
_singlePPTInkManager?.SaveAllStrokesToFile(pres);
}
else
{
_multiPPTInkManager?.SaveAllStrokesToFile(pres);
}
await Application.Current.Dispatcher.InvokeAsync(() =>
{
@@ -879,6 +929,9 @@ namespace Ink_Canvas
if (GridTransparencyFakeBackground.Background != Brushes.Transparent)
BtnHideInkCanvas_Click(BtnHideInkCanvas, null);
SetCurrentToolMode(InkCanvasEditingMode.None);
UpdateCurrentToolMode("cursor");
SetFloatingBarHighlightPosition("cursor");
}
catch (Exception ex)
{
@@ -889,8 +942,6 @@ namespace Ink_Canvas
await Task.Delay(100);
await Application.Current.Dispatcher.InvokeAsync(() =>
{
// 强制重新计算浮动栏位置,确保在退出PPT模式后正确复位
// 先调用桌面模式的复位方法,然后调用通用的位置计算方法
PureViewboxFloatingBarMarginAnimationInDesktopMode();
ViewboxFloatingBarMarginAnimation(100, true);
});
@@ -941,7 +992,24 @@ namespace Ink_Canvas
_lastPlaybackPage = page;
new YesOrNoNotificationWindow($"上次播放到了第 {page} 页, 是否立即跳转", () =>
{
_shouldNavigateToLastPage = true;
try
{
if (_pptManager?.PPTApplication != null)
{
if (_pptManager.PPTApplication.SlideShowWindows.Count >= 1)
{
pres.SlideShowWindow.View.GotoSlide(page);
}
else
{
pres.Windows[1].View.GotoSlide(page);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"跳转到第{page}页失败: {ex}", LogHelper.LogType.Error);
}
}).ShowDialog();
}
}
@@ -1060,7 +1128,16 @@ namespace Ink_Canvas
{
try
{
var strokes = _multiPPTInkManager?.LoadSlideStrokes(slideIndex);
StrokeCollection strokes = null;
if (Settings.PowerPointSettings.IsSupportWPS)
{
strokes = _singlePPTInkManager?.LoadSlideStrokes(slideIndex);
}
else
{
strokes = _multiPPTInkManager?.LoadSlideStrokes(slideIndex);
}
if (strokes != null)
{
inkCanvas.Strokes.Clear();
@@ -1080,15 +1157,18 @@ namespace Ink_Canvas
{
try
{
// 获取当前活跃的演示文稿
var activePresentation = _pptManager?.GetCurrentActivePresentation();
if (activePresentation != null)
if (Settings.PowerPointSettings.IsSupportWPS)
{
// 切换到对应的墨迹管理器
_multiPPTInkManager?.SwitchToPresentation(activePresentation);
// 重置锁定状态
_multiPPTInkManager?.ResetCurrentPresentationLockState();
_singlePPTInkManager?.ResetLockState();
}
else
{
var activePresentation = _pptManager?.GetCurrentActivePresentation();
if (activePresentation != null)
{
_multiPPTInkManager?.SwitchToPresentation(activePresentation);
_multiPPTInkManager?.ResetCurrentPresentationLockState();
}
}
}
catch (Exception ex)
@@ -1202,26 +1282,41 @@ namespace Ink_Canvas
// 如果有当前墨迹且不是第一次切换,先保存到当前页面
if (inkCanvas.Strokes.Count > 0 && currentSlideIndex > 0 && currentSlideIndex != newSlideIndex)
{
// 检查是否可以写入墨迹
bool canWrite = _multiPPTInkManager?.CanWriteInk(currentSlideIndex) == true;
if (canWrite)
bool canWrite = false;
if (Settings.PowerPointSettings.IsSupportWPS)
{
// 正常保存
_multiPPTInkManager?.SaveCurrentSlideStrokes(currentSlideIndex, inkCanvas.Strokes);
canWrite = _singlePPTInkManager?.CanWriteInk(currentSlideIndex) == true;
}
else
{
// 墨迹被锁定,跳过保存以避免墨迹错页
canWrite = _multiPPTInkManager?.CanWriteInk(currentSlideIndex) == true;
}
if (canWrite)
{
if (Settings.PowerPointSettings.IsSupportWPS)
{
_singlePPTInkManager?.SaveCurrentSlideStrokes(currentSlideIndex, inkCanvas.Strokes);
}
else
{
_multiPPTInkManager?.SaveCurrentSlideStrokes(currentSlideIndex, inkCanvas.Strokes);
}
}
}
else if (inkCanvas.Strokes.Count > 0 && currentSlideIndex <= 0)
{
// 无法获取当前页面索引时,不保存墨迹,直接清空
}
// 切换到新页面并加载墨迹
var newStrokes = _multiPPTInkManager?.SwitchToSlide(newSlideIndex, null);
StrokeCollection newStrokes = null;
if (Settings.PowerPointSettings.IsSupportWPS)
{
newStrokes = _singlePPTInkManager?.SwitchToSlide(newSlideIndex, null);
}
else
{
newStrokes = _multiPPTInkManager?.SwitchToSlide(newSlideIndex, null);
}
if (newStrokes != null)
{
inkCanvas.Strokes.Clear();
@@ -1362,7 +1457,14 @@ namespace Ink_Canvas
var currentSlide = _pptManager?.GetCurrentSlideNumber() ?? 0;
if (currentSlide > 0)
{
_multiPPTInkManager?.SaveCurrentSlideStrokes(currentSlide, inkCanvas.Strokes);
if (Settings.PowerPointSettings.IsSupportWPS)
{
_singlePPTInkManager?.SaveCurrentSlideStrokes(currentSlide, inkCanvas.Strokes);
}
else
{
_multiPPTInkManager?.SaveCurrentSlideStrokes(currentSlide, inkCanvas.Strokes);
}
}
// 保存截图(如果启用)
@@ -1402,7 +1504,14 @@ namespace Ink_Canvas
var currentSlide = _pptManager?.GetCurrentSlideNumber() ?? 0;
if (currentSlide > 0)
{
_multiPPTInkManager?.SaveCurrentSlideStrokes(currentSlide, inkCanvas.Strokes);
if (Settings.PowerPointSettings.IsSupportWPS)
{
_singlePPTInkManager?.SaveCurrentSlideStrokes(currentSlide, inkCanvas.Strokes);
}
else
{
_multiPPTInkManager?.SaveCurrentSlideStrokes(currentSlide, inkCanvas.Strokes);
}
}
// 保存截图(如果启用)
@@ -1432,7 +1541,7 @@ namespace Ink_Canvas
});
}
private async void PPTNavigationBtn_MouseDown(object sender, MouseButtonEventArgs e)
private void PPTNavigationBtn_MouseDown(object sender, MouseButtonEventArgs e)
{
lastBorderMouseDownObject = sender;
if (!Settings.PowerPointSettings.EnablePPTButtonPageClickable) return;
@@ -1454,7 +1563,7 @@ namespace Ink_Canvas
}
}
private async void PPTNavigationBtn_MouseLeave(object sender, MouseEventArgs e)
private void PPTNavigationBtn_MouseLeave(object sender, MouseEventArgs e)
{
lastBorderMouseDownObject = null;
if (sender == PPTLSPageButton)
@@ -1475,7 +1584,7 @@ namespace Ink_Canvas
}
}
private async void PPTNavigationBtn_MouseUp(object sender, MouseButtonEventArgs e)
private void PPTNavigationBtn_MouseUp(object sender, MouseButtonEventArgs e)
{
if (lastBorderMouseDownObject != sender) return;
@@ -1524,7 +1633,6 @@ namespace Ink_Canvas
// 控制居中
if (!isFloatingBarFolded)
{
await Task.Delay(100);
ViewboxFloatingBarMarginAnimation(60);
}
}
@@ -1562,7 +1670,14 @@ namespace Ink_Canvas
{
Application.Current.Dispatcher.Invoke(() =>
{
_multiPPTInkManager?.SaveCurrentSlideStrokes(currentSlide, inkCanvas.Strokes);
if (Settings.PowerPointSettings.IsSupportWPS)
{
_singlePPTInkManager?.SaveCurrentSlideStrokes(currentSlide, inkCanvas.Strokes);
}
else
{
_multiPPTInkManager?.SaveCurrentSlideStrokes(currentSlide, inkCanvas.Strokes);
}
timeMachine.ClearStrokeHistory();
});
}
+214 -7
View File
@@ -433,8 +433,8 @@ namespace Ink_Canvas
public void UpdateCustomIconsInComboBox()
{
// 保留前11个内置图标选项
while (ComboBoxFloatingBarImg.Items.Count > 11)
// 保留前12个内置图标选项
while (ComboBoxFloatingBarImg.Items.Count > 12)
{
ComboBoxFloatingBarImg.Items.RemoveAt(ComboBoxFloatingBarImg.Items.Count - 1);
}
@@ -2611,17 +2611,17 @@ namespace Ink_Canvas
Settings.RandSettings.UseLegacyTimerUI = ToggleSwitchUseLegacyTimerUI.IsOn;
if (ToggleSwitchUseLegacyTimerUI.IsOn)
{
ToggleSwitchUseSeewoStyleUI.IsOn = false;
Settings.RandSettings.UseSeewoStyleUI = false;
ToggleSwitchUseNewStyleUI.IsOn = false;
Settings.RandSettings.UseNewStyleUI = false;
}
SaveSettingsToFile();
}
private void ToggleSwitchUseSeewoStyleUI_Toggled(object sender, RoutedEventArgs e)
private void ToggleSwitchUseNewStyleUI_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
Settings.RandSettings.UseSeewoStyleUI = ToggleSwitchUseSeewoStyleUI.IsOn;
if (ToggleSwitchUseSeewoStyleUI.IsOn)
Settings.RandSettings.UseNewStyleUI = ToggleSwitchUseNewStyleUI.IsOn;
if (ToggleSwitchUseNewStyleUI.IsOn)
{
ToggleSwitchUseLegacyTimerUI.IsOn = false;
Settings.RandSettings.UseLegacyTimerUI = false;
@@ -2629,6 +2629,34 @@ namespace Ink_Canvas
SaveSettingsToFile();
}
private void ToggleSwitchEnableOvertimeCountUp_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
Settings.RandSettings.EnableOvertimeCountUp = ToggleSwitchEnableOvertimeCountUp.IsOn;
if (!ToggleSwitchEnableOvertimeCountUp.IsOn)
{
ToggleSwitchEnableOvertimeRedText.IsOn = false;
Settings.RandSettings.EnableOvertimeRedText = false;
}
SaveSettingsToFile();
}
private void ToggleSwitchEnableOvertimeRedText_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
if (ToggleSwitchEnableOvertimeRedText.IsOn && !ToggleSwitchEnableOvertimeCountUp.IsOn)
{
ToggleSwitchEnableOvertimeRedText.IsOn = false;
return;
}
Settings.RandSettings.EnableOvertimeRedText = ToggleSwitchEnableOvertimeRedText.IsOn;
SaveSettingsToFile();
}
private void TimerVolumeSlider_ValueChanged(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
@@ -2636,6 +2664,42 @@ namespace Ink_Canvas
SaveSettingsToFile();
}
private void ToggleSwitchEnableProgressiveReminder_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
Settings.RandSettings.EnableProgressiveReminder = ToggleSwitchEnableProgressiveReminder.IsOn;
SaveSettingsToFile();
}
private void ProgressiveReminderVolumeSlider_ValueChanged(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
Settings.RandSettings.ProgressiveReminderVolume = ProgressiveReminderVolumeSlider.Value;
SaveSettingsToFile();
}
private void ButtonSelectCustomProgressiveReminderSound_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog
{
Title = "选择渐进提醒音频文件",
Filter = "音频文件 (*.wav)|*.wav|所有文件 (*.*)|*.*",
DefaultExt = "wav"
};
if (openFileDialog.ShowDialog() == true)
{
Settings.RandSettings.ProgressiveReminderSoundPath = openFileDialog.FileName;
SaveSettingsToFile();
}
}
private void ButtonResetProgressiveReminderSound_Click(object sender, RoutedEventArgs e)
{
Settings.RandSettings.ProgressiveReminderSoundPath = "";
SaveSettingsToFile();
}
private void ButtonSelectCustomTimerSound_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog
@@ -3181,6 +3245,149 @@ namespace Ink_Canvas
}
}
private async void ManualUpdateButton_Click(object sender, RoutedEventArgs e)
{
ManualUpdateButton.IsEnabled = false;
ManualUpdateButton.Content = "正在检查更新...";
try
{
LogHelper.WriteLogToFile("ManualUpdate | Manual update button clicked");
// 使用当前选择的更新通道检查更新
var (remoteVersion, lineGroup, apiReleaseNotes) = await AutoUpdateHelper.CheckForUpdates(Settings.Startup.UpdateChannel, true, false);
if (remoteVersion != null)
{
LogHelper.WriteLogToFile($"ManualUpdate | Found new version: {remoteVersion}");
// 获取当前版本
string currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
// 创建并显示更新窗口
HasNewUpdateWindow updateWindow = new HasNewUpdateWindow(currentVersion, remoteVersion, "", apiReleaseNotes);
updateWindow.Owner = Application.Current.MainWindow;
bool? dialogResult = updateWindow.ShowDialog();
// 如果窗口被关闭但没有点击按钮,则不执行任何操作
if (dialogResult != true)
{
LogHelper.WriteLogToFile("ManualUpdate | Update dialog closed without selection");
return;
}
// 根据用户选择处理更新
switch (updateWindow.Result)
{
case HasNewUpdateWindow.UpdateResult.UpdateNow:
// 立即更新:显示下载进度,下载完成后立即安装
LogHelper.WriteLogToFile("ManualUpdate | User chose to update now");
// 显示下载进度提示
MessageBox.Show("开始下载更新,请稍候...", "正在更新", MessageBoxButton.OK, MessageBoxImage.Information);
// 下载更新文件,使用多线路组下载功能
bool isDownloadSuccessful = await DownloadUpdateWithFallback(remoteVersion, lineGroup, Settings.Startup.UpdateChannel);
if (isDownloadSuccessful)
{
// 下载成功,提示用户准备安装
MessageBoxResult result = MessageBox.Show("更新已下载完成,点击确定后将关闭软件并安装新版本!", "安装更新", MessageBoxButton.OKCancel, MessageBoxImage.Information);
// 只有当用户点击确定按钮后才关闭软件
if (result == MessageBoxResult.OK)
{
// 设置为用户主动退出,避免被看门狗判定为崩溃
App.IsAppExitByUser = true;
// 准备批处理脚本
AutoUpdateHelper.InstallNewVersionApp(remoteVersion, true);
// 关闭软件,让安装程序接管
Application.Current.Shutdown();
}
else
{
LogHelper.WriteLogToFile("ManualUpdate | User cancelled update installation");
}
}
else
{
// 下载失败
MessageBox.Show("更新下载失败,请检查网络连接后重试。", "下载失败", MessageBoxButton.OK, MessageBoxImage.Error);
}
break;
case HasNewUpdateWindow.UpdateResult.UpdateLater:
// 稍后更新:静默下载,在软件关闭时自动安装
LogHelper.WriteLogToFile("ManualUpdate | User chose to update later");
// 不管设置如何,都进行下载,使用多线路组下载功能
isDownloadSuccessful = await DownloadUpdateWithFallback(remoteVersion, lineGroup, Settings.Startup.UpdateChannel);
if (isDownloadSuccessful)
{
LogHelper.WriteLogToFile("ManualUpdate | Update downloaded successfully, will install when application closes");
// 设置标志,在应用程序关闭时安装
Settings.Startup.IsAutoUpdate = true;
Settings.Startup.IsAutoUpdateWithSilence = true;
// 启动检查定时器
timerCheckAutoUpdateWithSilence.Start();
// 通知用户
MessageBox.Show("更新已下载完成,将在软件关闭时自动安装。", "更新已准备就绪", MessageBoxButton.OK, MessageBoxImage.Information);
}
else
{
LogHelper.WriteLogToFile("ManualUpdate | Update download failed", LogHelper.LogType.Error);
MessageBox.Show("更新下载失败,请检查网络连接后重试。", "下载失败", MessageBoxButton.OK, MessageBoxImage.Error);
}
break;
case HasNewUpdateWindow.UpdateResult.SkipVersion:
// 跳过该版本:记录到设置中
LogHelper.WriteLogToFile($"ManualUpdate | User chose to skip version {remoteVersion}");
// 记录要跳过的版本号
Settings.Startup.SkippedVersion = remoteVersion;
// 保存设置到文件
SaveSettingsToFile();
// 通知用户
MessageBox.Show($"已设置跳过版本 {remoteVersion},在下次发布新版本之前不会再提示更新。",
"已跳过此版本",
MessageBoxButton.OK,
MessageBoxImage.Information);
break;
}
}
else
{
// 没有更新
LogHelper.WriteLogToFile("ManualUpdate | No updates available");
MessageBox.Show("当前已是最新版本!", "无可用更新", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"Error in ManualUpdateButton_Click: {ex.Message}", LogHelper.LogType.Error);
MessageBox.Show(
$"手动更新过程中发生错误: {ex.Message}",
"更新错误",
MessageBoxButton.OK,
MessageBoxImage.Error);
}
finally
{
// 恢复按钮状态
ManualUpdateButton.IsEnabled = true;
ManualUpdateButton.Content = "手动更新";
}
}
private async void FixVersionButton_Click(object sender, RoutedEventArgs e)
{
// 显示确认对话框
+28 -2
View File
@@ -883,9 +883,22 @@ namespace Ink_Canvas
// 计时器设置
ToggleSwitchUseLegacyTimerUI.IsOn = Settings.RandSettings.UseLegacyTimerUI;
ToggleSwitchUseSeewoStyleUI.IsOn = Settings.RandSettings.UseSeewoStyleUI;
ToggleSwitchUseNewStyleUI.IsOn = Settings.RandSettings.UseNewStyleUI;
ToggleSwitchEnableOvertimeCountUp.IsOn = Settings.RandSettings.EnableOvertimeCountUp;
bool canEnableRedText = Settings.RandSettings.EnableOvertimeCountUp && Settings.RandSettings.EnableOvertimeRedText;
ToggleSwitchEnableOvertimeRedText.IsOn = canEnableRedText;
if (!canEnableRedText)
{
Settings.RandSettings.EnableOvertimeRedText = false;
}
TimerVolumeSlider.Value = Settings.RandSettings.TimerVolume;
// 渐进提醒设置
ToggleSwitchEnableProgressiveReminder.IsOn = Settings.RandSettings.EnableProgressiveReminder;
ProgressiveReminderVolumeSlider.Value = Settings.RandSettings.ProgressiveReminderVolume;
// 加载自定义点名背景
UpdatePickNameBackgroundsInComboBox();
@@ -905,8 +918,21 @@ namespace Ink_Canvas
ToggleSwitchExternalCaller.IsOn = Settings.RandSettings.DirectCallCiRand;
ComboBoxExternalCallerType.SelectedIndex = Settings.RandSettings.ExternalCallerType;
ToggleSwitchUseLegacyTimerUI.IsOn = Settings.RandSettings.UseLegacyTimerUI;
ToggleSwitchUseSeewoStyleUI.IsOn = Settings.RandSettings.UseSeewoStyleUI;
ToggleSwitchUseNewStyleUI.IsOn = Settings.RandSettings.UseNewStyleUI;
ToggleSwitchEnableOvertimeCountUp.IsOn = Settings.RandSettings.EnableOvertimeCountUp;
bool canEnableRedText = Settings.RandSettings.EnableOvertimeCountUp && Settings.RandSettings.EnableOvertimeRedText;
ToggleSwitchEnableOvertimeRedText.IsOn = canEnableRedText;
if (!canEnableRedText)
{
Settings.RandSettings.EnableOvertimeRedText = false;
}
TimerVolumeSlider.Value = Settings.RandSettings.TimerVolume;
// 渐进提醒设置
ToggleSwitchEnableProgressiveReminder.IsOn = Settings.RandSettings.EnableProgressiveReminder;
ProgressiveReminderVolumeSlider.Value = Settings.RandSettings.ProgressiveReminderVolume;
}
// ModeSettings
+10 -10
View File
@@ -61,10 +61,10 @@ namespace Ink_Canvas
private Timer timerCheckAutoFold = new Timer();
private string AvailableLatestVersion;
private Timer timerCheckAutoUpdateWithSilence = new Timer();
private Timer timerCheckAutoUpdateRetry = new Timer();
private Timer timerCheckAutoUpdateRetry = new Timer();
private bool isHidingSubPanelsWhenInking; // 避免书写时触发二次关闭二级菜单导致动画不连续
private int updateCheckRetryCount = 0;
private const int MAX_UPDATE_CHECK_RETRIES = 6;
private int updateCheckRetryCount = 0;
private const int MAX_UPDATE_CHECK_RETRIES = 6;
private Timer timerDisplayTime = new Timer();
private Timer timerDisplayDate = new Timer();
private Timer timerNtpSync = new Timer();
@@ -120,7 +120,7 @@ namespace Ink_Canvas
timerCheckAutoUpdateWithSilence.Elapsed += timerCheckAutoUpdateWithSilence_Elapsed;
timerCheckAutoUpdateWithSilence.Interval = 1000 * 60 * 10;
timerCheckAutoUpdateRetry.Elapsed += timerCheckAutoUpdateRetry_Elapsed;
timerCheckAutoUpdateRetry.Interval = 1000 * 60 * 10;
timerCheckAutoUpdateRetry.Interval = 1000 * 60 * 10;
WaterMarkTime.DataContext = nowTimeVM;
WaterMarkDate.DataContext = nowTimeVM;
timerDisplayTime.Elapsed += TimerDisplayTime_Elapsed;
@@ -863,7 +863,7 @@ namespace Ink_Canvas
// 执行更新检查
LogHelper.WriteLogToFile("AutoUpdate | Retrying update check after failure");
// 清除之前的更新状态
AvailableLatestVersion = null;
AvailableLatestLineGroup = null;
@@ -878,7 +878,7 @@ namespace Ink_Canvas
// 检查更新成功,重置重试计数
updateCheckRetryCount = 0;
LogHelper.WriteLogToFile($"AutoUpdate | Retry successful, found new version: {AvailableLatestVersion}");
// 停止重试定时器,因为已经找到了更新
return;
}
@@ -886,7 +886,7 @@ namespace Ink_Canvas
{
// 检查更新仍然失败,继续重试
LogHelper.WriteLogToFile($"AutoUpdate | Retry {updateCheckRetryCount} failed, will retry in 10 minutes");
// 重新启动定时器,10分钟后再次尝试
timerCheckAutoUpdateRetry.Start();
}
@@ -894,7 +894,7 @@ namespace Ink_Canvas
catch (Exception ex)
{
LogHelper.WriteLogToFile($"AutoUpdate | Error in retry check: {ex.Message}", LogHelper.LogType.Error);
// 出错时也重新启动定时器,稍后再检查
if (updateCheckRetryCount <= MAX_UPDATE_CHECK_RETRIES)
{
@@ -910,10 +910,10 @@ namespace Ink_Canvas
{
// 停止重试定时器
timerCheckAutoUpdateRetry.Stop();
// 重置重试计数
updateCheckRetryCount = 0;
LogHelper.WriteLogToFile("AutoUpdate | Update check retry state reset");
}
catch (Exception ex)
@@ -259,7 +259,6 @@ namespace Ink_Canvas
// 只保留普通橡皮逻辑
TouchDownPointsList[e.TouchDevice.Id] = InkCanvasEditingMode.None;
inkCanvas.EraserShape = new EllipseStylusShape(50, 50);
if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint
&& inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke)
{
@@ -682,8 +681,6 @@ namespace Ink_Canvas
if (Settings.Advanced.IsSpecialScreen)
boundWidth *= Settings.Advanced.TouchMultiplier;
inkCanvas.EraserShape = new EllipseStylusShape(boundWidth, boundWidth);
inkCanvas.EditingMode = InkCanvasEditingMode.EraseByPoint;
isPalmEraserActive = true;
+2 -2
View File
@@ -49,5 +49,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.7.13.0")]
[assembly: AssemblyFileVersion("1.7.13.0")]
[assembly: AssemblyVersion("1.7.14.0")]
[assembly: AssemblyFileVersion("1.7.14.0")]
@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>dist\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
</PropertyGroup>
</Project>
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
</Project>
+9
View File
@@ -74,5 +74,14 @@ namespace Ink_Canvas.Properties {
return ResourceManager.GetStream("TimerDownNotice", resourceCulture);
}
}
/// <summary>
/// Looks up a localized resource of type System.IO.UnmanagedMemoryStream similar to System.IO.MemoryStream.
/// </summary>
internal static UnmanagedMemoryStream ProgressiveAudio {
get {
return ResourceManager.GetStream("ProgressiveAudio", resourceCulture);
}
}
}
}
+3
View File
@@ -121,4 +121,7 @@
<data name="TimerDownNotice" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\TimerDownNotice.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="ProgressiveAudio" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ProgressiveAudio.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>
Binary file not shown.
+15 -2
View File
@@ -591,6 +591,9 @@ namespace Ink_Canvas
[JsonProperty("isAlwaysOnTop")]
public bool IsAlwaysOnTop { get; set; } = true;
[JsonProperty("enableUIAccessTopMost")]
public bool EnableUIAccessTopMost { get; set; } = false;
}
public class InkToShape
@@ -631,12 +634,22 @@ namespace Ink_Canvas
public List<CustomPickNameBackground> CustomPickNameBackgrounds { get; set; } = new List<CustomPickNameBackground>();
[JsonProperty("useLegacyTimerUI")]
public bool UseLegacyTimerUI { get; set; } = false;
[JsonProperty("useSeewoStyleUI")]
public bool UseSeewoStyleUI { get; set; } = false;
[JsonProperty("useNewStyleUI")]
public bool UseNewStyleUI { get; set; } = true;
[JsonProperty("timerVolume")]
public double TimerVolume { get; set; } = 1.0;
[JsonProperty("customTimerSoundPath")]
public string CustomTimerSoundPath { get; set; } = "";
[JsonProperty("enableOvertimeCountUp")]
public bool EnableOvertimeCountUp { get; set; } = false;
[JsonProperty("enableOvertimeRedText")]
public bool EnableOvertimeRedText { get; set; } = false;
[JsonProperty("enableProgressiveReminder")]
public bool EnableProgressiveReminder { get; set; } = false;
[JsonProperty("progressiveReminderVolume")]
public double ProgressiveReminderVolume { get; set; } = 1.0;
[JsonProperty("progressiveReminderSoundPath")]
public string ProgressiveReminderSoundPath { get; set; } = "";
}
public class CustomPickNameBackground
+15 -9
View File
@@ -113,15 +113,15 @@
<BitmapImage x:Key="TimerWindowClockIcon" UriSource="/Resources/Icons-Fluent/ic_fluent_timer_24_regular-light.png"/>
<!-- 倒计时窗口主题颜色 -->
<SolidColorBrush x:Key="SeewoTimerWindowBackground" Color="#1f1f1f"/>
<SolidColorBrush x:Key="SeewoTimerWindowBorderBrush" Color="#E0E0E0"/>
<SolidColorBrush x:Key="SeewoTimerWindowTextForeground" Color="White"/>
<SolidColorBrush x:Key="SeewoTimerWindowButtonBackground" Color="#2a2a2a"/>
<SolidColorBrush x:Key="SeewoTimerWindowButtonForeground" Color="White"/>
<SolidColorBrush x:Key="SeewoTimerWindowDigitForeground" Color="White"/>
<SolidColorBrush x:Key="SeewoTimerWindowTitleForeground" Color="White"/>
<SolidColorBrush x:Key="SeewoTimerWindowPrimaryButtonBackground" Color="#4CAF50"/>
<SolidColorBrush x:Key="SeewoTimerWindowPrimaryButtonForeground" Color="White"/>
<SolidColorBrush x:Key="NewTimerWindowBackground" Color="#1f1f1f"/>
<SolidColorBrush x:Key="NewTimerWindowBorderBrush" Color="#E0E0E0"/>
<SolidColorBrush x:Key="NewTimerWindowTextForeground" Color="White"/>
<SolidColorBrush x:Key="NewTimerWindowButtonBackground" Color="#2a2a2a"/>
<SolidColorBrush x:Key="NewTimerWindowButtonForeground" Color="White"/>
<SolidColorBrush x:Key="NewTimerWindowDigitForeground" Color="White"/>
<SolidColorBrush x:Key="NewTimerWindowTitleForeground" Color="White"/>
<SolidColorBrush x:Key="NewTimerWindowPrimaryButtonBackground" Color="#4CAF50"/>
<SolidColorBrush x:Key="NewTimerWindowPrimaryButtonForeground" Color="White"/>
<!-- 说明书窗口主题颜色 -->
<SolidColorBrush x:Key="OperatingGuideWindowBackground" Color="#1f1f1f"/>
@@ -139,4 +139,10 @@
<BitmapImage x:Key="OperatingGuideWindowControlIcon1" UriSource="/Resources/Icons-Fluent/ic_fluent_control_button_24_regular_white.png"/>
<BitmapImage x:Key="OperatingGuideWindowControlIcon2" UriSource="/Resources/Icons-Fluent/ic_fluent_control_button_24_regular_white.png"/>
<BitmapImage x:Key="OperatingGuideWindowControlIcon3" UriSource="/Resources/Icons-Fluent/ic_fluent_control_button_24_regular_white.png"/>
<!-- 手势选项面板图标资源 - 深色主题 -->
<BitmapImage x:Key="MultiTouchIcon" UriSource="/Resources/new-icons/multi-touch_white.png"/>
<BitmapImage x:Key="HandMoveIcon" UriSource="/Resources/new-icons/hand-move_white.png"/>
<BitmapImage x:Key="ZoomIcon" UriSource="/Resources/new-icons/zoom_white.png"/>
<BitmapImage x:Key="RotateIcon" UriSource="/Resources/new-icons/rotate_white.png"/>
</ResourceDictionary>
+15 -9
View File
@@ -113,15 +113,15 @@
<BitmapImage x:Key="TimerWindowClockIcon" UriSource="/Resources/Icons-Fluent/ic_fluent_timer_24_regular.png"/>
<!-- 倒计时窗口主题颜色 -->
<SolidColorBrush x:Key="SeewoTimerWindowBackground" Color="White"/>
<SolidColorBrush x:Key="SeewoTimerWindowBorderBrush" Color="#E0E0E0"/>
<SolidColorBrush x:Key="SeewoTimerWindowTextForeground" Color="#333333"/>
<SolidColorBrush x:Key="SeewoTimerWindowButtonBackground" Color="#F0F0F0"/>
<SolidColorBrush x:Key="SeewoTimerWindowButtonForeground" Color="#666666"/>
<SolidColorBrush x:Key="SeewoTimerWindowDigitForeground" Color="#333333"/>
<SolidColorBrush x:Key="SeewoTimerWindowTitleForeground" Color="#333333"/>
<SolidColorBrush x:Key="SeewoTimerWindowPrimaryButtonBackground" Color="#4CAF50"/>
<SolidColorBrush x:Key="SeewoTimerWindowPrimaryButtonForeground" Color="White"/>
<SolidColorBrush x:Key="NewTimerWindowBackground" Color="White"/>
<SolidColorBrush x:Key="NewTimerWindowBorderBrush" Color="#E0E0E0"/>
<SolidColorBrush x:Key="NewTimerWindowTextForeground" Color="#333333"/>
<SolidColorBrush x:Key="NewTimerWindowButtonBackground" Color="#F0F0F0"/>
<SolidColorBrush x:Key="NewTimerWindowButtonForeground" Color="#666666"/>
<SolidColorBrush x:Key="NewTimerWindowDigitForeground" Color="#333333"/>
<SolidColorBrush x:Key="NewTimerWindowTitleForeground" Color="#333333"/>
<SolidColorBrush x:Key="NewTimerWindowPrimaryButtonBackground" Color="#4CAF50"/>
<SolidColorBrush x:Key="NewTimerWindowPrimaryButtonForeground" Color="White"/>
<!-- 说明书窗口主题颜色 -->
<SolidColorBrush x:Key="OperatingGuideWindowBackground" Color="#F0F3F9"/>
@@ -139,4 +139,10 @@
<BitmapImage x:Key="OperatingGuideWindowControlIcon1" UriSource="/Resources/Icons-Fluent/ic_fluent_control_button_24_regular.png"/>
<BitmapImage x:Key="OperatingGuideWindowControlIcon2" UriSource="/Resources/Icons-Fluent/ic_fluent_control_button_24_regular.png"/>
<BitmapImage x:Key="OperatingGuideWindowControlIcon3" UriSource="/Resources/Icons-Fluent/ic_fluent_control_button_24_regular.png"/>
<!-- 手势选项面板图标资源 - 浅色主题 -->
<BitmapImage x:Key="MultiTouchIcon" UriSource="/Resources/new-icons/multi-touch.png"/>
<BitmapImage x:Key="HandMoveIcon" UriSource="/Resources/new-icons/hand-move.png"/>
<BitmapImage x:Key="ZoomIcon" UriSource="/Resources/new-icons/zoom.png"/>
<BitmapImage x:Key="RotateIcon" UriSource="/Resources/new-icons/rotate.png"/>
</ResourceDictionary>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.
Binary file not shown.
@@ -0,0 +1,26 @@
using System.Windows;
using System.Windows.Controls.Primitives;
namespace Ink_Canvas.Windows.Controls
{
public class WinUI3CloseButton : ButtonBase
{
static WinUI3CloseButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(WinUI3CloseButton), new FrameworkPropertyMetadata(typeof(WinUI3CloseButton)));
}
public bool IsActive
{
get => (bool)GetValue(IsActiveProperty);
set => SetValue(IsActiveProperty, value);
}
public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register(
nameof(IsActive),
typeof(bool),
typeof(WinUI3CloseButton),
new PropertyMetadata(true)
);
}
}
@@ -0,0 +1,62 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Ink_Canvas.Windows.Controls"
xmlns:system="clr-namespace:System;assembly=netstandard">
<Style TargetType="{x:Type local:WinUI3CloseButton}">
<Setter Property="Width" Value="46" />
<Setter Property="Height" Value="32" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="{DynamicResource NewTimerWindowButtonForeground}" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:WinUI3CloseButton}">
<Border
x:Name="ButtonBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="0,15,0,0">
<ContentPresenter
x:Name="PART_ContentPresenter"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsActive" Value="False">
<Setter TargetName="PART_ContentPresenter" Property="Opacity" Value="0.382" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="#808080" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ButtonBorder" Property="Background" Value="#E81123" />
<Setter Property="Foreground" Value="White" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="ButtonBorder" Property="Background" Value="#F1707A" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- 关闭按钮图标模板 -->
<DataTemplate x:Key="CloseButtonIconTemplate" DataType="system:String">
<TextBlock
FontSize="12"
Text="✕"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</DataTemplate>
</ResourceDictionary>
+71 -36
View File
@@ -22,16 +22,16 @@ namespace Ink_Canvas
timer.Elapsed += Timer_Elapsed;
timer.Interval = 50;
InitializeUI();
// 应用主题
ApplyTheme();
}
public static Window CreateTimerWindow()
{
if (MainWindow.Settings.RandSettings?.UseSeewoStyleUI == true)
if (MainWindow.Settings.RandSettings?.UseNewStyleUI == true)
{
return new SeewoStyleTimerWindow();
return new NewStyleTimerWindow();
}
else
{
@@ -49,46 +49,72 @@ namespace Ink_Canvas
TimeSpan timeSpan = DateTime.Now - startTime;
TimeSpan totalTimeSpan = new TimeSpan(hour, minute, second);
TimeSpan leftTimeSpan = totalTimeSpan - timeSpan;
if (leftTimeSpan.Milliseconds > 0) leftTimeSpan += new TimeSpan(0, 0, 1);
double spentTimePercent = timeSpan.TotalMilliseconds / (totalSeconds * 1000.0);
Application.Current.Dispatcher.Invoke(() =>
{
ProcessBarTime.CurrentValue = 1 - spentTimePercent;
TextBlockHour.Text = leftTimeSpan.Hours.ToString("00");
TextBlockMinute.Text = leftTimeSpan.Minutes.ToString("00");
TextBlockSecond.Text = leftTimeSpan.Seconds.ToString("00");
TbCurrentTime.Text = leftTimeSpan.ToString(@"hh\:mm\:ss");
if (spentTimePercent >= 1)
if (!isOvertimeMode)
{
ProcessBarTime.CurrentValue = 0;
TextBlockHour.Text = "00";
TextBlockMinute.Text = "00";
TextBlockSecond.Text = "00";
timer.Stop();
isTimerRunning = false;
SymbolIconStart.Symbol = iNKORE.UI.WPF.Modern.Controls.Symbol.Play;
BtnStartCover.Visibility = Visibility.Visible;
var textForeground = Application.Current.FindResource("TimerWindowTextForeground") as SolidColorBrush;
if (textForeground != null)
TimeSpan leftTimeSpan = totalTimeSpan - timeSpan;
if (leftTimeSpan.Milliseconds > 0) leftTimeSpan += new TimeSpan(0, 0, 1);
ProcessBarTime.CurrentValue = 1 - spentTimePercent;
TextBlockHour.Text = leftTimeSpan.Hours.ToString("00");
TextBlockMinute.Text = leftTimeSpan.Minutes.ToString("00");
TextBlockSecond.Text = leftTimeSpan.Seconds.ToString("00");
TbCurrentTime.Text = leftTimeSpan.ToString(@"hh\:mm\:ss");
if (spentTimePercent >= 1 && MainWindow.Settings.RandSettings?.EnableOvertimeCountUp == true)
{
TextBlockHour.Foreground = textForeground;
isOvertimeMode = true;
ProcessBarTime.CurrentValue = 0;
ProcessBarTime.Visibility = Visibility.Collapsed;
BorderStopTime.Visibility = Visibility.Collapsed;
// 播放提醒音
PlayTimerSound();
}
else
else if (spentTimePercent >= 1)
{
TextBlockHour.Foreground = new SolidColorBrush(StringToColor("#FF5B5D5F"));
ProcessBarTime.CurrentValue = 0;
TextBlockHour.Text = "00";
TextBlockMinute.Text = "00";
TextBlockSecond.Text = "00";
timer.Stop();
isTimerRunning = false;
SymbolIconStart.Symbol = iNKORE.UI.WPF.Modern.Controls.Symbol.Play;
BtnStartCover.Visibility = Visibility.Visible;
var textForeground = Application.Current.FindResource("TimerWindowTextForeground") as SolidColorBrush;
if (textForeground != null)
{
TextBlockHour.Foreground = textForeground;
}
else
{
TextBlockHour.Foreground = new SolidColorBrush(StringToColor("#FF5B5D5F"));
}
BorderStopTime.Visibility = Visibility.Collapsed;
// 播放提醒音
PlayTimerSound();
}
}
else
{
TimeSpan overtimeSpan = timeSpan - totalTimeSpan;
TextBlockHour.Text = overtimeSpan.Hours.ToString("00");
TextBlockMinute.Text = overtimeSpan.Minutes.ToString("00");
TextBlockSecond.Text = overtimeSpan.Seconds.ToString("00");
TbCurrentTime.Text = overtimeSpan.ToString(@"hh\:mm\:ss");
if (MainWindow.Settings.RandSettings?.EnableOvertimeRedText == true)
{
TextBlockHour.Foreground = Brushes.Red;
TextBlockMinute.Foreground = Brushes.Red;
TextBlockSecond.Foreground = Brushes.Red;
}
BorderStopTime.Visibility = Visibility.Collapsed;
}
});
if (spentTimePercent >= 1)
{
Application.Current.Dispatcher.Invoke(() =>
{
//Play sound
PlayTimerSound();
});
}
}
SoundPlayer player = new SoundPlayer();
@@ -105,15 +131,16 @@ namespace Ink_Canvas
bool isTimerRunning = false;
bool isPaused = false;
bool useLegacyUI = false;
bool isOvertimeMode = false;
Timer timer = new Timer();
private void Grid_MouseUp(object sender, MouseButtonEventArgs e)
{
if (isTimerRunning) return;
var textForeground = Application.Current.FindResource("TimerWindowTextForeground") as SolidColorBrush;
if (ProcessBarTime.Visibility == Visibility.Visible && isTimerRunning == false)
{
ProcessBarTime.Visibility = Visibility.Collapsed;
@@ -268,6 +295,9 @@ namespace Ink_Canvas
TextBlockHour.Foreground = textForeground3;
else
TextBlockHour.Foreground = new SolidColorBrush(StringToColor("#FF5B5D5F"));
isOvertimeMode = false;
ProcessBarTime.Visibility = Visibility.Visible;
}
else if (isTimerRunning && isPaused)
{
@@ -288,6 +318,9 @@ namespace Ink_Canvas
isPaused = false;
ProcessBarTime.CurrentValue = 0;
ProcessBarTime.IsPaused = false;
isOvertimeMode = false;
ProcessBarTime.Visibility = Visibility.Visible;
}
else
{
@@ -390,6 +423,8 @@ namespace Ink_Canvas
isPaused = false;
isTimerRunning = true;
isOvertimeMode = false;
ProcessBarTime.Visibility = Visibility.Visible;
timer.Start();
UpdateStopTime();
BorderStopTime.Visibility = Visibility.Visible;
@@ -439,7 +474,7 @@ namespace Ink_Canvas
{
// 重新应用主题
ApplyTheme();
// 强制刷新UI
InvalidateVisual();
}
+2 -2
View File
@@ -37,8 +37,8 @@ namespace Ink_Canvas
}
// 如果当前选中的是被删除的图标,重置为默认图标
if (MainWindow.Settings.Appearance.FloatingBarImg >= 8 &&
MainWindow.Settings.Appearance.FloatingBarImg - 8 >= MainWindow.Settings.Appearance.CustomFloatingBarImgs.Count)
if (MainWindow.Settings.Appearance.FloatingBarImg >= 12 &&
MainWindow.Settings.Appearance.FloatingBarImg - 12 >= MainWindow.Settings.Appearance.CustomFloatingBarImgs.Count)
{
MainWindow.Settings.Appearance.FloatingBarImg = 0;
mainWindow.ComboBoxFloatingBarImg.SelectedIndex = 0;
+25
View File
@@ -0,0 +1,25 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- 数字0-9的SVG路径数据 -->
<Geometry x:Key="Digit0">M2.432,34.536 C2.432,30.6533333 2.83733333,27.2506667 3.648,24.328 C4.45866667,21.4053333 5.6,18.984 7.072,17.064 C8.544,15.144 10.304,13.704 12.352,12.744 C14.4,11.784 16.6826667,11.304 19.2,11.304 C24.576,11.304 28.7146667,13.192 31.616,16.968 C34.5173333,20.744 35.968,26.6 35.968,34.536 C35.968,38.4613333 35.5626667,41.8853333 34.752,44.808 C33.9413333,47.7306667 32.8,50.1626667 31.328,52.104 C29.856,54.0453333 28.0853333,55.496 26.016,56.456 C23.9466667,57.416 21.6533333,57.896 19.136,57.896 C13.7173333,57.896 9.57866667,55.9013333 6.72,51.912 C3.86133333,47.9226667 2.432,42.1306667 2.432,34.536 Z M27.776,34.536 C27.776,33.8533333 27.7653333,33.2026667 27.744,32.584 C27.7226667,31.9653333 27.6906667,31.3573333 27.648,30.76 L11.968,45.032 C13.2906667,48.9146667 15.7013333,50.856 19.2,50.856 C21.9306667,50.856 24.0426667,49.5546667 25.536,46.952 C27.0293333,44.3493333 27.776,40.2106667 27.776,34.536 Z M10.624,34.536 C10.624,35.176 10.6346667,35.784 10.656,36.36 C10.6773333,36.936 10.7093333,37.5226667 10.752,38.12 L26.368,23.848 C25.088,20.1786667 22.6773333,18.344 19.136,18.344 C16.4053333,18.344 14.304,19.656 12.832,22.28 C11.36,24.904 10.624,28.9893333 10.624,34.536 Z</Geometry>
<Geometry x:Key="Digit1">M46.184 49.96 L55.976 49.96 L55.976 21.992 L47.528 28.456 L43.688 23.336 L58.28 12.2 L63.912 12.2 L63.912 49.96 L73.512 49.96 L73.512 57 L46.184 57 Z</Geometry>
<Geometry x:Key="Digit2">M112.272,57 L83.728,57 L83.728,50.792 C84.24,50.3653333 84.88,49.8 85.648,49.096 C86.416,48.392 87.28,47.592 88.24,46.696 C89.2,45.8 90.2133333,44.8186667 91.28,43.752 C92.3466667,42.6853333 93.392,41.576 94.416,40.424 C95.8666667,38.8026667 97.136,37.3306667 98.224,36.008 C99.312,34.6853333 100.208,33.4373333 100.912,32.264 C101.616,31.0906667 102.138667,29.9386667 102.48,28.808 C102.821333,27.6773333 102.992,26.5146667 102.992,25.32 C102.992,24.4666667 102.8,23.6346667 102.416,22.824 C102.032,22.0133333 101.498667,21.2986667 100.816,20.68 C100.133333,20.0613333 99.312,19.5706667 98.352,19.208 C97.392,18.8453333 96.336,18.664 95.184,18.664 C93.648,18.664 92.2506667,18.8986667 90.992,19.368 C89.7333333,19.8373333 88.4213333,20.6266667 87.056,21.736 L83.728,15.848 C85.52,14.568 87.5146667,13.4906667 89.712,12.616 C91.9093333,11.7413333 94.4373333,11.304 97.296,11.304 C99.1306667,11.304 100.890667,11.56 102.576,12.072 C104.261333,12.584 105.754667,13.3413333 107.056,14.344 C108.357333,15.3466667 109.392,16.5946667 110.16,18.088 C110.928,19.5813333 111.312,21.3093333 111.312,23.272 C111.312,24.6373333 111.194667,25.9066667 110.96,27.08 C110.725333,28.2533333 110.362667,29.4266667 109.872,30.6 C109.381333,31.7733333 108.741333,32.9786667 107.952,34.216 C107.162667,35.4533333 106.213333,36.7973333 105.104,38.248 C104.250667,39.3573333 103.322667,40.4773333 102.32,41.608 C101.317333,42.7386667 100.325333,43.816 99.344,44.84 C98.3626667,45.864 97.392,46.824 96.432,47.72 C95.472,48.616 94.608,49.3626667 93.84,49.96 L112.272,49.96 L112.272,57 Z</Geometry>
<Geometry x:Key="Digit3">M134.072,50.856 C135.48,50.856 136.770667,50.6746667 137.944,50.312 C139.117333,49.9493333 140.12,49.4373333 140.952,48.776 C141.784,48.1146667 142.434667,47.3466667 142.904,46.472 C143.373333,45.5973333 143.608,44.648 143.608,43.624 C143.608,42.344 143.341333,41.2666667 142.808,40.392 C142.274667,39.5173333 141.538667,38.824 140.6,38.312 C139.661333,37.8 138.530667,37.4373333 137.208,37.224 C135.885333,37.0106667 134.456,36.904 132.92,36.904 L129.336,36.904 L129.336,32.36 L140.088,19.24 L123.896,19.24 L123.896,12.2 L150.008,12.2 L150.008,18.024 L138.744,30.888 L140.216,30.888 C141.709333,30.888 143.16,31.144 144.568,31.656 C145.976,32.168 147.224,32.936 148.312,33.96 C149.4,34.984 150.274667,36.264 150.936,37.8 C151.597333,39.336 151.928,41.1066667 151.928,43.112 C151.928,45.544 151.426667,47.6773333 150.424,49.512 C149.421333,51.3466667 148.098667,52.8933333 146.456,54.152 C144.813333,55.4106667 142.925333,56.3493333 140.792,56.968 C138.658667,57.5866667 136.461333,57.896 134.2,57.896 C132.28,57.896 130.36,57.7253333 128.44,57.384 C126.52,57.0426667 124.664,56.5093333 122.872,55.784 L125.112,48.872 C125.496,49.0853333 126.018667,49.2986667 126.68,49.512 C127.341333,49.7253333 128.088,49.9386667 128.92,50.152 C129.752,50.3653333 130.605333,50.536 131.48,50.664 C132.354667,50.792 133.218667,50.856 134.072,50.856 Z</Geometry>
<Geometry x:Key="Digit4">M194.528,44.52 L186.848,44.52 L186.848,57 L179.104,57 L179.104,44.52 L159.712,44.52 L159.712,38.824 L180,11.88 L186.848,11.88 L186.848,37.864 L194.528,37.864 L194.528,44.52 Z M179.104,23.656 L167.968,37.864 L179.104,37.864 L179.104,23.656 Z</Geometry>
<Geometry x:Key="Digit5">M212.168,50.536 C213.576,50.536 214.877333,50.3653333 216.072,50.024 C217.266667,49.6826667 218.301333,49.192 219.176,48.552 C220.050667,47.912 220.733333,47.1226667 221.224,46.184 C221.714667,45.2453333 221.96,44.1786667 221.96,42.984 C221.96,40.6373333 221.032,38.792 219.176,37.448 C217.32,36.104 214.536,35.432 210.824,35.432 C210.354667,35.432 209.810667,35.4426667 209.192,35.464 C208.573333,35.4853333 207.986667,35.5173333 207.432,35.56 C206.792,35.6026667 206.130667,35.624 205.448,35.624 L205.448,12.2 L228.616,12.2 L228.616,19.88 L212.616,19.88 L212.616,28.648 C212.957333,28.648 213.298667,28.6266667 213.64,28.584 C213.938667,28.584 214.226667,28.5733333 214.504,28.552 C214.781333,28.5306667 215.026667,28.52 215.24,28.52 C217.373333,28.52 219.357333,28.8293333 221.192,29.448 C223.026667,30.0666667 224.626667,30.9946667 225.992,32.232 C227.357333,33.4693333 228.413333,34.9733333 229.16,36.744 C229.906667,38.5146667 230.28,40.4666667 230.28,42.6 C230.28,45.1173333 229.810667,47.3253333 228.872,49.224 C227.933333,51.1226667 226.653333,52.712 225.032,53.992 C223.410667,55.272 221.533333,56.2426667 219.4,56.904 C217.266667,57.5653333 214.984,57.896 212.552,57.896 C211.613333,57.896 210.610667,57.8 209.544,57.608 C208.477333,57.416 207.432,57.1813333 206.408,56.904 C205.384,56.6266667 204.434667,56.3173333 203.56,55.976 C202.685333,55.6346667 201.949333,55.3146667 201.352,55.016 L204.04,48.36 C204.765333,48.7866667 205.885333,49.256 207.4,49.768 C208.914667,50.28 210.504,50.536 212.168,50.536 Z</Geometry>
<Geometry x:Key="Digit6">M271.344,43.112 C271.344,45.2026667 270.949333,47.144 270.16,48.936 C269.370667,50.728 268.293333,52.2853333 266.928,53.608 C265.562667,54.9306667 263.930667,55.976 262.032,56.744 C260.133333,57.512 258.096,57.896 255.92,57.896 C253.701333,57.896 251.621333,57.544 249.68,56.84 C247.738667,56.136 246.042667,55.08 244.592,53.672 C243.141333,52.264 241.989333,50.4933333 241.136,48.36 C240.282667,46.2266667 239.856,43.752 239.856,40.936 C239.856,36.712 240.592,32.872 242.064,29.416 C243.536,25.96 245.424,22.9626667 247.728,20.424 C250.032,17.8853333 252.613333,15.8373333 255.472,14.28 C258.330667,12.7226667 261.168,11.7306667 263.984,11.304 L265.84,17.896 C263.578667,18.3226667 261.466667,19.016 259.504,19.976 C257.541333,20.936 255.792,22.0986667 254.256,23.464 C252.72,24.8293333 251.429333,26.344 250.384,28.008 C249.338667,29.672 248.624,31.4 248.24,33.192 C249.093333,32.1253333 250.373333,31.2186667 252.08,30.472 C253.786667,29.7253333 255.664,29.352 257.712,29.352 C259.632,29.352 261.424,29.6613333 263.088,30.28 C264.752,30.8986667 266.192,31.7946667 267.408,32.968 C268.624,34.1413333 269.584,35.5813333 270.288,37.288 C270.992,38.9946667 271.344,40.936 271.344,43.112 Z M263.28,43.432 C263.28,41.128 262.586667,39.3786667 261.2,38.184 C259.813333,36.9893333 257.946667,36.392 255.6,36.392 C253.893333,36.392 252.357333,36.776 250.992,37.544 C249.626667,38.312 248.624,39.208 247.984,40.232 C247.898667,40.7013333 247.845333,41.224 247.824,41.8 C247.802667,42.376 247.792,42.8346667 247.792,43.176 C247.792,44.2 247.962667,45.1813333 248.304,46.12 C248.645333,47.0586667 249.146667,47.88 249.808,48.584 C250.469333,49.288 251.269333,49.8426667 252.208,50.248 C253.146667,50.6533333 254.234667,50.856 255.472,50.856 C256.453333,50.856 257.413333,50.6746667 258.352,50.312 C259.290667,49.9493333 260.122667,49.448 260.848,48.808 C261.573333,48.168 262.16,47.3893333 262.608,46.472 C263.056,45.5546667 263.28,44.5413333 263.28,43.432 Z</Geometry>
<Geometry x:Key="Digit7">M282.328 57 L300.76 19.752 L279.896 19.752 L279.896 12.2 L309.08 12.2 L309.08 18.472 L290.456 57 Z</Geometry>
<Geometry x:Key="Digit8">M319.04,46.056 C319.04,44.5626667 319.285333,43.1973333 319.776,41.96 C320.266667,40.7226667 320.906667,39.6133333 321.696,38.632 C322.485333,37.6506667 323.392,36.7653333 324.416,35.976 C325.44,35.1866667 326.485333,34.4933333 327.552,33.896 C325.418667,32.6586667 323.648,31.1973333 322.24,29.512 C320.832,27.8266667 320.128,25.704 320.128,23.144 C320.128,21.48 320.490667,19.9226667 321.216,18.472 C321.941333,17.0213333 322.954667,15.7626667 324.256,14.696 C325.557333,13.6293333 327.104,12.7973333 328.896,12.2 C330.688,11.6026667 332.629333,11.304 334.72,11.304 C336.64,11.304 338.442667,11.56 340.128,12.072 C341.813333,12.584 343.296,13.3093333 344.576,14.248 C345.856,15.1866667 346.858667,16.328 347.584,17.672 C348.309333,19.016 348.672,20.4986667 348.672,22.12 C348.672,24.6373333 348.021333,26.8346667 346.72,28.712 C345.418667,30.5893333 343.637333,32.2106667 341.376,33.576 C343.936,34.8986667 345.973333,36.456 347.488,38.248 C349.002667,40.04 349.76,42.344 349.76,45.16 C349.76,47.08 349.344,48.8186667 348.512,50.376 C347.68,51.9333333 346.56,53.2666667 345.152,54.376 C343.744,55.4853333 342.090667,56.3493333 340.192,56.968 C338.293333,57.5866667 336.277333,57.896 334.144,57.896 C332.010667,57.896 330.026667,57.608 328.192,57.032 C326.357333,56.456 324.757333,55.656 323.392,54.632 C322.026667,53.608 320.96,52.3706667 320.192,50.92 C319.424,49.4693333 319.04,47.848 319.04,46.056 Z M341.824,44.968 C341.824,43.9013333 341.546667,42.984 340.992,42.216 C340.437333,41.448 339.744,40.7653333 338.912,40.168 C338.08,39.5706667 337.162667,39.0266667 336.16,38.536 C335.157333,38.0453333 334.186667,37.544 333.248,37.032 C331.114667,37.9706667 329.472,39.176 328.32,40.648 C327.168,42.12 326.592,43.5173333 326.592,44.84 C326.592,46.76 327.274667,48.2426667 328.64,49.288 C330.005333,50.3333333 331.904,50.856 334.336,50.856 C336.512,50.856 338.304,50.3546667 339.712,49.352 C341.12,48.3493333 341.824,46.888 341.824,44.968 Z M328.064,23.528 C328.064,24.552 328.288,25.416 328.736,26.12 C329.184,26.824 329.76,27.4426667 330.464,27.976 C331.168,28.5093333 331.968,28.9893333 332.864,29.416 C333.76,29.8426667 334.656,30.2693333 335.552,30.696 C336.234667,30.3546667 336.906667,29.928 337.568,29.416 C338.229333,28.904 338.816,28.3386667 339.328,27.72 C339.84,27.1013333 340.256,26.4613333 340.576,25.8 C340.896,25.1386667 341.056,24.4666667 341.056,23.784 C341.056,22.888 340.864,22.1093333 340.48,21.448 C340.096,20.7866667 339.594667,20.2213333 338.976,19.752 C338.357333,19.2826667 337.664,18.9306667 336.896,18.696 C336.128,18.4613333 335.338667,18.344 334.528,18.344 C333.589333,18.344 332.725333,18.4933333 331.936,18.792 C331.146667,19.0906667 330.464,19.4746667 329.888,19.944 C329.312,20.4133333 328.864,20.968 328.544,21.608 C328.224,22.248 328.064,22.888 328.064,23.528 Z</Geometry>
<Geometry x:Key="Digit9">M358.056,26.216 C358.056,24.04 358.429333,22.0346667 359.176,20.2 C359.922667,18.3653333 360.968,16.7973333 362.312,15.496 C363.656,14.1946667 365.277333,13.1706667 367.176,12.424 C369.074667,11.6773333 371.197333,11.304 373.544,11.304 C375.933333,11.304 378.109333,11.6666667 380.072,12.392 C382.034667,13.1173333 383.72,14.1946667 385.128,15.624 C386.536,17.0533333 387.624,18.824 388.392,20.936 C389.16,23.048 389.544,25.4693333 389.544,28.2 C389.544,33.1493333 388.904,37.416 387.624,41 C386.344,44.584 384.626667,47.5706667 382.472,49.96 C380.317333,52.3493333 377.810667,54.184 374.952,55.464 C372.093333,56.744 369.106667,57.5546667 365.992,57.896 L364.2,51.368 C366.546667,51.0693333 368.669333,50.4933333 370.568,49.64 C372.466667,48.7866667 374.12,47.7306667 375.528,46.472 C376.936,45.2133333 378.088,43.784 378.984,42.184 C379.88,40.584 380.456,38.8666667 380.712,37.032 C379.816,37.928 378.664,38.6426667 377.256,39.176 C375.848,39.7093333 374.162667,39.976 372.2,39.976 L372.072,39.976 C370.450667,39.976 368.808,39.6986667 367.144,39.144 C365.48,38.5893333 363.976,37.736 362.632,36.584 C361.288,35.432 360.189333,33.992 359.336,32.264 C358.482667,30.536 358.056,28.52 358.056,26.216 Z M366.12,25.768 C366.12,26.9626667 366.344,28.0186667 366.792,28.936 C367.24,29.8533333 367.826667,30.6213333 368.552,31.24 C369.277333,31.8586667 370.12,32.328 371.08,32.648 C372.04,32.968 373.032,33.128 374.056,33.128 C375.805333,33.128 377.32,32.8506667 378.6,32.296 C379.88,31.7413333 380.818667,31.0586667 381.416,30.248 C381.544,29.352 381.608,28.4986667 381.608,27.688 C381.608,26.4933333 381.437333,25.32 381.096,24.168 C380.754667,23.016 380.242667,21.992 379.56,21.096 C378.877333,20.2 378.024,19.4853333 377,18.952 C375.976,18.4186667 374.802667,18.152 373.48,18.152 C371.389333,18.152 369.64,18.824 368.232,20.168 C366.824,21.512 366.12,23.3786667 366.12,25.768 Z</Geometry>
</ResourceDictionary>
@@ -0,0 +1,95 @@
<Window x:Class="Ink_Canvas.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"
Topmost="True" Background="Black"
mc:Ignorable="d" WindowStyle="None" AllowsTransparency="False"
WindowState="Maximized" WindowStartupLocation="Manual"
MouseLeftButtonDown="Window_MouseLeftButtonDown"
KeyDown="Window_KeyDown">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="DigitResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid Background="Black">
<!-- 时间显示 -->
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<!-- 小时 -->
<Path x:Name="FullHour1Display" Data="{StaticResource Digit0}"
Fill="White"
Width="120" Height="120"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Margin="0,0,20,0"/>
<Path x:Name="FullHour2Display" Data="{StaticResource Digit0}"
Fill="White"
Width="120" Height="120"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Margin="0,0,20,0"/>
<!-- 冒号 -->
<TextBlock x:Name="FullColon1Display" Text=":" FontSize="120" FontWeight="Bold"
Foreground="White"
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="0,0,20,0"/>
<!-- 分钟 -->
<Path x:Name="FullMinute1Display" Data="{StaticResource Digit0}"
Fill="White"
Width="120" Height="120"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Margin="0,0,20,0"/>
<Path x:Name="FullMinute2Display" Data="{StaticResource Digit0}"
Fill="White"
Width="120" Height="120"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Margin="0,0,20,0"/>
<!-- 冒号 -->
<TextBlock x:Name="FullColon2Display" Text=":" FontSize="120" FontWeight="Bold"
Foreground="White"
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="0,0,20,0"/>
<!-- 秒 -->
<Path x:Name="FullSecond1Display" Data="{StaticResource Digit0}"
Fill="White"
Width="120" Height="120"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Margin="0,0,20,0"/>
<Path x:Name="FullSecond2Display" Data="{StaticResource Digit0}"
Fill="White"
Width="120" Height="120"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Margin="0,0,0,0"/>
</StackPanel>
</Grid>
<!-- 退出提示 -->
<TextBlock Text="点击屏幕退出全屏"
FontSize="16"
Foreground="Gray"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Margin="0,0,0,50"/>
</Grid>
</Window>
@@ -0,0 +1,255 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Timers;
namespace Ink_Canvas
{
/// <summary>
/// 全屏计时器窗口
/// </summary>
public partial class FullscreenTimerWindow : Window
{
private NewStyleTimerWindow parentWindow;
private System.Timers.Timer updateTimer;
public FullscreenTimerWindow(NewStyleTimerWindow parent)
{
InitializeComponent();
parentWindow = 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;
}
private void UpdateTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (parentWindow != null)
{
Application.Current.Dispatcher.Invoke(() =>
{
if (ShouldCloseWindow())
{
this.Close();
return;
}
UpdateTimeDisplay();
});
}
}
private bool ShouldCloseWindow()
{
if (parentWindow == null) return true;
if (MainWindow.Settings.RandSettings?.EnableOvertimeCountUp == true)
{
if (parentWindow.IsTimerRunning)
{
return false;
}
var remainingTime = parentWindow.GetRemainingTime();
if (remainingTime.HasValue && remainingTime.Value.TotalSeconds < 0)
{
return false;
}
return true;
}
else
{
return !parentWindow.IsTimerRunning;
}
}
private void UpdateTimeDisplay()
{
if (parentWindow == null) return;
// 获取剩余时间
var remainingTime = parentWindow.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 = parentWindow.GetTotalTimeSpan();
if (totalTimeSpan.HasValue)
{
var elapsedTime = parentWindow.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("FullHour1Display", hours / 10, shouldShowRed);
SetDigitDisplay("FullHour2Display", hours % 10, shouldShowRed);
// 更新分钟显示
SetDigitDisplay("FullMinute1Display", minutes / 10, shouldShowRed);
SetDigitDisplay("FullMinute2Display", minutes % 10, shouldShowRed);
// 更新秒显示
SetDigitDisplay("FullSecond1Display", seconds / 10, shouldShowRed);
SetDigitDisplay("FullSecond2Display", seconds % 10, shouldShowRed);
SetColonDisplay(shouldShowRed);
}
}
private void ParentWindow_TimerCompleted(object sender, EventArgs e)
{
Application.Current.Dispatcher.Invoke(() =>
{
this.Close();
});
}
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
{
path.Fill = Brushes.White;
}
}
}
/// <summary>
/// 设置全屏窗口冒号显示颜色
/// </summary>
/// <param name="isRed">是否显示为红色</param>
private void SetColonDisplay(bool isRed = false)
{
var colon1 = this.FindName("FullColon1Display") as TextBlock;
var colon2 = this.FindName("FullColon2Display") as TextBlock;
if (colon1 != null)
{
if (isRed)
{
colon1.Foreground = Brushes.Red;
}
else
{
colon1.Foreground = Brushes.White;
}
}
if (colon2 != null)
{
if (isRed)
{
colon2.Foreground = Brushes.Red;
}
else
{
colon2.Foreground = Brushes.White;
}
}
}
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// 点击屏幕退出全屏
ExitFullscreen();
}
private void Window_KeyDown(object sender, KeyEventArgs e)
{
// 按ESC键退出全屏
if (e.Key == Key.Escape)
{
ExitFullscreen();
}
}
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)
{
parentWindow.TimerCompleted -= ParentWindow_TimerCompleted;
}
// 清理资源
if (updateTimer != null)
{
updateTimer.Stop();
updateTimer.Dispose();
}
base.OnClosed(e);
}
}
}
@@ -0,0 +1,125 @@
<Window x:Class="Ink_Canvas.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:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
Topmost="True" Background="Transparent"
mc:Ignorable="d" WindowStyle="None" AllowsTransparency="True"
WindowStartupLocation="Manual" Title="计时器" Height="200" Width="600"
MouseLeftButtonDown="Window_MouseLeftButtonDown" MouseLeftButtonUp="Window_MouseLeftButtonUp"
MouseEnter="Window_MouseEnter" MouseLeave="Window_MouseLeave" MouseMove="Window_MouseMove">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="DigitResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Border x:Name="MainBorder" Background="{DynamicResource NewTimerWindowBackground}"
CornerRadius="15"
BorderThickness="1"
BorderBrush="{DynamicResource NewTimerWindowBorderBrush}"
Margin="0"
UseLayoutRounding="True"
SnapsToDevicePixels="True">
<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>
</Window>
@@ -0,0 +1,392 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Media.Animation;
namespace Ink_Canvas
{
/// <summary>
/// 最小化计时器窗口
/// </summary>
public partial class MinimizedTimerWindow : Window
{
private NewStyleTimerWindow parentWindow;
private System.Timers.Timer updateTimer;
private bool isMouseOver = false;
private bool isDragging = false;
private Point lastMousePosition;
public MinimizedTimerWindow(NewStyleTimerWindow parent)
{
InitializeComponent();
parentWindow = parent;
// 设置窗口位置
this.Left = parent.Left;
this.Top = parent.Top;
// 启动更新定时器
updateTimer = new System.Timers.Timer(100); // 100ms更新一次
updateTimer.Elapsed += UpdateTimer_Elapsed;
updateTimer.Start();
parentWindow.TimerCompleted += ParentWindow_TimerCompleted;
// 应用主题
ApplyTheme();
}
private void UpdateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (parentWindow != null)
{
Application.Current.Dispatcher.Invoke(() =>
{
if (ShouldCloseWindow())
{
this.Close();
return;
}
UpdateTimeDisplay();
});
}
}
private bool ShouldCloseWindow()
{
if (parentWindow == null) return true;
if (MainWindow.Settings.RandSettings?.EnableOvertimeCountUp == true)
{
if (parentWindow.IsTimerRunning)
{
return false;
}
var remainingTime = parentWindow.GetRemainingTime();
if (remainingTime.HasValue && remainingTime.Value.TotalSeconds < 0)
{
return false;
}
return true;
}
else
{
return !parentWindow.IsTimerRunning;
}
}
private void UpdateTimeDisplay()
{
if (parentWindow == null) return;
// 获取剩余时间
var remainingTime = parentWindow.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 = parentWindow.GetTotalTimeSpan();
if (totalTimeSpan.HasValue)
{
var elapsedTime = parentWindow.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", hours / 10, shouldShowRed);
SetDigitDisplay("MinHour2Display", hours % 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 ParentWindow_TimerCompleted(object sender, EventArgs e)
{
Application.Current.Dispatcher.Invoke(() =>
{
this.Close();
});
}
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;
}
}
}
}
/// <summary>
/// 设置最小化窗口冒号显示颜色
/// </summary>
/// <param name="isRed">是否显示为红色</param>
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
{
// 找到Border元素并设置灰色边框
var border = this.FindName("MainBorder") as Border;
if (border != null)
{
border.BorderBrush = new SolidColorBrush(Color.FromRgb(64, 64, 64));
}
}
catch
{
}
}
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// 记录点击时间
lastClickTime = DateTime.Now;
// 开始拖动
isDragging = true;
lastMousePosition = e.GetPosition(this);
this.CaptureMouse();
}
private void Window_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
var currentPosition = e.GetPosition(this);
var deltaX = currentPosition.X - lastMousePosition.X;
var deltaY = currentPosition.Y - lastMousePosition.Y;
this.Left += deltaX;
this.Top += deltaY;
}
}
private void Window_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (isDragging)
{
isDragging = false;
this.ReleaseMouseCapture();
// 如果点击时间很短,认为是单击,恢复主窗口
var clickDuration = DateTime.Now - lastClickTime;
if (clickDuration.TotalMilliseconds < 200) // 200ms内认为是单击
{
// 恢复主窗口
if (parentWindow != null)
{
parentWindow.Show();
parentWindow.Activate();
parentWindow.WindowState = WindowState.Normal;
this.Close();
}
}
}
}
private DateTime lastClickTime = DateTime.Now;
private void Window_MouseEnter(object sender, MouseEventArgs e)
{
isMouseOver = true;
// 鼠标进入时显示关闭按钮
if (CloseButton != null)
{
CloseButton.Opacity = 1.0;
}
}
private void Window_MouseLeave(object sender, MouseEventArgs e)
{
isMouseOver = false;
// 鼠标离开时隐藏关闭按钮
if (CloseButton != null)
{
CloseButton.Opacity = 0.7;
}
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
// 停止计时器并关闭窗口
if (parentWindow != null)
{
parentWindow.StopTimer();
}
this.Close();
}
protected override void OnClosed(EventArgs e)
{
if (parentWindow != null)
{
parentWindow.TimerCompleted -= ParentWindow_TimerCompleted;
}
// 清理资源
if (updateTimer != null)
{
updateTimer.Stop();
updateTimer.Dispose();
}
base.OnClosed(e);
}
}
}
File diff suppressed because it is too large Load Diff
+783
View File
@@ -0,0 +1,783 @@
<Window x:Class="Ink_Canvas.NewStyleTimerWindow"
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"
Loaded="Window_Loaded" Closing="Window_Closing" WindowStartupLocation="CenterScreen"
MouseMove="Window_MouseMove" MouseEnter="Window_MouseEnter"
Title="Ink Canvas 画板 - 计时器" Height="450" Width="900">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Controls/WinUI3CloseButton.xaml" />
<ResourceDictionary Source="DigitResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Border Background="{DynamicResource NewTimerWindowBackground}" CornerRadius="15" BorderThickness="1" BorderBrush="{DynamicResource NewTimerWindowBorderBrush}" Margin="10" x:Name="MainBorder" MouseLeftButtonDown="WindowDragMove">
<Grid>
<controls:WinUI3CloseButton x:Name="CloseButton"
HorizontalAlignment="Right" VerticalAlignment="Top"
Margin="0,0,0,0" Cursor="Hand" Click="CloseButton_Click"
Content="✕"/>
<!-- 主要内容区域 -->
<Grid>
<!-- 使用Viewbox自动缩放内容 -->
<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">
<!-- 计时器图标 -->
<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}"
StrokeThickness="2"
StrokeLineJoin="Round"
Fill="Transparent"
Width="24" Height="24"
Stretch="Uniform"
Margin="0,0,8,0"/>
<!-- 计时文字 -->
<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">
<!-- 左侧:6位数字显示区域 -->
<Grid HorizontalAlignment="Left" VerticalAlignment="Center"
x:Name="MainDisplayGrid" Width="500" Margin="-10,0,0,0">
<!-- 6位数字水平排列 -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"
x:Name="DigitsPanel">
<!-- 小时组(十位和个位) -->
<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">
<!-- 上方+按钮 -->
<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>
</ControlTemplate>
</Button.Template>
<Path Data="M12 5l0 14 M5 12l14 0"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"/>
</Button>
<!-- 数字显示 -->
<Path x:Name="Digit1Display" Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="48" Height="48"
HorizontalAlignment="Center"
VerticalAlignment="Center"
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.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<Path Data="M5 12l14 0"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"/>
</Button>
</StackPanel>
</Grid>
<!-- 第2位数字(小时个位) -->
<Grid>
<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.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<Path Data="M12 5l0 14 M5 12l14 0"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"/>
</Button>
<!-- 数字显示 -->
<Path x:Name="Digit2Display" Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="48" Height="48"
HorizontalAlignment="Center"
VerticalAlignment="Center"
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.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<Path Data="M5 12l14 0"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"/>
</Button>
</StackPanel>
</Grid>
</StackPanel>
</Grid>
<!-- 冒号分隔符 -->
<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">
<!-- 第3位数字(分钟十位) -->
<Grid Margin="0,0,15,0">
<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.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<Path Data="M12 5l0 14 M5 12l14 0"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"/>
</Button>
<!-- 数字显示 -->
<Path x:Name="Digit3Display" Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="48" Height="48"
HorizontalAlignment="Center"
VerticalAlignment="Center"
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.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<Path Data="M5 12l14 0"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"/>
</Button>
</StackPanel>
</Grid>
<!-- 第4位数字(分钟个位) -->
<Grid>
<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.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<Path Data="M12 5l0 14 M5 12l14 0"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"/>
</Button>
<!-- 数字显示 -->
<Path x:Name="Digit4Display" Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="48" Height="48"
HorizontalAlignment="Center"
VerticalAlignment="Center"
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.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<Path Data="M5 12l14 0"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"/>
</Button>
</StackPanel>
</Grid>
</StackPanel>
</Grid>
<!-- 冒号分隔符 -->
<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">
<!-- 第5位数字(秒十位) -->
<Grid Margin="0,0,15,0">
<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.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<Path Data="M12 5l0 14 M5 12l14 0"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"/>
</Button>
<!-- 数字显示 -->
<Path x:Name="Digit5Display" Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="48" Height="48"
HorizontalAlignment="Center"
VerticalAlignment="Center"
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.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<Path Data="M5 12l14 0"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"/>
</Button>
</StackPanel>
</Grid>
<!-- 第6位数字(秒个位) -->
<Grid>
<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.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<Path Data="M12 5l0 14 M5 12l14 0"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"/>
</Button>
<!-- 数字显示 -->
<Path x:Name="Digit6Display" Data="{StaticResource Digit0}"
Fill="{DynamicResource NewTimerWindowDigitForeground}"
Width="48" Height="48"
HorizontalAlignment="Center"
VerticalAlignment="Center"
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.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<Path Data="M5 12l14 0"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"/>
</Button>
</StackPanel>
</Grid>
</StackPanel>
</Grid>
</StackPanel>
</Grid>
<!-- 分割线 -->
<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">
<!-- Segmented Control -->
<Grid Margin="0,0,0,20">
<Border Background="{DynamicResource NewTimerWindowButtonBackground}"
CornerRadius="8"
BorderThickness="1"
BorderBrush="#616161"
Width="240" Height="40">
<Grid>
<!-- 背景指示器 -->
<Border x:Name="SegmentedIndicator"
Background="{DynamicResource NewTimerWindowPrimaryButtonBackground}"
CornerRadius="7.5,0,0,7.5"
Width="120" Height="38"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="0,0,0,0"/>
<!-- 按钮容器 -->
<Grid>
<Button x:Name="CommonTabBtn"
Width="120" Height="40"
Background="Transparent"
BorderThickness="0"
Click="CommonTab_Click"
Cursor="Hand"
HorizontalAlignment="Left">
<TextBlock x:Name="CommonTabText" Text="常用" FontSize="16" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</Button>
<Button x:Name="RecentTabBtn"
Width="120" Height="40"
Background="Transparent"
BorderThickness="0"
Click="RecentTab_Click"
Cursor="Hand"
HorizontalAlignment="Right">
<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">
<!-- 第一排:5分钟, 10分钟, 15分钟 -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,0,0,10">
<Button x:Name="Common5MinBtn" Width="100" Height="55" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Common5Min_Click" Cursor="Hand" Margin="0,0,15,0">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Path Data="M10 15h2a1.5 1.5 0 0 0 0 -3h-2v-3h3.5 M3 12v.01 M21 12v.01 M12 21v.01 M7.5 4.2v.01 M16.5 19.8v.01 M7.5 19.8v.01 M4.2 16.5v.01 M19.8 16.5v.01 M19.8 7.5v.01 M4.2 7.5v.01 M16.5 4.206a9.042 9.042 0 0 0 -4.5 -1.206"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"
Margin="0,0,8,0"/>
<TextBlock Text="05:00" FontSize="16" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</StackPanel>
</Button>
<Button x:Name="Common10MinBtn" Width="100" Height="55" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Common10Min_Click" Cursor="Hand" Margin="0,0,15,0">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Path Data="M9 9v6 M12 11v2a2 2 0 1 0 4 0v-2a2 2 0 1 0 -4 0z M3 12v.01 M21 12v.01 M12 21v.01 M7.5 4.2v.01 M16.5 19.8v.01 M7.5 19.8v.01 M4.2 16.5v.01 M19.8 16.5v.01 M4.2 7.5v.01 M19.81 7.527a8.994 8.994 0 0 0 -7.81 -4.527"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"
Margin="0,0,8,0"/>
<TextBlock Text="10:00" FontSize="16" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</StackPanel>
</Button>
<Button x:Name="Common15MinBtn" Width="100" Height="55" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Common15Min_Click" Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Path Data="M12 15h2a1 1 0 0 0 1 -1v-1a1 1 0 0 0 -1 -1h-2v-3h3 M9 9v6 M3 12v.01 M12 21v.01 M7.5 4.2v.01 M16.5 19.8v.01 M7.5 19.8v.01 M4.2 16.5v.01 M19.8 16.5v.01 M4.2 7.5v.01 M21 12a9 9 0 0 0 -9 -9"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"
Margin="0,0,8,0"/>
<TextBlock Text="15:00" FontSize="16" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</StackPanel>
</Button>
</StackPanel>
<!-- 第二排:30分钟, 45分钟, 60分钟 -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button x:Name="Common30MinBtn" Width="100" Height="55" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Common30Min_Click" Cursor="Hand" Margin="0,0,15,0">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Path Data="M14 10.5v3a1.5 1.5 0 0 0 3 0v-3a1.5 1.5 0 0 0 -3 0z M8 9h1.5a1.5 1.5 0 0 1 0 3h-.5h.5a1.5 1.5 0 0 1 0 3h-1.5 M3 12v.01 M7.5 4.2v.01 M7.5 19.8v.01 M4.2 16.5v.01 M4.2 7.5v.01 M12 21a9 9 0 0 0 0 -18"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"
Margin="0,0,8,0"/>
<TextBlock Text="30:00" FontSize="16" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</StackPanel>
</Button>
<Button x:Name="Common45MinBtn" Width="100" Height="55" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Common45Min_Click" Cursor="Hand" Margin="0,0,15,0">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Path Data="M13 15h2a1 1 0 0 0 1 -1v-1a1 1 0 0 0 -1 -1h-2v-3h3 M7 9v2a1 1 0 0 0 1 1h1 M10 9v6 M7.5 4.2v.01 M4.2 7.5v.01 M3 12a9 9 0 1 0 9 -9"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"
Margin="0,0,8,0"/>
<TextBlock Text="45:00" FontSize="16" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</StackPanel>
</Button>
<Button x:Name="Common60MinBtn" Width="100" Height="55" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="Common60Min_Click" Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Path Data="M14 10.5v3a1.5 1.5 0 0 0 3 0v-3a1.5 1.5 0 0 0 -3 0z M11 9h-2a1 1 0 0 0 -1 1v4a1 1 0 0 0 1 1h1a1 1 0 0 0 1 -1v-1a1 1 0 0 0 -1 -1h-2 M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"
Stroke="{DynamicResource NewTimerWindowButtonForeground}"
StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"
Margin="0,0,8,0"/>
<TextBlock Text="60:00" FontSize="16" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</StackPanel>
</Button>
</StackPanel>
</StackPanel>
</Grid>
<!-- 最近计时区域 -->
<Grid x:Name="RecentTimersGrid" Visibility="Collapsed">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<!-- 第一排:最近3个 -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,0,0,10">
<Button x:Name="RecentTimer1Btn" Width="100" Height="55" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="RecentTimer1_Click" Cursor="Hand" Margin="0,0,15,0">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock x:Name="RecentTimer1Text" Text="--:--" FontSize="16" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</Button>
<Button x:Name="RecentTimer2Btn" Width="100" Height="55" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="RecentTimer2_Click" Cursor="Hand" Margin="0,0,15,0">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock x:Name="RecentTimer2Text" Text="--:--" FontSize="16" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</Button>
<Button x:Name="RecentTimer3Btn" Width="100" Height="55" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="RecentTimer3_Click" Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock x:Name="RecentTimer3Text" Text="--:--" FontSize="16" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</Button>
</StackPanel>
<!-- 第二排:最近3个 -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button x:Name="RecentTimer4Btn" Width="100" Height="55" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="RecentTimer4_Click" Cursor="Hand" Margin="0,0,15,0">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock x:Name="RecentTimer4Text" Text="--:--" FontSize="16" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</Button>
<Button x:Name="RecentTimer5Btn" Width="100" Height="55" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="RecentTimer5_Click" Cursor="Hand" Margin="0,0,15,0">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock x:Name="RecentTimer5Text" Text="--:--" FontSize="16" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</Button>
<Button x:Name="RecentTimer6Btn" Width="100" Height="55" Background="{DynamicResource NewTimerWindowButtonBackground}"
BorderThickness="0" Click="RecentTimer6_Click" Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock x:Name="RecentTimer6Text" Text="--:--" FontSize="16" FontWeight="Bold"
Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</Button>
</StackPanel>
</StackPanel>
</Grid>
</StackPanel>
</Grid>
</Grid>
<!-- 底部控制按钮区域 -->
<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">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="8">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<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"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"
Margin="0,0,5,0"/>
<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.Template>
<ControlTemplate TargetType="Button">
<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"
Fill="{DynamicResource NewTimerWindowPrimaryButtonForeground}"
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.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="8">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<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"
StrokeLineJoin="Round"
Fill="Transparent"
Width="20" Height="20"
Stretch="Uniform"
Margin="0,0,5,0"/>
<TextBlock Text="重置" FontSize="16" Foreground="{DynamicResource NewTimerWindowButtonForeground}"/>
</StackPanel>
</Button>
</StackPanel>
</Grid>
</Grid>
</Viewbox>
</Grid>
</Grid>
</Border>
</Window>
@@ -1,8 +1,8 @@
using Ink_Canvas.Helpers;
using System.Windows;
using System.Windows.Input;
using iNKORE.UI.WPF.Modern;
using System;
using System.Windows;
using System.Windows.Input;
namespace Ink_Canvas
{
@@ -54,9 +54,9 @@ namespace Ink_Canvas
try
{
// 根据当前主题设置窗口主题
bool isDarkTheme = MainWindow.Settings.Appearance.Theme == 1 ||
bool isDarkTheme = MainWindow.Settings.Appearance.Theme == 1 ||
(MainWindow.Settings.Appearance.Theme == 2 && !IsSystemThemeLight());
if (isDarkTheme)
{
ThemeManager.SetRequestedTheme(this, ElementTheme.Dark);
+1 -1
View File
@@ -487,7 +487,7 @@ namespace Ink_Canvas
{
// 重新应用主题
ApplyTheme(MainWindow.Settings);
// 强制刷新UI
InvalidateVisual();
}
@@ -1,322 +0,0 @@
<Window x:Class="Ink_Canvas.SeewoStyleTimerWindow"
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"
Topmost="True" Background="Transparent"
mc:Ignorable="d" WindowStyle="None" AllowsTransparency="True"
Loaded="Window_Loaded" Closing="Window_Closing" WindowStartupLocation="CenterScreen"
Title="Ink Canvas 画板 - 计时器" Height="400" Width="600">
<Border Background="{DynamicResource SeewoTimerWindowBackground}" CornerRadius="15" BorderThickness="1" BorderBrush="{DynamicResource SeewoTimerWindowBorderBrush}" Margin="10">
<Grid>
<!-- 主要内容区域 -->
<Grid>
<!-- 使用Viewbox自动缩放内容 -->
<Viewbox x:Name="MainViewController" Margin="20,20,20,20">
<Grid Height="350" Width="600">
<!-- 顶部标题栏 -->
<Grid Height="50" Background="{DynamicResource SeewoTimerWindowBackground}" x:Name="TitleBar" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<TextBlock Text="计时" FontSize="20" FontWeight="Bold"
HorizontalAlignment="Left" VerticalAlignment="Center"
Margin="22,0,0,0" Foreground="{DynamicResource SeewoTimerWindowTitleForeground}" x:Name="TitleText"/>
<Border x:Name="BtnClose" MouseUp="BtnClose_MouseUp"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,22,0" Background="{DynamicResource SeewoTimerWindowButtonBackground}" Height="30" Width="30"
CornerRadius="15" Cursor="Hand">
<TextBlock Text="×" FontSize="16" FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center"
Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</Border>
</Grid>
<!-- 6位数字显示区域 -->
<Grid HorizontalAlignment="Center" VerticalAlignment="Center"
x:Name="MainDisplayGrid">
<!-- 6位数字水平排列 -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"
x:Name="DigitsPanel" Margin="0,-25,0,25">
<!-- 小时组(十位和个位) -->
<Grid Margin="0,0,30,0" HorizontalAlignment="Center" Width="120">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<!-- 第1位数字(小时十位) -->
<Grid Margin="0,0,15,0">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<!-- 上方+按钮 -->
<Button x:Name="Digit1PlusBtn" Width="40" Height="40" Background="{DynamicResource SeewoTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit1Plus_Click" Cursor="Hand" Margin="0,0,0,8">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock Text="+" FontSize="14" FontWeight="Bold" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</Button>
<!-- 数字显示 -->
<TextBlock x:Name="Digit1Display" Text="0" FontSize="64" FontWeight="Bold"
HorizontalAlignment="Center" Foreground="{DynamicResource SeewoTimerWindowDigitForeground}" Margin="0,0,0,8"/>
<!-- 下方-按钮 -->
<Button x:Name="Digit1MinusBtn" Width="40" Height="40" Background="{DynamicResource SeewoTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit1Minus_Click" Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock Text="-" FontSize="14" FontWeight="Bold" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</Button>
</StackPanel>
</Grid>
<!-- 第2位数字(小时个位) -->
<Grid>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<!-- 上方+按钮 -->
<Button x:Name="Digit2PlusBtn" Width="40" Height="40" Background="{DynamicResource SeewoTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit2Plus_Click" Cursor="Hand" Margin="0,0,0,8">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock Text="+" FontSize="14" FontWeight="Bold" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</Button>
<!-- 数字显示 -->
<TextBlock x:Name="Digit2Display" Text="0" FontSize="64" FontWeight="Bold"
HorizontalAlignment="Center" Foreground="{DynamicResource SeewoTimerWindowDigitForeground}" Margin="0,0,0,8"/>
<!-- 下方-按钮 -->
<Button x:Name="Digit2MinusBtn" Width="40" Height="40" Background="{DynamicResource SeewoTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit2Minus_Click" Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock Text="-" FontSize="14" FontWeight="Bold" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</Button>
</StackPanel>
</Grid>
</StackPanel>
<!-- 时标签 -->
<TextBlock Text="时" FontSize="16" HorizontalAlignment="Center"
Foreground="{DynamicResource SeewoTimerWindowButtonForeground}" Margin="0,112,0,-13"/>
</Grid>
<!-- 分钟组(十位和个位) -->
<Grid Margin="0,0,30,0" HorizontalAlignment="Center" Width="120">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<!-- 第3位数字(分钟十位) -->
<Grid Margin="0,0,15,0">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<!-- 上方+按钮 -->
<Button x:Name="Digit3PlusBtn" Width="40" Height="40" Background="{DynamicResource SeewoTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit3Plus_Click" Cursor="Hand" Margin="0,0,0,8">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock Text="+" FontSize="14" FontWeight="Bold" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</Button>
<!-- 数字显示 -->
<TextBlock x:Name="Digit3Display" Text="0" FontSize="64" FontWeight="Bold"
HorizontalAlignment="Center" Foreground="{DynamicResource SeewoTimerWindowDigitForeground}" Margin="0,0,0,8"/>
<!-- 下方-按钮 -->
<Button x:Name="Digit3MinusBtn" Width="40" Height="40" Background="{DynamicResource SeewoTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit3Minus_Click" Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock Text="-" FontSize="14" FontWeight="Bold" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</Button>
</StackPanel>
</Grid>
<!-- 第4位数字(分钟个位) -->
<Grid>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<!-- 上方+按钮 -->
<Button x:Name="Digit4PlusBtn" Width="40" Height="40" Background="{DynamicResource SeewoTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit4Plus_Click" Cursor="Hand" Margin="0,0,0,8">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock Text="+" FontSize="14" FontWeight="Bold" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</Button>
<!-- 数字显示 -->
<TextBlock x:Name="Digit4Display" Text="5" FontSize="64" FontWeight="Bold"
HorizontalAlignment="Center" Foreground="{DynamicResource SeewoTimerWindowDigitForeground}" Margin="0,0,0,8"/>
<!-- 下方-按钮 -->
<Button x:Name="Digit4MinusBtn" Width="40" Height="40" Background="{DynamicResource SeewoTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit4Minus_Click" Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock Text="-" FontSize="14" FontWeight="Bold" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</Button>
</StackPanel>
</Grid>
</StackPanel>
<!-- 分标签 -->
<TextBlock Text="分" FontSize="16" HorizontalAlignment="Center"
Foreground="{DynamicResource SeewoTimerWindowButtonForeground}" Margin="0,112,0,-12"/>
</Grid>
<!-- 秒组(十位和个位) -->
<Grid Width="120">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<!-- 第5位数字(秒十位) -->
<Grid Margin="0,0,15,0">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<!-- 上方+按钮 -->
<Button x:Name="Digit5PlusBtn" Width="40" Height="40" Background="{DynamicResource SeewoTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit5Plus_Click" Cursor="Hand" Margin="0,0,0,8">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock Text="+" FontSize="14" FontWeight="Bold" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</Button>
<!-- 数字显示 -->
<TextBlock x:Name="Digit5Display" Text="0" FontSize="64" FontWeight="Bold"
HorizontalAlignment="Center" Foreground="{DynamicResource SeewoTimerWindowDigitForeground}" Margin="0,0,0,8"/>
<!-- 下方-按钮 -->
<Button x:Name="Digit5MinusBtn" Width="40" Height="40" Background="{DynamicResource SeewoTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit5Minus_Click" Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock Text="-" FontSize="14" FontWeight="Bold" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</Button>
</StackPanel>
</Grid>
<!-- 第6位数字(秒个位) -->
<Grid>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<!-- 上方+按钮 -->
<Button x:Name="Digit6PlusBtn" Width="40" Height="40" Background="{DynamicResource SeewoTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit6Plus_Click" Cursor="Hand" Margin="0,0,0,8">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock Text="+" FontSize="14" FontWeight="Bold" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</Button>
<!-- 数字显示 -->
<TextBlock x:Name="Digit6Display" Text="0" FontSize="64" FontWeight="Bold"
HorizontalAlignment="Center" Foreground="{DynamicResource SeewoTimerWindowDigitForeground}" Margin="0,0,0,8"/>
<!-- 下方-按钮 -->
<Button x:Name="Digit6MinusBtn" Width="40" Height="40" Background="{DynamicResource SeewoTimerWindowButtonBackground}"
BorderThickness="0" Click="Digit6Minus_Click" Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="15">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<TextBlock Text="-" FontSize="14" FontWeight="Bold" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</Button>
</StackPanel>
</Grid>
</StackPanel>
<!-- 秒标签 -->
<TextBlock Text="秒" FontSize="16" HorizontalAlignment="Center"
Foreground="{DynamicResource SeewoTimerWindowButtonForeground}" Margin="0,112,0,-12"/>
</Grid>
</StackPanel>
</Grid>
<!-- 底部控制按钮区域 -->
<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 SeewoTimerWindowButtonBackground}"
BorderThickness="0" Click="Fullscreen_Click" Cursor="Hand" Margin="0,0,30,0">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="8">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="⛶" FontSize="16" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}" Margin="0,0,5,0"/>
<TextBlock Text="全屏" FontSize="16" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</StackPanel>
</Button>
<!-- 开始/暂停按钮 -->
<Button x:Name="StartPauseBtn" Width="80" Height="80" Background="{DynamicResource SeewoTimerWindowPrimaryButtonBackground}"
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>
</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"
Fill="{DynamicResource SeewoTimerWindowPrimaryButtonForeground}"
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 SeewoTimerWindowButtonBackground}"
BorderThickness="0" Click="Reset_Click" Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="8">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="↻" FontSize="16" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}" Margin="0,0,5,0"/>
<TextBlock Text="重置" FontSize="16" Foreground="{DynamicResource SeewoTimerWindowButtonForeground}"/>
</StackPanel>
</Button>
</StackPanel>
</Grid>
</Grid>
</Viewbox>
</Grid>
</Grid>
</Border>
</Window>
@@ -1,434 +0,0 @@
using Ink_Canvas.Helpers;
using System;
using System.Media;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
namespace Ink_Canvas
{
/// <summary>
/// 仿希沃风格的倒计时器窗口
/// </summary>
public partial class SeewoStyleTimerWindow : Window
{
public SeewoStyleTimerWindow()
{
InitializeComponent();
AnimationsHelper.ShowWithSlideFromBottomAndFade(this, 0.25);
timer.Elapsed += Timer_Elapsed;
timer.Interval = 50;
InitializeUI();
// 应用主题
ApplyTheme();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (!isTimerRunning || isPaused)
{
timer.Stop();
return;
}
TimeSpan timeSpan = DateTime.Now - startTime;
TimeSpan totalTimeSpan = new TimeSpan(hour, minute, second);
TimeSpan leftTimeSpan = totalTimeSpan - timeSpan;
if (leftTimeSpan.Milliseconds > 0) leftTimeSpan += new TimeSpan(0, 0, 1);
Application.Current.Dispatcher.Invoke(() =>
{
Digit1Display.Text = (leftTimeSpan.Hours / 10).ToString();
Digit2Display.Text = (leftTimeSpan.Hours % 10).ToString();
Digit3Display.Text = (leftTimeSpan.Minutes / 10).ToString();
Digit4Display.Text = (leftTimeSpan.Minutes % 10).ToString();
Digit5Display.Text = (leftTimeSpan.Seconds / 10).ToString();
Digit6Display.Text = (leftTimeSpan.Seconds % 10).ToString();
if (leftTimeSpan.TotalSeconds <= 0)
{
Digit1Display.Text = "0";
Digit2Display.Text = "0";
Digit3Display.Text = "0";
Digit4Display.Text = "0";
Digit5Display.Text = "0";
Digit6Display.Text = "0";
timer.Stop();
isTimerRunning = false;
StartPauseIcon.Data = Geometry.Parse(PlayIconData);
PlayTimerSound();
}
});
}
SoundPlayer player = new SoundPlayer();
MediaPlayer mediaPlayer = new MediaPlayer();
int hour = 0;
int minute = 5;
int second = 0;
DateTime startTime = DateTime.Now;
DateTime pauseTime = DateTime.Now;
bool isTimerRunning = false;
bool isPaused = false;
Timer timer = new Timer();
private void InitializeUI()
{
UpdateDigitDisplays();
}
private void ApplyTheme()
{
try
{
// 应用主题设置
if (MainWindow.Settings != null)
{
ApplyTheme(MainWindow.Settings);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"应用仿希沃倒计时窗口主题出错: {ex.Message}", LogHelper.LogType.Error);
}
}
private void ApplyTheme(Settings settings)
{
try
{
if (settings.Appearance.Theme == 0) // 浅色主题
{
iNKORE.UI.WPF.Modern.ThemeManager.SetRequestedTheme(this, iNKORE.UI.WPF.Modern.ElementTheme.Light);
}
else if (settings.Appearance.Theme == 1) // 深色主题
{
iNKORE.UI.WPF.Modern.ThemeManager.SetRequestedTheme(this, iNKORE.UI.WPF.Modern.ElementTheme.Dark);
}
else // 跟随系统主题
{
bool isSystemLight = IsSystemThemeLight();
if (isSystemLight)
{
iNKORE.UI.WPF.Modern.ThemeManager.SetRequestedTheme(this, iNKORE.UI.WPF.Modern.ElementTheme.Light);
}
else
{
iNKORE.UI.WPF.Modern.ThemeManager.SetRequestedTheme(this, iNKORE.UI.WPF.Modern.ElementTheme.Dark);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"应用仿希沃倒计时窗口主题出错: {ex.Message}", LogHelper.LogType.Error);
}
}
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;
}
private void UpdateDigitDisplays()
{
Digit1Display.Text = (hour / 10).ToString();
Digit2Display.Text = (hour % 10).ToString();
Digit3Display.Text = (minute / 10).ToString();
Digit4Display.Text = (minute % 10).ToString();
Digit5Display.Text = (second / 10).ToString();
Digit6Display.Text = (second % 10).ToString();
}
// 第1位数字(小时十位)
private void Digit1Plus_Click(object sender, RoutedEventArgs e)
{
if (isTimerRunning) return;
hour += 10;
if (hour >= 100) hour = 0;
UpdateDigitDisplays();
}
private void Digit1Minus_Click(object sender, RoutedEventArgs e)
{
if (isTimerRunning) return;
hour -= 10;
if (hour < 0) hour = 90;
UpdateDigitDisplays();
}
// 第2位数字(小时个位)
private void Digit2Plus_Click(object sender, RoutedEventArgs e)
{
if (isTimerRunning) return;
hour++;
if (hour >= 100) hour = 0;
UpdateDigitDisplays();
}
private void Digit2Minus_Click(object sender, RoutedEventArgs e)
{
if (isTimerRunning) return;
hour--;
if (hour < 0) hour = 99;
UpdateDigitDisplays();
}
// 第3位数字(分钟十位)
private void Digit3Plus_Click(object sender, RoutedEventArgs e)
{
if (isTimerRunning) return;
minute += 10;
if (minute >= 60) minute = 0;
UpdateDigitDisplays();
}
private void Digit3Minus_Click(object sender, RoutedEventArgs e)
{
if (isTimerRunning) return;
minute -= 10;
if (minute < 0) minute = 50;
UpdateDigitDisplays();
}
// 第4位数字(分钟个位)
private void Digit4Plus_Click(object sender, RoutedEventArgs e)
{
if (isTimerRunning) return;
minute++;
if (minute >= 60) minute = 0;
UpdateDigitDisplays();
}
private void Digit4Minus_Click(object sender, RoutedEventArgs e)
{
if (isTimerRunning) return;
minute--;
if (minute < 0) minute = 59;
UpdateDigitDisplays();
}
// 第5位数字(秒十位)
private void Digit5Plus_Click(object sender, RoutedEventArgs e)
{
if (isTimerRunning) return;
second += 10;
if (second >= 60) second = 0;
UpdateDigitDisplays();
}
private void Digit5Minus_Click(object sender, RoutedEventArgs e)
{
if (isTimerRunning) return;
second -= 10;
if (second < 0) second = 50;
UpdateDigitDisplays();
}
// 第6位数字(秒个位)
private void Digit6Plus_Click(object sender, RoutedEventArgs e)
{
if (isTimerRunning) return;
second++;
if (second >= 60) second = 0;
UpdateDigitDisplays();
}
private void Digit6Minus_Click(object sender, RoutedEventArgs e)
{
if (isTimerRunning) return;
second--;
if (second < 0) second = 59;
UpdateDigitDisplays();
}
// 图标数据常量
private const string PlayIconData = "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";
private const string PauseIconData = "M9.5 4H7.5C6.96957 4 6.46086 4.21071 6.08579 4.58579C5.71071 4.96086 5.5 5.46957 5.5 6V18C5.5 18.5304 5.71071 19.0391 6.08579 19.4142C6.46086 19.7893 6.96957 20 7.5 20H9.5C10.0304 20 10.5391 19.7893 10.9142 19.4142C11.2893 19.0391 11.5 18.5304 11.5 18V6C11.5 5.46957 11.2893 4.96086 10.9142 4.58579C10.5391 4.21071 10.0304 4 9.5 4Z M17.5 4H15.5C14.9696 4 14.4609 4.21071 14.0858 4.58579C13.7107 4.96086 13.5 5.46957 13.5 6V18C13.5 18.5304 13.7107 19.0391 14.0858 19.4142C14.4609 19.7893 14.9696 20 15.5 20H17.5C18.0304 20 18.5391 19.7893 18.9142 19.4142C19.2893 19.0391 19.5 18.5304 19.5 18V6C19.5 5.46957 19.2893 4.96086 18.9142 4.58579C18.5391 4.21071 18.0304 4 17.5 4Z";
private void StartPause_Click(object sender, RoutedEventArgs e)
{
if (isPaused && isTimerRunning)
{
// 继续计时
startTime += DateTime.Now - pauseTime;
StartPauseIcon.Data = Geometry.Parse(PauseIconData);
isPaused = false;
timer.Start();
}
else if (isTimerRunning)
{
// 暂停计时
pauseTime = DateTime.Now;
StartPauseIcon.Data = Geometry.Parse(PlayIconData);
isPaused = true;
timer.Stop();
}
else
{
// 开始计时
if (hour == 0 && minute == 0 && second == 0)
{
second = 1;
UpdateDigitDisplays();
}
startTime = DateTime.Now;
StartPauseIcon.Data = Geometry.Parse(PauseIconData);
isPaused = false;
isTimerRunning = true;
timer.Start();
}
}
private void Reset_Click(object sender, RoutedEventArgs e)
{
if (!isTimerRunning)
{
UpdateDigitDisplays();
}
else if (isTimerRunning && isPaused)
{
UpdateDigitDisplays();
StartPauseIcon.Data = Geometry.Parse(PlayIconData);
isTimerRunning = false;
timer.Stop();
isPaused = false;
}
else
{
startTime = DateTime.Now;
Timer_Elapsed(timer, null);
}
}
private void Fullscreen_Click(object sender, RoutedEventArgs e)
{
if (WindowState == WindowState.Normal)
{
WindowState = WindowState.Maximized;
}
else
{
WindowState = WindowState.Normal;
}
}
private void PlayTimerSound()
{
try
{
double volume = MainWindow.Settings.RandSettings?.TimerVolume ?? 1.0;
mediaPlayer.Volume = volume;
if (!string.IsNullOrEmpty(MainWindow.Settings.RandSettings?.CustomTimerSoundPath) &&
System.IO.File.Exists(MainWindow.Settings.RandSettings.CustomTimerSoundPath))
{
// 播放自定义铃声
mediaPlayer.Open(new Uri(MainWindow.Settings.RandSettings.CustomTimerSoundPath));
}
else
{
// 播放默认铃声
string tempPath = System.IO.Path.GetTempFileName() + ".wav";
using (var stream = Properties.Resources.TimerDownNotice)
{
using (var fileStream = new System.IO.FileStream(tempPath, System.IO.FileMode.Create))
{
stream.CopyTo(fileStream);
}
}
mediaPlayer.Open(new Uri(tempPath));
}
mediaPlayer.Play();
}
catch (Exception ex)
{
// 如果播放失败,静默处理
System.Diagnostics.Debug.WriteLine($"播放计时器铃声失败: {ex.Message}");
}
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// 窗口加载时的初始化
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
isTimerRunning = false;
if (MainWindow.Settings != null)
{
var mainWindow = Application.Current.MainWindow as MainWindow;
if (mainWindow != null)
{
try
{
var currentModeField = mainWindow.GetType().GetField("currentMode",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (currentModeField != null)
{
int currentMode = (int)currentModeField.GetValue(mainWindow);
if (currentMode == 1) // 白板模式
{
mainWindow.Topmost = false; // 保持白板模式下的非置顶状态
}
else
{
mainWindow.Topmost = true; // 其他模式恢复置顶
}
}
}
catch
{
// 如果反射失败,使用默认行为
mainWindow.Topmost = true;
}
}
}
}
private void BtnClose_MouseUp(object sender, MouseButtonEventArgs e)
{
Close();
}
private void WindowDragMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
DragMove();
}
}
}
+1
View File
@@ -114,3 +114,4 @@ GPLv3
## 项目引用
[Alan-CRL/DesktopDrawpadBlocker](https://github.com/Alan-CRL/DesktopDrawpadBlocker)
[Awesome-Iwb/iwbicons-gallery](https://github.com/awesome-iwb/awesome-iwb/wiki/iwbicons-gallery)「本项目部分图标来自 Awesome Iwb 的 IwbIcons 图标库,由 Douxiba 制作。」
+2 -1
View File
@@ -98,4 +98,5 @@ ICC CE 1.7.X.X更新日志
97. 改进橡皮系统
98. 新增启动动画
99. 修复仅调色盘状态下浮动栏不居中
100. 修复希沃白板查杀与思锐希沃启动器导致的重复启动
100. 修复希沃白板查杀与思锐希沃启动器导致的重复启动
101. 新增UIA窗口置顶