diff --git a/BetterGenshinImpact.sln b/BetterGenshinImpact.sln index 92b305cc..3cd75161 100644 --- a/BetterGenshinImpact.sln +++ b/BetterGenshinImpact.sln @@ -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 diff --git a/BetterGenshinImpact/app.manifest b/BetterGenshinImpact/app.manifest deleted file mode 100644 index 2dd0dace..00000000 --- a/BetterGenshinImpact/app.manifest +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - - - - - - diff --git a/Build/.gitignore b/Build/.gitignore new file mode 100644 index 00000000..42475343 --- /dev/null +++ b/Build/.gitignore @@ -0,0 +1,5 @@ +.vs/ +dist/ +/*.exe +/*.7z +/*.zip diff --git a/Build/LICENSE b/Build/LICENSE new file mode 100644 index 00000000..781844a0 --- /dev/null +++ b/Build/LICENSE @@ -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. diff --git a/Build/MicaSetup.Tools/7-Zip/7z.dll b/Build/MicaSetup.Tools/7-Zip/7z.dll new file mode 100644 index 00000000..7113c59b Binary files /dev/null and b/Build/MicaSetup.Tools/7-Zip/7z.dll differ diff --git a/Build/MicaSetup.Tools/7-Zip/7z.exe b/Build/MicaSetup.Tools/7-Zip/7z.exe new file mode 100644 index 00000000..69946dbc Binary files /dev/null and b/Build/MicaSetup.Tools/7-Zip/7z.exe differ diff --git a/Build/MicaSetup/.gitignore b/Build/MicaSetup/.gitignore new file mode 100644 index 00000000..11b8c04f --- /dev/null +++ b/Build/MicaSetup/.gitignore @@ -0,0 +1,4 @@ +bin/ +obj/ + +*.user diff --git a/Build/MicaSetup/App.xaml b/Build/MicaSetup/App.xaml new file mode 100644 index 00000000..b32e93cb --- /dev/null +++ b/Build/MicaSetup/App.xaml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + diff --git a/Build/MicaSetup/App.xaml.cs b/Build/MicaSetup/App.xaml.cs new file mode 100644 index 00000000..c08820f1 --- /dev/null +++ b/Build/MicaSetup/App.xaml.cs @@ -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(); +} diff --git a/Build/MicaSetup/AssemblyInfo.cs b/Build/MicaSetup/AssemblyInfo.cs new file mode 100644 index 00000000..f79fc71c --- /dev/null +++ b/Build/MicaSetup/AssemblyInfo.cs @@ -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")] diff --git a/Build/MicaSetup/Core/IsExternalInit.cs b/Build/MicaSetup/Core/IsExternalInit.cs new file mode 100644 index 00000000..f0392094 --- /dev/null +++ b/Build/MicaSetup/Core/IsExternalInit.cs @@ -0,0 +1,11 @@ +using System.ComponentModel; + +namespace System.Runtime.CompilerServices; + +/// +/// Workaround class for records and "init" keyword +/// +[EditorBrowsable(EditorBrowsableState.Never)] +internal class IsExternalInit +{ +} diff --git a/Build/MicaSetup/Core/Logger.cs b/Build/MicaSetup/Core/Logger.cs new file mode 100644 index 00000000..85ab67e6 --- /dev/null +++ b/Build/MicaSetup/Core/Logger.cs @@ -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; + } +} diff --git a/Build/MicaSetup/Core/MuiLanguage.cs b/Build/MicaSetup/Core/MuiLanguage.cs new file mode 100644 index 00000000..291256d9 --- /dev/null +++ b/Build/MicaSetup/Core/MuiLanguage.cs @@ -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 +{ + /// + /// 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 + /// + public static List 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; + } +} diff --git a/Build/MicaSetup/Core/ServiceManager.cs b/Build/MicaSetup/Core/ServiceManager.cs new file mode 100644 index 00000000..459b3022 --- /dev/null +++ b/Build/MicaSetup/Core/ServiceManager.cs @@ -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() + { + return Services.GetService()!; + } +} diff --git a/Build/MicaSetup/Design/Animations/DoubleEasingAnimation.cs b/Build/MicaSetup/Design/Animations/DoubleEasingAnimation.cs new file mode 100644 index 00000000..2ff605d4 --- /dev/null +++ b/Build/MicaSetup/Design/Animations/DoubleEasingAnimation.cs @@ -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, +} diff --git a/Build/MicaSetup/Design/Animations/ProgressAccumulator.cs b/Build/MicaSetup/Design/Animations/ProgressAccumulator.cs new file mode 100644 index 00000000..bcdd76df --- /dev/null +++ b/Build/MicaSetup/Design/Animations/ProgressAccumulator.cs @@ -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? 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 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 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; + } +} diff --git a/Build/MicaSetup/Design/Controls/BitmapIcon/BitmapIcon.cs b/Build/MicaSetup/Design/Controls/BitmapIcon/BitmapIcon.cs new file mode 100644 index 00000000..8dead176 --- /dev/null +++ b/Build/MicaSetup/Design/Controls/BitmapIcon/BitmapIcon.cs @@ -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; +} diff --git a/Build/MicaSetup/Design/Controls/BitmapIcon/IconElement.cs b/Build/MicaSetup/Design/Controls/BitmapIcon/IconElement.cs new file mode 100644 index 00000000..4489c829 --- /dev/null +++ b/Build/MicaSetup/Design/Controls/BitmapIcon/IconElement.cs @@ -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; +} diff --git a/Build/MicaSetup/Design/Controls/Button/Button.xaml b/Build/MicaSetup/Design/Controls/Button/Button.xaml new file mode 100644 index 00000000..8b75791c --- /dev/null +++ b/Build/MicaSetup/Design/Controls/Button/Button.xaml @@ -0,0 +1,129 @@ + + + 11,5,11,6 + 1 + 0,0,8,0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Build/MicaSetup/Design/Controls/MessageBox/MessageBoxDialog.xaml.cs b/Build/MicaSetup/Design/Controls/MessageBox/MessageBoxDialog.xaml.cs new file mode 100644 index 00000000..9e1f613b --- /dev/null +++ b/Build/MicaSetup/Design/Controls/MessageBox/MessageBoxDialog.xaml.cs @@ -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 +} diff --git a/Build/MicaSetup/Design/Controls/MessageBox/MessageBoxX.cs b/Build/MicaSetup/Design/Controls/MessageBox/MessageBoxX.cs new file mode 100644 index 00000000..6acc9853 --- /dev/null +++ b/Build/MicaSetup/Design/Controls/MessageBox/MessageBoxX.cs @@ -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); + } +} diff --git a/Build/MicaSetup/Design/Controls/ProgressBar/ProgressBar.xaml b/Build/MicaSetup/Design/Controls/ProgressBar/ProgressBar.xaml new file mode 100644 index 00000000..6ef08d82 --- /dev/null +++ b/Build/MicaSetup/Design/Controls/ProgressBar/ProgressBar.xaml @@ -0,0 +1,102 @@ + + + + + #73EBF3 + #238EFA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +