diff --git a/src/MaaWpfGui/Constants/ConfigurationKeys.cs b/src/MaaWpfGui/Constants/ConfigurationKeys.cs index 63e2253e5f..55645c6600 100644 --- a/src/MaaWpfGui/Constants/ConfigurationKeys.cs +++ b/src/MaaWpfGui/Constants/ConfigurationKeys.cs @@ -21,6 +21,16 @@ namespace MaaWpfGui.Constants public const string Localization = "GUI.Localization"; public const string MinimizeToTray = "GUI.MinimizeToTray"; public const string UseNotify = "GUI.UseNotify"; + public const string WindowPlacement = "GUI.Placement"; + public const string LoadWindowPlacement = "GUI.Placement.Load"; + public const string SaveWindowPlacement = "GUI.Placement.SaveOnClosing"; + public const string UseAlternateStage = "GUI.UseAlternateStage"; + public const string HideUnavailableStage = "GUI.HideUnavailableStage"; + public const string CustomStageCode = "GUI.CustomStageCode"; + public const string InverseClearMode = "GUI.InverseClearMode"; + public const string WindowTitlePrefix = "GUI.WindowTitlePrefix"; + public const string DarkMode = "GUI.DarkMode"; + public const string MonitorNumber = "GUI.Monitor.Number"; public const string MonitorWidth = "GUI.Monitor.Width"; public const string MonitorHeight = "GUI.Monitor.Height"; @@ -30,12 +40,6 @@ namespace MaaWpfGui.Constants public const string WindowHeight = "GUI.Size.Height"; public const string LoadPositionAndSize = "GUI.PositionAndSize.Load"; public const string SavePositionAndSize = "GUI.PositionAndSize.SaveOnClosing"; - public const string UseAlternateStage = "GUI.UseAlternateStage"; - public const string HideUnavailableStage = "GUI.HideUnavailableStage"; - public const string CustomStageCode = "GUI.CustomStageCode"; - public const string InverseClearMode = "GUI.InverseClearMode"; - public const string WindowTitlePrefix = "GUI.WindowTitlePrefix"; - public const string DarkMode = "GUI.DarkMode"; public const string AddressHistory = "Connect.AddressHistory"; public const string AutoDetect = "Connect.AutoDetect"; diff --git a/src/MaaWpfGui/Helper/WindowManager.cs b/src/MaaWpfGui/Helper/WindowManager.cs index 0af287f7fb..19d344c9a4 100644 --- a/src/MaaWpfGui/Helper/WindowManager.cs +++ b/src/MaaWpfGui/Helper/WindowManager.cs @@ -14,11 +14,15 @@ using System; using System.Globalization; using System.Linq; +using System.Runtime.InteropServices; using System.Windows; using MaaWpfGui.Constants; +using MaaWpfGui.Models; using MaaWpfGui.Views.UI; +using Newtonsoft.Json; +using Serilog; using Stylet; -using Screen = System.Windows.Forms.Screen; +using Rect = MaaWpfGui.Models.Rect; namespace MaaWpfGui.Helper { @@ -29,40 +33,12 @@ namespace MaaWpfGui.Helper { } - private readonly string ScreenName = ConfigurationHelper.GetValue(ConfigurationKeys.MonitorNumber, string.Empty); - private readonly int ScreenWidth = int.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.MonitorWidth, "-1")); - private readonly int ScreenHeight = int.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.MonitorHeight, "-1")); + private static readonly ILogger _logger = Log.ForContext(); - private static readonly double DefaultDouble = -114514; - private readonly double Left = double.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.PositionLeft, DefaultDouble.ToString(CultureInfo.InvariantCulture)), CultureInfo.InvariantCulture); - private readonly double Top = double.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.PositionTop, DefaultDouble.ToString(CultureInfo.InvariantCulture)), CultureInfo.InvariantCulture); - private readonly double Width = double.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.WindowWidth, DefaultDouble.ToString(CultureInfo.InvariantCulture)), CultureInfo.InvariantCulture); - private readonly double Height = double.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.WindowHeight, DefaultDouble.ToString(CultureInfo.InvariantCulture)), CultureInfo.InvariantCulture); - - /// - /// Move MaaWpfGui.RootView - /// - private void MoveWindowToDisplay(string displayName, Window window) - { - if (Math.Abs(Left - DefaultDouble) < 0.01f || Math.Abs(Top - DefaultDouble) < 0.01f) - { - return; - } - - var screen = Screen.AllScreens.FirstOrDefault(x => x.DeviceName == displayName); - if (screen != null) - { - var screenRect = screen.Bounds; - if (screenRect.Height == ScreenHeight && screenRect.Width == ScreenWidth) - { - window.WindowStartupLocation = WindowStartupLocation.Manual; - window.Left = (int)(screenRect.Left + Left); - window.Top = (int)(screenRect.Top + Top); - window.Width = Width; - window.Height = Height; - } - } - } + private readonly bool _loadWindowPlacement = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.LoadWindowPlacement, bool.TrueString)); + private readonly bool _saveWindowPlacement = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.SaveWindowPlacement, bool.TrueString)); + private readonly bool _minimizeDirectly = bool.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.MinimizeDirectly, bool.FalseString)); + private readonly bool _minimizeToTray = bool.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.MinimizeToTray, bool.FalseString)); /// /// Center other windows in MaaWpfGui.RootView @@ -85,20 +61,30 @@ namespace MaaWpfGui.Helper Window window = base.CreateWindow(viewModel, isDialog, ownerViewModel); if (window is RootView) { - bool needMoveRootView = bool.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.LoadPositionAndSize, bool.TrueString)); - if (needMoveRootView) + if (_loadWindowPlacement && GetConfiguration(out WindowPlacement wp, window)) { - MoveWindowToDisplay(ScreenName, window); + window.SourceInitialized += (s, e) => + { + bool success = SetWindowPlacement(window, ref wp); + _logger.Information("Whether the window placement was set successfully: {Success}", success); + }; } - bool minimizeDirectly = bool.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.MinimizeDirectly, bool.FalseString)); - if (minimizeDirectly) + if (_loadWindowPlacement && _saveWindowPlacement) + { + window.Closing += (s, e) => + { + GetWindowPlacement(window, out WindowPlacement wp); + SetConfiguration(wp); + }; + } + + if (_minimizeDirectly) { window.WindowState = WindowState.Minimized; } - bool minimizeToTray = bool.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.MinimizeToTray, bool.FalseString)); - if (minimizeDirectly && minimizeToTray) + if (_minimizeDirectly && _minimizeToTray) { window.ShowInTaskbar = false; window.Visibility = Visibility.Hidden; @@ -111,5 +97,155 @@ namespace MaaWpfGui.Helper return window; } + + private bool SetConfiguration(WindowPlacement wp) + { + try + { + // 请在配置文件中修改该部分配置,暂不支持从GUI设置 + // Please modify this part of configuration in the configuration file. + ConfigurationHelper.SetValue(ConfigurationKeys.LoadWindowPlacement, _loadWindowPlacement.ToString()); + ConfigurationHelper.SetValue(ConfigurationKeys.SaveWindowPlacement, _saveWindowPlacement.ToString()); + + return ConfigurationHelper.SetValue(ConfigurationKeys.WindowPlacement, JsonConvert.SerializeObject(wp)); + } + catch (Exception e) + { + _logger.Error(e, "Failed to serialize json string to {Key}", ConfigurationKeys.WindowPlacement); + } + + return false; + } + + private bool GetConfiguration(out WindowPlacement wp, Window window) + { + wp = default; + var jsonStr = ConfigurationHelper.GetValue(ConfigurationKeys.WindowPlacement, string.Empty); + if (string.IsNullOrEmpty(jsonStr)) + { + SetOldConfiguration(window); + DeleteOldConfiguration(); + return false; + } + + try + { + wp = JsonConvert.DeserializeObject(jsonStr) ?? throw new Exception("Failed to parse json string"); + return true; + } + catch (Exception e) + { + _logger.Error(e, "Failed to deserialize json string from {Key}", ConfigurationKeys.WindowPlacement); + } + + return false; + } + + private bool SetWindowPlacement(WindowHandle window, ref WindowPlacement wp) + { + try + { + // Load window placement details for previous application session from application settings + // Note - if window was closed on a monitor that is now disconnected from the computer, + // SetWindowPlacement will place the window onto a visible monitor. + wp.Length = Marshal.SizeOf(typeof(WindowPlacement)); + wp.Flags = 0; + + // wp.ShowCmd = wp.ShowCmd == SwShowminimized ? SwShownormal : wp.ShowCmd; + wp.ShowCmd = _minimizeDirectly ? SwShowminimized : SwShownormal; + return SetWindowPlacement(window.Handle, ref wp); + } + catch + { + return false; + } + } + + private bool GetWindowPlacement(WindowHandle window, out WindowPlacement wp) + { + if (GetWindowPlacement(window.Handle, out wp)) + { + // get the aero snap position of the window + if (wp.ShowCmd == SwShownormal && GetWindowRect(window.Handle, out Rect rect)) + { + wp.NormalPosition = rect; + } + + return true; + } + + return false; + } + + #region Win32 API declarations to set and get window placement + + [DllImport("user32.dll")] + private static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WindowPlacement lpwndpl); + + [DllImport("user32.dll")] + private static extern bool GetWindowPlacement(IntPtr hWnd, out WindowPlacement lpwndpl); + + [DllImport("user32.dll")] + private static extern bool GetWindowRect(IntPtr hWnd, out Rect lpRect); + + private const int SwShownormal = 1; + private const int SwShowminimized = 2; + + #endregion + + /// + /// TODO: Delete this + /// 兼容旧配置,过几个版本删(请直接revert) + /// + private void SetOldConfiguration(Window window) + { + // 初始化 + string screenName = ConfigurationHelper.GetValue(ConfigurationKeys.MonitorNumber, string.Empty); + int screenWidth = int.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.MonitorWidth, "-1")); + int screenHeight = int.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.MonitorHeight, "-1")); + + double defaultDouble = -114514; + double left = double.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.PositionLeft, defaultDouble.ToString(CultureInfo.InvariantCulture)), CultureInfo.InvariantCulture); + double top = double.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.PositionTop, defaultDouble.ToString(CultureInfo.InvariantCulture)), CultureInfo.InvariantCulture); + double width = double.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.WindowWidth, defaultDouble.ToString(CultureInfo.InvariantCulture)), CultureInfo.InvariantCulture); + double height = double.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.WindowHeight, defaultDouble.ToString(CultureInfo.InvariantCulture)), CultureInfo.InvariantCulture); + + // Move MaaWpfGui.RootView + if (Math.Abs(left - defaultDouble) < 0.01f || Math.Abs(top - defaultDouble) < 0.01f) + { + return; + } + + var screen = System.Windows.Forms.Screen.AllScreens.FirstOrDefault(x => x.DeviceName == screenName); + if (screen != null) + { + var screenRect = screen.Bounds; + if (screenRect.Height == screenHeight && screenRect.Width == screenWidth) + { + window.WindowStartupLocation = WindowStartupLocation.Manual; + window.Left = (int)(screenRect.Left + left); + window.Top = (int)(screenRect.Top + top); + window.Width = width; + window.Height = height; + } + } + } + + /// + /// TODO: Delete this + /// 兼容旧配置,过几个版本删(请直接revert) + /// + private void DeleteOldConfiguration() + { + ConfigurationHelper.DeleteValue(ConfigurationKeys.MonitorNumber); + ConfigurationHelper.DeleteValue(ConfigurationKeys.MonitorWidth); + ConfigurationHelper.DeleteValue(ConfigurationKeys.MonitorHeight); + ConfigurationHelper.DeleteValue(ConfigurationKeys.PositionLeft); + ConfigurationHelper.DeleteValue(ConfigurationKeys.PositionTop); + ConfigurationHelper.DeleteValue(ConfigurationKeys.WindowWidth); + ConfigurationHelper.DeleteValue(ConfigurationKeys.WindowHeight); + ConfigurationHelper.DeleteValue(ConfigurationKeys.LoadPositionAndSize); + ConfigurationHelper.DeleteValue(ConfigurationKeys.SavePositionAndSize); + } } } diff --git a/src/MaaWpfGui/Models/WindowPlacement.cs b/src/MaaWpfGui/Models/WindowPlacement.cs new file mode 100644 index 0000000000..cddc66dea5 --- /dev/null +++ b/src/MaaWpfGui/Models/WindowPlacement.cs @@ -0,0 +1,62 @@ +// +// MaaWpfGui - A part of the MaaCoreArknights project +// Copyright (C) 2021 MistEO and Contributors +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY +// + +using System; +using System.Runtime.InteropServices; + +namespace MaaWpfGui.Models +{ + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct WindowPlacement + { + public int Length; + public int Flags; + public int ShowCmd; + public Point MinPosition; + public Point MaxPosition; + public Rect NormalPosition; + } + + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Rect + { + public int Left; + public int Top; + public int Right; + public int Bottom; + + public Rect(int left, int top, int right, int bottom) + { + Left = left; + Top = top; + Right = right; + Bottom = bottom; + } + } + + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Point + { + public int X; + public int Y; + + public Point(int x, int y) + { + X = x; + Y = y; + } + } +} diff --git a/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs b/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs index 4e76f40f97..28846a044d 100644 --- a/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs +++ b/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs @@ -2422,96 +2422,6 @@ namespace MaaWpfGui.ViewModels.UI } } - private bool _loadGUIParameters = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.LoadPositionAndSize, bool.TrueString)); - - /// - /// Gets or sets a value indicating whether to load GUI parameters. - /// - public bool LoadGUIParameters - { - get => _loadGUIParameters; - set - { - SetAndNotify(ref _loadGUIParameters, value); - ConfigurationHelper.SetValue(ConfigurationKeys.LoadPositionAndSize, value.ToString()); - if (value) - { - if (SaveGUIParametersOnClosing) - { - Application.Current.MainWindow.Closing += SaveGUIParameters; - } - else - { - SaveGUIParameters(); - } - } - } - } - - private bool _saveGUIParametersOnClosing = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.SavePositionAndSize, bool.TrueString)); - - /// - /// Gets or sets a value indicating whether to save GUI parameters on closing main window. - /// - public bool SaveGUIParametersOnClosing - { - get => _saveGUIParametersOnClosing; - set - { - SetAndNotify(ref _saveGUIParametersOnClosing, value); - ConfigurationHelper.SetValue(ConfigurationKeys.SavePositionAndSize, value.ToString()); - if (value) - { - Application.Current.MainWindow.Closing += SaveGUIParameters; - } - else - { - Application.Current.MainWindow.Closing -= SaveGUIParameters; - } - } - } - - public void SaveGUIParameters(object sender, EventArgs e) - { - SaveGUIParameters(); - } - - /// - /// Save main window left edge, top edge, width and heigth. - /// - public void SaveGUIParameters() - { - var mainWindow = Application.Current.MainWindow; - if (mainWindow.WindowState != WindowState.Normal) - { - return; - } - - var mainWindowRect = new Rect(mainWindow.Left + 25, mainWindow.Top + 25, mainWindow.Width - 50, mainWindow.Height - 50); - var virtualScreenRect = new Rect(SystemParameters.VirtualScreenLeft, SystemParameters.VirtualScreenTop, SystemParameters.VirtualScreenWidth, SystemParameters.VirtualScreenHeight); - if (!virtualScreenRect.IntersectsWith(mainWindowRect)) - { - return; - } - - // 请在配置文件中修改该部分配置,暂不支持从GUI设置 - // Please modify this part of configuration in the configuration file. - ConfigurationHelper.SetValue(ConfigurationKeys.LoadPositionAndSize, LoadGUIParameters.ToString()); - ConfigurationHelper.SetValue(ConfigurationKeys.SavePositionAndSize, SaveGUIParametersOnClosing.ToString()); - - System.Windows.Forms.Screen currentScreen = - System.Windows.Forms.Screen.FromHandle(new WindowInteropHelper(mainWindow).Handle); - var screenRect = currentScreen.Bounds; - ConfigurationHelper.SetValue(ConfigurationKeys.MonitorNumber, currentScreen.DeviceName); - ConfigurationHelper.SetValue(ConfigurationKeys.MonitorWidth, screenRect.Width.ToString()); - ConfigurationHelper.SetValue(ConfigurationKeys.MonitorHeight, screenRect.Height.ToString()); - - ConfigurationHelper.SetValue(ConfigurationKeys.PositionLeft, (mainWindow.Left - screenRect.Left).ToString(CultureInfo.InvariantCulture)); - ConfigurationHelper.SetValue(ConfigurationKeys.PositionTop, (mainWindow.Top - screenRect.Top).ToString(CultureInfo.InvariantCulture)); - ConfigurationHelper.SetValue(ConfigurationKeys.WindowWidth, mainWindow.Width.ToString(CultureInfo.InvariantCulture)); - ConfigurationHelper.SetValue(ConfigurationKeys.WindowHeight, mainWindow.Height.ToString(CultureInfo.InvariantCulture)); - } - private bool _useAlternateStage = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.UseAlternateStage, bool.FalseString)); /// diff --git a/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs b/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs index 206684e58e..15bbab8ecb 100644 --- a/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs +++ b/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs @@ -135,11 +135,6 @@ namespace MaaWpfGui.ViewModels.UI LogItemViewModels = new ObservableCollection(); InitializeItems(); InitTimer(); - - if (Instances.SettingsViewModel.LoadGUIParameters && Instances.SettingsViewModel.SaveGUIParametersOnClosing) - { - Application.Current.MainWindow!.Closing += Instances.SettingsViewModel.SaveGUIParameters; - } } /*