refactor: 重写记住主界面位置功能 (#4666)

This commit is contained in:
uye
2023-05-12 13:26:26 +08:00
committed by GitHub
5 changed files with 249 additions and 142 deletions

View File

@@ -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";

View File

@@ -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<WindowManager>();
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);
/// <summary>
/// Move MaaWpfGui.RootView
/// </summary>
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));
/// <summary>
/// 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<WindowPlacement?>(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
/// <summary>
/// TODO: Delete this
/// 兼容旧配置过几个版本删请直接revert
/// </summary>
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;
}
}
}
/// <summary>
/// TODO: Delete this
/// 兼容旧配置过几个版本删请直接revert
/// </summary>
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);
}
}
}

View File

@@ -0,0 +1,62 @@
// <copyright file="WindowPlacement.cs" company="MaaAssistantArknights">
// 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
// </copyright>
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;
}
}
}

View File

@@ -2422,96 +2422,6 @@ namespace MaaWpfGui.ViewModels.UI
}
}
private bool _loadGUIParameters = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.LoadPositionAndSize, bool.TrueString));
/// <summary>
/// Gets or sets a value indicating whether to load GUI parameters.
/// </summary>
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));
/// <summary>
/// Gets or sets a value indicating whether to save GUI parameters on closing main window.
/// </summary>
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();
}
/// <summary>
/// Save main window left edge, top edge, width and heigth.
/// </summary>
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));
/// <summary>

View File

@@ -135,11 +135,6 @@ namespace MaaWpfGui.ViewModels.UI
LogItemViewModels = new ObservableCollection<LogItemViewModel>();
InitializeItems();
InitTimer();
if (Instances.SettingsViewModel.LoadGUIParameters && Instances.SettingsViewModel.SaveGUIParametersOnClosing)
{
Application.Current.MainWindow!.Closing += Instances.SettingsViewModel.SaveGUIParameters;
}
}
/*