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 <gab.dark.100@gmail.com>

* Update MainWindow.cs

* Update Ryujinx/Ui/MainWindow.cs

Co-authored-by: gdkchan <gab.dark.100@gmail.com>

* 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 <gab.dark.100@gmail.com>
This commit is contained in:
MutantAura 2023-04-28 21:59:53 +01:00 committed by GitHub
parent 3b4ff2d6d9
commit 21c4176157
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 189 additions and 15 deletions

View file

@ -95,6 +95,9 @@ namespace Ryujinx.Ava.UI.ViewModels
private string _currentEmulatedGamePath; private string _currentEmulatedGamePath;
private AutoResetEvent _rendererWaitEvent; private AutoResetEvent _rendererWaitEvent;
private WindowState _windowState; private WindowState _windowState;
private double _windowWidth;
private double _windowHeight;
private bool _isActive; private bool _isActive;
public ApplicationData ListSelectedApplication; public ApplicationData ListSelectedApplication;
@ -623,6 +626,28 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
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 IsGrid => Glyph == Glyph.Grid;
public bool IsList => Glyph == Glyph.List; public bool IsList => Glyph == Glyph.List;

View file

@ -12,15 +12,14 @@
Cursor="{Binding Cursor}" Cursor="{Binding Cursor}"
Title="{Binding Title}" Title="{Binding Title}"
WindowState="{Binding WindowState}" WindowState="{Binding WindowState}"
Width="1280" Width="{Binding WindowWidth}"
Height="777" Height="{Binding WindowHeight}"
MinWidth="1092" MinWidth="1092"
MinHeight="672" MinHeight="672"
d:DesignHeight="720" d:DesignHeight="720"
d:DesignWidth="1280" d:DesignWidth="1280"
x:CompileBindings="True" x:CompileBindings="True"
x:DataType="viewModels:MainWindowViewModel" x:DataType="viewModels:MainWindowViewModel"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d" mc:Ignorable="d"
Focusable="True"> Focusable="True">
<Window.Styles> <Window.Styles>

View file

@ -62,6 +62,8 @@ namespace Ryujinx.Ava.UI.Windows
DataContext = ViewModel; DataContext = ViewModel;
SetWindowSizePosition();
InitializeComponent(); InitializeComponent();
Load(); Load();
@ -297,6 +299,51 @@ namespace Ryujinx.Ava.UI.Windows
LoadHotKeys(); 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) protected override void OnOpened(EventArgs e)
{ {
base.OnOpened(e); base.OnOpened(e);
@ -388,6 +435,8 @@ namespace Ryujinx.Ava.UI.Windows
return; return;
} }
SaveWindowSizePosition();
ApplicationLibrary.CancelLoading(); ApplicationLibrary.CancelLoading();
InputManager.Dispose(); InputManager.Dispose();
Program.Exit(); Program.Exit();

View file

@ -14,7 +14,7 @@ namespace Ryujinx.Ui.Common.Configuration
/// <summary> /// <summary>
/// The current version of the file format /// The current version of the file format
/// </summary> /// </summary>
public const int CurrentVersion = 46; public const int CurrentVersion = 47;
/// <summary> /// <summary>
/// Version of the configuration file format /// Version of the configuration file format
@ -251,6 +251,11 @@ namespace Ryujinx.Ui.Common.Configuration
/// </summary> /// </summary>
public ShownFileTypes ShownFileTypes { get; set; } public ShownFileTypes ShownFileTypes { get; set; }
/// <summary>
/// Main window start-up position, size and state
/// </summary>
public WindowStartup WindowStartup { get; set; }
/// <summary> /// <summary>
/// Language Code for the UI /// Language Code for the UI
/// </summary> /// </summary>

View file

