From 21c4176157a1c7ef3086333ddb5036325869eac3 Mon Sep 17 00:00:00 2001 From: MutantAura <44103205+MutantAura@users.noreply.github.com> Date: Fri, 28 Apr 2023 21:59:53 +0100 Subject: [PATCH] Allow window to remember its size, position and state (GTK + Avalonia) (#4657) * Update ConfigurationState.cs * Update ConfigurationFileFormat.cs * Update MainWindow.cs * Update ConfigurationFileFormat.cs * Update ConfigurationState.cs * Update MainWindow.cs * Update MainWindow.cs * Update Ryujinx.Ui.Common/Configuration/ConfigurationState.cs Co-authored-by: gdkchan * Update MainWindow.cs * Update Ryujinx/Ui/MainWindow.cs Co-authored-by: gdkchan * Initial properties * Viewmodel adjustments and additions * abstract and monitor dimension changes * Remove position from ViewModel and simplify methods * Remove unused dep * Update configuration and fix typo from AA * review changes * Review changes * Screensize checks - Ava * Review changes 2 * basic review changes * Standardise GTK/Ava functions * Actually call function --------- Co-authored-by: HaizenTrist <123991082+HaizenTrist@users.noreply.github.com> Co-authored-by: gdkchan --- .../UI/ViewModels/MainWindowViewModel.cs | 25 +++++++ src/Ryujinx.Ava/UI/Windows/MainWindow.axaml | 5 +- .../UI/Windows/MainWindow.axaml.cs | 49 +++++++++++++ .../Configuration/ConfigurationFileFormat.cs | 7 +- .../Configuration/ConfigurationState.cs | 69 +++++++++++++++++-- .../Configuration/Ui/WindowStartup.cs | 11 +++ src/Ryujinx/Ui/MainWindow.cs | 38 ++++++++-- 7 files changed, 189 insertions(+), 15 deletions(-) create mode 100644 src/Ryujinx.Ui.Common/Configuration/Ui/WindowStartup.cs diff --git a/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs index 14d7a0fe4a..f4556bc3c9 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs @@ -95,6 +95,9 @@ namespace Ryujinx.Ava.UI.ViewModels private string _currentEmulatedGamePath; private AutoResetEvent _rendererWaitEvent; private WindowState _windowState; + private double _windowWidth; + private double _windowHeight; + private bool _isActive; public ApplicationData ListSelectedApplication; @@ -622,6 +625,28 @@ namespace Ryujinx.Ava.UI.ViewModels OnPropertyChanged(); } } + + public double WindowWidth + { + get => _windowWidth; + set + { + _windowWidth = value; + + OnPropertyChanged(); + } + } + + public double WindowHeight + { + get => _windowHeight; + set + { + _windowHeight = value; + + OnPropertyChanged(); + } + } public bool IsGrid => Glyph == Glyph.Grid; public bool IsList => Glyph == Glyph.List; diff --git a/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml b/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml index 08b99cf535..de01f90fb4 100644 --- a/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml +++ b/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml @@ -12,15 +12,14 @@ Cursor="{Binding Cursor}" Title="{Binding Title}" WindowState="{Binding WindowState}" - Width="1280" - Height="777" + Width="{Binding WindowWidth}" + Height="{Binding WindowHeight}" MinWidth="1092" MinHeight="672" d:DesignHeight="720" d:DesignWidth="1280" x:CompileBindings="True" x:DataType="viewModels:MainWindowViewModel" - WindowStartupLocation="CenterScreen" mc:Ignorable="d" Focusable="True"> diff --git a/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs b/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs index 81e055063f..404d4ee051 100644 --- a/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs +++ b/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs @@ -62,6 +62,8 @@ namespace Ryujinx.Ava.UI.Windows DataContext = ViewModel; + SetWindowSizePosition(); + InitializeComponent(); Load(); @@ -297,6 +299,51 @@ namespace Ryujinx.Ava.UI.Windows LoadHotKeys(); } + private void SetWindowSizePosition() + { + PixelPoint SavedPoint = new PixelPoint(ConfigurationState.Instance.Ui.WindowStartup.WindowPositionX, + ConfigurationState.Instance.Ui.WindowStartup.WindowPositionY); + + ViewModel.WindowHeight = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeHeight * Program.WindowScaleFactor; + ViewModel.WindowWidth = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeWidth * Program.WindowScaleFactor; + + ViewModel.WindowState = ConfigurationState.Instance.Ui.WindowStartup.WindowMaximized.Value is true ? WindowState.Maximized : WindowState.Normal; + + if (CheckScreenBounds(SavedPoint)) + { + Position = SavedPoint; + } + + else WindowStartupLocation = WindowStartupLocation.CenterScreen; + } + + private bool CheckScreenBounds(PixelPoint configPoint) + { + for (int i = 0; i < Screens.ScreenCount; i++) + { + if (Screens.All[i].Bounds.Contains(configPoint)) + { + return true; + } + } + + Logger.Warning?.Print(LogClass.Application, $"Failed to find valid start-up coordinates. Defaulting to primary monitor center."); + return false; + } + + private void SaveWindowSizePosition() + { + ConfigurationState.Instance.Ui.WindowStartup.WindowSizeHeight.Value = (int)Height; + ConfigurationState.Instance.Ui.WindowStartup.WindowSizeWidth.Value = (int)Width; + + ConfigurationState.Instance.Ui.WindowStartup.WindowPositionX.Value = Position.X; + ConfigurationState.Instance.Ui.WindowStartup.WindowPositionY.Value = Position.Y; + + ConfigurationState.Instance.Ui.WindowStartup.WindowMaximized.Value = WindowState == WindowState.Maximized; + + MainWindowViewModel.SaveConfig(); + } + protected override void OnOpened(EventArgs e) { base.OnOpened(e); @@ -388,6 +435,8 @@ namespace Ryujinx.Ava.UI.Windows return; } + SaveWindowSizePosition(); + ApplicationLibrary.CancelLoading(); InputManager.Dispose(); Program.Exit(); diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs b/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs index c9e7f80e81..3168766b53 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs +++ b/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs @@ -14,7 +14,7 @@ namespace Ryujinx.Ui.Common.Configuration /// /// The current version of the file format /// - public const int CurrentVersion = 46; + public const int CurrentVersion = 47; /// /// Version of the configuration file format @@ -251,6 +251,11 @@ namespace Ryujinx.Ui.Common.Configuration /// public ShownFileTypes ShownFileTypes { get; set; } + /// + /// Main window start-up position, size and state + /// + public WindowStartup WindowStartup { get; set; } + /// /// Language Code for the UI /// diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs b/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs index 3a68cc2650..fc3693ae86 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs +++ b/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs @@ -83,6 +83,27 @@ namespace Ryujinx.Ui.Common.Configuration } } + // + /// Determines main window start-up position, size and state + /// + public class WindowStartupSettings + { + public ReactiveObject WindowSizeWidth { get; private set; } + public ReactiveObject WindowSizeHeight { get; private set; } + public ReactiveObject WindowPositionX { get; private set; } + public ReactiveObject WindowPositionY { get; private set; } + public ReactiveObject WindowMaximized { get; private set; } + + public WindowStartupSettings() + { + WindowSizeWidth = new ReactiveObject(); + WindowSizeHeight = new ReactiveObject(); + WindowPositionX = new ReactiveObject(); + WindowPositionY = new ReactiveObject(); + WindowMaximized = new ReactiveObject(); + } + } + /// /// Used to toggle columns in the GUI /// @@ -103,6 +124,11 @@ namespace Ryujinx.Ui.Common.Configuration /// public ShownFileTypeSettings ShownFileTypes { get; private set; } + /// + /// Determines main window start-up position, size and state + /// + public WindowStartupSettings WindowStartup { get; private set; } + /// /// Language Code for the UI /// @@ -163,7 +189,8 @@ namespace Ryujinx.Ui.Common.Configuration GuiColumns = new Columns(); ColumnSort = new ColumnSortSettings(); GameDirs = new ReactiveObject>(); - ShownFileTypes = new ShownFileTypeSettings(); + ShownFileTypes = new ShownFileTypeSettings(); + WindowStartup = new WindowStartupSettings(); EnableCustomTheme = new ReactiveObject(); CustomThemePath = new ReactiveObject(); BaseStyle = new ReactiveObject(); @@ -663,12 +690,12 @@ namespace Ryujinx.Ui.Common.Configuration FileSizeColumn = Ui.GuiColumns.FileSizeColumn, PathColumn = Ui.GuiColumns.PathColumn }, - ColumnSort = new ColumnSort + ColumnSort = new ColumnSort { SortColumnId = Ui.ColumnSort.SortColumnId, SortAscending = Ui.ColumnSort.SortAscending }, - GameDirs = Ui.GameDirs, + GameDirs = Ui.GameDirs, ShownFileTypes = new ShownFileTypes { NSP = Ui.ShownFileTypes.NSP, @@ -678,6 +705,14 @@ namespace Ryujinx.Ui.Common.Configuration NRO = Ui.ShownFileTypes.NRO, NSO = Ui.ShownFileTypes.NSO, }, + WindowStartup = new WindowStartup + { + WindowSizeWidth = Ui.WindowStartup.WindowSizeWidth, + WindowSizeHeight = Ui.WindowStartup.WindowSizeHeight, + WindowPositionX = Ui.WindowStartup.WindowPositionX, + WindowPositionY = Ui.WindowStartup.WindowPositionY, + WindowMaximized = Ui.WindowStartup.WindowMaximized, + }, LanguageCode = Ui.LanguageCode, EnableCustomTheme = Ui.EnableCustomTheme, CustomThemePath = Ui.CustomThemePath, @@ -781,6 +816,11 @@ namespace Ryujinx.Ui.Common.Configuration Ui.IsAscendingOrder.Value = true; Ui.StartFullscreen.Value = false; Ui.ShowConsole.Value = true; + Ui.WindowStartup.WindowSizeWidth.Value = 1280; + Ui.WindowStartup.WindowSizeHeight.Value = 760; + Ui.WindowStartup.WindowPositionX.Value = 0; + Ui.WindowStartup.WindowPositionY.Value = 0; + Ui.WindowStartup.WindowMaximized.Value = false; Hid.EnableKeyboard.Value = false; Hid.EnableMouse.Value = false; Hid.Hotkeys.Value = new KeyboardHotkeys @@ -1334,13 +1374,29 @@ namespace Ryujinx.Ui.Common.Configuration if (configurationFileFormat.Version < 46) { - Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 45."); + Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 46."); configurationFileFormat.MultiplayerLanInterfaceId = "0"; configurationFileUpdated = true; } + if (configurationFileFormat.Version < 47) + { + Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 47."); + + configurationFileFormat.WindowStartup = new WindowStartup + { + WindowPositionX = 0, + WindowPositionY = 0, + WindowSizeHeight = 760, + WindowSizeWidth = 1280, + WindowMaximized = false, + }; + + configurationFileUpdated = true; + } + Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog; Graphics.ResScale.Value = configurationFileFormat.ResScale; Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom; @@ -1416,6 +1472,11 @@ namespace Ryujinx.Ui.Common.Configuration Ui.ApplicationSort.Value = configurationFileFormat.ApplicationSort; Ui.StartFullscreen.Value = configurationFileFormat.StartFullscreen; Ui.ShowConsole.Value = configurationFileFormat.ShowConsole; + Ui.WindowStartup.WindowSizeWidth.Value = configurationFileFormat.WindowStartup.WindowSizeWidth; + Ui.WindowStartup.WindowSizeHeight.Value = configurationFileFormat.WindowStartup.WindowSizeHeight; + Ui.WindowStartup.WindowPositionX.Value = configurationFileFormat.WindowStartup.WindowPositionX; + Ui.WindowStartup.WindowPositionY.Value = configurationFileFormat.WindowStartup.WindowPositionY; + Ui.WindowStartup.WindowMaximized.Value = configurationFileFormat.WindowStartup.WindowMaximized; Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard; Hid.EnableMouse.Value = configurationFileFormat.EnableMouse; Hid.Hotkeys.Value = configurationFileFormat.Hotkeys; diff --git a/src/Ryujinx.Ui.Common/Configuration/Ui/WindowStartup.cs b/src/Ryujinx.Ui.Common/Configuration/Ui/WindowStartup.cs new file mode 100644 index 0000000000..ce0dde6aaf --- /dev/null +++ b/src/Ryujinx.Ui.Common/Configuration/Ui/WindowStartup.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.Ui.Common.Configuration.Ui +{ + public struct WindowStartup + { + public int WindowSizeWidth { get; set; } + public int WindowSizeHeight { get; set; } + public int WindowPositionX { get; set; } + public int WindowPositionY { get; set; } + public bool WindowMaximized { get; set; } + } +} diff --git a/src/Ryujinx/Ui/MainWindow.cs b/src/Ryujinx/Ui/MainWindow.cs index bf96e18a4e..4911c90063 100644 --- a/src/Ryujinx/Ui/MainWindow.cs +++ b/src/Ryujinx/Ui/MainWindow.cs @@ -153,13 +153,8 @@ namespace Ryujinx.Ui // Apply custom theme if needed. ThemeHelper.ApplyTheme(); - Gdk.Monitor monitor = Display.GetMonitor(0); - // Sets overridden fields. - int monitorWidth = monitor.Geometry.Width * monitor.ScaleFactor; - int monitorHeight = monitor.Geometry.Height * monitor.ScaleFactor; - DefaultWidth = monitorWidth < 1280 ? monitorWidth : 1280; - DefaultHeight = monitorHeight < 760 ? monitorHeight : 760; + SetWindowSizePosition(); Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); Title = $"Ryujinx {Program.Version}"; @@ -1314,6 +1309,7 @@ namespace Ryujinx.Ui { if (!_gameLoaded || !ConfigurationState.Instance.ShowConfirmExit || GtkDialog.CreateExitDialog()) { + SaveWindowSizePosition(); End(); } } @@ -1322,6 +1318,7 @@ namespace Ryujinx.Ui { if (!_gameLoaded || !ConfigurationState.Instance.ShowConfirmExit || GtkDialog.CreateExitDialog()) { + SaveWindowSizePosition(); End(); } else @@ -1330,6 +1327,33 @@ namespace Ryujinx.Ui } } + private void SetWindowSizePosition() + { + DefaultWidth = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeWidth; + DefaultHeight = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeHeight; + + Move(ConfigurationState.Instance.Ui.WindowStartup.WindowPositionX, ConfigurationState.Instance.Ui.WindowStartup.WindowPositionY); + + if (ConfigurationState.Instance.Ui.WindowStartup.WindowMaximized) + { + Maximize(); + } + } + + private void SaveWindowSizePosition() + { + GetSize(out int windowWidth, out int windowHeight); + GetPosition(out int windowXPos, out int windowYPos); + + ConfigurationState.Instance.Ui.WindowStartup.WindowMaximized.Value = IsMaximized; + ConfigurationState.Instance.Ui.WindowStartup.WindowSizeWidth.Value = windowWidth; + ConfigurationState.Instance.Ui.WindowStartup.WindowSizeHeight.Value = windowHeight; + ConfigurationState.Instance.Ui.WindowStartup.WindowPositionX.Value = windowXPos; + ConfigurationState.Instance.Ui.WindowStartup.WindowPositionY.Value = windowYPos; + + SaveConfig(); + } + private void StopEmulation_Pressed(object sender, EventArgs args) { if (_emulationContext != null) @@ -1831,4 +1855,4 @@ namespace Ryujinx.Ui UpdateGameTable(); } } -} \ No newline at end of file +}