mirror of
https://github.com/babalae/better-genshin-impact
synced 2025-01-07 03:17:16 +08:00
create a setup builder impl from MicaSetup
This commit is contained in:
parent
edc597a19a
commit
a6891e29dc
@ -17,44 +17,100 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fischless.HotkeyCapture", "
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fischless.KeyboardCapture", "Fischless.KeyboardCapture\Fischless.KeyboardCapture.csproj", "{10A48327-7E58-4B51-B1FC-55506C703C8F}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Deploy", "Deploy", "{458E1106-43A4-47E6-B11B-D243035D4C76}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MicaSetup", "Build\MicaSetup\MicaSetup.csproj", "{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MicaSetup.Uninst", "Build\MicaSetup\MicaSetup.Uninst.csproj", "{673344BC-B860-44AE-AD88-D33465BDE25B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Debug|x64.Build.0 = Debug|x64
|
||||
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Release|Any CPU.Build.0 = Release|x64
|
||||
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Release|x64.ActiveCfg = Release|x64
|
||||
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Release|x64.Build.0 = Release|x64
|
||||
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Debug|x64.Build.0 = Debug|x64
|
||||
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Release|Any CPU.Build.0 = Release|x64
|
||||
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Release|x64.ActiveCfg = Release|x64
|
||||
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Release|x64.Build.0 = Release|x64
|
||||
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Debug|x64.Build.0 = Debug|x64
|
||||
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Release|Any CPU.Build.0 = Release|x64
|
||||
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Release|x64.ActiveCfg = Release|x64
|
||||
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Release|x64.Build.0 = Release|x64
|
||||
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Debug|x64.Build.0 = Debug|x64
|
||||
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Release|Any CPU.Build.0 = Release|x64
|
||||
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Release|x64.ActiveCfg = Release|x64
|
||||
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Release|x64.Build.0 = Release|x64
|
||||
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Debug|x64.Build.0 = Debug|x64
|
||||
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Release|Any CPU.Build.0 = Release|x64
|
||||
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Release|x64.ActiveCfg = Release|x64
|
||||
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Release|x64.Build.0 = Release|x64
|
||||
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Debug|x64.Build.0 = Debug|x64
|
||||
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Release|Any CPU.Build.0 = Release|x64
|
||||
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Release|x64.ActiveCfg = Release|x64
|
||||
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Release|x64.Build.0 = Release|x64
|
||||
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Debug|x64.Build.0 = Debug|x64
|
||||
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Release|Any CPU.Build.0 = Release|x64
|
||||
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Release|x64.ActiveCfg = Release|x64
|
||||
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Release|x64.Build.0 = Release|x64
|
||||
{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15}.Debug|x64.Build.0 = Debug|x64
|
||||
{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15}.Release|x64.ActiveCfg = Release|x64
|
||||
{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15}.Release|x64.Build.0 = Release|x64
|
||||
{673344BC-B860-44AE-AD88-D33465BDE25B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{673344BC-B860-44AE-AD88-D33465BDE25B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{673344BC-B860-44AE-AD88-D33465BDE25B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{673344BC-B860-44AE-AD88-D33465BDE25B}.Debug|x64.Build.0 = Debug|x64
|
||||
{673344BC-B860-44AE-AD88-D33465BDE25B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{673344BC-B860-44AE-AD88-D33465BDE25B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{673344BC-B860-44AE-AD88-D33465BDE25B}.Release|x64.ActiveCfg = Release|x64
|
||||
{673344BC-B860-44AE-AD88-D33465BDE25B}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15} = {458E1106-43A4-47E6-B11B-D243035D4C76}
|
||||
{673344BC-B860-44AE-AD88-D33465BDE25B} = {458E1106-43A4-47E6-B11B-D243035D4C76}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {352D8B78-9DE3-4E58-985F-FADD22594DB4}
|
||||
EndGlobalSection
|
||||
|
@ -1,75 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<!-- UAC 清单选项
|
||||
如果想要更改 Windows 用户帐户控制级别,请使用
|
||||
以下节点之一替换 requestedExecutionLevel 节点。n
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||
|
||||
指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。
|
||||
如果你的应用程序需要此虚拟化来实现向后兼容性,则删除此
|
||||
元素。
|
||||
-->
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- 设计此应用程序与其一起工作且已针对此应用程序进行测试的
|
||||
Windows 版本的列表。取消评论适当的元素,
|
||||
Windows 将自动选择最兼容的环境。 -->
|
||||
|
||||
<!-- Windows Vista -->
|
||||
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
|
||||
|
||||
<!-- Windows 7 -->
|
||||
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
|
||||
|
||||
<!-- Windows 8 -->
|
||||
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
|
||||
|
||||
<!-- Windows 8.1 -->
|
||||
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
|
||||
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<!-- 指示该应用程序可以感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
|
||||
自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI,无需
|
||||
选择加入。选择加入此设置的 Windows 窗体应用程序(目标设定为 .NET Framework 4.6 )还应
|
||||
在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。-->
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
|
||||
|
||||
<!-- 启用 Windows 公共控件和对话框的主题(Windows XP 和更高版本) -->
|
||||
<!--
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
</assembly>
|
5
Build/.gitignore
vendored
Normal file
5
Build/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.vs/
|
||||
dist/
|
||||
/*.exe
|
||||
/*.7z
|
||||
/*.zip
|
21
Build/LICENSE
Normal file
21
Build/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Lemutec Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
BIN
Build/MicaSetup.Tools/7-Zip/7z.dll
Normal file
BIN
Build/MicaSetup.Tools/7-Zip/7z.dll
Normal file
Binary file not shown.
BIN
Build/MicaSetup.Tools/7-Zip/7z.exe
Normal file
BIN
Build/MicaSetup.Tools/7-Zip/7z.exe
Normal file
Binary file not shown.
4
Build/MicaSetup/.gitignore
vendored
Normal file
4
Build/MicaSetup/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
bin/
|
||||
obj/
|
||||
|
||||
*.user
|
21
Build/MicaSetup/App.xaml
Normal file
21
Build/MicaSetup/App.xaml
Normal file
@ -0,0 +1,21 @@
|
||||
<Application
|
||||
x:Class="MicaSetup.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:control="clr-namespace:MicaSetup.Design.Controls"
|
||||
xmlns:design="clr-namespace:MicaSetup.Design"
|
||||
xmlns:local="clr-namespace:MicaSetup"
|
||||
StartupUri="Views/MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/Resources/Languages/zh.xaml" />
|
||||
<ResourceDictionary Source="/Resources/Languages/ja.xaml" />
|
||||
<ResourceDictionary Source="/Resources/Languages/en.xaml" />
|
||||
<design:ResourceResourceDictionary />
|
||||
<design:GenericResourceDictionary />
|
||||
<design:ThemeResourceDictionary />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
17
Build/MicaSetup/App.xaml.cs
Normal file
17
Build/MicaSetup/App.xaml.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using MicaSetup.Helper;
|
||||
using System.Windows;
|
||||
|
||||
namespace MicaSetup;
|
||||
|
||||
public partial class App : Application, IApp
|
||||
{
|
||||
public App()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
|
||||
public interface IApp
|
||||
{
|
||||
public int Run();
|
||||
}
|
16
Build/MicaSetup/AssemblyInfo.cs
Normal file
16
Build/MicaSetup/AssemblyInfo.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media;
|
||||
|
||||
[assembly: DisableDpiAwareness]
|
||||
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
|
||||
[assembly: ObfuscateAssembly(true)]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: XmlnsPrefix("urn:MicaSetup", "mica")]
|
||||
[assembly: XmlnsDefinition("urn:MicaSetup", "MicaSetup.Design.Controls")]
|
||||
[assembly: XmlnsDefinition("urn:MicaSetup", "MicaSetup.Design.Converters")]
|
11
Build/MicaSetup/Core/IsExternalInit.cs
Normal file
11
Build/MicaSetup/Core/IsExternalInit.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace System.Runtime.CompilerServices;
|
||||
|
||||
/// <summary>
|
||||
/// Workaround class for records and "init" keyword
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
internal class IsExternalInit
|
||||
{
|
||||
}
|
104
Build/MicaSetup/Core/Logger.cs
Normal file
104
Build/MicaSetup/Core/Logger.cs
Normal file
@ -0,0 +1,104 @@
|
||||
using MicaSetup.Helper;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using DebugOut = System.Diagnostics.Debug;
|
||||
|
||||
namespace MicaSetup.Core;
|
||||
|
||||
public static class Logger
|
||||
{
|
||||
private static readonly string ApplicationLogPath = SpecialPathHelper.GetFolder();
|
||||
private static readonly TextWriterTraceListener TraceListener = null!;
|
||||
|
||||
static Logger()
|
||||
{
|
||||
if (!Directory.Exists(ApplicationLogPath))
|
||||
{
|
||||
_ = Directory.CreateDirectory(ApplicationLogPath);
|
||||
}
|
||||
|
||||
string logFilePath = Path.Combine(ApplicationLogPath, DateTime.Now.ToString(@"yyyyMMdd", CultureInfo.InvariantCulture) + ".log");
|
||||
TraceListener = new TextWriterTraceListener(logFilePath);
|
||||
#if LEGACY
|
||||
Trace.AutoFlush = true;
|
||||
Trace.Listeners.Clear();
|
||||
Trace.Listeners.Add(TraceListener);
|
||||
#endif
|
||||
}
|
||||
|
||||
[SuppressMessage("Style", "IDE0060:")]
|
||||
public static void Ignore(params object[] values)
|
||||
{
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
public static void Debug(params object[] values)
|
||||
{
|
||||
Log("DEBUG", string.Join(" ", values));
|
||||
}
|
||||
|
||||
public static void Info(params object[] values)
|
||||
{
|
||||
Log("INFO", string.Join(" ", values));
|
||||
}
|
||||
|
||||
public static void Warn(params object[] values)
|
||||
{
|
||||
Log("ERROR", string.Join(" ", values));
|
||||
}
|
||||
|
||||
public static void Error(params object[] values)
|
||||
{
|
||||
Log("ERROR", string.Join(" ", values));
|
||||
}
|
||||
|
||||
public static void Fatal(params object[] values)
|
||||
{
|
||||
Log("FATAL", string.Join(" ", values));
|
||||
}
|
||||
|
||||
public static void Exception(Exception e, string message = null!)
|
||||
{
|
||||
Log(
|
||||
(message ?? string.Empty) + Environment.NewLine +
|
||||
e?.Message + Environment.NewLine +
|
||||
"Inner exception: " + Environment.NewLine +
|
||||
e?.InnerException?.Message + Environment.NewLine +
|
||||
"Stack trace: " + Environment.NewLine +
|
||||
e?.StackTrace,
|
||||
"ERROR");
|
||||
#if DEBUG
|
||||
Debugger.Break();
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void Log(string type, string message)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append(type + "|" + DateTime.Now.ToString(@"yyyy-MM-dd|HH:mm:ss.fff", CultureInfo.InvariantCulture))
|
||||
.Append("|" + GetCallerInfo())
|
||||
.Append("|" + message);
|
||||
|
||||
DebugOut.WriteLine(sb.ToString());
|
||||
if (Option.Current.Logging)
|
||||
{
|
||||
TraceListener.WriteLine(sb.ToString());
|
||||
TraceListener.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetCallerInfo()
|
||||
{
|
||||
StackTrace stackTrace = new();
|
||||
|
||||
MethodBase methodName = stackTrace.GetFrame(3)?.GetMethod()!;
|
||||
string? className = methodName?.DeclaringType?.Name;
|
||||
return className + "|" + methodName?.Name;
|
||||
}
|
||||
}
|
183
Build/MicaSetup/Core/MuiLanguage.cs
Normal file
183
Build/MicaSetup/Core/MuiLanguage.cs
Normal file
@ -0,0 +1,183 @@
|
||||
using MicaSetup.Helper;
|
||||
using MicaSetup.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows;
|
||||
using System.Windows.Baml2006;
|
||||
using System.Xaml;
|
||||
|
||||
namespace MicaSetup.Core;
|
||||
|
||||
public static class MuiLanguage
|
||||
{
|
||||
/// <summary>
|
||||
/// https://learn.microsoft.com/en-us/typography/fonts/windows_11_font_list
|
||||
/// https://learn.microsoft.com/en-us/typography/fonts/windows_10_font_list
|
||||
/// https://learn.microsoft.com/en-us/typography/fonts/windows_81_font_list
|
||||
/// https://learn.microsoft.com/en-us/typography/fonts/windows_8_font_list
|
||||
/// https://learn.microsoft.com/en-us/typography/fonts/windows_7_font_list
|
||||
/// </summary>
|
||||
public static List<MuiLanguageFont> FontSelector { get; } = new();
|
||||
|
||||
public static void SetupLanguage()
|
||||
{
|
||||
_ = SetLanguage();
|
||||
}
|
||||
|
||||
public static bool SetLanguage() => CultureInfo.CurrentUICulture.TwoLetterISOLanguageName switch
|
||||
{
|
||||
"zh" => SetLanguage("zh"),
|
||||
"ja" => SetLanguage("ja"),
|
||||
"en" or _ => SetLanguage("en"),
|
||||
};
|
||||
|
||||
public static bool SetLanguage(string name = "en")
|
||||
{
|
||||
if (Application.Current == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
foreach (ResourceDictionary dictionary in Application.Current.Resources.MergedDictionaries)
|
||||
{
|
||||
if (dictionary.Source != null && dictionary.Source.OriginalString.Equals($"/Resources/Languages/{name}.xaml", StringComparison.Ordinal))
|
||||
{
|
||||
Application.Current.Resources.MergedDictionaries.Remove(dictionary);
|
||||
Application.Current.Resources.MergedDictionaries.Add(dictionary);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_ = e;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string Mui(string key)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Application.Current == null)
|
||||
{
|
||||
return MuiBaml(key);
|
||||
}
|
||||
if (Application.Current!.FindResource(key) is string value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_ = e;
|
||||
}
|
||||
return null!;
|
||||
}
|
||||
|
||||
public static string Mui(string key, params object[] args)
|
||||
{
|
||||
return string.Format(Mui(key)?.ToString(), args);
|
||||
}
|
||||
|
||||
private static string MuiBaml(string key)
|
||||
{
|
||||
try
|
||||
{
|
||||
using Stream resourceXaml = ResourceHelper.GetStream(new MuiLanguageService().GetXamlUriString());
|
||||
if (BamlHelper.LoadBaml(resourceXaml) is ResourceDictionary resourceDictionary)
|
||||
{
|
||||
return (resourceDictionary[key] as string)!;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_ = e;
|
||||
}
|
||||
return null!;
|
||||
}
|
||||
}
|
||||
|
||||
file static class BamlHelper
|
||||
{
|
||||
public static object LoadBaml(Stream stream)
|
||||
{
|
||||
using Baml2006Reader reader = new(stream);
|
||||
using XamlObjectWriter writer = new(reader.SchemaContext);
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
writer.WriteNode(reader);
|
||||
}
|
||||
return writer.Result;
|
||||
}
|
||||
}
|
||||
|
||||
public class MuiLanguageFont
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
public string? TwoName { get; set; }
|
||||
public string? ThreeName { get; set; }
|
||||
|
||||
public string? ResourceFontFileName { get; set; }
|
||||
public string? ResourceFontFamilyName { get; set; }
|
||||
public string? ResourceFamilyName => !string.IsNullOrWhiteSpace(ResourceFontFileName) && !string.IsNullOrWhiteSpace(ResourceFontFamilyName) ? $"./{ResourceFontFileName}#{ResourceFontFamilyName}" : null!;
|
||||
|
||||
public string? SystemFamilyName { get; set; }
|
||||
public string? SystemFamilyNameBackup { get; set; }
|
||||
}
|
||||
|
||||
public static class MuiLanguageFontExtension
|
||||
{
|
||||
public static MuiLanguageFont OnNameOf(this MuiLanguageFont self, string name)
|
||||
{
|
||||
self.Name = name ?? throw new ArgumentNullException(nameof(name));
|
||||
self.TwoName = null!;
|
||||
self.ThreeName = null!;
|
||||
return self;
|
||||
}
|
||||
|
||||
public static MuiLanguageFont OnTwoNameOf(this MuiLanguageFont self, string twoName)
|
||||
{
|
||||
self.Name = null!;
|
||||
self.TwoName = twoName ?? throw new ArgumentNullException(nameof(twoName));
|
||||
self.ThreeName = null!;
|
||||
return self;
|
||||
}
|
||||
|
||||
public static MuiLanguageFont OnThreeNameOf(this MuiLanguageFont self, string threeName)
|
||||
{
|
||||
self.Name = null!;
|
||||
self.TwoName = null!;
|
||||
self.ThreeName = threeName ?? throw new ArgumentNullException(nameof(threeName));
|
||||
return self;
|
||||
}
|
||||
|
||||
public static MuiLanguageFont OnAnyName(this MuiLanguageFont self)
|
||||
{
|
||||
self.Name = null!;
|
||||
self.TwoName = null!;
|
||||
self.ThreeName = null!;
|
||||
return self;
|
||||
}
|
||||
|
||||
public static MuiLanguageFont ForResourceFont(this MuiLanguageFont self, string fontFileName, string familyName)
|
||||
{
|
||||
self.ResourceFontFileName = fontFileName ?? throw new ArgumentNullException(nameof(fontFileName));
|
||||
self.ResourceFontFamilyName = familyName ?? throw new ArgumentNullException(nameof(familyName));
|
||||
return self;
|
||||
}
|
||||
|
||||
public static MuiLanguageFont ForSystemFont(this MuiLanguageFont self, string familyName, string familyNameBackup = null!)
|
||||
{
|
||||
self.SystemFamilyName = familyName ?? throw new ArgumentNullException(nameof(familyName));
|
||||
self.SystemFamilyNameBackup = familyNameBackup;
|
||||
_ = !new Regex("^[a-zA-Z ]+$").IsMatch(familyName) ? throw new ArgumentException(nameof(familyName)) : default(object);
|
||||
return self;
|
||||
}
|
||||
}
|
15
Build/MicaSetup/Core/ServiceManager.cs
Normal file
15
Build/MicaSetup/Core/ServiceManager.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace MicaSetup.Services;
|
||||
|
||||
#pragma warning disable CS8618
|
||||
|
||||
public class ServiceManager
|
||||
{
|
||||
public static ServiceProvider Services { get; set; }
|
||||
|
||||
public static T GetService<T>()
|
||||
{
|
||||
return Services.GetService<T>()!;
|
||||
}
|
||||
}
|
372
Build/MicaSetup/Design/Animations/DoubleEasingAnimation.cs
Normal file
372
Build/MicaSetup/Design/Animations/DoubleEasingAnimation.cs
Normal file
@ -0,0 +1,372 @@
|
||||
using System;
|
||||
|
||||
namespace MicaSetup.Controls.Animations;
|
||||
|
||||
public delegate double DoubleEasingAnimation(double t, double b, double c, double d);
|
||||
|
||||
public static class DoubleEasingAnimations
|
||||
{
|
||||
public static double EaseInOutQuad(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
if ((t /= d / 2d) < 1d)
|
||||
{
|
||||
return c / 2d * t * t + b;
|
||||
}
|
||||
return -c / 2d * ((t -= 1d) * (t - 2d) - 1d) + b;
|
||||
}
|
||||
|
||||
public static double EaseInQuad(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return c * (t /= d) * t + b;
|
||||
}
|
||||
|
||||
public static double EaseOutQuad(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return -c * (t /= d) * (t - 2d) + b;
|
||||
}
|
||||
|
||||
public static double EaseInCubic(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return c * (t /= d) * t * t + b;
|
||||
}
|
||||
|
||||
public static double EaseOutCubic(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return c * ((t = t / d - 1d) * t * t + 1d) + b;
|
||||
}
|
||||
|
||||
public static double EaseInOutCubic(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
if ((t /= d / 2d) < 1d)
|
||||
{
|
||||
return c / 2d * t * t * t + b;
|
||||
}
|
||||
return c / 2d * ((t -= 2d) * t * t + 2d) + b;
|
||||
}
|
||||
|
||||
public static double EaseInQuart(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return c * (t /= d) * t * t * t + b;
|
||||
}
|
||||
|
||||
public static double EaseOutQuart(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return -c * ((t = t / d - 1d) * t * t * t - 1d) + b;
|
||||
}
|
||||
|
||||
public static double EaseInOutQuart(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
if ((t /= d / 2d) < 1d)
|
||||
{
|
||||
return c / 2d * t * t * t * t + b;
|
||||
}
|
||||
return -c / 2d * ((t -= 2d) * t * t * t - 2d) + b;
|
||||
}
|
||||
|
||||
public static double EaseInQuint(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return c * (t /= d) * t * t * t * t + b;
|
||||
}
|
||||
|
||||
public static double EaseOutQuint(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return c * ((t = t / d - 1d) * t * t * t * t + 1d) + b;
|
||||
}
|
||||
|
||||
public static double EaseInOutQuint(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
if ((t /= d / 2d) < 1d)
|
||||
{
|
||||
return c / 2d * t * t * t * t * t + b;
|
||||
}
|
||||
return c / 2d * ((t -= 2d) * t * t * t * t + 2d) + b;
|
||||
}
|
||||
|
||||
public static double EaseInSine(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return -c * Math.Cos(t / d * 1.5707963267948966d) + c + b;
|
||||
}
|
||||
|
||||
public static double EaseOutSine(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return c * Math.Sin(t / d * 1.5707963267948966d) + b;
|
||||
}
|
||||
|
||||
public static double EaseInOutSine(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return -c / 2d * (Math.Cos(3.141592653589793d * t / d) - 1d) + b;
|
||||
}
|
||||
|
||||
public static double EaseInExpo(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
if (t != 0d)
|
||||
{
|
||||
return c * Math.Pow(2d, 10d * (t / d - 1d)) + b;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
public static double EaseOutExpo(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
if (t != d)
|
||||
{
|
||||
return c * (-Math.Pow(2d, -10d * t / d) + 1d) + b;
|
||||
}
|
||||
return b + c;
|
||||
}
|
||||
|
||||
public static double EaseInOutExpo(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
if (t == 0d)
|
||||
{
|
||||
return b;
|
||||
}
|
||||
if (t == d)
|
||||
{
|
||||
return b + c;
|
||||
}
|
||||
if ((t /= d / 2d) < 1d)
|
||||
{
|
||||
return c / 2d * Math.Pow(2d, 10d * (t - 1d)) + b;
|
||||
}
|
||||
return c / 2d * (-Math.Pow(2d, -10d * (t -= 1d)) + 2d) + b;
|
||||
}
|
||||
|
||||
public static double EaseInCirc(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return -c * (Math.Sqrt(1d - (t /= d) * t) - 1d) + b;
|
||||
}
|
||||
|
||||
public static double EaseOutCirc(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return c * Math.Sqrt(1d - (t = t / d - 1d) * t) + b;
|
||||
}
|
||||
|
||||
public static double EaseInOutCirc(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
if ((t /= d / 2d) < 1d)
|
||||
{
|
||||
return -c / 2d * (Math.Sqrt(1d - t * t) - 1d) + b;
|
||||
}
|
||||
return c / 2d * (Math.Sqrt(1d - (t -= 2d) * t) + 1d) + b;
|
||||
}
|
||||
|
||||
public static double EaseInElastic(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
double num = 0d;
|
||||
double num2 = c;
|
||||
if (t == 0d)
|
||||
{
|
||||
return b;
|
||||
}
|
||||
if ((t /= d) == 1d)
|
||||
{
|
||||
return b + c;
|
||||
}
|
||||
if (num == 0d)
|
||||
{
|
||||
num = d * 0.3d;
|
||||
}
|
||||
double num3;
|
||||
if (num2 < Math.Abs(c))
|
||||
{
|
||||
num2 = c;
|
||||
num3 = num / 4d;
|
||||
}
|
||||
else
|
||||
{
|
||||
num3 = num / 6.283185307179586d * Math.Asin(c / num2);
|
||||
}
|
||||
return -(num2 * Math.Pow(2d, 10d * (t -= 1d)) * Math.Sin((t * d - num3) * 6.283185307179586d / num)) + b;
|
||||
}
|
||||
|
||||
public static double EaseOutElastic(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
double num = 0d;
|
||||
double num2 = c;
|
||||
if (t == 0d)
|
||||
{
|
||||
return b;
|
||||
}
|
||||
if ((t /= d) == 1d)
|
||||
{
|
||||
return b + c;
|
||||
}
|
||||
if (num == 0d)
|
||||
{
|
||||
num = d * 0.3d;
|
||||
}
|
||||
double num3;
|
||||
if (num2 < Math.Abs(c))
|
||||
{
|
||||
num2 = c;
|
||||
num3 = num / 4d;
|
||||
}
|
||||
else
|
||||
{
|
||||
num3 = num / 6.283185307179586d * Math.Asin(c / num2);
|
||||
}
|
||||
return num2 * Math.Pow(2d, -10d * t) * Math.Sin((t * d - num3) * 6.283185307179586d / num) + c + b;
|
||||
}
|
||||
|
||||
public static double EaseInOutElastic(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
double num = 0d;
|
||||
double num2 = c;
|
||||
if (t == 0d)
|
||||
{
|
||||
return b;
|
||||
}
|
||||
if ((t /= d / 2d) == 2d)
|
||||
{
|
||||
return b + c;
|
||||
}
|
||||
if (num == 0d)
|
||||
{
|
||||
num = d * 0.44999999999999996d;
|
||||
}
|
||||
double num3;
|
||||
if (num2 < Math.Abs(c))
|
||||
{
|
||||
num2 = c;
|
||||
num3 = num / 4d;
|
||||
}
|
||||
else
|
||||
{
|
||||
num3 = num / 6.283185307179586d * Math.Asin(c / num2);
|
||||
}
|
||||
if (t < 1d)
|
||||
{
|
||||
return -0.5d * (num2 * Math.Pow(2d, 10d * (t -= 1d)) * Math.Sin((t * d - num3) * 6.283185307179586d / num)) + b;
|
||||
}
|
||||
return num2 * Math.Pow(2d, -10d * (t -= 1d)) * Math.Sin((t * d - num3) * 6.283185307179586d / num) * 0.5d + c + b;
|
||||
}
|
||||
|
||||
public static double EaseInBounce(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return c - EaseOutBounce(d - t, 0d, c, d) + b;
|
||||
}
|
||||
|
||||
public static double EaseOutBounce(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
if ((t /= d) < 0.36363636363636365d)
|
||||
{
|
||||
return c * (7.5625d * t * t) + b;
|
||||
}
|
||||
if (t < 0.7272727272727273d)
|
||||
{
|
||||
return c * (7.5625d * (t -= 0.5454545454545454d) * t + 0.75d) + b;
|
||||
}
|
||||
if (t < 0.9090909090909091d)
|
||||
{
|
||||
return c * (7.5625d * (t -= 0.8181818181818182d) * t + 0.9375d) + b;
|
||||
}
|
||||
return c * (7.5625d * (t -= 0.9545454545454546d) * t + 0.984375d) + b;
|
||||
}
|
||||
|
||||
public static double EaseInOutBounce(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
if (t < d / 2d)
|
||||
{
|
||||
return EaseInBounce(t * 2d, 0d, c, d) * 0.5d + b;
|
||||
}
|
||||
return EaseOutBounce(t * 2d - d, 0d, c, d) * 0.5d + c * 0.5d + b;
|
||||
}
|
||||
|
||||
public static double Linear(double t, double b, double c, double d)
|
||||
{
|
||||
c -= b;
|
||||
return t / d * c + b;
|
||||
}
|
||||
|
||||
public static DoubleEasingAnimation[] Function { get; } = new DoubleEasingAnimation[]
|
||||
{
|
||||
EaseInOutQuad,
|
||||
EaseInQuad,
|
||||
EaseOutQuad,
|
||||
EaseInCubic,
|
||||
EaseOutCubic,
|
||||
EaseInOutCubic,
|
||||
EaseInQuart,
|
||||
EaseOutQuart,
|
||||
EaseInOutQuart,
|
||||
EaseInQuint,
|
||||
EaseOutQuint,
|
||||
EaseInOutQuint,
|
||||
EaseInSine,
|
||||
EaseOutSine,
|
||||
EaseInOutSine,
|
||||
EaseInExpo,
|
||||
EaseOutExpo,
|
||||
EaseInOutExpo,
|
||||
EaseInCirc,
|
||||
EaseOutCirc,
|
||||
EaseInOutCirc,
|
||||
EaseInElastic,
|
||||
EaseOutElastic,
|
||||
EaseInOutElastic,
|
||||
EaseInBounce,
|
||||
EaseOutBounce,
|
||||
EaseInOutBounce,
|
||||
Linear,
|
||||
};
|
||||
}
|
||||
|
||||
public enum DoubleEasingAnimationType
|
||||
{
|
||||
InOutQuad,
|
||||
InQuad,
|
||||
OutQuad,
|
||||
InCubic,
|
||||
OutCubic,
|
||||
InOutCubic,
|
||||
InQuart,
|
||||
OutQuart,
|
||||
InOutQuart,
|
||||
InQuint,
|
||||
OutQuint,
|
||||
InOutQuint,
|
||||
InSine,
|
||||
OutSine,
|
||||
InOutSine,
|
||||
InExpo,
|
||||
OutExpo,
|
||||
InOutExpo,
|
||||
InCirc,
|
||||
OutCirc,
|
||||
InOutCirc,
|
||||
InElastic,
|
||||
OutElastic,
|
||||
InOutElastic,
|
||||
InBounce,
|
||||
OutBounce,
|
||||
InOutBounce,
|
||||
Linear,
|
||||
}
|
88
Build/MicaSetup/Design/Animations/ProgressAccumulator.cs
Normal file
88
Build/MicaSetup/Design/Animations/ProgressAccumulator.cs
Normal file
@ -0,0 +1,88 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MicaSetup.Controls.Animations;
|
||||
|
||||
public partial class ProgressAccumulator : ObservableObject, IDisposable
|
||||
{
|
||||
public Action<double>? Handler;
|
||||
public DoubleEasingAnimation? Animation;
|
||||
|
||||
[ObservableProperty]
|
||||
private double duration = 3000d;
|
||||
|
||||
[ObservableProperty]
|
||||
private double current = 0d;
|
||||
|
||||
[ObservableProperty]
|
||||
private double from = 0d;
|
||||
|
||||
[ObservableProperty]
|
||||
private double to = 100d;
|
||||
|
||||
private Task task = null!;
|
||||
private bool isRunning = false;
|
||||
private DateTime startTime = default;
|
||||
private double durationTime = default;
|
||||
|
||||
public ProgressAccumulator(double from = 0d, double to = 100d, double duration = 3000d, Action<double> handler = null!, DoubleEasingAnimation anime = null!)
|
||||
{
|
||||
Reset(from, to, duration, handler);
|
||||
Animation = anime;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
public ProgressAccumulator Start()
|
||||
{
|
||||
isRunning = true;
|
||||
startTime = DateTime.Now;
|
||||
durationTime = default;
|
||||
task = Task.Run(Handle);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProgressAccumulator Stop()
|
||||
{
|
||||
isRunning = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProgressAccumulator Reset(double from = 0d, double to = 100d, double duration = 3000d, Action<double> handler = null!)
|
||||
{
|
||||
Stop();
|
||||
|
||||
Current = From = from;
|
||||
To = to;
|
||||
Duration = duration;
|
||||
Handler = handler;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void Handle()
|
||||
{
|
||||
while (isRunning)
|
||||
{
|
||||
if (!SpinWait.SpinUntil(() => !isRunning, 50))
|
||||
{
|
||||
Calc();
|
||||
Handler?.Invoke(Current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private double Calc()
|
||||
{
|
||||
if (durationTime <= Duration)
|
||||
{
|
||||
Current = (Animation ?? DoubleEasingAnimations.EaseOutCirc).Invoke(durationTime, From, To, Duration);
|
||||
durationTime = DateTime.Now.Subtract(startTime).TotalMilliseconds;
|
||||
}
|
||||
return Current;
|
||||
}
|
||||
}
|
151
Build/MicaSetup/Design/Controls/BitmapIcon/BitmapIcon.cs
Normal file
151
Build/MicaSetup/Design/Controls/BitmapIcon/BitmapIcon.cs
Normal file
@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
#pragma warning disable CS8618
|
||||
|
||||
public class BitmapIcon : IconElement
|
||||
{
|
||||
static BitmapIcon()
|
||||
{
|
||||
ForegroundProperty.OverrideMetadata(typeof(BitmapIcon), new FrameworkPropertyMetadata(OnForegroundChanged));
|
||||
}
|
||||
|
||||
public BitmapIcon()
|
||||
{
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty UriSourceProperty =
|
||||
BitmapImage.UriSourceProperty.AddOwner(
|
||||
typeof(BitmapIcon),
|
||||
new FrameworkPropertyMetadata(OnUriSourceChanged));
|
||||
|
||||
public Uri UriSource
|
||||
{
|
||||
get => (Uri)GetValue(UriSourceProperty);
|
||||
set => SetValue(UriSourceProperty, value);
|
||||
}
|
||||
|
||||
private static void OnUriSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((BitmapIcon)d).ApplyUriSource();
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowAsMonochromeProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(ShowAsMonochrome),
|
||||
typeof(bool),
|
||||
typeof(BitmapIcon),
|
||||
new PropertyMetadata(true, OnShowAsMonochromeChanged));
|
||||
|
||||
public bool ShowAsMonochrome
|
||||
{
|
||||
get => (bool)GetValue(ShowAsMonochromeProperty);
|
||||
set => SetValue(ShowAsMonochromeProperty, value);
|
||||
}
|
||||
|
||||
private static void OnShowAsMonochromeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((BitmapIcon)d).ApplyShowAsMonochrome();
|
||||
}
|
||||
|
||||
private protected override void InitializeChildren()
|
||||
{
|
||||
_image = new Image
|
||||
{
|
||||
Visibility = Visibility.Hidden
|
||||
};
|
||||
|
||||
_opacityMask = new ImageBrush();
|
||||
_foreground = new Rectangle
|
||||
{
|
||||
OpacityMask = _opacityMask
|
||||
};
|
||||
|
||||
ApplyForeground();
|
||||
ApplyUriSource();
|
||||
|
||||
Children.Add(_image);
|
||||
|
||||
ApplyShowAsMonochrome();
|
||||
}
|
||||
|
||||
private protected override void OnShouldInheritForegroundFromVisualParentChanged()
|
||||
{
|
||||
ApplyForeground();
|
||||
}
|
||||
|
||||
private protected override void OnVisualParentForegroundPropertyChanged(DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (ShouldInheritForegroundFromVisualParent)
|
||||
{
|
||||
ApplyForeground();
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnForegroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((BitmapIcon)d).ApplyForeground();
|
||||
}
|
||||
|
||||
private void ApplyForeground()
|
||||
{
|
||||
if (_foreground != null)
|
||||
{
|
||||
_foreground.Fill = ShouldInheritForegroundFromVisualParent ? VisualParentForeground : Foreground;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyUriSource()
|
||||
{
|
||||
if (_image != null && _opacityMask != null)
|
||||
{
|
||||
var uriSource = UriSource;
|
||||
if (uriSource != null)
|
||||
{
|
||||
var imageSource = new BitmapImage(uriSource);
|
||||
_image.Source = imageSource;
|
||||
_opacityMask.ImageSource = imageSource;
|
||||
}
|
||||
else
|
||||
{
|
||||
_image.ClearValue(Image.SourceProperty);
|
||||
_opacityMask.ClearValue(ImageBrush.ImageSourceProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyShowAsMonochrome()
|
||||
{
|
||||
bool showAsMonochrome = ShowAsMonochrome;
|
||||
|
||||
if (_image != null)
|
||||
{
|
||||
_image.Visibility = showAsMonochrome ? Visibility.Hidden : Visibility.Visible;
|
||||
}
|
||||
|
||||
if (_foreground != null)
|
||||
{
|
||||
if (showAsMonochrome)
|
||||
{
|
||||
if (!Children.Contains(_foreground))
|
||||
{
|
||||
Children.Add(_foreground);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Children.Remove(_foreground);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Image _image;
|
||||
private Rectangle _foreground;
|
||||
private ImageBrush _opacityMask;
|
||||
}
|
172
Build/MicaSetup/Design/Controls/BitmapIcon/IconElement.cs
Normal file
172
Build/MicaSetup/Design/Controls/BitmapIcon/IconElement.cs
Normal file
@ -0,0 +1,172 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
#pragma warning disable CS8618
|
||||
|
||||
public abstract class IconElement : FrameworkElement
|
||||
{
|
||||
private protected IconElement()
|
||||
{
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ForegroundProperty =
|
||||
TextElement.ForegroundProperty.AddOwner(
|
||||
typeof(IconElement),
|
||||
new FrameworkPropertyMetadata(SystemColors.ControlTextBrush,
|
||||
FrameworkPropertyMetadataOptions.Inherits,
|
||||
OnForegroundPropertyChanged));
|
||||
|
||||
private static void OnForegroundPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
((IconElement)sender).OnForegroundPropertyChanged(args);
|
||||
}
|
||||
|
||||
private void OnForegroundPropertyChanged(DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
var baseValueSource = DependencyPropertyHelper.GetValueSource(this, args.Property).BaseValueSource;
|
||||
_isForegroundDefaultOrInherited = baseValueSource <= BaseValueSource.Inherited;
|
||||
UpdateShouldInheritForegroundFromVisualParent();
|
||||
}
|
||||
|
||||
[Bindable(true), Category("Appearance")]
|
||||
public Brush Foreground
|
||||
{
|
||||
get { return (Brush)GetValue(ForegroundProperty); }
|
||||
set { SetValue(ForegroundProperty, value); }
|
||||
}
|
||||
|
||||
private static readonly DependencyProperty VisualParentForegroundProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(VisualParentForeground),
|
||||
typeof(Brush),
|
||||
typeof(IconElement),
|
||||
new PropertyMetadata(null, OnVisualParentForegroundPropertyChanged));
|
||||
|
||||
protected Brush VisualParentForeground
|
||||
{
|
||||
get => (Brush)GetValue(VisualParentForegroundProperty);
|
||||
set => SetValue(VisualParentForegroundProperty, value);
|
||||
}
|
||||
|
||||
private static void OnVisualParentForegroundPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
((IconElement)sender).OnVisualParentForegroundPropertyChanged(args);
|
||||
}
|
||||
|
||||
private protected virtual void OnVisualParentForegroundPropertyChanged(DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
}
|
||||
|
||||
protected bool ShouldInheritForegroundFromVisualParent
|
||||
{
|
||||
get => _shouldInheritForegroundFromVisualParent;
|
||||
private set
|
||||
{
|
||||
if (_shouldInheritForegroundFromVisualParent != value)
|
||||
{
|
||||
_shouldInheritForegroundFromVisualParent = value;
|
||||
|
||||
if (_shouldInheritForegroundFromVisualParent)
|
||||
{
|
||||
SetBinding(VisualParentForegroundProperty,
|
||||
new Binding
|
||||
{
|
||||
Path = new PropertyPath(TextElement.ForegroundProperty),
|
||||
Source = VisualParent
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearValue(VisualParentForegroundProperty);
|
||||
}
|
||||
|
||||
OnShouldInheritForegroundFromVisualParentChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private protected virtual void OnShouldInheritForegroundFromVisualParentChanged()
|
||||
{
|
||||
}
|
||||
|
||||
private void UpdateShouldInheritForegroundFromVisualParent()
|
||||
{
|
||||
ShouldInheritForegroundFromVisualParent =
|
||||
_isForegroundDefaultOrInherited &&
|
||||
Parent != null &&
|
||||
VisualParent != null &&
|
||||
Parent != VisualParent;
|
||||
}
|
||||
|
||||
protected UIElementCollection Children
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureLayoutRoot();
|
||||
return _layoutRoot.Children;
|
||||
}
|
||||
}
|
||||
|
||||
private protected abstract void InitializeChildren();
|
||||
|
||||
protected override int VisualChildrenCount => 1;
|
||||
|
||||
protected override Visual GetVisualChild(int index)
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
EnsureLayoutRoot();
|
||||
return _layoutRoot;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
EnsureLayoutRoot();
|
||||
_layoutRoot.Measure(availableSize);
|
||||
return _layoutRoot.DesiredSize;
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
EnsureLayoutRoot();
|
||||
_layoutRoot.Arrange(new Rect(new Point(), finalSize));
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
protected override void OnVisualParentChanged(DependencyObject oldParent)
|
||||
{
|
||||
base.OnVisualParentChanged(oldParent);
|
||||
UpdateShouldInheritForegroundFromVisualParent();
|
||||
}
|
||||
|
||||
private void EnsureLayoutRoot()
|
||||
{
|
||||
if (_layoutRoot != null)
|
||||
return;
|
||||
|
||||
_layoutRoot = new Grid
|
||||
{
|
||||
Background = Brushes.Transparent,
|
||||
SnapsToDevicePixels = true,
|
||||
};
|
||||
InitializeChildren();
|
||||
|
||||
AddVisualChild(_layoutRoot);
|
||||
}
|
||||
|
||||
private Grid _layoutRoot;
|
||||
private bool _isForegroundDefaultOrInherited = true;
|
||||
private bool _shouldInheritForegroundFromVisualParent;
|
||||
}
|
129
Build/MicaSetup/Design/Controls/Button/Button.xaml
Normal file
129
Build/MicaSetup/Design/Controls/Button/Button.xaml
Normal file
@ -0,0 +1,129 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:MicaSetup.Design.Controls">
|
||||
|
||||
<Thickness x:Key="ButtonPadding">11,5,11,6</Thickness>
|
||||
<Thickness x:Key="ButtonBorderThemeThickness">1</Thickness>
|
||||
<Thickness x:Key="ButtonIconMargin">0,0,8,0</Thickness>
|
||||
|
||||
<Style x:Key="DefaultButtonStyle" TargetType="{x:Type Button}">
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonBackground}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonForeground}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ControlElevationBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="{StaticResource ButtonBorderThemeThickness}" />
|
||||
<Setter Property="Padding" Value="{StaticResource ButtonPadding}" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
|
||||
<Setter Property="FontWeight" Value="Normal" />
|
||||
<Setter Property="Border.CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border x:Name="ContentBorder"
|
||||
Width="{TemplateBinding Width}"
|
||||
Height="{TemplateBinding Height}"
|
||||
MinWidth="{TemplateBinding MinWidth}"
|
||||
MinHeight="{TemplateBinding MinHeight}"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalAlignment}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding Border.CornerRadius}">
|
||||
<ContentPresenter x:Name="ContentPresenter"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
TextElement.Foreground="{TemplateBinding Foreground}" />
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPointerOver}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ControlElevationBorderBrush}" />
|
||||
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" />
|
||||
<Setter Property="Opacity" Value="0.6" />
|
||||
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{DynamicResource ButtonForegroundDisabled}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPressed}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPressed}" />
|
||||
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{DynamicResource TextFillColorSecondaryBrush}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="PrimaryButtonStyle" TargetType="{x:Type Button}">
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
|
||||
<Setter Property="Background" Value="{DynamicResource AccentButtonBackground}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForeground}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource AccentControlElevationBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="{StaticResource ButtonBorderThemeThickness}" />
|
||||
<Setter Property="Padding" Value="{StaticResource ButtonPadding}" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
|
||||
<Setter Property="FontWeight" Value="Normal" />
|
||||
<Setter Property="Border.CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border x:Name="ContentBorder"
|
||||
Width="{TemplateBinding Width}"
|
||||
Height="{TemplateBinding Height}"
|
||||
MinWidth="{TemplateBinding MinWidth}"
|
||||
MinHeight="{TemplateBinding MinHeight}"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalAlignment}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding Border.CornerRadius}">
|
||||
<ContentPresenter x:Name="ContentPresenter"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
TextElement.Foreground="{TemplateBinding Foreground}" />
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPointerOver}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource AccentControlElevationBorderBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Opacity" Value="0.3" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Foreground" Value="{DynamicResource PressedForeground}" />
|
||||
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPressed}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPressed}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style BasedOn="{StaticResource DefaultButtonStyle}" TargetType="{x:Type Button}" />
|
||||
|
||||
</ResourceDictionary>
|
75
Build/MicaSetup/Design/Controls/CheckBox/CheckBox.xaml
Normal file
75
Build/MicaSetup/Design/Controls/CheckBox/CheckBox.xaml
Normal file
@ -0,0 +1,75 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:design="clr-namespace:MicaSetup.Design"
|
||||
xmlns:local="clr-namespace:MicaSetup.Design.Controls">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<design:ResourceResourceDictionary />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<Style x:Key="DefaultCheckBoxStyle"
|
||||
BasedOn="{StaticResource {x:Type CheckBox}}"
|
||||
TargetType="{x:Type CheckBox}">
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="Padding" Value="4,0,0,0" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="CheckBox">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Grid Width="20"
|
||||
Height="20"
|
||||
Background="Transparent">
|
||||
<Border x:Name="border"
|
||||
Width="20"
|
||||
Height="20"
|
||||
Margin="0,0,0,0"
|
||||
BorderBrush="#8E8E93"
|
||||
BorderThickness="1"
|
||||
CornerRadius="2" />
|
||||
<TextBlock x:Name="checkIcon"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="{StaticResource IcoMoon}"
|
||||
FontSize="18"
|
||||
Foreground="{DynamicResource HighGreenBrush}"
|
||||
Opacity="0"
|
||||
Text="{x:Static local:Selection.PublicOk}" />
|
||||
</Grid>
|
||||
<ContentPresenter Margin="5,0,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Trigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<BeginStoryboard.Storyboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetName="checkIcon"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
To="1"
|
||||
Duration="0:0:0.05" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard.Storyboard>
|
||||
</BeginStoryboard>
|
||||
</Trigger.EnterActions>
|
||||
<Trigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<BeginStoryboard.Storyboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetName="checkIcon"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
To="0"
|
||||
Duration="0:0:0.05" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard.Storyboard>
|
||||
</BeginStoryboard>
|
||||
</Trigger.ExitActions>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style BasedOn="{StaticResource DefaultCheckBoxStyle}" TargetType="{x:Type CheckBox}" />
|
||||
|
||||
</ResourceDictionary>
|
144
Build/MicaSetup/Design/Controls/MessageBox/MessageBoxDialog.xaml
Normal file
144
Build/MicaSetup/Design/Controls/MessageBox/MessageBoxDialog.xaml
Normal file
@ -0,0 +1,144 @@
|
||||
<Window x:Class="MicaSetup.Design.Controls.MessageBoxDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:conv="clr-namespace:MicaSetup.Design.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:design="clr-namespace:MicaSetup.Design"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:local="clr-namespace:MicaSetup.Design.Controls"
|
||||
xmlns:markups="clr-namespace:MicaSetup.Design.Markups"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
x:Name="Self"
|
||||
Title="{DynamicResource TitleTips}"
|
||||
Width="400"
|
||||
Height="250"
|
||||
d:Height="250"
|
||||
d:Opacity="1"
|
||||
d:Width="300"
|
||||
AllowsTransparency="True"
|
||||
Background="Transparent"
|
||||
FontFamily="{markups:LocalizedFontFamily}"
|
||||
Opacity="0"
|
||||
RenderOptions.BitmapScalingMode="Fant"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
WindowStyle="None"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<design:GenericResourceDictionary />
|
||||
<design:ResourceResourceDictionary />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<conv:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
<Window.Style>
|
||||
<Style TargetType="{x:Type Window}">
|
||||
<Style.Triggers>
|
||||
<EventTrigger RoutedEvent="Window.Loaded">
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation BeginTime="0:0:0.0"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
From="0"
|
||||
To="1"
|
||||
Duration="0:0:0.15">
|
||||
<DoubleAnimation.EasingFunction>
|
||||
<SineEase EasingMode="EaseOut" />
|
||||
</DoubleAnimation.EasingFunction>
|
||||
</DoubleAnimation>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Window.Style>
|
||||
<Grid>
|
||||
<i:Interaction.Behaviors>
|
||||
<local:WindowDragMoveBehavior />
|
||||
</i:Interaction.Behaviors>
|
||||
<Border Margin="5" CornerRadius="3">
|
||||
<Border.Background>
|
||||
<SolidColorBrush Color="{DynamicResource ApplicationBackgroundColor}" />
|
||||
</Border.Background>
|
||||
<Border.Effect>
|
||||
<DropShadowEffect BlurRadius="5"
|
||||
ShadowDepth="0"
|
||||
Color="LightGray" />
|
||||
</Border.Effect>
|
||||
</Border>
|
||||
<Border Margin="5" CornerRadius="3">
|
||||
<Grid Margin="5">
|
||||
<TextBlock Margin="15,5"
|
||||
FontSize="15"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
Text="{DynamicResource TitleTips}" />
|
||||
<StackPanel Margin="15,0,0,0" Orientation="Horizontal">
|
||||
<Grid>
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
FontFamily="{StaticResource IcoMoon}"
|
||||
FontSize="30"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
Text="{x:Static local:Selection.PublicFail}" />
|
||||
</Grid>
|
||||
<StackPanel Margin="5,5,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock Width="300"
|
||||
FontSize="16"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
LineHeight="25"
|
||||
Text="{Binding Message}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0,0,15,8"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
<Button Height="30"
|
||||
MinWidth="65"
|
||||
Padding="10,0,10,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
Command="{Binding OkayCommand}"
|
||||
FontSize="15"
|
||||
Style="{StaticResource PrimaryButtonStyle}"
|
||||
Visibility="{Binding OkayVisiable, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<Button.Content>
|
||||
<TextBlock Text="{DynamicResource ButtonOK}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
<Button Height="30"
|
||||
MinWidth="65"
|
||||
Margin="8,0,0,0"
|
||||
Padding="10,0,10,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
Command="{Binding YesCommand}"
|
||||
FontSize="15"
|
||||
Style="{StaticResource PrimaryButtonStyle}"
|
||||
Visibility="{Binding YesVisiable, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<Button.Content>
|
||||
<TextBlock Text="{DynamicResource ButtonYes}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
<Button Height="30"
|
||||
MinWidth="65"
|
||||
Margin="8,0,0,0"
|
||||
Padding="10,0,10,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
Command="{Binding NoCommand}"
|
||||
FontSize="15"
|
||||
Style="{StaticResource PrimaryButtonStyle}"
|
||||
Visibility="{Binding NoVisiable, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<Button.Content>
|
||||
<TextBlock Text="{DynamicResource ButtonNo}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
@ -0,0 +1,109 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System.Windows;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
[INotifyPropertyChanged]
|
||||
public partial class MessageBoxDialog : Window
|
||||
{
|
||||
[ObservableProperty]
|
||||
private string message = null!;
|
||||
|
||||
[ObservableProperty]
|
||||
protected bool okayVisiable = true;
|
||||
|
||||
[ObservableProperty]
|
||||
protected bool yesVisiable = false;
|
||||
|
||||
[ObservableProperty]
|
||||
protected bool noVisiable = false;
|
||||
|
||||
[ObservableProperty]
|
||||
protected WindowDialogResult result = WindowDialogResult.None;
|
||||
|
||||
partial void OnResultChanged(WindowDialogResult value)
|
||||
{
|
||||
_ = value;
|
||||
Close();
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private string iconString = "\xe915";
|
||||
|
||||
[ObservableProperty]
|
||||
private MessageBoxType type = MessageBoxType.Info;
|
||||
|
||||
partial void OnTypeChanged(MessageBoxType value)
|
||||
{
|
||||
IconString = value switch
|
||||
{
|
||||
MessageBoxType.Question => "\xe918",
|
||||
MessageBoxType.Info or _ => "\xe915",
|
||||
};
|
||||
|
||||
OkayVisiable = value switch
|
||||
{
|
||||
MessageBoxType.Question => false,
|
||||
MessageBoxType.Info or _ => true,
|
||||
};
|
||||
|
||||
YesVisiable = value switch
|
||||
{
|
||||
MessageBoxType.Question => true,
|
||||
MessageBoxType.Info or _ => false,
|
||||
};
|
||||
|
||||
NoVisiable = value switch
|
||||
{
|
||||
MessageBoxType.Question => true,
|
||||
MessageBoxType.Info or _ => false,
|
||||
};
|
||||
}
|
||||
|
||||
public MessageBoxDialog()
|
||||
{
|
||||
DataContext = this;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void Okay()
|
||||
{
|
||||
Result = WindowDialogResult.OK;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void Yes()
|
||||
{
|
||||
Result = WindowDialogResult.Yes;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void No()
|
||||
{
|
||||
Result = WindowDialogResult.No;
|
||||
}
|
||||
|
||||
public WindowDialogResult ShowDialog(Window owner)
|
||||
{
|
||||
Owner = owner;
|
||||
ShowDialog();
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
|
||||
public enum MessageBoxType
|
||||
{
|
||||
Info,
|
||||
Question,
|
||||
}
|
||||
|
||||
public enum WindowDialogResult
|
||||
{
|
||||
None = 0,
|
||||
OK = 1,
|
||||
Cancel = 2,
|
||||
Yes = 6,
|
||||
No = 7
|
||||
}
|
29
Build/MicaSetup/Design/Controls/MessageBox/MessageBoxX.cs
Normal file
29
Build/MicaSetup/Design/Controls/MessageBox/MessageBoxX.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using MicaSetup.Helper;
|
||||
using System.Windows;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public static class MessageBoxX
|
||||
{
|
||||
public static WindowDialogResult Info(DependencyObject dependencyObject, string message)
|
||||
{
|
||||
Window owner = (dependencyObject is Window win ? win : dependencyObject == null ? UIDispatcherHelper.MainWindow : Window.GetWindow(dependencyObject)) ?? UIDispatcherHelper.MainWindow;
|
||||
|
||||
return new MessageBoxDialog()
|
||||
{
|
||||
Type = MessageBoxType.Info,
|
||||
Message = message,
|
||||
}.ShowDialog(owner);
|
||||
}
|
||||
|
||||
public static WindowDialogResult Question(DependencyObject dependencyObject, string message)
|
||||
{
|
||||
Window owner = (dependencyObject is Window win ? win : dependencyObject == null ? UIDispatcherHelper.MainWindow : Window.GetWindow(dependencyObject)) ?? UIDispatcherHelper.MainWindow;
|
||||
|
||||
return new MessageBoxDialog()
|
||||
{
|
||||
Type = MessageBoxType.Question,
|
||||
Message = message,
|
||||
}.ShowDialog(owner);
|
||||
}
|
||||
}
|
102
Build/MicaSetup/Design/Controls/ProgressBar/ProgressBar.xaml
Normal file
102
Build/MicaSetup/Design/Controls/ProgressBar/ProgressBar.xaml
Normal file
@ -0,0 +1,102 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:design="clr-namespace:MicaSetup.Design"
|
||||
xmlns:local="clr-namespace:MicaSetup.Design.Controls">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<design:ResourceResourceDictionary />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<Color x:Key="ProgressBarForeground1">#73EBF3</Color>
|
||||
<Color x:Key="ProgressBarForeground2">#238EFA</Color>
|
||||
<Style
|
||||
x:Key="DefaultProgressBarStyle"
|
||||
BasedOn="{StaticResource {x:Type ProgressBar}}"
|
||||
TargetType="{x:Type ProgressBar}">
|
||||
<Setter Property="Foreground" Value="#2196F3" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Height" Value="4" />
|
||||
<Setter Property="Minimum" Value="0" />
|
||||
<Setter Property="Maximum" Value="100" />
|
||||
<Setter Property="local:ProgressBarHelper.Foreground1" Value="{StaticResource ProgressBarForeground1}" />
|
||||
<Setter Property="local:ProgressBarHelper.Foreground2" Value="{StaticResource ProgressBarForeground2}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ProgressBar}">
|
||||
<Border
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="1">
|
||||
<Grid x:Name="PART_Track">
|
||||
<Rectangle
|
||||
x:Name="PART_Indicator"
|
||||
Height="{TemplateBinding Height}"
|
||||
HorizontalAlignment="Left"
|
||||
RadiusX="1"
|
||||
RadiusY="1">
|
||||
<Rectangle.Fill>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
|
||||
<GradientStopCollection>
|
||||
<GradientStop Offset="0" Color="{Binding Path=(local:ProgressBarHelper.Foreground1), RelativeSource={RelativeSource AncestorType=ProgressBar}, Mode=OneWay, FallbackValue={StaticResource ProgressBarForeground1}}" />
|
||||
<GradientStop Offset="1" Color="{Binding Path=(local:ProgressBarHelper.Foreground2), RelativeSource={RelativeSource AncestorType=ProgressBar}, Mode=OneWay, FallbackValue={StaticResource ProgressBarForeground2}}" />
|
||||
</GradientStopCollection>
|
||||
</LinearGradientBrush>
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
<Rectangle
|
||||
x:Name="PART_IndeterminateIndicator"
|
||||
Width="100"
|
||||
Height="{TemplateBinding Height}"
|
||||
HorizontalAlignment="Left"
|
||||
RadiusX="1"
|
||||
RadiusY="1">
|
||||
<Rectangle.Fill>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
|
||||
<GradientStopCollection>
|
||||
<GradientStop Offset="0" Color="{Binding Path=(local:ProgressBarHelper.Foreground1), RelativeSource={RelativeSource AncestorType=ProgressBar}, Mode=OneWay, FallbackValue={StaticResource ProgressBarForeground1}}" />
|
||||
<GradientStop Offset="1" Color="{Binding Path=(local:ProgressBarHelper.Foreground2), RelativeSource={RelativeSource AncestorType=ProgressBar}, Mode=OneWay, FallbackValue={StaticResource ProgressBarForeground2}}" />
|
||||
</GradientStopCollection>
|
||||
</LinearGradientBrush>
|
||||
</Rectangle.Fill>
|
||||
<Rectangle.Triggers>
|
||||
<EventTrigger RoutedEvent="Loaded">
|
||||
<BeginStoryboard>
|
||||
<Storyboard RepeatBehavior="Forever">
|
||||
<ThicknessAnimation
|
||||
BeginTime="0:0:0.5"
|
||||
Storyboard.TargetName="PART_IndeterminateIndicator"
|
||||
Storyboard.TargetProperty="Margin"
|
||||
From="0,0,0,0"
|
||||
To="450,0,0,0"
|
||||
Duration="0:0:2" />
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="PART_IndeterminateIndicator"
|
||||
Storyboard.TargetProperty="Width"
|
||||
From="0"
|
||||
To="100"
|
||||
Duration="0:0:0.5" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
</Rectangle.Triggers>
|
||||
</Rectangle>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsIndeterminate" Value="True">
|
||||
<Setter TargetName="PART_Indicator" Property="Visibility" Value="Collapsed" />
|
||||
<Setter TargetName="PART_IndeterminateIndicator" Property="Visibility" Value="Visible" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsIndeterminate" Value="False">
|
||||
<Setter TargetName="PART_Indicator" Property="Visibility" Value="Visible" />
|
||||
<Setter TargetName="PART_IndeterminateIndicator" Property="Visibility" Value="Collapsed" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style BasedOn="{StaticResource DefaultProgressBarStyle}" TargetType="{x:Type ProgressBar}" />
|
||||
|
||||
</ResourceDictionary>
|
@ -0,0 +1,31 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public class ProgressBarHelper
|
||||
{
|
||||
public static Color GetForeground1(DependencyObject obj)
|
||||
{
|
||||
return (Color)obj.GetValue(Foreground1Property);
|
||||
}
|
||||
|
||||
public static void SetForeground1(DependencyObject obj, Color value)
|
||||
{
|
||||
obj.SetValue(Foreground1Property, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty Foreground1Property = DependencyProperty.RegisterAttached("Foreground1", typeof(Color), typeof(ProgressBarHelper), new((Color)ColorConverter.ConvertFromString("#73EBF3")));
|
||||
|
||||
public static Color GetForeground2(DependencyObject obj)
|
||||
{
|
||||
return (Color)obj.GetValue(Foreground2Property);
|
||||
}
|
||||
|
||||
public static void SetForeground2(DependencyObject obj, Color value)
|
||||
{
|
||||
obj.SetValue(Foreground2Property, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty Foreground2Property = DependencyProperty.RegisterAttached("Foreground2", typeof(Color), typeof(ProgressBarHelper), new((Color)ColorConverter.ConvertFromString("#238EFA")));
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Shell;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public class SetupProgressBar : ProgressBar
|
||||
{
|
||||
public bool SyncToWindowTaskbar
|
||||
{
|
||||
get => (bool)GetValue(LinkToWindowTaskbarProperty);
|
||||
set => SetValue(LinkToWindowTaskbarProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LinkToWindowTaskbarProperty = DependencyProperty.Register("SyncToWindowTaskbar", typeof(bool), typeof(SetupProgressBar), new PropertyMetadata(true));
|
||||
|
||||
public SetupProgressBar()
|
||||
{
|
||||
ValueChanged += OnValueChanged;
|
||||
}
|
||||
|
||||
private void OnValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
if (!SyncToWindowTaskbar)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.FindTaskbar() is TaskbarItemInfo taskbar)
|
||||
{
|
||||
if (Value >= 0d)
|
||||
{
|
||||
taskbar.ProgressValue = Value / 100d;
|
||||
|
||||
if (Value >= 100d)
|
||||
{
|
||||
taskbar.ProgressState = TaskbarItemProgressState.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
taskbar.ProgressState = TaskbarItemProgressState.Normal;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
taskbar.ProgressValue = 0d;
|
||||
taskbar.ProgressState = TaskbarItemProgressState.Indeterminate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Shell;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public static class TaskbarExtension
|
||||
{
|
||||
public static TaskbarItemInfo FindTaskbar(this FrameworkElement owner)
|
||||
{
|
||||
if ((owner is Window ? owner as Window : Window.GetWindow(owner)) is Window win)
|
||||
{
|
||||
return win.TaskbarItemInfo ??= new();
|
||||
}
|
||||
return null!;
|
||||
}
|
||||
|
||||
public static TaskbarItemInfo FindTaskbar(this Window owner)
|
||||
{
|
||||
return owner.TaskbarItemInfo ??= new();
|
||||
}
|
||||
|
||||
public static void SetProgress(this TaskbarItemInfo taskbarItem, double value, TaskbarItemProgressState state = TaskbarItemProgressState.Normal)
|
||||
{
|
||||
taskbarItem.ProgressState = state;
|
||||
taskbarItem.ProgressValue = value;
|
||||
}
|
||||
}
|
206
Build/MicaSetup/Design/Controls/ScrollViewer/ScrollViewer.xaml
Normal file
206
Build/MicaSetup/Design/Controls/ScrollViewer/ScrollViewer.xaml
Normal file
@ -0,0 +1,206 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:design="clr-namespace:MicaSetup.Design"
|
||||
xmlns:local="clr-namespace:MicaSetup.Design.Controls">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<design:ResourceResourceDictionary />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Style x:Key="DefaultScrollBarStyle" TargetType="{x:Type ScrollBar}">
|
||||
<Setter Property="Stylus.IsPressAndHoldEnabled" Value="false" />
|
||||
<Setter Property="Stylus.IsFlicksEnabled" Value="false" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="MinWidth" Value="0" />
|
||||
<Setter Property="Height" Value="Auto" />
|
||||
<Setter Property="Cursor" Value="Arrow" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ScrollBar}">
|
||||
<Border Background="{Binding Path=(local:ScrollViewerHelper.TrackBrush), RelativeSource={RelativeSource AncestorType=ScrollViewer}}" CornerRadius="{Binding Path=(local:ScrollViewerHelper.ScrollBarCornerRadius), RelativeSource={RelativeSource AncestorType=ScrollViewer}}">
|
||||
<Track
|
||||
x:Name="PART_Track"
|
||||
IsDirectionReversed="true"
|
||||
IsEnabled="{TemplateBinding IsMouseOver}">
|
||||
<Track.Thumb>
|
||||
<Thumb>
|
||||
<Thumb.Template>
|
||||
<ControlTemplate TargetType="Thumb">
|
||||
<Border Background="{Binding Path=(local:ScrollViewerHelper.ThumbBrush), RelativeSource={RelativeSource AncestorType=ScrollViewer}}" CornerRadius="{Binding Path=(local:ScrollViewerHelper.ScrollBarCornerRadius), RelativeSource={RelativeSource AncestorType=ScrollViewer}}" />
|
||||
</ControlTemplate>
|
||||
</Thumb.Template>
|
||||
</Thumb>
|
||||
</Track.Thumb>
|
||||
</Track>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="Orientation" Value="Horizontal">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Margin" Value="1,0,1,1" />
|
||||
<Setter Property="MinHeight" Value="0" />
|
||||
<Setter Property="Width" Value="Auto" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ScrollBar}">
|
||||
<Border Background="{Binding Path=(local:ScrollViewerHelper.TrackBrush), RelativeSource={RelativeSource AncestorType=ScrollViewer}}" CornerRadius="{Binding Path=(local:ScrollViewerHelper.ScrollBarCornerRadius), RelativeSource={RelativeSource AncestorType=ScrollViewer}}">
|
||||
<Track x:Name="PART_Track" IsEnabled="{TemplateBinding IsMouseOver}">
|
||||
<Track.Thumb>
|
||||
<Thumb>
|
||||
<Thumb.Template>
|
||||
<ControlTemplate TargetType="Thumb">
|
||||
<Border Background="{Binding Path=(local:ScrollViewerHelper.ThumbBrush), RelativeSource={RelativeSource AncestorType=ScrollViewer}}" CornerRadius="{Binding Path=(local:ScrollViewerHelper.ScrollBarCornerRadius), RelativeSource={RelativeSource AncestorType=ScrollViewer}}" />
|
||||
</ControlTemplate>
|
||||
</Thumb.Template>
|
||||
</Thumb>
|
||||
</Track.Thumb>
|
||||
</Track>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="DefaultScrollViewerStyle" TargetType="{x:Type ScrollViewer}">
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="VerticalScrollBarVisibility" Value="Auto" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="local:ScrollViewerHelper.TrackBrush" Value="Transparent" />
|
||||
<Setter Property="local:ScrollViewerHelper.ThumbBrush" Value="#CCCCCC" />
|
||||
<Setter Property="local:ScrollViewerHelper.ScrollBarCornerRadius" Value="4" />
|
||||
<Setter Property="local:ScrollViewerHelper.ScrollBarThickness" Value="8" />
|
||||
<Setter Property="local:ScrollViewerHelper.ScrollViewerHook" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ScrollViewer}">
|
||||
<Border
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ScrollContentPresenter
|
||||
Margin="{TemplateBinding Padding}"
|
||||
CanContentScroll="{TemplateBinding CanContentScroll}"
|
||||
VirtualizingStackPanel.IsVirtualizing="{Binding Path=(VirtualizingStackPanel.IsVirtualizing), RelativeSource={RelativeSource AncestorType=ScrollViewer}}"
|
||||
VirtualizingStackPanel.VirtualizationMode="{Binding Path=(VirtualizingStackPanel.VirtualizationMode), RelativeSource={RelativeSource AncestorType=ScrollViewer}}" />
|
||||
<ScrollBar
|
||||
x:Name="PART_VerticalScrollBar"
|
||||
Grid.Column="1"
|
||||
Width="{Binding Path=(local:ScrollViewerHelper.ScrollBarThickness), RelativeSource={RelativeSource AncestorType=ScrollViewer}}"
|
||||
Maximum="{TemplateBinding ScrollableHeight}"
|
||||
Opacity="0.5"
|
||||
ViewportSize="{TemplateBinding ViewportHeight}"
|
||||
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
|
||||
Value="{TemplateBinding VerticalOffset}" />
|
||||
<ScrollBar
|
||||
x:Name="PART_HorizontalScrollBar"
|
||||
Grid.Row="1"
|
||||
Height="{Binding Path=(local:ScrollViewerHelper.ScrollBarThickness), RelativeSource={RelativeSource AncestorType=ScrollViewer}}"
|
||||
Maximum="{TemplateBinding ScrollableWidth}"
|
||||
Opacity="0.5"
|
||||
Orientation="Horizontal"
|
||||
ViewportSize="{TemplateBinding ViewportWidth}"
|
||||
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
|
||||
Value="{TemplateBinding HorizontalOffset}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<EventTrigger RoutedEvent="ScrollChanged">
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="PART_VerticalScrollBar"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0.9"
|
||||
Duration="0:0:0.15" />
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="PART_HorizontalScrollBar"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0.9"
|
||||
Duration="0:0:0.15" />
|
||||
<DoubleAnimation
|
||||
BeginTime="0:0:1.5"
|
||||
Storyboard.TargetName="PART_VerticalScrollBar"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0.5"
|
||||
Duration="0:0:0.15" />
|
||||
<DoubleAnimation
|
||||
BeginTime="0:0:1.5"
|
||||
Storyboard.TargetName="PART_HorizontalScrollBar"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0.5"
|
||||
Duration="0:0:0.15" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
<EventTrigger RoutedEvent="MouseEnter" SourceName="PART_VerticalScrollBar">
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="PART_VerticalScrollBar"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0.9"
|
||||
Duration="0:0:0.15" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
<EventTrigger RoutedEvent="MouseLeave" SourceName="PART_VerticalScrollBar">
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="PART_VerticalScrollBar"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0.5"
|
||||
Duration="0:0:0.15" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
<EventTrigger RoutedEvent="MouseEnter" SourceName="PART_HorizontalScrollBar">
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="PART_HorizontalScrollBar"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0.9"
|
||||
Duration="0:0:0.15" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
<EventTrigger RoutedEvent="MouseLeave" SourceName="PART_HorizontalScrollBar">
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="PART_HorizontalScrollBar"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0.5"
|
||||
Duration="0:0:0.15" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style BasedOn="{StaticResource DefaultScrollBarStyle}" TargetType="{x:Type ScrollBar}" />
|
||||
|
||||
<Style BasedOn="{StaticResource DefaultScrollViewerStyle}" TargetType="{x:Type ScrollViewer}" />
|
||||
|
||||
<Style BasedOn="{StaticResource DefaultScrollViewerStyle}" TargetType="{x:Type local:SmoothScrollViewer}" />
|
||||
|
||||
</ResourceDictionary>
|
@ -0,0 +1,110 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public class ScrollViewerHelper
|
||||
{
|
||||
public static Brush GetTrackBrush(DependencyObject obj)
|
||||
{
|
||||
return (Brush)obj.GetValue(TrackBrushProperty);
|
||||
}
|
||||
|
||||
public static void SetTrackBrush(DependencyObject obj, Brush value)
|
||||
{
|
||||
obj.SetValue(TrackBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TrackBrushProperty = DependencyProperty.RegisterAttached("TrackBrush", typeof(Brush), typeof(ScrollViewerHelper));
|
||||
|
||||
public static Brush GetThumbBrush(DependencyObject obj)
|
||||
{
|
||||
return (Brush)obj.GetValue(ThumbBrushProperty);
|
||||
}
|
||||
|
||||
public static void SetThumbBrush(DependencyObject obj, Brush value)
|
||||
{
|
||||
obj.SetValue(ThumbBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ThumbBrushProperty = DependencyProperty.RegisterAttached("ThumbBrush", typeof(Brush), typeof(ScrollViewerHelper));
|
||||
|
||||
public static CornerRadius GetScrollBarCornerRadius(DependencyObject obj)
|
||||
{
|
||||
return (CornerRadius)obj.GetValue(ScrollBarCornerRadiusProperty);
|
||||
}
|
||||
|
||||
public static void SetScrollBarCornerRadius(DependencyObject obj, CornerRadius value)
|
||||
{
|
||||
obj.SetValue(ScrollBarCornerRadiusProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ScrollBarCornerRadiusProperty = DependencyProperty.RegisterAttached("ScrollBarCornerRadius", typeof(CornerRadius), typeof(ScrollViewerHelper));
|
||||
|
||||
public static double GetScrollBarThickness(DependencyObject obj)
|
||||
{
|
||||
return (double)obj.GetValue(ScrollBarThicknessProperty);
|
||||
}
|
||||
|
||||
public static void SetScrollBarThickness(DependencyObject obj, double value)
|
||||
{
|
||||
obj.SetValue(ScrollBarThicknessProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ScrollBarThicknessProperty = DependencyProperty.RegisterAttached("ScrollBarThickness", typeof(double), typeof(ScrollViewerHelper));
|
||||
|
||||
internal static bool GetScrollViewerHook(DependencyObject obj)
|
||||
{
|
||||
return (bool)obj.GetValue(ScrollViewerHookProperty);
|
||||
}
|
||||
|
||||
internal static void SetScrollViewerHook(DependencyObject obj, bool value)
|
||||
{
|
||||
obj.SetValue(ScrollViewerHookProperty, value);
|
||||
}
|
||||
|
||||
internal static readonly DependencyProperty ScrollViewerHookProperty = DependencyProperty.RegisterAttached("ScrollViewerHook", typeof(bool), typeof(ScrollViewerHelper), new PropertyMetadata(OnScrollViewerHookChanged));
|
||||
|
||||
private static void OnScrollViewerHookChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var scrollViewer = d as ScrollViewer;
|
||||
scrollViewer!.PreviewMouseWheel += ScrollViewer_PreviewMouseWheel;
|
||||
}
|
||||
|
||||
private static void ScrollViewer_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
|
||||
{
|
||||
var scrollViewer = sender as ScrollViewer;
|
||||
var handle = true;
|
||||
|
||||
if (e.Delta > 0)
|
||||
{
|
||||
if (scrollViewer!.ComputedVerticalScrollBarVisibility == Visibility.Visible)
|
||||
{ handle = false; }
|
||||
else if (scrollViewer.ComputedHorizontalScrollBarVisibility == Visibility.Visible)
|
||||
scrollViewer.LineLeft();
|
||||
else if (scrollViewer.VerticalScrollBarVisibility != ScrollBarVisibility.Disabled)
|
||||
{ handle = false; }
|
||||
else if (scrollViewer.HorizontalScrollBarVisibility != ScrollBarVisibility.Disabled)
|
||||
scrollViewer.LineLeft();
|
||||
else
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (scrollViewer!.ComputedVerticalScrollBarVisibility == Visibility.Visible)
|
||||
{ handle = false; }
|
||||
else if (scrollViewer.ComputedHorizontalScrollBarVisibility == Visibility.Visible)
|
||||
scrollViewer.LineRight();
|
||||
else if (scrollViewer.VerticalScrollBarVisibility != ScrollBarVisibility.Disabled)
|
||||
{ handle = false; }
|
||||
else if (scrollViewer.HorizontalScrollBarVisibility != ScrollBarVisibility.Disabled)
|
||||
scrollViewer.LineRight();
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle)
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
@ -0,0 +1,222 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public class SmoothScrollViewer : ScrollViewer
|
||||
{
|
||||
private double _totalVerticalOffset;
|
||||
private double _totalHorizontalOffset;
|
||||
private bool _isRunning;
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
get => (Orientation)GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(nameof(Orientation), typeof(Orientation), typeof(SmoothScrollViewer), new PropertyMetadata(Orientation.Vertical));
|
||||
|
||||
public bool CanMouseWheel
|
||||
{
|
||||
get => (bool)GetValue(CanMouseWheelProperty);
|
||||
set => SetValue(CanMouseWheelProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CanMouseWheelProperty = DependencyProperty.Register(nameof(CanMouseWheel), typeof(bool), typeof(SmoothScrollViewer), new PropertyMetadata(true));
|
||||
|
||||
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
{
|
||||
if (ViewportHeight + VerticalOffset >= ExtentHeight && e.Delta <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (VerticalOffset == 0 && e.Delta >= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CanMouseWheel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsInertiaEnabled)
|
||||
{
|
||||
if (Orientation == Orientation.Vertical)
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
_totalHorizontalOffset = HorizontalOffset;
|
||||
CurrentHorizontalOffset = HorizontalOffset;
|
||||
_totalHorizontalOffset = Math.Min(Math.Max(0, _totalHorizontalOffset - e.Delta), ScrollableWidth);
|
||||
CurrentHorizontalOffset = _totalHorizontalOffset;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
|
||||
if (Orientation == Orientation.Vertical)
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
_totalVerticalOffset = VerticalOffset;
|
||||
CurrentVerticalOffset = VerticalOffset;
|
||||
}
|
||||
|
||||
_totalVerticalOffset = Math.Min(Math.Max(0, _totalVerticalOffset - e.Delta), ScrollableHeight);
|
||||
ScrollToVerticalOffsetWithAnimation(_totalVerticalOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
_totalHorizontalOffset = HorizontalOffset;
|
||||
CurrentHorizontalOffset = HorizontalOffset;
|
||||
}
|
||||
|
||||
_totalHorizontalOffset = Math.Min(Math.Max(0, _totalHorizontalOffset - e.Delta), ScrollableWidth);
|
||||
ScrollToHorizontalOffsetWithAnimation(_totalHorizontalOffset);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ScrollToTopInternal(double milliseconds = 500)
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
_totalVerticalOffset = VerticalOffset;
|
||||
CurrentVerticalOffset = VerticalOffset;
|
||||
}
|
||||
|
||||
ScrollToVerticalOffsetWithAnimation(0, milliseconds);
|
||||
}
|
||||
|
||||
public void ScrollToVerticalOffsetWithAnimation(double offset, double milliseconds = 500)
|
||||
{
|
||||
DoubleAnimation animation = AnimationHelper.CreateAnimation(offset, milliseconds);
|
||||
animation.EasingFunction = new CubicEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseOut
|
||||
};
|
||||
animation.FillBehavior = FillBehavior.Stop;
|
||||
animation.Completed += (s, e1) =>
|
||||
{
|
||||
CurrentVerticalOffset = offset;
|
||||
_isRunning = false;
|
||||
};
|
||||
_isRunning = true;
|
||||
|
||||
BeginAnimation(CurrentVerticalOffsetProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
public void ScrollToHorizontalOffsetWithAnimation(double offset, double milliseconds = 500)
|
||||
{
|
||||
DoubleAnimation animation = AnimationHelper.CreateAnimation(offset, milliseconds);
|
||||
animation.EasingFunction = new CubicEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseOut
|
||||
};
|
||||
animation.FillBehavior = FillBehavior.Stop;
|
||||
animation.Completed += (s, e1) =>
|
||||
{
|
||||
CurrentHorizontalOffset = offset;
|
||||
_isRunning = false;
|
||||
};
|
||||
_isRunning = true;
|
||||
|
||||
BeginAnimation(CurrentHorizontalOffsetProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
protected override HitTestResult? HitTestCore(PointHitTestParameters hitTestParameters)
|
||||
{
|
||||
return IsPenetrating ? null : base.HitTestCore(hitTestParameters);
|
||||
}
|
||||
|
||||
public static void SetIsInertiaEnabled(DependencyObject element, bool value)
|
||||
{
|
||||
element.SetValue(IsInertiaEnabledProperty, value);
|
||||
}
|
||||
|
||||
public static bool GetIsInertiaEnabled(DependencyObject element)
|
||||
{
|
||||
return (bool)element.GetValue(IsInertiaEnabledProperty);
|
||||
}
|
||||
|
||||
public bool IsInertiaEnabled
|
||||
{
|
||||
get => (bool)GetValue(IsInertiaEnabledProperty);
|
||||
set => SetValue(IsInertiaEnabledProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsInertiaEnabledProperty = DependencyProperty.RegisterAttached(nameof(IsInertiaEnabled), typeof(bool), typeof(SmoothScrollViewer), new PropertyMetadata(true));
|
||||
|
||||
public bool IsPenetrating
|
||||
{
|
||||
get => (bool)GetValue(IsPenetratingProperty);
|
||||
set => SetValue(IsPenetratingProperty, value);
|
||||
}
|
||||
|
||||
public static void SetIsPenetrating(DependencyObject element, bool value)
|
||||
{
|
||||
element.SetValue(IsPenetratingProperty, value);
|
||||
}
|
||||
|
||||
public static bool GetIsPenetrating(DependencyObject element)
|
||||
{
|
||||
return (bool)element.GetValue(IsPenetratingProperty);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsPenetratingProperty = DependencyProperty.RegisterAttached(nameof(IsPenetrating), typeof(bool), typeof(SmoothScrollViewer), new PropertyMetadata(false));
|
||||
|
||||
internal double CurrentVerticalOffset
|
||||
{
|
||||
get => (double)GetValue(CurrentVerticalOffsetProperty);
|
||||
set => SetValue(CurrentVerticalOffsetProperty, value);
|
||||
}
|
||||
|
||||
internal static readonly DependencyProperty CurrentVerticalOffsetProperty = DependencyProperty.Register(nameof(CurrentVerticalOffset), typeof(double), typeof(SmoothScrollViewer), new PropertyMetadata(0d, OnCurrentVerticalOffsetChanged));
|
||||
|
||||
private static void OnCurrentVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is SmoothScrollViewer ctl && e.NewValue is double v)
|
||||
{
|
||||
ctl.ScrollToVerticalOffset(v);
|
||||
}
|
||||
}
|
||||
|
||||
internal double CurrentHorizontalOffset
|
||||
{
|
||||
get => (double)GetValue(CurrentHorizontalOffsetProperty);
|
||||
set => SetValue(CurrentHorizontalOffsetProperty, value);
|
||||
}
|
||||
|
||||
internal static readonly DependencyProperty CurrentHorizontalOffsetProperty = DependencyProperty.Register(nameof(CurrentHorizontalOffset), typeof(double), typeof(SmoothScrollViewer), new PropertyMetadata(0d, OnCurrentHorizontalOffsetChanged));
|
||||
|
||||
private static void OnCurrentHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is SmoothScrollViewer ctl && e.NewValue is double v)
|
||||
{
|
||||
ctl.ScrollToHorizontalOffset(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class AnimationHelper
|
||||
{
|
||||
public static DoubleAnimation CreateAnimation(double toValue, double milliseconds = 200)
|
||||
{
|
||||
return new(toValue, new Duration(TimeSpan.FromMilliseconds(milliseconds)))
|
||||
{
|
||||
EasingFunction = new PowerEase { EasingMode = EasingMode.EaseInOut }
|
||||
};
|
||||
}
|
||||
}
|
104
Build/MicaSetup/Design/Controls/Selection.cs
Normal file
104
Build/MicaSetup/Design/Controls/Selection.cs
Normal file
@ -0,0 +1,104 @@
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public static class Selection
|
||||
{
|
||||
public const string CeliakeyboardEnassociate = "\xe900";
|
||||
public const string CeliakeyboardMenuLanguage = "\xe901";
|
||||
public const string ContactsDelete = "\xe902";
|
||||
public const string DeviceMateBook = "\xe903";
|
||||
public const string FilesNameDrive = "\xe904";
|
||||
public const string GalleryCollage = "\xe905";
|
||||
public const string GalleryCreate = "\xe906";
|
||||
public const string GalleryMaterialSelectCheckbo = "\xe907";
|
||||
public const string GalleryMoveIn10 = "\xe908";
|
||||
public const string GalleryMoveOut = "\xe909";
|
||||
public const string GalleryPhotoEditMore = "\xe90a";
|
||||
public const string GalleryRectify = "\xe90b";
|
||||
public const string GalleryRename = "\xe90c";
|
||||
public const string GallerySet = "\xe90d";
|
||||
public const string GallerySortOrder = "\xe90e";
|
||||
public const string GallerySortReverse = "\xe90f";
|
||||
public const string MessageForwarding = "\xe910";
|
||||
public const string MessageTheme = "\xe911";
|
||||
public const string PowerOff = "\xe912";
|
||||
public const string PublicAdd = "\xe913";
|
||||
public const string PublicAddFilled = "\xe914";
|
||||
public const string PublicAddNorm = "\xe915";
|
||||
public const string PublicApp = "\xe916";
|
||||
public const string PublicArrowLeft = "\xe917";
|
||||
public const string PublicArrowRight = "\xe918";
|
||||
public const string PublicArrowUp0 = "\xe919";
|
||||
public const string PublicArrowUp1 = "\xe91a";
|
||||
public const string PublicBack = "\xe91b";
|
||||
public const string PublicBackToTop = "\xe91c";
|
||||
public const string PublicBrightness = "\xe91d";
|
||||
public const string PublicCancel = "\xe91e";
|
||||
public const string PublicCancelFilled = "\xe91f";
|
||||
public const string PublicClose = "\xe920";
|
||||
public const string PublicCloudDownload = "\xe921";
|
||||
public const string PublicCloudUpload = "\xe922";
|
||||
public const string PublicConnection = "\xe923";
|
||||
public const string PublicContacts = "\xe924";
|
||||
public const string PublicCopy = "\xe925";
|
||||
public const string PublicDelete = "\xe926";
|
||||
public const string PublicDoNotDisturb = "\xe927";
|
||||
public const string PublicDownload = "\xe928";
|
||||
public const string PublicEdit = "\xe929";
|
||||
public const string PublicEmail = "\xe92a";
|
||||
public const string PublicEmailSend = "\xe92b";
|
||||
public const string PublicEnlarge = "\xe92c";
|
||||
public const string PublicFail = "\xe92d";
|
||||
public const string PublicFolder = "\xe92e";
|
||||
public const string PublicForbid = "\xe92f";
|
||||
public const string PublicHelp = "\xe930";
|
||||
public const string PublicHighLights = "\xe931";
|
||||
public const string PublicHome = "\xe932";
|
||||
public const string PublicInputSearch = "\xe933";
|
||||
public const string PublicKeyboard = "\xe934";
|
||||
public const string PublicListCycle = "\xe935";
|
||||
public const string PubliClock = "\xe936";
|
||||
public const string PublicMessage = "\xe937";
|
||||
public const string PublicMobileData = "\xe938";
|
||||
public const string PublicMove = "\xe939";
|
||||
public const string PublicNavigation = "\xe93a";
|
||||
public const string PublicOk = "\xe93b";
|
||||
public const string PublicOkFilled = "\xe93c";
|
||||
public const string PublicPicture = "\xe93d";
|
||||
public const string PublicPrinter = "\xe93e";
|
||||
public const string PublicQuit = "\xe93f";
|
||||
public const string PublicRandom = "\xe940";
|
||||
public const string PublicReduce = "\xe941";
|
||||
public const string PublicRefresh = "\xe942";
|
||||
public const string PublicRemove = "\xe943";
|
||||
public const string PublicReset = "\xe944";
|
||||
public const string PublicRing = "\xe945";
|
||||
public const string PublicRingOff = "\xe946";
|
||||
public const string PublicRotate = "\xe947";
|
||||
public const string PublicSave = "\xe948";
|
||||
public const string PublicScan = "\xe949";
|
||||
public const string PublicSearch = "\xe94a";
|
||||
public const string PublicSecurity = "\xe94b";
|
||||
public const string PublicSend = "\xe94c";
|
||||
public const string PublicSettings = "\xe94d";
|
||||
public const string PublicShare = "\xe94e";
|
||||
public const string PublicSift = "\xe94f";
|
||||
public const string PublicSound = "\xe950";
|
||||
public const string PublicText = "\xe951";
|
||||
public const string PublicThemes = "\xe952";
|
||||
public const string PublicThumbsup = "\xe953";
|
||||
public const string PublicTodo = "\xe954";
|
||||
public const string PublicTopping = "\xe955";
|
||||
public const string PublicUnlock = "\xe956";
|
||||
public const string PublicUpgrade = "\xe957";
|
||||
public const string PublicUpload = "\xe958";
|
||||
public const string PublicVolumeDown = "\xe959";
|
||||
public const string PublicWirelessProjection = "\xe95b";
|
||||
public const string PublicWorldClock = "\xe95c";
|
||||
public const string QuickReply = "\xe95d";
|
||||
public const string Reboot = "\xe95e";
|
||||
public const string SearchThings = "\xe95f";
|
||||
public const string ContactSencryptionCalls = "\xe960";
|
||||
public const string Circle = "\xe961";
|
||||
public const string Squircle = "\xe962";
|
||||
public const string IcoMoon = "\xe95a";
|
||||
}
|
112
Build/MicaSetup/Design/Controls/Shell/Routing.cs
Normal file
112
Build/MicaSetup/Design/Controls/Shell/Routing.cs
Normal file
@ -0,0 +1,112 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public static class Routing
|
||||
{
|
||||
public static ServiceProvider Provider { get; internal set; } = null!;
|
||||
public static WeakReference<ShellControl> Shell { get; internal set; } = null!;
|
||||
|
||||
public static void RegisterRoute()
|
||||
{
|
||||
ServiceCollection serviceCollection = new();
|
||||
|
||||
foreach (var pageItem in ShellPageSetting.PageDict)
|
||||
{
|
||||
serviceCollection.Register(pageItem.Key, pageItem.Value);
|
||||
}
|
||||
Provider = serviceCollection.BuildServiceProvider();
|
||||
}
|
||||
|
||||
public static FrameworkElement ResolveRoute(string route)
|
||||
{
|
||||
if (string.IsNullOrEmpty(route))
|
||||
{
|
||||
return null!;
|
||||
}
|
||||
return Provider?.Resolve<FrameworkElement>(route)!;
|
||||
}
|
||||
|
||||
public static void GoTo(string route)
|
||||
{
|
||||
if (Shell != null)
|
||||
{
|
||||
if (Shell.TryGetTarget(out ShellControl shell))
|
||||
{
|
||||
OnGoTo(route);
|
||||
shell.Content = ResolveRoute(route);
|
||||
shell.Route = route;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void GoToNext()
|
||||
{
|
||||
if (Shell != null)
|
||||
{
|
||||
if (Shell.TryGetTarget(out ShellControl shell))
|
||||
{
|
||||
if (ShellPageSetting.PageDict.ContainsKey(shell.Route))
|
||||
{
|
||||
bool found = false;
|
||||
foreach (var item in ShellPageSetting.PageDict)
|
||||
{
|
||||
if (found)
|
||||
{
|
||||
OnGoTo(item.Key);
|
||||
shell.Content = ResolveRoute(item.Key);
|
||||
shell.Route = item.Key;
|
||||
break;
|
||||
}
|
||||
if (item.Key == shell.Route)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnGoTo(string route)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
file class RoutingServiceInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Type Type { get; set; }
|
||||
|
||||
public RoutingServiceInfo(string name, Type type)
|
||||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
|
||||
file static class RoutingExtension
|
||||
{
|
||||
public static IServiceCollection Register(this IServiceCollection services, string name, Type type)
|
||||
{
|
||||
services.AddSingleton(type);
|
||||
services.AddSingleton(new RoutingServiceInfo(name, type));
|
||||
return services;
|
||||
}
|
||||
|
||||
public static T Resolve<T>(this IServiceProvider serviceProvider, string name)
|
||||
{
|
||||
var serviceInfo = serviceProvider.GetRequiredService<IEnumerable<RoutingServiceInfo>>()
|
||||
.FirstOrDefault(x => x.Name == name);
|
||||
|
||||
if (serviceInfo == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Service '{name}' not found");
|
||||
}
|
||||
return (T)serviceProvider.GetRequiredService(serviceInfo.Type);
|
||||
}
|
||||
}
|
23
Build/MicaSetup/Design/Controls/Shell/ShellControl.cs
Normal file
23
Build/MicaSetup/Design/Controls/Shell/ShellControl.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public class ShellControl : ContentControl
|
||||
{
|
||||
public string Route
|
||||
{
|
||||
get => (string)GetValue(RouteProperty);
|
||||
set => SetCurrentValue(RouteProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty RouteProperty = DependencyProperty.Register(nameof(Route), typeof(string), typeof(ShellControl), new(string.Empty));
|
||||
|
||||
public ShellControl()
|
||||
{
|
||||
Routing.Shell = new WeakReference<ShellControl>(this);
|
||||
FocusVisualStyle = null!;
|
||||
Loaded += (_, _) => Routing.GoTo(Route);
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public class ShellPageSetting
|
||||
{
|
||||
public static Dictionary<string, Type> PageDict = new();
|
||||
}
|
102
Build/MicaSetup/Design/Controls/TextBox/TextBox.cs
Normal file
102
Build/MicaSetup/Design/Controls/TextBox/TextBox.cs
Normal file
@ -0,0 +1,102 @@
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public class TextBoxEx : TextBox
|
||||
{
|
||||
public static readonly DependencyProperty PlaceholderTextProperty = DependencyProperty.Register(
|
||||
nameof(PlaceholderText),
|
||||
typeof(string),
|
||||
typeof(TextBoxEx),
|
||||
new PropertyMetadata(string.Empty)
|
||||
);
|
||||
|
||||
public static readonly DependencyProperty PlaceholderEnabledProperty = DependencyProperty.Register(
|
||||
nameof(PlaceholderEnabled),
|
||||
typeof(bool),
|
||||
typeof(TextBoxEx),
|
||||
new PropertyMetadata(true)
|
||||
);
|
||||
|
||||
public static readonly DependencyProperty IsTextSelectionEnabledProperty = DependencyProperty.Register(
|
||||
nameof(IsTextSelectionEnabled),
|
||||
typeof(bool),
|
||||
typeof(TextBoxEx),
|
||||
new PropertyMetadata(false)
|
||||
);
|
||||
|
||||
public static readonly DependencyProperty TemplateButtonCommandProperty = DependencyProperty.Register(
|
||||
nameof(TemplateButtonCommand),
|
||||
typeof(IRelayCommand),
|
||||
typeof(TextBoxEx),
|
||||
new PropertyMetadata(null)
|
||||
);
|
||||
|
||||
public string PlaceholderText
|
||||
{
|
||||
get => (string)GetValue(PlaceholderTextProperty);
|
||||
set => SetValue(PlaceholderTextProperty, value);
|
||||
}
|
||||
|
||||
public bool PlaceholderEnabled
|
||||
{
|
||||
get => (bool)GetValue(PlaceholderEnabledProperty);
|
||||
set => SetValue(PlaceholderEnabledProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TODO
|
||||
/// </summary>
|
||||
public bool IsTextSelectionEnabled
|
||||
{
|
||||
get => (bool)GetValue(IsTextSelectionEnabledProperty);
|
||||
set => SetValue(IsTextSelectionEnabledProperty, value);
|
||||
}
|
||||
|
||||
public IRelayCommand TemplateButtonCommand => (IRelayCommand)GetValue(TemplateButtonCommandProperty);
|
||||
|
||||
public TextBoxEx()
|
||||
{
|
||||
SetValue(TemplateButtonCommandProperty, new RelayCommand<string>(OnTemplateButtonClick));
|
||||
}
|
||||
|
||||
protected override void OnTextChanged(TextChangedEventArgs e)
|
||||
{
|
||||
base.OnTextChanged(e);
|
||||
|
||||
if (PlaceholderEnabled && Text.Length > 0)
|
||||
PlaceholderEnabled = false;
|
||||
|
||||
if (!PlaceholderEnabled && Text.Length < 1)
|
||||
PlaceholderEnabled = true;
|
||||
}
|
||||
|
||||
protected override void OnGotFocus(RoutedEventArgs e)
|
||||
{
|
||||
base.OnGotFocus(e);
|
||||
|
||||
CaretIndex = Text.Length;
|
||||
}
|
||||
|
||||
protected override void OnLostFocus(RoutedEventArgs e)
|
||||
{
|
||||
base.OnLostFocus(e);
|
||||
}
|
||||
|
||||
protected virtual void OnClearButtonClick()
|
||||
{
|
||||
if (Text.Length > 0)
|
||||
{
|
||||
Text = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnTemplateButtonClick(string? parameter)
|
||||
{
|
||||
Debug.WriteLine($"INFO: {typeof(TextBoxEx)} button clicked");
|
||||
OnClearButtonClick();
|
||||
}
|
||||
}
|
286
Build/MicaSetup/Design/Controls/TextBox/TextBox.xaml
Normal file
286
Build/MicaSetup/Design/Controls/TextBox/TextBox.xaml
Normal file
@ -0,0 +1,286 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:MicaSetup.Design.Controls"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib">
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/MicaSetup;component/Resources/Variables.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Thickness x:Key="TextBoxBorderThemeThickness">1,1,1,0</Thickness>
|
||||
<Thickness x:Key="TextBoxAccentBorderThemeThickness">0,0,0,1</Thickness>
|
||||
<Thickness x:Key="TextBoxLeftIconMargin">10,0,0,0</Thickness>
|
||||
<Thickness x:Key="TextBoxRightIconMargin">0,0,10,0</Thickness>
|
||||
<Thickness x:Key="TextBoxClearButtonMargin">0,0,4,0</Thickness>
|
||||
<Thickness x:Key="TextBoxClearButtonPadding">0,0,0,0</Thickness>
|
||||
<sys:Double x:Key="TextBoxClearButtonHeight">24</sys:Double>
|
||||
|
||||
<Style x:Key="DefaultTextBoxScrollViewerStyle" TargetType="{x:Type ScrollViewer}">
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ScrollViewer}">
|
||||
<Grid>
|
||||
<ScrollContentPresenter Margin="0" CanContentScroll="{TemplateBinding CanContentScroll}" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="DefaultTextBoxStyle" TargetType="{x:Type TextBox}">
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextControlForeground}" />
|
||||
<Setter Property="CaretBrush" Value="{DynamicResource TextControlForeground}" />
|
||||
<Setter Property="Background" Value="{DynamicResource TextControlBackground}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource TextControlElevationBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="{StaticResource TextBoxBorderThemeThickness}" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
|
||||
<Setter Property="ScrollViewer.CanContentScroll" Value="False" />
|
||||
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
|
||||
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden" />
|
||||
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Top" />
|
||||
<Setter Property="MinHeight" Value="{DynamicResource TextControlThemeMinHeight}" />
|
||||
<Setter Property="MinWidth" Value="{DynamicResource TextControlThemeMinWidth}" />
|
||||
<Setter Property="Padding" Value="{DynamicResource TextControlThemePadding}" />
|
||||
<Setter Property="Border.CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type TextBox}">
|
||||
<Grid HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}">
|
||||
<Border
|
||||
x:Name="ContentBorder"
|
||||
MinWidth="{TemplateBinding MinWidth}"
|
||||
MinHeight="{TemplateBinding MinHeight}"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding Border.CornerRadius}">
|
||||
<Grid
|
||||
Margin="{TemplateBinding Padding}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
|
||||
<ScrollViewer
|
||||
x:Name="PART_ContentHost"
|
||||
VerticalAlignment="Center"
|
||||
CanContentScroll="{TemplateBinding ScrollViewer.CanContentScroll}"
|
||||
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
|
||||
IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
|
||||
IsTabStop="{TemplateBinding ScrollViewer.IsTabStop}"
|
||||
Style="{StaticResource DefaultTextBoxScrollViewerStyle}"
|
||||
TextElement.Foreground="{TemplateBinding Foreground}"
|
||||
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- The Accent Border is a separate element so that changes to the border thickness do not affect the position of the element -->
|
||||
<Border
|
||||
x:Name="AccentBorder"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderThickness="{StaticResource TextBoxAccentBorderThemeThickness}"
|
||||
CornerRadius="{TemplateBinding Border.CornerRadius}">
|
||||
<Border.BorderBrush>
|
||||
<SolidColorBrush Color="{DynamicResource ControlStrongStrokeColorDefault}" />
|
||||
</Border.BorderBrush>
|
||||
</Border>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsFocused" Value="True">
|
||||
<Setter TargetName="AccentBorder" Property="BorderThickness" Value="0,0,0,2" />
|
||||
<Setter TargetName="AccentBorder" Property="BorderBrush" Value="{DynamicResource TextControlFocusedBorderBrush}" />
|
||||
<Setter TargetName="ContentBorder" Property="Background" Value="{DynamicResource TextControlBackgroundFocused}" />
|
||||
</Trigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsEnabled" Value="True" />
|
||||
<Condition Property="IsMouseOver" Value="True" />
|
||||
<Condition Property="IsFocused" Value="False" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter TargetName="ContentBorder" Property="Background" Value="{DynamicResource TextControlBackgroundPointerOver}" />
|
||||
</MultiTrigger>
|
||||
<Trigger Property="IsEnabled" Value="True">
|
||||
<Setter Property="Cursor" Value="IBeam" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="ContentBorder" Property="Background" Value="{DynamicResource TextControlBackgroundDisabled}" />
|
||||
<Setter TargetName="ContentBorder" Property="BorderBrush" Value="{DynamicResource TextControlBorderBrushDisabled}" />
|
||||
<Setter TargetName="AccentBorder" Property="BorderBrush" Value="{DynamicResource TextControlBorderBrushDisabled}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextControlForegroundDisabled}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
|
||||
<ControlTemplate x:Key="DefaultUiTextBoxControlTemplate" TargetType="{x:Type controls:TextBoxEx}">
|
||||
<Grid HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}">
|
||||
<Border
|
||||
x:Name="ContentBorder"
|
||||
MinWidth="{TemplateBinding MinWidth}"
|
||||
MinHeight="{TemplateBinding MinHeight}"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding Border.CornerRadius}">
|
||||
<Grid HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Column="1" Margin="{TemplateBinding Padding}">
|
||||
<ScrollViewer
|
||||
x:Name="PART_ContentHost"
|
||||
VerticalAlignment="Center"
|
||||
CanContentScroll="{TemplateBinding ScrollViewer.CanContentScroll}"
|
||||
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
|
||||
IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
|
||||
IsTabStop="{TemplateBinding ScrollViewer.IsTabStop}"
|
||||
Style="{StaticResource DefaultTextBoxScrollViewerStyle}"
|
||||
TextElement.Foreground="{TemplateBinding Foreground}"
|
||||
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" />
|
||||
<TextBlock
|
||||
x:Name="PlaceholderTextBox"
|
||||
Margin="0"
|
||||
Padding="1,0"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource TextControlPlaceholderForeground}"
|
||||
Text="{TemplateBinding PlaceholderText}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- The Accent Border is a separate element so that changes to the border thickness do not affect the position of the element -->
|
||||
<Border
|
||||
x:Name="AccentBorder"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderThickness="{StaticResource TextBoxAccentBorderThemeThickness}"
|
||||
CornerRadius="{TemplateBinding Border.CornerRadius}">
|
||||
<Border.BorderBrush>
|
||||
<SolidColorBrush Color="{DynamicResource ControlStrongStrokeColorDefault}" />
|
||||
</Border.BorderBrush>
|
||||
</Border>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="PlaceholderEnabled" Value="False">
|
||||
<Setter TargetName="PlaceholderTextBox" Property="Visibility" Value="Collapsed" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsFocused" Value="True">
|
||||
<Setter TargetName="AccentBorder" Property="BorderThickness" Value="0,0,0,2" />
|
||||
<Setter TargetName="AccentBorder" Property="BorderBrush" Value="{DynamicResource TextControlFocusedBorderBrush}" />
|
||||
<Setter TargetName="ContentBorder" Property="Background" Value="{DynamicResource TextControlBackgroundFocused}" />
|
||||
</Trigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsEnabled" Value="True" />
|
||||
<Condition Property="IsMouseOver" Value="True" />
|
||||
<Condition Property="IsFocused" Value="False" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter TargetName="ContentBorder" Property="Background" Value="{DynamicResource TextControlBackgroundPointerOver}" />
|
||||
</MultiTrigger>
|
||||
<Trigger Property="IsEnabled" Value="True">
|
||||
<Setter Property="Cursor" Value="IBeam" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="ContentBorder" Property="Background" Value="{DynamicResource TextControlBackgroundDisabled}" />
|
||||
<Setter TargetName="ContentBorder" Property="BorderBrush" Value="{DynamicResource TextControlBorderBrushDisabled}" />
|
||||
<Setter TargetName="AccentBorder" Property="BorderBrush" Value="{DynamicResource TextControlBorderBrushDisabled}" />
|
||||
<Setter TargetName="PlaceholderTextBox" Property="Foreground" Value="{DynamicResource TextControlForegroundDisabled}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextControlForegroundDisabled}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="DefaultUiTextBoxTextSelectionEnabledControlTemplate" TargetType="{x:Type controls:TextBoxEx}">
|
||||
<Grid HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}">
|
||||
<Border
|
||||
x:Name="ContentBorder"
|
||||
MinWidth="{TemplateBinding MinWidth}"
|
||||
MinHeight="{TemplateBinding MinHeight}"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding Border.CornerRadius}"
|
||||
Focusable="False">
|
||||
<Grid HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
|
||||
<Grid Margin="{TemplateBinding Padding}">
|
||||
<ScrollViewer
|
||||
x:Name="PART_ContentHost"
|
||||
VerticalAlignment="Center"
|
||||
CanContentScroll="{TemplateBinding ScrollViewer.CanContentScroll}"
|
||||
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
|
||||
IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
|
||||
IsTabStop="{TemplateBinding ScrollViewer.IsTabStop}"
|
||||
Style="{StaticResource DefaultTextBoxScrollViewerStyle}"
|
||||
TextElement.Foreground="{TemplateBinding Foreground}"
|
||||
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style x:Key="DefaultUiTextBoxStyle" TargetType="{x:Type controls:TextBoxEx}">
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextControlForeground}" />
|
||||
<Setter Property="CaretBrush" Value="{DynamicResource TextControlForeground}" />
|
||||
<Setter Property="Background" Value="{DynamicResource TextControlBackground}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource TextControlElevationBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="{StaticResource TextBoxBorderThemeThickness}" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
|
||||
<Setter Property="ScrollViewer.CanContentScroll" Value="False" />
|
||||
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
|
||||
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden" />
|
||||
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Top" />
|
||||
<Setter Property="MinHeight" Value="{DynamicResource TextControlThemeMinHeight}" />
|
||||
<Setter Property="MinWidth" Value="{DynamicResource TextControlThemeMinWidth}" />
|
||||
<Setter Property="Padding" Value="{DynamicResource TextControlThemePadding}" />
|
||||
<Setter Property="Border.CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsTextSelectionEnabled" Value="False">
|
||||
<Setter Property="Template" Value="{StaticResource DefaultUiTextBoxControlTemplate}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsTextSelectionEnabled" Value="True">
|
||||
<Setter Property="IsReadOnly" Value="True" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Template" Value="{StaticResource DefaultUiTextBoxTextSelectionEnabledControlTemplate}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style BasedOn="{StaticResource DefaultTextBoxStyle}" TargetType="{x:Type TextBox}" />
|
||||
<Style BasedOn="{StaticResource DefaultUiTextBoxStyle}" TargetType="{x:Type controls:TextBoxEx}" />
|
||||
|
||||
</ResourceDictionary>
|
@ -0,0 +1,22 @@
|
||||
using MicaSetup.Natives;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public class ApplicationThemeManager
|
||||
{
|
||||
public static ApplicationTheme GetAppTheme()
|
||||
{
|
||||
using RegistryKey? key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
|
||||
object? registryValueObject = key?.GetValue("AppsUseLightTheme");
|
||||
|
||||
if (registryValueObject == null)
|
||||
{
|
||||
return ApplicationTheme.Light;
|
||||
}
|
||||
|
||||
var registryValue = (int)registryValueObject;
|
||||
|
||||
return registryValue > 0 ? ApplicationTheme.Light : ApplicationTheme.Dark;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
using Microsoft.Xaml.Behaviors;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public sealed class WindowClearOwnerOnClosingBehavior : Behavior<Window>
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
AssociatedObject.Closing += OnWindowClosing;
|
||||
base.OnAttached();
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
AssociatedObject.Closing -= OnWindowClosing;
|
||||
base.OnDetaching();
|
||||
}
|
||||
|
||||
private void OnWindowClosing(object? sender, CancelEventArgs e)
|
||||
{
|
||||
if (!e.Cancel)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (AssociatedObject.Owner != null)
|
||||
{
|
||||
AssociatedObject.Owner = null!;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Don't attach this {nameof(WindowClearOwnerOnClosingBehavior)} for {nameof(Window)} called from {nameof(Window.ShowDialog)}.", ex);
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
Debugger.Break();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
using Microsoft.Xaml.Behaviors;
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public sealed class WindowDragMoveBehavior : Behavior<FrameworkElement>
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
AssociatedObject.MouseLeftButtonDown += MouseLeftButtonDown;
|
||||
base.OnAttached();
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
AssociatedObject.MouseLeftButtonDown -= MouseLeftButtonDown;
|
||||
base.OnDetaching();
|
||||
}
|
||||
|
||||
private void MouseLeftButtonDown(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is UIElement ui)
|
||||
{
|
||||
Window.GetWindow(ui)?.DragMove();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
using MicaSetup.Natives;
|
||||
using Microsoft.Xaml.Behaviors;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public sealed class WindowHideTitleButtonBehavior : Behavior<Window>
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
AssociatedObject.SourceInitialized += OnSourceInitialized;
|
||||
base.OnAttached();
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
AssociatedObject.Loaded -= OnSourceInitialized;
|
||||
base.OnDetaching();
|
||||
}
|
||||
|
||||
private void OnSourceInitialized(object? sender, EventArgs e)
|
||||
{
|
||||
NativeMethods.HideAllWindowButton(new WindowInteropHelper(AssociatedObject).Handle);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
using Microsoft.Xaml.Behaviors;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public sealed class WindowRestorePathBehavior : Behavior<FrameworkElement>
|
||||
{
|
||||
private WindowState windowStatePrev = WindowState.Normal;
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
AssociatedObject.Loaded += Loaded;
|
||||
base.OnAttached();
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
AssociatedObject.Loaded -= Loaded;
|
||||
base.OnDetaching();
|
||||
}
|
||||
|
||||
private void Loaded(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is UIElement maximizeButtonContent && Window.GetWindow(maximizeButtonContent) is Window window)
|
||||
{
|
||||
window.SizeChanged += (s, e) =>
|
||||
{
|
||||
if (windowStatePrev != window.WindowState)
|
||||
{
|
||||
if (maximizeButtonContent is Path path)
|
||||
{
|
||||
if (window.WindowState == WindowState.Maximized)
|
||||
{
|
||||
path.Data = Geometry.Parse("M0 0.2 L0.8 0.2 M0 01 L0.8 1 M0.8 1 L0.8 0.2 M0 0.2 L0 1 M0.3 0 L0.95 0 M01 0.05 L1 0.7");
|
||||
}
|
||||
else
|
||||
{
|
||||
path.Data = Geometry.Parse("M0.025 0 L0.975 0 M0.025 1 L0.975 1 M1 0.975 L1 0.025 M0 0.025 L0 0.975");
|
||||
}
|
||||
}
|
||||
windowStatePrev = window.WindowState;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
using MicaSetup.Helper;
|
||||
using MicaSetup.Natives;
|
||||
using Microsoft.Xaml.Behaviors;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public sealed class WindowTitleHeaderBehavior : Behavior<FrameworkElement>
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
AssociatedObject.Loaded += Loaded;
|
||||
base.OnAttached();
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
AssociatedObject.Loaded -= Loaded;
|
||||
base.OnDetaching();
|
||||
}
|
||||
|
||||
private void Loaded(object sender, EventArgs e)
|
||||
{
|
||||
AssociatedObject.RegisterAsTitleHeader();
|
||||
}
|
||||
}
|
||||
|
||||
file static class RegisterAsTitleHeaderBehaviorExtension
|
||||
{
|
||||
public static void RegisterAsTitleHeader(this UIElement self)
|
||||
{
|
||||
self.MouseLeftButtonDown += (s, e) =>
|
||||
{
|
||||
if (s is UIElement titleHeader && Window.GetWindow(titleHeader) is Window window)
|
||||
{
|
||||
if (e.ClickCount == 2)
|
||||
{
|
||||
if (window.ResizeMode == ResizeMode.CanResize || window.ResizeMode == ResizeMode.CanResizeWithGrip)
|
||||
{
|
||||
switch (window.WindowState)
|
||||
{
|
||||
case WindowState.Normal:
|
||||
WindowSystemCommands.MaximizeWindow(window);
|
||||
break;
|
||||
|
||||
case WindowState.Maximized:
|
||||
WindowSystemCommands.RestoreWindow(window);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
WindowSystemCommands.FastRestoreWindow(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.MouseRightButtonDown += (s, e) =>
|
||||
{
|
||||
if (s is UIElement titleHeader && Window.GetWindow(titleHeader) is Window window)
|
||||
{
|
||||
if (window.Cursor != null && window.Cursor.ToString() == Cursors.None.ToString())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (e.RightButton == MouseButtonState.Pressed)
|
||||
{
|
||||
if (User32.GetCursorPos(out POINT pt))
|
||||
{
|
||||
e.Handled = true;
|
||||
SystemCommands.ShowSystemMenu(window, new Point(DpiHelper.CalcDPiX(pt.X), DpiHelper.CalcDPiY(pt.Y)));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
using MicaSetup.Helper;
|
||||
using MicaSetup.Natives;
|
||||
using Microsoft.Xaml.Behaviors;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public sealed class WindowTitleIconBehavior : Behavior<FrameworkElement>
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
AssociatedObject.Loaded += Loaded;
|
||||
base.OnAttached();
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
AssociatedObject.Loaded -= Loaded;
|
||||
base.OnDetaching();
|
||||
}
|
||||
|
||||
private void Loaded(object sender, EventArgs e)
|
||||
{
|
||||
AssociatedObject.RegisterAsTitleIcon();
|
||||
}
|
||||
}
|
||||
|
||||
public static class RegisterAsTitleIconBehaviorExtension
|
||||
{
|
||||
public static void RegisterAsTitleIcon(this UIElement self)
|
||||
{
|
||||
self.MouseLeftButtonDown += (s, e) =>
|
||||
{
|
||||
if (s is UIElement titleHeader && Window.GetWindow(titleHeader) is Window window)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
if (User32.GetCursorPos(out POINT pt))
|
||||
{
|
||||
SystemCommands.ShowSystemMenu(window, new Point(DpiHelper.CalcDPiX(pt.X), DpiHelper.CalcDPiY(pt.Y)));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
174
Build/MicaSetup/Design/Controls/Window/SnapLayout.cs
Normal file
174
Build/MicaSetup/Design/Controls/Window/SnapLayout.cs
Normal file
@ -0,0 +1,174 @@
|
||||
using MicaSetup.Helper;
|
||||
using MicaSetup.Natives;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation.Peers;
|
||||
using System.Windows.Automation.Provider;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using Point = System.Windows.Point;
|
||||
using Size = System.Windows.Size;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// https://learn.microsoft.com/zh-cn/windows/apps/desktop/modernize/apply-snap-layout-menu
|
||||
/// </summary>
|
||||
public sealed class SnapLayout
|
||||
{
|
||||
public bool IsRegistered { get; private set; } = false;
|
||||
public bool IsSupported => Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.Build > 20000;
|
||||
public static bool IsEnabled { get; } = IsSnapLayoutEnabled();
|
||||
|
||||
private Button? button;
|
||||
private bool isButtonFocused;
|
||||
|
||||
private Window? window;
|
||||
|
||||
public void Register(Button button)
|
||||
{
|
||||
isButtonFocused = false;
|
||||
this.button = button;
|
||||
IsRegistered = true;
|
||||
}
|
||||
|
||||
public nint WndProc(nint hWnd, int msg, nint wParam, nint lParam, ref bool handled)
|
||||
{
|
||||
if (!IsRegistered) return 0;
|
||||
switch ((User32.WindowMessage)msg)
|
||||
{
|
||||
case User32.WindowMessage.WM_NCLBUTTONDOWN:
|
||||
if (IsOverButton(lParam))
|
||||
{
|
||||
window ??= Window.GetWindow(button);
|
||||
if (window != null)
|
||||
{
|
||||
WindowSystemCommands.MaximizeOrRestoreWindow(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (new ButtonAutomationPeer(button).GetPattern(PatternInterface.Invoke) is IInvokeProvider invokeProv)
|
||||
{
|
||||
invokeProv?.Invoke();
|
||||
}
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case User32.WindowMessage.WM_NCMOUSELEAVE:
|
||||
DefocusButton();
|
||||
break;
|
||||
|
||||
case User32.WindowMessage.WM_NCHITTEST:
|
||||
if (IsEnabled)
|
||||
{
|
||||
if (IsOverButton(lParam))
|
||||
{
|
||||
FocusButton();
|
||||
handled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DefocusButton();
|
||||
}
|
||||
}
|
||||
return (int)User32.HitTestValues.HTMAXBUTTON;
|
||||
|
||||
case User32.WindowMessage.WM_SETCURSOR:
|
||||
if (isButtonFocused)
|
||||
{
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
handled = false;
|
||||
break;
|
||||
}
|
||||
return (int)User32.HitTestValues.HTCLIENT;
|
||||
}
|
||||
|
||||
private void FocusButton()
|
||||
{
|
||||
if (isButtonFocused) return;
|
||||
|
||||
if (button != null)
|
||||
{
|
||||
button.Background = (Brush)Application.Current.FindResource("ButtonBackgroundPointerOver");
|
||||
button.BorderBrush = (Brush)Application.Current.FindResource("ButtonBorderBrushPointerOver");
|
||||
button.Foreground = (Brush)Application.Current.FindResource("ButtonForegroundPointerOver");
|
||||
}
|
||||
isButtonFocused = true;
|
||||
}
|
||||
|
||||
private void DefocusButton()
|
||||
{
|
||||
if (!isButtonFocused) return;
|
||||
|
||||
button?.ClearValue(Control.BackgroundProperty);
|
||||
button?.ClearValue(Control.BorderBrushProperty);
|
||||
button?.ClearValue(Control.ForegroundProperty);
|
||||
isButtonFocused = false;
|
||||
}
|
||||
|
||||
private bool IsOverButton(nint lParam)
|
||||
{
|
||||
if (button == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
int x = Macro.GET_X_LPARAM(lParam);
|
||||
int y = Macro.GET_Y_LPARAM(lParam);
|
||||
|
||||
Rect rect = new(button.PointToScreen(new Point()), new Size(DpiHelper.CalcDPIX(button.ActualWidth), DpiHelper.CalcDPIY(button.ActualHeight)));
|
||||
|
||||
if (rect.Contains(new Point(x, y)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsSnapLayoutEnabled()
|
||||
{
|
||||
try
|
||||
{
|
||||
using RegistryKey? key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced", true);
|
||||
object? registryValueObject = key?.GetValue("EnableSnapAssistFlyout");
|
||||
|
||||
if (registryValueObject == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
int registryValue = (int)registryValueObject;
|
||||
return registryValue > 0;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
file static class Macro
|
||||
{
|
||||
public static ushort LOWORD(nint value) => (ushort)((long)value & 0xFFFF);
|
||||
|
||||
public static ushort HIWORD(nint value) => (ushort)((((long)value) >> 0x10) & 0xFFFF);
|
||||
|
||||
public static int GET_X_LPARAM(nint wParam) => LOWORD(wParam);
|
||||
|
||||
public static int GET_Y_LPARAM(nint wParam) => HIWORD(wParam);
|
||||
}
|
187
Build/MicaSetup/Design/Controls/Window/WindowBackdrop.cs
Normal file
187
Build/MicaSetup/Design/Controls/Window/WindowBackdrop.cs
Normal file
@ -0,0 +1,187 @@
|
||||
using MicaSetup.Helper;
|
||||
using MicaSetup.Natives;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public static class WindowBackdrop
|
||||
{
|
||||
private static bool IsSupported(WindowBackdropType backdropType)
|
||||
{
|
||||
return backdropType switch
|
||||
{
|
||||
WindowBackdropType.Auto => OsVersionHelper.IsWindows11_22523,
|
||||
WindowBackdropType.Tabbed => OsVersionHelper.IsWindows11_22523,
|
||||
WindowBackdropType.Mica => OsVersionHelper.IsWindows11_OrGreater,
|
||||
WindowBackdropType.Acrylic => OsVersionHelper.IsWindows7_OrGreater,
|
||||
WindowBackdropType.None => OsVersionHelper.IsWindows11_OrGreater,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
||||
public static bool ApplyBackdrop(Window window, WindowBackdropType backdropType = WindowBackdropType.Mica, ApplicationTheme theme = ApplicationTheme.Unknown)
|
||||
{
|
||||
if (!IsSupported(backdropType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (window is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (window.IsLoaded)
|
||||
{
|
||||
nint windowHandle = new WindowInteropHelper(window).Handle;
|
||||
|
||||
if (windowHandle == 0x00)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ApplyBackdrop(windowHandle, backdropType, theme);
|
||||
}
|
||||
|
||||
window.Loaded += (sender, _) =>
|
||||
{
|
||||
nint windowHandle =
|
||||
new WindowInteropHelper(sender as Window ?? null)?.Handle
|
||||
?? IntPtr.Zero;
|
||||
|
||||
if (windowHandle == 0x00)
|
||||
return;
|
||||
|
||||
ApplyBackdrop(windowHandle, backdropType, theme);
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ApplyBackdrop(nint hWnd, WindowBackdropType backdropType = WindowBackdropType.Mica, ApplicationTheme theme = ApplicationTheme.Unknown)
|
||||
{
|
||||
if (!IsSupported(backdropType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hWnd == 0x00 || !User32.IsWindow(hWnd))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (backdropType != WindowBackdropType.Auto)
|
||||
{
|
||||
WindowDarkMode.RemoveBackground(hWnd);
|
||||
}
|
||||
|
||||
switch (theme)
|
||||
{
|
||||
case ApplicationTheme.Unknown:
|
||||
if (ApplicationThemeManager.GetAppTheme() == ApplicationTheme.Dark)
|
||||
{
|
||||
WindowDarkMode.ApplyWindowDarkMode(hWnd);
|
||||
}
|
||||
break;
|
||||
|
||||
case ApplicationTheme.Dark:
|
||||
WindowDarkMode.ApplyWindowDarkMode(hWnd);
|
||||
break;
|
||||
|
||||
case ApplicationTheme.Light:
|
||||
case ApplicationTheme.HighContrast:
|
||||
WindowDarkMode.RemoveWindowDarkMode(hWnd);
|
||||
break;
|
||||
}
|
||||
|
||||
var wtaOptions = new UxTheme.WTA_OPTIONS()
|
||||
{
|
||||
Flags = UxTheme.WTNCA.WTNCA_NODRAWCAPTION,
|
||||
Mask = (uint)UxTheme.ThemeDialogTextureFlags.ETDT_VALIDBITS,
|
||||
};
|
||||
|
||||
UxTheme.SetWindowThemeAttribute(
|
||||
hWnd,
|
||||
UxTheme.WINDOWTHEMEATTRIBUTETYPE.WTA_NONCLIENT,
|
||||
wtaOptions,
|
||||
(uint)Marshal.SizeOf(typeof(UxTheme.WTA_OPTIONS))
|
||||
);
|
||||
|
||||
var dwmApiResult = DwmApi.DwmSetWindowAttribute(
|
||||
hWnd,
|
||||
DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE,
|
||||
(int)(backdropType switch
|
||||
{
|
||||
WindowBackdropType.Auto => DwmApi.DWM_SYSTEMBACKDROP_TYPE.DWMSBT_AUTO,
|
||||
WindowBackdropType.Mica => DwmApi.DWM_SYSTEMBACKDROP_TYPE.DWMSBT_MAINWINDOW,
|
||||
WindowBackdropType.Acrylic => DwmApi.DWM_SYSTEMBACKDROP_TYPE.DWMSBT_TRANSIENTWINDOW,
|
||||
WindowBackdropType.Tabbed => DwmApi.DWM_SYSTEMBACKDROP_TYPE.DWMSBT_TABBEDWINDOW,
|
||||
_ => DwmApi.DWM_SYSTEMBACKDROP_TYPE.DWMSBT_NONE,
|
||||
}),
|
||||
Marshal.SizeOf(typeof(int))
|
||||
);
|
||||
|
||||
return dwmApiResult == HRESULT.S_OK;
|
||||
}
|
||||
|
||||
public static bool RemoveBackdrop(Window window)
|
||||
{
|
||||
if (window == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
nint hWnd = new WindowInteropHelper(window).Handle;
|
||||
|
||||
return RemoveBackdrop(hWnd);
|
||||
}
|
||||
|
||||
public static bool RemoveBackdrop(nint hWnd)
|
||||
{
|
||||
if (hWnd == 0x00 || !User32.IsWindow(hWnd))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var windowSource = HwndSource.FromHwnd(hWnd);
|
||||
|
||||
if (windowSource?.Handle.ToInt32() != 0x00 && windowSource?.CompositionTarget != null)
|
||||
{
|
||||
windowSource.CompositionTarget.BackgroundColor = SystemColors.WindowColor;
|
||||
}
|
||||
|
||||
if (windowSource?.RootVisual is Window window)
|
||||
{
|
||||
var backgroundBrush = window.Resources["ApplicationBackgroundBrush"];
|
||||
|
||||
if (backgroundBrush is not SolidColorBrush)
|
||||
{
|
||||
backgroundBrush = ApplicationThemeManager.GetAppTheme() == ApplicationTheme.Dark
|
||||
? new SolidColorBrush(Color.FromArgb(0xFF, 0x20, 0x20, 0x20))
|
||||
: new SolidColorBrush(Color.FromArgb(0xFF, 0xFA, 0xFA, 0xFA));
|
||||
}
|
||||
|
||||
window.Background = (SolidColorBrush)backgroundBrush;
|
||||
}
|
||||
|
||||
_ = DwmApi.DwmSetWindowAttribute(
|
||||
hWnd,
|
||||
DWMWINDOWATTRIBUTE.DWMWA_MICA_EFFECT,
|
||||
0x0,
|
||||
Marshal.SizeOf(typeof(int))
|
||||
);
|
||||
|
||||
_ = DwmApi.DwmSetWindowAttribute(
|
||||
hWnd,
|
||||
DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE,
|
||||
(int)DwmApi.DWM_SYSTEMBACKDROP_TYPE.DWMSBT_NONE,
|
||||
Marshal.SizeOf(typeof(int))
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
100
Build/MicaSetup/Design/Controls/Window/WindowDarkMode.cs
Normal file
100
Build/MicaSetup/Design/Controls/Window/WindowDarkMode.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using MicaSetup.Helper;
|
||||
using MicaSetup.Natives;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public static class WindowDarkMode
|
||||
{
|
||||
public static bool ApplyWindowDarkMode(nint hWnd)
|
||||
{
|
||||
if (hWnd == 0x00 || !User32.IsWindow(hWnd))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var dwAttribute = DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE;
|
||||
|
||||
if (!OsVersionHelper.IsWindows11_22523_OrGreater)
|
||||
{
|
||||
dwAttribute = DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE_OLD;
|
||||
}
|
||||
|
||||
_ = DwmApi.DwmSetWindowAttribute(
|
||||
hWnd,
|
||||
dwAttribute,
|
||||
0x1,
|
||||
Marshal.SizeOf(typeof(int))
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool RemoveWindowDarkMode(nint handle)
|
||||
{
|
||||
if (handle == 0x00 || !User32.IsWindow(handle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var dwAttribute = DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE;
|
||||
|
||||
if (!OsVersionHelper.IsWindows11_22523_OrGreater)
|
||||
{
|
||||
dwAttribute = DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE_OLD;
|
||||
}
|
||||
|
||||
_ = DwmApi.DwmSetWindowAttribute(
|
||||
handle,
|
||||
dwAttribute,
|
||||
0x0,
|
||||
Marshal.SizeOf(typeof(int))
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool RemoveBackground(nint hWnd)
|
||||
{
|
||||
if (hWnd == 0x00 || !User32.IsWindow(hWnd))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var windowSource = HwndSource.FromHwnd(hWnd);
|
||||
|
||||
if (windowSource?.RootVisual is Window window)
|
||||
{
|
||||
return RemoveBackground(window);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool RemoveBackground(Window window)
|
||||
{
|
||||
if (window == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
window.Background = Brushes.Transparent;
|
||||
|
||||
nint windowHandle = new WindowInteropHelper(window).Handle;
|
||||
|
||||
if (windowHandle == 0x00)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var windowSource = HwndSource.FromHwnd(windowHandle);
|
||||
|
||||
if (windowSource?.Handle.ToInt32() != 0x00 && windowSource?.CompositionTarget != null)
|
||||
{
|
||||
windowSource.CompositionTarget.BackgroundColor = Colors.Transparent;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public static class WindowExtension
|
||||
{
|
||||
//public static void EnableBackdrop(this Window window, BackdropType backdropType = BackdropType.Mica)
|
||||
//{
|
||||
// ThemeService.Current.EnableBackdrop(window, backdropType);
|
||||
//}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
using MicaSetup.Helper;
|
||||
using MicaSetup.Natives;
|
||||
using System.Security;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
internal static class WindowSystemCommands
|
||||
{
|
||||
[SecuritySafeCritical]
|
||||
public static void ShowSystemMenu(Window window, Point? screenLocation = null!)
|
||||
{
|
||||
if (screenLocation == null)
|
||||
{
|
||||
if (User32.GetCursorPos(out POINT pt))
|
||||
{
|
||||
SystemCommands.ShowSystemMenu(window, new Point(DpiHelper.CalcDPiX(pt.X), DpiHelper.CalcDPiY(pt.Y)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SystemCommands.ShowSystemMenu(window, new Point(DpiHelper.CalcDPiX(screenLocation.Value.X), DpiHelper.CalcDPiY(screenLocation.Value.Y)));
|
||||
}
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
public static void CloseWindow(Window window)
|
||||
{
|
||||
SystemCommands.CloseWindow(window);
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
public static void MaximizeWindow(Window window)
|
||||
{
|
||||
SystemCommands.MaximizeWindow(window);
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
public static void MinimizeWindow(Window window)
|
||||
{
|
||||
SystemCommands.MinimizeWindow(window);
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
public static void RestoreWindow(Window window)
|
||||
{
|
||||
SystemCommands.RestoreWindow(window);
|
||||
window.WindowStyle = WindowStyle.SingleBorderWindow;
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
public static void FastRestoreWindow(Window window, bool force = false)
|
||||
{
|
||||
_ = User32.PostMessage(new WindowInteropHelper(window).Handle, (int)User32.WindowMessage.WM_NCLBUTTONDOWN, (int)User32.HitTestValues.HTCAPTION, 0);
|
||||
window.WindowStyle = WindowStyle.SingleBorderWindow;
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
public static void MaximizeOrRestoreWindow(Window window)
|
||||
{
|
||||
if (window.WindowState == WindowState.Maximized)
|
||||
{
|
||||
RestoreWindow(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
MaximizeWindow(window);
|
||||
}
|
||||
}
|
||||
}
|
149
Build/MicaSetup/Design/Controls/Window/WindowX.cs
Normal file
149
Build/MicaSetup/Design/Controls/Window/WindowX.cs
Normal file
@ -0,0 +1,149 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using MicaSetup.Natives;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Shell;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
[INotifyPropertyChanged]
|
||||
public partial class WindowX : Window
|
||||
{
|
||||
public HwndSource? HwndSource { get; private set; }
|
||||
public nint? Handle { get; private set; }
|
||||
public SnapLayout SnapLayout { get; } = new();
|
||||
|
||||
public bool IsActivated
|
||||
{
|
||||
get => (bool)GetValue(IsActivatedProperty);
|
||||
set => SetValue(IsActivatedProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsActivatedProperty = DependencyProperty.Register(nameof(IsActivated), typeof(bool), typeof(WindowX), new PropertyMetadata(false));
|
||||
|
||||
public WindowX()
|
||||
{
|
||||
Loaded += (s, e) =>
|
||||
{
|
||||
HwndSource = (PresentationSource.FromVisual(this) as HwndSource)!;
|
||||
HwndSource.AddHook(new HwndSourceHook(WndProc));
|
||||
Handle = new WindowInteropHelper(this).Handle;
|
||||
|
||||
if (GetTemplateChild("PART_BtnMaximize") is Button buttonMaximize)
|
||||
{
|
||||
if (SnapLayout.IsSupported)
|
||||
{
|
||||
SnapLayout.Register(buttonMaximize);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected private virtual nint WndProc(nint hWnd, int msg, nint wParam, nint lParam, ref bool handled)
|
||||
{
|
||||
return SnapLayout.WndProc(hWnd, msg, wParam, lParam, ref handled);
|
||||
}
|
||||
|
||||
protected override void OnActivated(EventArgs e)
|
||||
{
|
||||
IsActivated = true;
|
||||
_ = WindowBackdrop.ApplyBackdrop(this, WindowBackdropType.Mica, ThemeService.Current.CurrentTheme switch
|
||||
{
|
||||
WindowsTheme.Dark => ApplicationTheme.Dark,
|
||||
WindowsTheme.Light => ApplicationTheme.Light,
|
||||
WindowsTheme.Auto or _ => ApplicationTheme.Unknown,
|
||||
});
|
||||
base.OnActivated(e);
|
||||
}
|
||||
|
||||
protected override void OnDeactivated(EventArgs e)
|
||||
{
|
||||
IsActivated = false;
|
||||
base.OnDeactivated(e);
|
||||
}
|
||||
|
||||
protected override void OnSourceInitialized(EventArgs e)
|
||||
{
|
||||
base.OnSourceInitialized(e);
|
||||
WindowBackdrop.ApplyBackdrop(this, WindowBackdropType.None, ApplicationTheme.Unknown);
|
||||
NativeMethods.HideAllWindowButton(new WindowInteropHelper(this).Handle);
|
||||
}
|
||||
|
||||
public override void EndInit()
|
||||
{
|
||||
ApplyResizeBorderThickness(WindowState);
|
||||
base.EndInit();
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.Property.Name is nameof(WindowState))
|
||||
{
|
||||
ApplyResizeBorderThickness((WindowState)e.NewValue);
|
||||
}
|
||||
base.OnPropertyChanged(e);
|
||||
}
|
||||
|
||||
private void ApplyResizeBorderThickness(WindowState windowsState)
|
||||
{
|
||||
if (windowsState == WindowState.Maximized || ResizeMode == ResizeMode.NoResize || ResizeMode == ResizeMode.CanMinimize)
|
||||
{
|
||||
WindowChrome.SetWindowChrome(this, new WindowChrome()
|
||||
{
|
||||
CaptionHeight = 0d,
|
||||
CornerRadius = new CornerRadius(8d),
|
||||
GlassFrameThickness = new Thickness(-1d),
|
||||
ResizeBorderThickness = new Thickness(0d),
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowChrome.SetWindowChrome(this, new WindowChrome()
|
||||
{
|
||||
CaptionHeight = 0d,
|
||||
CornerRadius = new CornerRadius(8d),
|
||||
GlassFrameThickness = new Thickness(-1d),
|
||||
ResizeBorderThickness = new Thickness(3d),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CloseWindow()
|
||||
{
|
||||
WindowSystemCommands.CloseWindow(this);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void MinimizeWindow()
|
||||
{
|
||||
WindowSystemCommands.MinimizeWindow(this);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void MaximizeWindow()
|
||||
{
|
||||
WindowSystemCommands.MaximizeWindow(this);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void RestoreWindow()
|
||||
{
|
||||
WindowSystemCommands.RestoreWindow(this);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void MaximizeOrRestoreWindow()
|
||||
{
|
||||
WindowSystemCommands.MaximizeOrRestoreWindow(this);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ShowSystemMenu()
|
||||
{
|
||||
WindowSystemCommands.ShowSystemMenu(this);
|
||||
}
|
||||
}
|
370
Build/MicaSetup/Design/Controls/Window/WindowX.xaml
Normal file
370
Build/MicaSetup/Design/Controls/Window/WindowX.xaml
Normal file
@ -0,0 +1,370 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:conv="clr-namespace:MicaSetup.Design.Converters"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:local="clr-namespace:MicaSetup.Design.Controls"
|
||||
xmlns:markups="clr-namespace:MicaSetup.Design.Markups">
|
||||
|
||||
<Color x:Key="SystemAltHighColor">#FF000000</Color>
|
||||
<Color x:Key="SystemAltLowColor">#33000000</Color>
|
||||
<Color x:Key="SystemAltMediumColor">#99000000</Color>
|
||||
<Color x:Key="SystemAltMediumHighColor">#CC000000</Color>
|
||||
<Color x:Key="SystemAltMediumLowColor">#66000000</Color>
|
||||
<Color x:Key="SystemBaseHighColor">#FFFFFFFF</Color>
|
||||
<Color x:Key="SystemBaseLowColor">#33FFFFFF</Color>
|
||||
<Color x:Key="SystemBaseMediumColor">#99FFFFFF</Color>
|
||||
<Color x:Key="SystemBaseMediumHighColor">#CCFFFFFF</Color>
|
||||
<Color x:Key="SystemBaseMediumLowColor">#66FFFFFF</Color>
|
||||
<Color x:Key="SystemChromeAltLowColor">#FFF2F2F2</Color>
|
||||
<Color x:Key="SystemChromeBlackHighColor">#FF000000</Color>
|
||||
<Color x:Key="SystemChromeBlackLowColor">#33000000</Color>
|
||||
<Color x:Key="SystemChromeBlackMediumLowColor">#66000000</Color>
|
||||
<Color x:Key="SystemChromeBlackMediumColor">#CC000000</Color>
|
||||
<Color x:Key="SystemChromeDisabledHighColor">#FF333333</Color>
|
||||
<Color x:Key="SystemChromeDisabledLowColor">#FF858585</Color>
|
||||
<Color x:Key="SystemChromeHighColor">#FF767676</Color>
|
||||
<Color x:Key="SystemChromeLowColor">#FF171717</Color>
|
||||
<Color x:Key="SystemChromeMediumColor">#FF1F1F1F</Color>
|
||||
<Color x:Key="SystemChromeMediumHighColor">#FF323232</Color>
|
||||
<Color x:Key="SystemChromeMediumLowColor">#FF2B2B2B</Color>
|
||||
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
||||
<Color x:Key="SystemChromeGrayColor">#FF767676</Color>
|
||||
<Color x:Key="SystemListLowColor">#19FFFFFF</Color>
|
||||
<Color x:Key="SystemListMediumColor">#33FFFFFF</Color>
|
||||
<Color x:Key="SystemErrorTextColor">#FFF000</Color>
|
||||
|
||||
<SolidColorBrush x:Key="ButtonBackground" Color="{StaticResource SystemBaseLowColor}" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
|
||||
Opacity="0.1"
|
||||
Color="{StaticResource SystemBaseHighColor}" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPressed" Color="{StaticResource SystemBaseMediumLowColor}" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundDisabled" Color="{StaticResource SystemBaseLowColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForeground" Color="{StaticResource SystemBaseHighColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPointerOver" Color="{StaticResource SystemBaseHighColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPressed" Color="{StaticResource SystemBaseHighColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundDisabled" Color="{StaticResource SystemBaseMediumLowColor}" />
|
||||
<SolidColorBrush x:Key="ButtonBorderBrush" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="ButtonBorderBrushPointerOver" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="ButtonBorderBrushPressed" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="ButtonBorderBrushDisabled" Color="Transparent" />
|
||||
|
||||
<conv:AddConverter x:Key="AddConverter" />
|
||||
<conv:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
||||
<conv:BoolNegationConverter x:Key="BoolNegationConverter" />
|
||||
<conv:NullToBoolConverter x:Key="NullToBoolConverter" />
|
||||
<conv:NullToBoolConverter x:Key="NullToBoolInvertedConverter" IsInverted="True" />
|
||||
|
||||
<Style x:Key="DefaultWindowXStyle" TargetType="{x:Type local:WindowX}">
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
|
||||
<Setter Property="BorderBrush" Value="#313A4C" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Background" Value="White" />
|
||||
<Setter Property="local:WindowXCaption.Background" Value="Transparent" />
|
||||
<Setter Property="local:WindowXCaption.Foreground">
|
||||
<Setter.Value>
|
||||
<SolidColorBrush Color="{DynamicResource TextFillColorPrimary}" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="local:WindowXCaption.Height" Value="36" />
|
||||
<Setter Property="WindowChrome.WindowChrome">
|
||||
<Setter.Value>
|
||||
<WindowChrome CaptionHeight="0"
|
||||
CornerRadius="8"
|
||||
GlassFrameThickness="-1"
|
||||
NonClientFrameEdges="None"
|
||||
ResizeBorderThickness="3"
|
||||
UseAeroCaptionButtons="False" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type local:WindowX}">
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}">
|
||||
<Grid x:Name="PART_GrdMain">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid x:Name="PART_GrdCaption"
|
||||
Height="{Binding Path=(local:WindowXCaption.Height), RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
Background="{Binding Path=(local:WindowXCaption.Background), RelativeSource={RelativeSource AncestorType=Window}}">
|
||||
<i:Interaction.Behaviors>
|
||||
<local:WindowTitleHeaderBehavior />
|
||||
</i:Interaction.Behaviors>
|
||||
<Grid Margin="{Binding Path=(local:WindowXCaption.Padding), RelativeSource={RelativeSource AncestorType=Window}}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel x:Name="PART_StkTitle"
|
||||
VerticalAlignment="Stretch"
|
||||
Orientation="Horizontal">
|
||||
<Image x:Name="PART_ImgIcon"
|
||||
Width="{TemplateBinding FontSize,
|
||||
Converter={StaticResource AddConverter},
|
||||
ConverterParameter={markups:Double Value=5}}"
|
||||
Height="{TemplateBinding FontSize,
|
||||
Converter={StaticResource AddConverter},
|
||||
ConverterParameter={markups:Double Value=5}}"
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
RenderOptions.BitmapScalingMode="HighQuality"
|
||||
Source="{Binding Path=Icon, RelativeSource={RelativeSource AncestorType=Window}}">
|
||||
<i:Interaction.Behaviors>
|
||||
<local:WindowTitleIconBehavior />
|
||||
</i:Interaction.Behaviors>
|
||||
<Image.Style>
|
||||
<Style TargetType="{x:Type Image}">
|
||||
<Style.Triggers />
|
||||
</Style>
|
||||
</Image.Style>
|
||||
</Image>
|
||||
<TextBlock x:Name="PART_TxtTitle"
|
||||
Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{Binding Path=(local:WindowXCaption.Foreground), RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
Text="{TemplateBinding Title}" />
|
||||
</StackPanel>
|
||||
<ContentControl x:Name="PART_CpHeader"
|
||||
Content="{Binding Path=(local:WindowXCaption.Header), RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
TextBlock.Foreground="{Binding Path=(local:WindowXCaption.Foreground), RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
TextElement.Foreground="{Binding Path=(local:WindowXCaption.Foreground), RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
Visibility="Visible" />
|
||||
<ContentControl x:Name="PART_CcExtend"
|
||||
Grid.Column="1"
|
||||
Content="{Binding Path=(local:WindowXCaption.ExtendControl), RelativeSource={RelativeSource AncestorType=Window}}" />
|
||||
<Button x:Name="PART_BtnMinimize"
|
||||
Grid.Column="3"
|
||||
Command="{Binding MinimizeWindowCommand, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
CommandParameter="{Binding RelativeSource={x:Static RelativeSource.TemplatedParent}}"
|
||||
Style="{Binding Path=(local:WindowXCaption.MinimizeButtonStyle), RelativeSource={RelativeSource AncestorType=Window}}" />
|
||||
<Button x:Name="PART_BtnMaximize"
|
||||
Grid.Column="4"
|
||||
Command="{Binding MaximizeOrRestoreWindowCommand, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
CommandParameter="{Binding RelativeSource={x:Static RelativeSource.TemplatedParent}}"
|
||||
Style="{Binding Path=(local:WindowXCaption.MaximizeButtonStyle), RelativeSource={RelativeSource AncestorType=Window}}" />
|
||||
<Button x:Name="PART_BtnClose"
|
||||
Grid.Column="5"
|
||||
Command="{Binding CloseWindowCommand, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
CommandParameter="{Binding RelativeSource={x:Static RelativeSource.TemplatedParent}}"
|
||||
IsEnabled="{Binding Path=(local:WindowXCaption.DisableCloseButton), RelativeSource={RelativeSource AncestorType=Window}, Converter={StaticResource BoolNegationConverter}}"
|
||||
Style="{Binding Path=(local:WindowXCaption.CloseButtonStyle), RelativeSource={RelativeSource AncestorType=Window}}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<AdornerDecorator Grid.Row="1" Panel.ZIndex="-1">
|
||||
<ContentPresenter />
|
||||
</AdornerDecorator>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="ResizeMode" Value="NoResize">
|
||||
<Setter TargetName="PART_BtnMinimize" Property="Visibility" Value="Collapsed" />
|
||||
<Setter TargetName="PART_BtnMaximize" Property="Visibility" Value="Collapsed" />
|
||||
</Trigger>
|
||||
<Trigger Property="ResizeMode" Value="CanMinimize">
|
||||
<Setter TargetName="PART_BtnMaximize" Property="Visibility" Value="Collapsed" />
|
||||
</Trigger>
|
||||
<Trigger Property="WindowState" Value="Maximized">
|
||||
<Setter TargetName="PART_GrdMain" Property="Margin" Value="5" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsActivated" Value="false">
|
||||
<Setter TargetName="PART_TxtTitle" Property="Opacity" Value="0.9" />
|
||||
</Trigger>
|
||||
<DataTrigger Binding="{Binding Path=(local:WindowXCaption.Icon), RelativeSource={RelativeSource Self}, Mode=OneWay, Converter={StaticResource NullToBoolConverter}}" Value="True">
|
||||
<Setter TargetName="PART_ImgIcon" Property="Source" Value="{Binding Path=Icon, RelativeSource={RelativeSource AncestorType=Window}}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=(local:WindowXCaption.Icon), RelativeSource={RelativeSource Self}, Mode=OneWay, Converter={StaticResource NullToBoolInvertedConverter}}" Value="True">
|
||||
<Setter TargetName="PART_ImgIcon" Property="Source" Value="{Binding Path=(local:WindowXCaption.Icon), RelativeSource={RelativeSource AncestorType=Window}}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Icon, RelativeSource={RelativeSource Self}, Mode=OneWay, Converter={StaticResource NullToBoolConverter}}" Value="True">
|
||||
<Setter TargetName="PART_ImgIcon" Property="Visibility" Value="Collapsed" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=(local:WindowXCaption.Header), RelativeSource={RelativeSource Self}, Mode=OneWay, Converter={StaticResource NullToBoolInvertedConverter}}" Value="True">
|
||||
<Setter TargetName="PART_StkTitle" Property="Visibility" Value="Collapsed" />
|
||||
<Setter TargetName="PART_CpHeader" Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=(local:WindowXCaption.HideBasicButtons), RelativeSource={RelativeSource Self}, Mode=OneWay}" Value="True">
|
||||
<Setter TargetName="PART_BtnMinimize" Property="Visibility" Value="Collapsed" />
|
||||
<Setter TargetName="PART_BtnMaximize" Property="Visibility" Value="Collapsed" />
|
||||
<Setter TargetName="PART_BtnClose" Property="Visibility" Value="Collapsed" />
|
||||
</DataTrigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="local:WindowXCaption.MaximizeButtonStyle">
|
||||
<Setter.Value>
|
||||
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">
|
||||
<Setter Property="Background" Value="{Binding Path=(local:WindowXCaption.Background), RelativeSource={RelativeSource AncestorType=Window}}" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Height" Value="35" />
|
||||
<Setter Property="Width" Value="{Binding ActualHeight, Converter={StaticResource AddConverter}, ConverterParameter={markups:Double Value=10}, RelativeSource={RelativeSource Self}}" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="FontSize" Value="20" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border x:Name="border"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
SnapsToDevicePixels="true">
|
||||
<Path Width="10"
|
||||
Height="10"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Data="M0.025 0 L0.975 0 M0.025 1 L0.975 1 M1 0.975 L1 0.025 M0 0.025 L0 0.975"
|
||||
Stretch="Uniform"
|
||||
StrokeThickness="1">
|
||||
<Path.Stroke>
|
||||
<SolidColorBrush Color="{DynamicResource TextFillColorPrimary}" />
|
||||
</Path.Stroke>
|
||||
<i:Interaction.Behaviors>
|
||||
<local:WindowRestorePathBehavior />
|
||||
</i:Interaction.Behaviors>
|
||||
</Path>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPointerOver}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPointerOver}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPointerOver}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPressed}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="local:WindowXCaption.MinimizeButtonStyle">
|
||||
<Setter.Value>
|
||||
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border x:Name="border"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
SnapsToDevicePixels="true">
|
||||
<Path Width="10"
|
||||
Height="10"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Data="M1 0.5 L0 0.5"
|
||||
Stretch="Uniform"
|
||||
StrokeThickness="1">
|
||||
<Path.Stroke>
|
||||
<SolidColorBrush Color="{DynamicResource TextFillColorPrimary}" />
|
||||
</Path.Stroke>
|
||||
</Path>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<SolidColorBrush Color="{DynamicResource WindowControlButtonColorDefault}" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPointerOver}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPointerOver}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPressed}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Height" Value="35" />
|
||||
<Setter Property="Width" Value="{Binding ActualHeight, Converter={StaticResource AddConverter}, ConverterParameter={markups:Double Value=10}, RelativeSource={RelativeSource Self}}" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="FontSize" Value="20" />
|
||||
<Setter Property="Background" Value="{Binding Path=(local:WindowXCaption.Background), RelativeSource={RelativeSource AncestorType=Window}}" />
|
||||
</Style>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="local:WindowXCaption.CloseButtonStyle">
|
||||
<Setter.Value>
|
||||
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">
|
||||
<Setter Property="Background" Value="{Binding Path=(local:WindowXCaption.Background), RelativeSource={RelativeSource AncestorType=Window}}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border x:Name="border"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
SnapsToDevicePixels="true">
|
||||
<Path x:Name="borderPath"
|
||||
Width="10"
|
||||
Height="10"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Data="M0,0 L1,1 M0,1 L1,0"
|
||||
Stretch="Uniform"
|
||||
StrokeThickness="1">
|
||||
<Path.Stroke>
|
||||
<SolidColorBrush Color="{DynamicResource TextFillColorPrimary}" />
|
||||
</Path.Stroke>
|
||||
</Path>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#CCC53434" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPointerOver}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" />
|
||||
<Setter TargetName="borderPath" Property="Stroke" Value="White" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#DE6D6C" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPressed}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Height" Value="35" />
|
||||
<Setter Property="Width" Value="{Binding ActualHeight, Converter={StaticResource AddConverter}, ConverterParameter={markups:Double Value=10}, RelativeSource={RelativeSource Self}}" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="FontSize" Value="20" />
|
||||
</Style>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style BasedOn="{StaticResource DefaultWindowXStyle}" TargetType="{x:Type local:WindowX}" />
|
||||
|
||||
</ResourceDictionary>
|
189
Build/MicaSetup/Design/Controls/Window/WindowXCaption.cs
Normal file
189
Build/MicaSetup/Design/Controls/Window/WindowXCaption.cs
Normal file
@ -0,0 +1,189 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public sealed class WindowXCaption
|
||||
{
|
||||
public static ImageSource GetIcon(DependencyObject obj)
|
||||
{
|
||||
return (ImageSource)obj.GetValue(IconProperty);
|
||||
}
|
||||
|
||||
public static void SetIcon(DependencyObject obj, ImageSource value)
|
||||
{
|
||||
obj.SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IconProperty =
|
||||
DependencyProperty.RegisterAttached("Icon", typeof(ImageSource), typeof(WindowXCaption));
|
||||
|
||||
public static Thickness GetPadding(DependencyObject obj)
|
||||
{
|
||||
return (Thickness)obj.GetValue(PaddingProperty);
|
||||
}
|
||||
|
||||
public static void SetPadding(DependencyObject obj, Thickness value)
|
||||
{
|
||||
obj.SetValue(PaddingProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty PaddingProperty =
|
||||
DependencyProperty.RegisterAttached("Padding", typeof(Thickness), typeof(WindowXCaption));
|
||||
|
||||
public static double GetHeight(DependencyObject obj)
|
||||
{
|
||||
return (double)obj.GetValue(HeightProperty);
|
||||
}
|
||||
|
||||
public static void SetHeight(DependencyObject obj, double value)
|
||||
{
|
||||
obj.SetValue(HeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty HeightProperty =
|
||||
DependencyProperty.RegisterAttached("Height", typeof(double), typeof(WindowXCaption));
|
||||
|
||||
public static Brush GetForeground(DependencyObject obj)
|
||||
{
|
||||
return (Brush)obj.GetValue(ForegroundProperty);
|
||||
}
|
||||
|
||||
public static void SetForeground(DependencyObject obj, Brush value)
|
||||
{
|
||||
obj.SetValue(ForegroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ForegroundProperty =
|
||||
DependencyProperty.RegisterAttached("Foreground", typeof(Brush), typeof(WindowXCaption));
|
||||
|
||||
public static Brush GetBackground(DependencyObject obj)
|
||||
{
|
||||
return (Brush)obj.GetValue(BackgroundProperty);
|
||||
}
|
||||
|
||||
public static void SetBackground(DependencyObject obj, Brush value)
|
||||
{
|
||||
obj.SetValue(BackgroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BackgroundProperty =
|
||||
DependencyProperty.RegisterAttached("Background", typeof(Brush), typeof(WindowXCaption));
|
||||
|
||||
public static Style GetMinimizeButtonStyle(DependencyObject obj)
|
||||
{
|
||||
return (Style)obj.GetValue(MinimizeButtonStyleProperty);
|
||||
}
|
||||
|
||||
public static void SetMinimizeButtonStyle(DependencyObject obj, Style value)
|
||||
{
|
||||
obj.SetValue(MinimizeButtonStyleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MinimizeButtonStyleProperty =
|
||||
DependencyProperty.RegisterAttached("MinimizeButtonStyle", typeof(Style), typeof(WindowXCaption));
|
||||
|
||||
public static Style GetMaximizeButtonStyle(DependencyObject obj)
|
||||
{
|
||||
return (Style)obj.GetValue(MaximizeButtonStyleProperty);
|
||||
}
|
||||
|
||||
public static void SetMaximizeButtonStyle(DependencyObject obj, Style value)
|
||||
{
|
||||
obj.SetValue(MaximizeButtonStyleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaximizeButtonStyleProperty =
|
||||
DependencyProperty.RegisterAttached("MaximizeButtonStyle", typeof(Style), typeof(WindowXCaption));
|
||||
|
||||
public static Style GetCloseButtonStyle(DependencyObject obj)
|
||||
{
|
||||
return (Style)obj.GetValue(CloseButtonStyleProperty);
|
||||
}
|
||||
|
||||
public static void SetCloseButtonStyle(DependencyObject obj, Style value)
|
||||
{
|
||||
obj.SetValue(CloseButtonStyleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CloseButtonStyleProperty =
|
||||
DependencyProperty.RegisterAttached("CloseButtonStyle", typeof(Style), typeof(WindowXCaption));
|
||||
|
||||
public static Style GetFullScreenButtonStyle(DependencyObject obj)
|
||||
{
|
||||
return (Style)obj.GetValue(FullScreenButtonStyleProperty);
|
||||
}
|
||||
|
||||
public static void SetFullScreenButtonStyle(DependencyObject obj, Style value)
|
||||
{
|
||||
obj.SetValue(FullScreenButtonStyleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FullScreenButtonStyleProperty =
|
||||
DependencyProperty.RegisterAttached("FullScreenButtonStyle", typeof(Style), typeof(WindowXCaption));
|
||||
|
||||
public static object GetHeader(DependencyObject obj)
|
||||
{
|
||||
return obj.GetValue(HeaderProperty);
|
||||
}
|
||||
|
||||
public static void SetHeader(DependencyObject obj, object value)
|
||||
{
|
||||
obj.SetValue(HeaderProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty HeaderProperty =
|
||||
DependencyProperty.RegisterAttached("Header", typeof(object), typeof(WindowXCaption));
|
||||
|
||||
public static UIElement GetExtendControl(DependencyObject obj)
|
||||
{
|
||||
return (UIElement)obj.GetValue(ExtendControlProperty);
|
||||
}
|
||||
|
||||
public static void SetExtendControl(DependencyObject obj, UIElement value)
|
||||
{
|
||||
obj.SetValue(ExtendControlProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ExtendControlProperty =
|
||||
DependencyProperty.RegisterAttached("ExtendControl", typeof(UIElement), typeof(WindowXCaption));
|
||||
|
||||
public static bool GetDisableCloseButton(DependencyObject obj)
|
||||
{
|
||||
return (bool)obj.GetValue(DisableCloseButtonProperty);
|
||||
}
|
||||
|
||||
public static void SetDisableCloseButton(DependencyObject obj, bool value)
|
||||
{
|
||||
obj.SetValue(DisableCloseButtonProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DisableCloseButtonProperty =
|
||||
DependencyProperty.RegisterAttached("DisableCloseButton", typeof(bool), typeof(WindowXCaption));
|
||||
|
||||
public static bool GetHideBasicButtons(DependencyObject obj)
|
||||
{
|
||||
return (bool)obj.GetValue(HideBasicButtonsProperty);
|
||||
}
|
||||
|
||||
public static void SetHideBasicButtons(DependencyObject obj, bool value)
|
||||
{
|
||||
obj.SetValue(HideBasicButtonsProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty HideBasicButtonsProperty =
|
||||
DependencyProperty.RegisterAttached("HideBasicButtons", typeof(bool), typeof(WindowXCaption));
|
||||
|
||||
public static bool GetShowFullScreenButton(DependencyObject obj)
|
||||
{
|
||||
return (bool)obj.GetValue(ShowFullScreenButtonProperty);
|
||||
}
|
||||
|
||||
public static void SetShowFullScreenButton(DependencyObject obj, bool value)
|
||||
{
|
||||
obj.SetValue(ShowFullScreenButtonProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowFullScreenButtonProperty =
|
||||
DependencyProperty.RegisterAttached("ShowFullScreenButton", typeof(bool), typeof(WindowXCaption), new(false));
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
public abstract class BoolToValueConverterBase<T, TConverter> : SingletonConverterBase<TConverter> where TConverter : new()
|
||||
{
|
||||
public abstract T TrueValue { get; set; }
|
||||
|
||||
public abstract T FalseValue { get; set; }
|
||||
|
||||
public abstract bool IsInverted { get; set; }
|
||||
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var returnValue = this.FalseValue;
|
||||
|
||||
if (value is bool boolValue)
|
||||
{
|
||||
if (this.IsInverted)
|
||||
{
|
||||
returnValue = boolValue ? this.FalseValue : this.TrueValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
returnValue = boolValue ? this.TrueValue : this.FalseValue;
|
||||
}
|
||||
}
|
||||
|
||||
return returnValue!;
|
||||
}
|
||||
|
||||
protected override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
bool returnValue = false;
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
if (this.IsInverted)
|
||||
{
|
||||
returnValue = value.Equals(this.FalseValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
returnValue = value.Equals(this.TrueValue);
|
||||
}
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
public abstract class ConverterBase : DependencyObject, IValueConverter
|
||||
{
|
||||
public PreferredCulture PreferredCulture { get; set; } = ValueConvertersConfig.DefaultPreferredCulture;
|
||||
|
||||
protected abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);
|
||||
|
||||
protected virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException($"Converter '{this.GetType().Name}' does not support backward conversion.");
|
||||
}
|
||||
|
||||
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return this.Convert(value, targetType, parameter, this.SelectCulture(() => culture));
|
||||
}
|
||||
|
||||
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return this.ConvertBack(value, targetType, parameter, this.SelectCulture(() => culture));
|
||||
}
|
||||
|
||||
private CultureInfo SelectCulture(Func<CultureInfo> converterCulture)
|
||||
{
|
||||
return PreferredCulture switch
|
||||
{
|
||||
PreferredCulture.CurrentCulture => CultureInfo.CurrentCulture,
|
||||
PreferredCulture.CurrentUICulture => CultureInfo.CurrentUICulture,
|
||||
_ => converterCulture(),
|
||||
};
|
||||
}
|
||||
|
||||
public static readonly object UnsetValue = DependencyProperty.UnsetValue;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
public enum PreferredCulture
|
||||
{
|
||||
/// <summary>
|
||||
/// Uses the default culture provided by <seealso cref="IValueConverter"/>.
|
||||
/// </summary>
|
||||
ConverterCulture,
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the default converter culture with <seealso cref="CultureInfo.CurrentCulture"/>.
|
||||
/// </summary>
|
||||
CurrentCulture,
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the default converter culture with <seealso cref="CultureInfo.CurrentUICulture"/>.
|
||||
/// </summary>
|
||||
CurrentUICulture,
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
using System.Windows;
|
||||
using Property = System.Windows.DependencyProperty;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
#pragma warning disable WPF0011
|
||||
#pragma warning disable WPF0015
|
||||
|
||||
internal static class PropertyHelper
|
||||
{
|
||||
public static Property Create<T, TParent>(string name, T defaultValue) =>
|
||||
Property.Register(name, typeof(T), typeof(TParent), new PropertyMetadata(defaultValue));
|
||||
|
||||
public static Property Create<T, TParent>(string name) => Create<T, TParent>(name, default!);
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Property = System.Windows.DependencyProperty;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
public abstract class ReversibleValueToBoolConverterBase<T, TConverter> : ValueToBoolConverterBase<T, TConverter>
|
||||
where TConverter : new()
|
||||
{
|
||||
public abstract T FalseValue { get; set; }
|
||||
|
||||
public bool BaseOnFalseValue
|
||||
{
|
||||
get { return (bool)this.GetValue(BaseOnFalseValueProperty); }
|
||||
set { this.SetValue(BaseOnFalseValueProperty, value); }
|
||||
}
|
||||
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (!this.BaseOnFalseValue)
|
||||
{
|
||||
return base.Convert(value, targetType, parameter, culture);
|
||||
}
|
||||
|
||||
var falseValue = this.FalseValue;
|
||||
return !Equals(value, falseValue) ^ this.IsInverted;
|
||||
}
|
||||
|
||||
protected override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return true.Equals(value) ^ this.IsInverted ? this.TrueValue! : this.FalseValue!;
|
||||
}
|
||||
|
||||
public static readonly Property BaseOnFalseValueProperty = PropertyHelper.Create<bool, ValueToBoolConverterBase<T, TConverter>>(nameof(BaseOnFalseValueProperty));
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
public abstract class SingletonConverterBase<TConverter> : ConverterBase
|
||||
where TConverter : new()
|
||||
{
|
||||
private static readonly Lazy<TConverter> InstanceConstructor = new(() =>
|
||||
{
|
||||
return new TConverter();
|
||||
}, LazyThreadSafetyMode.PublicationOnly);
|
||||
|
||||
public static TConverter Instance => InstanceConstructor.Value;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ContentProperty(nameof(Converters))]
|
||||
[ValueConversion(typeof(object), typeof(object))]
|
||||
public class ValueConverterGroup : SingletonConverterBase<ValueConverterGroup>
|
||||
{
|
||||
public List<IValueConverter> Converters { get; set; } = new List<IValueConverter>();
|
||||
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (this.Converters is IEnumerable<IValueConverter> converters)
|
||||
{
|
||||
var language = culture;
|
||||
return converters.Aggregate(value, (current, converter) => converter.Convert(current, targetType, parameter, language));
|
||||
}
|
||||
|
||||
return UnsetValue;
|
||||
}
|
||||
|
||||
protected override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (this.Converters is IEnumerable<IValueConverter> converters)
|
||||
{
|
||||
var language = culture;
|
||||
return converters.Reverse<IValueConverter>().Aggregate(value, (current, converter) => converter.Convert(current, targetType, parameter, language));
|
||||
}
|
||||
|
||||
return UnsetValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
public static class ValueConvertersConfig
|
||||
{
|
||||
public static PreferredCulture DefaultPreferredCulture { get; set; } = PreferredCulture.ConverterCulture;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Property = System.Windows.DependencyProperty;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
public abstract class ValueToBoolConverterBase<T, TConverter> : ConverterBase
|
||||
where TConverter : new()
|
||||
{
|
||||
public abstract T TrueValue { get; set; }
|
||||
|
||||
public bool IsInverted
|
||||
{
|
||||
get { return (bool)this.GetValue(IsInvertedProperty); }
|
||||
set { this.SetValue(IsInvertedProperty, value); }
|
||||
}
|
||||
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var trueValue = this.TrueValue;
|
||||
return Equals(value, trueValue) ^ this.IsInverted;
|
||||
}
|
||||
|
||||
public static readonly Property IsInvertedProperty = PropertyHelper.Create<bool, ValueToBoolConverterBase<T, TConverter>>(nameof(IsInverted));
|
||||
}
|
20
Build/MicaSetup/Design/Converters/AddConverter.cs
Normal file
20
Build/MicaSetup/Design/Converters/AddConverter.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(double), typeof(double))]
|
||||
public class AddConverter : SingletonConverterBase<AddConverter>
|
||||
{
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (double.TryParse(value?.ToString(), NumberStyles.Any, culture, out var basis)
|
||||
&& double.TryParse(parameter?.ToString(), NumberStyles.Any, culture, out var subtract))
|
||||
{
|
||||
return basis + subtract;
|
||||
}
|
||||
|
||||
return UnsetValue;
|
||||
}
|
||||
}
|
8
Build/MicaSetup/Design/Converters/BoolInverter.cs
Normal file
8
Build/MicaSetup/Design/Converters/BoolInverter.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(bool), typeof(bool))]
|
||||
public class BoolInverter : BoolNegationConverter
|
||||
{
|
||||
}
|
14
Build/MicaSetup/Design/Converters/BoolNegationConverter.cs
Normal file
14
Build/MicaSetup/Design/Converters/BoolNegationConverter.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(bool), typeof(bool))]
|
||||
public class BoolNegationConverter : BoolToValueConverter<bool>
|
||||
{
|
||||
public BoolNegationConverter()
|
||||
{
|
||||
this.TrueValue = true;
|
||||
this.FalseValue = false;
|
||||
this.IsInverted = true;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(bool), typeof(Brush))]
|
||||
public class BoolToBrushConverter : BoolToValueConverter<Brush>
|
||||
{
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(bool), typeof(double))]
|
||||
public class BoolToDoubleConverter : BoolToValueConverter<double>
|
||||
{
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(bool), typeof(FontWeight))]
|
||||
public class BoolToFontWeightConverter : BoolToValueConverter<FontWeight>
|
||||
{
|
||||
public BoolToFontWeightConverter()
|
||||
{
|
||||
this.TrueValue = FontWeights.Bold;
|
||||
this.FalseValue = FontWeights.Normal;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(bool), typeof(object))]
|
||||
public class BoolToObjectConverter : BoolToValueConverter<object>
|
||||
{
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(bool), typeof(string))]
|
||||
public class BoolToStringConverter : BoolToValueConverter<string>
|
||||
{
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(bool), typeof(Style))]
|
||||
public class BoolToStyleConverter : BoolToValueConverter<Style>
|
||||
{
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(bool), typeof(Thickness))]
|
||||
public class BoolToThicknessConverter : BoolToValueConverter<Thickness>
|
||||
{
|
||||
}
|
44
Build/MicaSetup/Design/Converters/BoolToValueConverter.cs
Normal file
44
Build/MicaSetup/Design/Converters/BoolToValueConverter.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(bool), typeof(object))]
|
||||
public class BoolToValueConverter<T> : BoolToValueConverterBase<T, BoolToValueConverter<T>>
|
||||
{
|
||||
public static readonly DependencyProperty TrueValueProperty = DependencyProperty.Register(
|
||||
nameof(TrueValue),
|
||||
typeof(T),
|
||||
typeof(BoolToValueConverter<T>),
|
||||
new PropertyMetadata(default(T)));
|
||||
|
||||
public static readonly DependencyProperty FalseValueProperty = DependencyProperty.Register(
|
||||
nameof(FalseValue),
|
||||
typeof(T),
|
||||
typeof(BoolToValueConverter<T>),
|
||||
new PropertyMetadata(default(T)));
|
||||
|
||||
public static readonly DependencyProperty IsInvertedProperty = DependencyProperty.Register(
|
||||
nameof(IsInverted),
|
||||
typeof(bool),
|
||||
typeof(BoolToValueConverter<T>),
|
||||
new PropertyMetadata(false));
|
||||
|
||||
public override T TrueValue
|
||||
{
|
||||
get => (T)this.GetValue(TrueValueProperty);
|
||||
set => this.SetValue(TrueValueProperty, value);
|
||||
}
|
||||
|
||||
public override T FalseValue
|
||||
{
|
||||
get => (T)this.GetValue(FalseValueProperty);
|
||||
set => this.SetValue(FalseValueProperty, value);
|
||||
}
|
||||
|
||||
public override bool IsInverted
|
||||
{
|
||||
get => (bool)this.GetValue(IsInvertedProperty);
|
||||
set => this.SetValue(IsInvertedProperty, value);
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(bool), typeof(Visibility))]
|
||||
public class BoolToVisibilityConverter : BoolToValueConverter<Visibility>
|
||||
{
|
||||
public BoolToVisibilityConverter()
|
||||
{
|
||||
this.TrueValue = Visibility.Visible;
|
||||
this.FalseValue = Visibility.Collapsed;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(string), typeof(SolidColorBrush))]
|
||||
public sealed class ColorToSolidBrushConverter : ConverterBase
|
||||
{
|
||||
public bool Freeze { get; set; } = true;
|
||||
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is Color color)
|
||||
{
|
||||
SolidColorBrush brush = new(color);
|
||||
|
||||
if (Freeze)
|
||||
{
|
||||
brush.Freeze();
|
||||
}
|
||||
return brush;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
protected override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is SolidColorBrush brush)
|
||||
{
|
||||
return brush.Color;
|
||||
}
|
||||
return default(Color);
|
||||
}
|
||||
}
|
31
Build/MicaSetup/Design/Converters/DebugConverter.cs
Normal file
31
Build/MicaSetup/Design/Converters/DebugConverter.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(object), typeof(object))]
|
||||
public class DebugConverter : SingletonConverterBase<DebugConverter>
|
||||
{
|
||||
protected override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
Debug.WriteLine("DebugConverter.Convert(value={0}, targetType={1}, parameter={2}, culture={3}",
|
||||
value ?? "null",
|
||||
(object)targetType ?? "null",
|
||||
parameter ?? "null",
|
||||
(object)culture ?? "null");
|
||||
|
||||
return value!;
|
||||
}
|
||||
|
||||
protected override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
Debug.WriteLine("DebugConverter.ConvertBack(value={0}, targetType={1}, parameter={2}, culture={3}",
|
||||
value ?? "null",
|
||||
(object)targetType ?? "null",
|
||||
parameter ?? "null",
|
||||
(object)culture ?? "null");
|
||||
|
||||
return value!;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(double), typeof(bool))]
|
||||
public class DoubleToBoolConverter : ValueToBoolConverter<double>
|
||||
{
|
||||
}
|
36
Build/MicaSetup/Design/Converters/EnumToBoolConverter.cs
Normal file
36
Build/MicaSetup/Design/Converters/EnumToBoolConverter.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(object), typeof(bool))]
|
||||
public class EnumToBoolConverter : SingletonConverterBase<EnumToBoolConverter>
|
||||
{
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (parameter is string parameterString)
|
||||
{
|
||||
if (Enum.IsDefined(value.GetType(), value) == false)
|
||||
{
|
||||
return UnsetValue;
|
||||
}
|
||||
|
||||
var parameterValue = Enum.Parse(value.GetType(), parameterString);
|
||||
|
||||
return parameterValue.Equals(value);
|
||||
}
|
||||
|
||||
return UnsetValue;
|
||||
}
|
||||
|
||||
protected override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (parameter is string parameterString)
|
||||
{
|
||||
return Enum.Parse(targetType, parameterString);
|
||||
}
|
||||
|
||||
return UnsetValue;
|
||||
}
|
||||
}
|
21
Build/MicaSetup/Design/Converters/EnumToObjectConverter.cs
Normal file
21
Build/MicaSetup/Design/Converters/EnumToObjectConverter.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(object), typeof(object))]
|
||||
public class EnumToObjectConverter : StringToObjectConverter
|
||||
{
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return UnsetValue;
|
||||
}
|
||||
|
||||
var type = value.GetType();
|
||||
var key = Enum.GetName(type, value);
|
||||
return base.Convert(key, targetType, parameter, culture);
|
||||
}
|
||||
}
|
26
Build/MicaSetup/Design/Converters/FirstOrDefaultConverter.cs
Normal file
26
Build/MicaSetup/Design/Converters/FirstOrDefaultConverter.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(IEnumerable), typeof(object))]
|
||||
public class FirstOrDefaultConverter : SingletonConverterBase<FirstOrDefaultConverter>
|
||||
{
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is IEnumerable enumerable)
|
||||
{
|
||||
var enumerator = enumerable.GetEnumerator();
|
||||
{
|
||||
if (enumerator.MoveNext())
|
||||
{
|
||||
return enumerator.Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return UnsetValue;
|
||||
}
|
||||
}
|
23
Build/MicaSetup/Design/Converters/ImageToBitmapConverter.cs
Normal file
23
Build/MicaSetup/Design/Converters/ImageToBitmapConverter.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(Image), typeof(Bitmap))]
|
||||
public sealed class ImageToBitmapConverter : SingletonConverterBase<ImageToBitmapConverter>
|
||||
{
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is Image image)
|
||||
{
|
||||
return new Bitmap(image);
|
||||
}
|
||||
else if (value is Bitmap)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return null!;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(int), typeof(bool))]
|
||||
public class IntegerToBoolConverter : ValueToBoolConverter<int>
|
||||
{
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(bool), typeof(bool))]
|
||||
public class InvertedBoolConverter : BoolNegationConverter
|
||||
{
|
||||
}
|
35
Build/MicaSetup/Design/Converters/IsEmptyConverter.cs
Normal file
35
Build/MicaSetup/Design/Converters/IsEmptyConverter.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(IEnumerable), typeof(bool))]
|
||||
[ValueConversion(typeof(object), typeof(bool))]
|
||||
public class IsEmptyConverter : SingletonConverterBase<IsEmptyConverter>
|
||||
{
|
||||
public static readonly DependencyProperty IsInvertedProperty = DependencyProperty.Register(
|
||||
nameof(IsInverted),
|
||||
typeof(bool),
|
||||
typeof(IsEmptyConverter),
|
||||
new PropertyMetadata(false));
|
||||
|
||||
public bool IsInverted
|
||||
{
|
||||
get => (bool)this.GetValue(IsInvertedProperty);
|
||||
set => this.SetValue(IsInvertedProperty, value);
|
||||
}
|
||||
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is IEnumerable enumerable)
|
||||
{
|
||||
var hasAtLeastOne = enumerable.GetEnumerator().MoveNext();
|
||||
return (hasAtLeastOne == false) ^ this.IsInverted;
|
||||
}
|
||||
|
||||
return true ^ this.IsInverted;
|
||||
}
|
||||
}
|
54
Build/MicaSetup/Design/Converters/MathRoundConverter.cs
Normal file
54
Build/MicaSetup/Design/Converters/MathRoundConverter.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
internal sealed class MathRoundConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
double? valueNullable = default;
|
||||
|
||||
if (value is float @float)
|
||||
{
|
||||
valueNullable = @float;
|
||||
}
|
||||
else if (value is double @double)
|
||||
{
|
||||
valueNullable = @double;
|
||||
}
|
||||
else if (value is int @int)
|
||||
{
|
||||
valueNullable = @int;
|
||||
}
|
||||
|
||||
if (valueNullable != null)
|
||||
{
|
||||
int dec = default;
|
||||
|
||||
if (parameter is null)
|
||||
{
|
||||
dec = default;
|
||||
}
|
||||
else if (parameter is int decFromInt)
|
||||
{
|
||||
dec = decFromInt;
|
||||
}
|
||||
else if (parameter is string decString)
|
||||
{
|
||||
if (int.TryParse(decString, out int decFromString))
|
||||
{
|
||||
dec = decFromString;
|
||||
}
|
||||
}
|
||||
return Math.Round(valueNullable.Value, dec).ToString();
|
||||
}
|
||||
return value?.ToString()!;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
27
Build/MicaSetup/Design/Converters/NullToBoolConverter.cs
Normal file
27
Build/MicaSetup/Design/Converters/NullToBoolConverter.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(object), typeof(bool))]
|
||||
public class NullToBoolConverter : SingletonConverterBase<NullToBoolConverter>
|
||||
{
|
||||
public static readonly DependencyProperty IsInvertedProperty = DependencyProperty.Register(
|
||||
nameof(IsInverted),
|
||||
typeof(bool),
|
||||
typeof(NullToBoolConverter),
|
||||
new PropertyMetadata(false));
|
||||
|
||||
public bool IsInverted
|
||||
{
|
||||
get { return (bool)this.GetValue(IsInvertedProperty); }
|
||||
set { this.SetValue(IsInvertedProperty, value); }
|
||||
}
|
||||
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value == null ^ this.IsInverted;
|
||||
}
|
||||
}
|
40
Build/MicaSetup/Design/Converters/ProgressBarConverter.cs
Normal file
40
Build/MicaSetup/Design/Converters/ProgressBarConverter.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
internal class ProgressBarIndeterminateConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is double @double && @double < 0d)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
internal class ProgressBarValueVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is double @double && @double < 0d)
|
||||
{
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
return Visibility.Visible;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
29
Build/MicaSetup/Design/Converters/StringEqualityConverter.cs
Normal file
29
Build/MicaSetup/Design/Converters/StringEqualityConverter.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(string), typeof(bool))]
|
||||
public sealed class StringEqualityConverter : SingletonConverterBase<StringEqualityConverter>
|
||||
{
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is string inputString)
|
||||
{
|
||||
return inputString == parameter as string;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
protected override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
bool isChecked = (bool)value;
|
||||
|
||||
if (!isChecked)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
return (parameter as string) ?? string.Empty;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(string), typeof(bool))]
|
||||
public class StringIsNotNullOrEmptyConverter : StringIsNullOrEmptyConverter
|
||||
{
|
||||
public StringIsNotNullOrEmptyConverter()
|
||||
{
|
||||
this.IsInverted = true;
|
||||
}
|
||||
}
|
||||
|
||||
[ValueConversion(typeof(string), typeof(bool))]
|
||||
public class StringIsNullOrEmptyConverter : SingletonConverterBase<StringIsNotNullOrEmptyConverter>
|
||||
{
|
||||
public static readonly DependencyProperty IsInvertedProperty = DependencyProperty.Register(
|
||||
nameof(IsInverted),
|
||||
typeof(bool),
|
||||
typeof(StringIsNullOrEmptyConverter),
|
||||
new PropertyMetadata(false));
|
||||
|
||||
public bool IsInverted
|
||||
{
|
||||
get { return (bool)this.GetValue(IsInvertedProperty); }
|
||||
set { this.SetValue(IsInvertedProperty, value); }
|
||||
}
|
||||
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (targetType is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(targetType));
|
||||
}
|
||||
|
||||
if (this.IsInverted)
|
||||
{
|
||||
return !string.IsNullOrEmpty(value as string);
|
||||
}
|
||||
|
||||
return string.IsNullOrEmpty(value as string);
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(string), typeof(bool))]
|
||||
public class StringToBoolConverter : ValueToBoolConverter<string>
|
||||
{
|
||||
}
|
28
Build/MicaSetup/Design/Converters/StringToColorConverter.cs
Normal file
28
Build/MicaSetup/Design/Converters/StringToColorConverter.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(string), typeof(Color))]
|
||||
public sealed class StringToColorConverter : SingletonConverterBase<StringToColorConverter>
|
||||
{
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is string inputString)
|
||||
{
|
||||
return ColorConverter.ConvertFromString(inputString);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
protected override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is Color color)
|
||||
{
|
||||
return $"#{color.R:X2}{color.G:X2}{color.B:X2}";
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(string), typeof(decimal))]
|
||||
public class StringToDecimalConverter : SingletonConverterBase<StringToDecimalConverter>
|
||||
{
|
||||
private static readonly NumberStyles DefaultNumberStyles = NumberStyles.Any;
|
||||
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var dec = value as decimal?;
|
||||
if (dec != null)
|
||||
{
|
||||
return dec.Value.ToString("G", culture ?? CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (value is string str)
|
||||
{
|
||||
if (decimal.TryParse(str, DefaultNumberStyles, culture ?? CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return UnsetValue;
|
||||
}
|
||||
|
||||
protected override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return this.Convert(value, targetType, parameter, culture);
|
||||
}
|
||||
}
|
32
Build/MicaSetup/Design/Converters/StringToObjectConverter.cs
Normal file
32
Build/MicaSetup/Design/Converters/StringToObjectConverter.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(string), typeof(object))]
|
||||
[ContentProperty(nameof(Items))]
|
||||
public class StringToObjectConverter : SingletonConverterBase<StringToObjectConverter>
|
||||
{
|
||||
public ResourceDictionary Items { get; set; } = null!;
|
||||
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is string key)
|
||||
{
|
||||
if (this.Items != null && ContainsKey(this.Items, key))
|
||||
{
|
||||
return this.Items[key];
|
||||
}
|
||||
}
|
||||
|
||||
return UnsetValue;
|
||||
}
|
||||
|
||||
private static bool ContainsKey(ResourceDictionary dict, string key)
|
||||
{
|
||||
return dict.Contains(key);
|
||||
}
|
||||
}
|
20
Build/MicaSetup/Design/Converters/SubtractConverter.cs
Normal file
20
Build/MicaSetup/Design/Converters/SubtractConverter.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(object), typeof(object))]
|
||||
public class SubtractConverter : SingletonConverterBase<SubtractConverter>
|
||||
{
|
||||
protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (double.TryParse(value?.ToString(), NumberStyles.Any, culture, out var basis)
|
||||
&& double.TryParse(parameter?.ToString(), NumberStyles.Any, culture, out var subtract))
|
||||
{
|
||||
return basis - subtract;
|
||||
}
|
||||
|
||||
return UnsetValue;
|
||||
}
|
||||
}
|
31
Build/MicaSetup/Design/Converters/ValueToBoolConverter.cs
Normal file
31
Build/MicaSetup/Design/Converters/ValueToBoolConverter.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System.Windows.Data;
|
||||
using Property = System.Windows.DependencyProperty;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(object), typeof(bool))]
|
||||
public class ValueToBoolConverter<T> : ReversibleValueToBoolConverterBase<T, ValueToBoolConverter<T>>
|
||||
{
|
||||
public override T TrueValue
|
||||
{
|
||||
get => (T)this.GetValue(TrueValueProperty);
|
||||
set => this.SetValue(TrueValueProperty, value);
|
||||
}
|
||||
|
||||
public static readonly Property TrueValueProperty =
|
||||
PropertyHelper.Create<T, ValueToBoolConverter<T>>(nameof(TrueValue));
|
||||
|
||||
public override T FalseValue
|
||||
{
|
||||
get => (T)this.GetValue(FalseValueProperty);
|
||||
set => this.SetValue(FalseValueProperty, value);
|
||||
}
|
||||
|
||||
public static readonly Property FalseValueProperty =
|
||||
PropertyHelper.Create<T, ValueToBoolConverter<T>>(nameof(FalseValue));
|
||||
}
|
||||
|
||||
[ValueConversion(typeof(object), typeof(bool))]
|
||||
public class ValueToBoolConverter : ValueToBoolConverter<object>
|
||||
{
|
||||
}
|
15
Build/MicaSetup/Design/Converters/VisibilityInverter.cs
Normal file
15
Build/MicaSetup/Design/Converters/VisibilityInverter.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MicaSetup.Design.Converters;
|
||||
|
||||
[ValueConversion(typeof(Visibility), typeof(string))]
|
||||
public class VisibilityInverter : BoolToValueConverter<Visibility>
|
||||
{
|
||||
public VisibilityInverter()
|
||||
{
|
||||
this.TrueValue = Visibility.Visible;
|
||||
this.FalseValue = Visibility.Collapsed;
|
||||
this.IsInverted = true;
|
||||
}
|
||||
}
|
12
Build/MicaSetup/Design/GenericResourceDictionary.cs
Normal file
12
Build/MicaSetup/Design/GenericResourceDictionary.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace MicaSetup.Design;
|
||||
|
||||
public sealed class GenericResourceDictionary : ResourceDictionary
|
||||
{
|
||||
public GenericResourceDictionary()
|
||||
{
|
||||
Source = new Uri($"pack://application:,,,/MicaSetup;component/Resources/Generic.xaml");
|
||||
}
|
||||
}
|
22
Build/MicaSetup/Design/Hosts/HostBuilder.cs
Normal file
22
Build/MicaSetup/Design/Hosts/HostBuilder.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
#pragma warning disable CS8618
|
||||
|
||||
public class HostBuilder : IHostBuilder
|
||||
{
|
||||
public IApp App { get; set; }
|
||||
public ServiceProvider ServiceProvider { get; set; }
|
||||
|
||||
public IHostBuilder CreateApp()
|
||||
{
|
||||
App = new App();
|
||||
return this;
|
||||
}
|
||||
|
||||
public void RunApp()
|
||||
{
|
||||
App?.Run();
|
||||
}
|
||||
}
|
168
Build/MicaSetup/Design/Hosts/HostBuilderExtension.cs
Normal file
168
Build/MicaSetup/Design/Hosts/HostBuilderExtension.cs
Normal file
@ -0,0 +1,168 @@
|
||||
using MicaSetup.Helper;
|
||||
using MicaSetup.Natives;
|
||||
using MicaSetup.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
#pragma warning disable IDE0002
|
||||
|
||||
public static class HostBuilderExtension
|
||||
{
|
||||
public static IHostBuilder UseHostBuilder(this IHostBuilder builder, Action<IHostBuilder> custom)
|
||||
{
|
||||
custom?.Invoke(builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseAsUninst(this IHostBuilder builder)
|
||||
{
|
||||
Option.Current.IsUninst = true;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseLogger(this IHostBuilder builder, bool enabled = true)
|
||||
{
|
||||
Option.Current.Logging = enabled;
|
||||
Logger.Info("Setup run started ...");
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseServices(this IHostBuilder builder, Action<IServiceCollection> service)
|
||||
{
|
||||
ServiceCollection serviceCollection = new();
|
||||
service?.Invoke(serviceCollection);
|
||||
ServiceManager.Services = builder.ServiceProvider = serviceCollection.BuildServiceProvider();
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseTempPathFork(this IHostBuilder builder)
|
||||
{
|
||||
if (RuntimeHelper.IsDebuggerAttached)
|
||||
{
|
||||
return builder;
|
||||
}
|
||||
TempPathForkHelper.Fork();
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseElevated(this IHostBuilder builder)
|
||||
{
|
||||
RuntimeHelper.EnsureElevated();
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseDpiAware(this IHostBuilder builder)
|
||||
{
|
||||
_ = DpiAwareHelper.SetProcessDpiAwareness();
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseSingleInstance(this IHostBuilder builder, string instanceName, Action<bool> callback = null!)
|
||||
{
|
||||
RuntimeHelper.CheckSingleInstance(instanceName, callback);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseLanguage(this IHostBuilder builder, string name)
|
||||
{
|
||||
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = new CultureInfo(name);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseMuiLanguage(this IHostBuilder builder)
|
||||
{
|
||||
MuiLanguage.SetupLanguage();
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseTheme(this IHostBuilder builder, WindowsTheme theme = WindowsTheme.Auto)
|
||||
{
|
||||
ThemeService.Current.SetTheme(theme);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseFonts(this IHostBuilder builder, Action<List<MuiLanguageFont>> handler)
|
||||
{
|
||||
handler?.Invoke(MuiLanguage.FontSelector);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseOptions(this IHostBuilder builder, Action<Option> handler)
|
||||
{
|
||||
handler?.Invoke(Option.Current);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UsePages(this IHostBuilder builder, Action<Dictionary<string, Type>> handler)
|
||||
{
|
||||
handler?.Invoke(ShellPageSetting.PageDict);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseDispatcherUnhandledExceptionCatched(this IHostBuilder builder, DispatcherUnhandledExceptionEventHandler handler = null!)
|
||||
{
|
||||
if (builder?.App != null)
|
||||
{
|
||||
if (handler != null)
|
||||
{
|
||||
if (builder!.App is Application app)
|
||||
{
|
||||
app.DispatcherUnhandledException += handler;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (builder!.App is Application app)
|
||||
{
|
||||
app.DispatcherUnhandledException += (object s, DispatcherUnhandledExceptionEventArgs e) =>
|
||||
{
|
||||
Logger.Fatal("Application.DispatcherUnhandledException", e?.Exception?.ToString()!);
|
||||
e!.Handled = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder!;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseDomainUnhandledExceptionCatched(this IHostBuilder builder, UnhandledExceptionEventHandler handler = null!)
|
||||
{
|
||||
if (handler != null)
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += handler;
|
||||
}
|
||||
else
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += (object s, UnhandledExceptionEventArgs e) =>
|
||||
{
|
||||
Logger.Fatal("AppDomain.CurrentDomain.UnhandledException", e?.ExceptionObject?.ToString()!);
|
||||
};
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostBuilder UseUnobservedTaskExceptionCatched(this IHostBuilder builder, EventHandler<UnobservedTaskExceptionEventArgs> handler = null!)
|
||||
{
|
||||
if (handler != null)
|
||||
{
|
||||
TaskScheduler.UnobservedTaskException += handler;
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskScheduler.UnobservedTaskException += (s, e) =>
|
||||
{
|
||||
Logger.Fatal("TaskScheduler.UnobservedTaskException", e?.Exception?.ToString()!);
|
||||
e?.SetObserved();
|
||||
};
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
10
Build/MicaSetup/Design/Hosts/Hosting.cs
Normal file
10
Build/MicaSetup/Design/Hosts/Hosting.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public static class Hosting
|
||||
{
|
||||
public static IHostBuilder CreateBuilder()
|
||||
{
|
||||
HostBuilder builder = new();
|
||||
return builder;
|
||||
}
|
||||
}
|
13
Build/MicaSetup/Design/Hosts/IHostBuilder.cs
Normal file
13
Build/MicaSetup/Design/Hosts/IHostBuilder.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace MicaSetup.Design.Controls;
|
||||
|
||||
public interface IHostBuilder
|
||||
{
|
||||
public IApp App { get; set; }
|
||||
public ServiceProvider ServiceProvider { get; set; }
|
||||
|
||||
public IHostBuilder CreateApp();
|
||||
|
||||
public void RunApp();
|
||||
}
|
15
Build/MicaSetup/Design/Markups/DoubleExtension.cs
Normal file
15
Build/MicaSetup/Design/Markups/DoubleExtension.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace MicaSetup.Design.Markups;
|
||||
|
||||
[MarkupExtensionReturnType(typeof(double))]
|
||||
public sealed class DoubleExtension : MarkupExtension
|
||||
{
|
||||
public double Value { get; set; }
|
||||
|
||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user