@ -83,6 +83,27 @@ namespace Ryujinx.Ui.Common.Configuration
} }
} }
// <summary>
/// Determines main window start-up position, size and state
///<summary>
public class WindowStartupSettings
{
public ReactiveObject<int> WindowSizeWidth { get; private set; }
public ReactiveObject<int> WindowSizeHeight { get; private set; }
public ReactiveObject<int> WindowPositionX { get; private set; }
public ReactiveObject<int> WindowPositionY { get; private set; }
public ReactiveObject<bool> WindowMaximized { get; private set; }
public WindowStartupSettings()
{
WindowSizeWidth = new ReactiveObject<int>();
WindowSizeHeight = new ReactiveObject<int>();
WindowPositionX = new ReactiveObject<int>();
WindowPositionY = new ReactiveObject<int>();
WindowMaximized = new ReactiveObject<bool>();
}
}
/// <summary> /// <summary>
/// Used to toggle columns in the GUI /// Used to toggle columns in the GUI
/// </summary> /// </summary>
@ -103,6 +124,11 @@ namespace Ryujinx.Ui.Common.Configuration
/// </summary> /// </summary>
public ShownFileTypeSettings ShownFileTypes { get; private set; } public ShownFileTypeSettings ShownFileTypes { get; private set; }
/// <summary>
/// Determines main window start-up position, size and state
/// </summary>
public WindowStartupSettings WindowStartup { get; private set; }
/// <summary> /// <summary>
/// Language Code for the UI /// Language Code for the UI
/// </summary> /// </summary>
@ -163,7 +189,8 @@ namespace Ryujinx.Ui.Common.Configuration
GuiColumns = new Columns(); GuiColumns = new Columns();
ColumnSort = new ColumnSortSettings(); ColumnSort = new ColumnSortSettings();
GameDirs = new ReactiveObject<List<string>>(); GameDirs = new ReactiveObject<List<string>>();
ShownFileTypes = new ShownFileTypeSettings(); ShownFileTypes = new ShownFileTypeSettings();
WindowStartup = new WindowStartupSettings();
EnableCustomTheme = new ReactiveObject<bool>(); EnableCustomTheme = new ReactiveObject<bool>();
CustomThemePath = new ReactiveObject<string>(); CustomThemePath = new ReactiveObject<string>();
BaseStyle = new ReactiveObject<string>(); BaseStyle = new ReactiveObject<string>();
@ -663,12 +690,12 @@ namespace Ryujinx.Ui.Common.Configuration
FileSizeColumn = Ui.GuiColumns.FileSizeColumn, FileSizeColumn = Ui.GuiColumns.FileSizeColumn,
PathColumn = Ui.GuiColumns.PathColumn PathColumn = Ui.GuiColumns.PathColumn
}, },
ColumnSort = new ColumnSort ColumnSort = new ColumnSort
{ {
SortColumnId = Ui.ColumnSort.SortColumnId, SortColumnId = Ui.ColumnSort.SortColumnId,
SortAscending = Ui.ColumnSort.SortAscending SortAscending = Ui.ColumnSort.SortAscending
}, },
GameDirs = Ui.GameDirs, GameDirs = Ui.GameDirs,
ShownFileTypes = new ShownFileTypes ShownFileTypes = new ShownFileTypes
{ {
NSP = Ui.ShownFileTypes.NSP, NSP = Ui.ShownFileTypes.NSP,
@ -678,6 +705,14 @@ namespace Ryujinx.Ui.Common.Configuration
NRO = Ui.ShownFileTypes.NRO, NRO = Ui.ShownFileTypes.NRO,
NSO = Ui.ShownFileTypes.NSO, 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, LanguageCode = Ui.LanguageCode,
EnableCustomTheme = Ui.EnableCustomTheme, EnableCustomTheme = Ui.EnableCustomTheme,
CustomThemePath = Ui.CustomThemePath, CustomThemePath = Ui.CustomThemePath,
@ -781,6 +816,11 @@ namespace Ryujinx.Ui.Common.Configuration
Ui.IsAscendingOrder.Value = true; Ui.IsAscendingOrder.Value = true;
Ui.StartFullscreen.Value = false; Ui.StartFullscreen.Value = false;
Ui.ShowConsole.Value = true; 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.EnableKeyboard.Value = false;
Hid.EnableMouse.Value = false; Hid.EnableMouse.Value = false;
Hid.Hotkeys.Value = new KeyboardHotkeys Hid.Hotkeys.Value = new KeyboardHotkeys
@ -1334,13 +1374,29 @@ namespace Ryujinx.Ui.Common.Configuration
if (configurationFileFormat.Version < 46) 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"; configurationFileFormat.MultiplayerLanInterfaceId = "0";
configurationFileUpdated = true; 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; Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
Graphics.ResScale.Value = configurationFileFormat.ResScale; Graphics.ResScale.Value = configurationFileFormat.ResScale;
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom; Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
@ -1416,6 +1472,11 @@ namespace Ryujinx.Ui.Common.Configuration
Ui.ApplicationSort.Value = configurationFileFormat.ApplicationSort; Ui.ApplicationSort.Value = configurationFileFormat.ApplicationSort;
Ui.StartFullscreen.Value = configurationFileFormat.StartFullscreen; Ui.StartFullscreen.Value = configurationFileFormat.StartFullscreen;
Ui.ShowConsole.Value = configurationFileFormat.ShowConsole; 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.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard;
Hid.EnableMouse.Value = configurationFileFormat.EnableMouse; Hid.EnableMouse.Value = configurationFileFormat.EnableMouse;
Hid.Hotkeys.Value = configurationFileFormat.Hotkeys; Hid.Hotkeys.Value = configurationFileFormat.Hotkeys;

View file

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

View file

@ -153,13 +153,8 @@ namespace Ryujinx.Ui
// Apply custom theme if needed. // Apply custom theme if needed.
ThemeHelper.ApplyTheme(); 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; SetWindowSizePosition();
DefaultHeight = monitorHeight < 760 ? monitorHeight : 760;
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
Title = $"Ryujinx {Program.Version}"; Title = $"Ryujinx {Program.Version}";
@ -1314,6 +1309,7 @@ namespace Ryujinx.Ui
{ {
if (!_gameLoaded || !ConfigurationState.Instance.ShowConfirmExit || GtkDialog.CreateExitDialog()) if (!_gameLoaded || !ConfigurationState.Instance.ShowConfirmExit || GtkDialog.CreateExitDialog())
{ {
SaveWindowSizePosition();
End(); End();
} }
} }
@ -1322,6 +1318,7 @@ namespace Ryujinx.Ui
{ {
if (!_gameLoaded || !ConfigurationState.Instance.ShowConfirmExit || GtkDialog.CreateExitDialog()) if (!_gameLoaded || !ConfigurationState.Instance.ShowConfirmExit || GtkDialog.CreateExitDialog())
{ {
SaveWindowSizePosition();
End(); End();
} }
else 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) private void StopEmulation_Pressed(object sender, EventArgs args)
{ {
if (_emulationContext != null) if (_emulationContext != null)