diff --git a/Prowl.Editor/EditorApplication.cs b/Prowl.Editor/EditorApplication.cs index c273f2171..d3a2dae5d 100644 --- a/Prowl.Editor/EditorApplication.cs +++ b/Prowl.Editor/EditorApplication.cs @@ -34,12 +34,24 @@ public class EditorApplication : Game // All registered panel types (from [EditorWindow] attribute scan) private readonly List<(Type type, string path)> _registeredPanels = new(); + public override void InitializeWindow(string title, int width, int height) + { + var instance = EditorSettings.Instance; + Window.InitWindow(title, width, height, instance.WindowMaximized ? Silk.NET.Windowing.WindowState.Maximized : Silk.NET.Windowing.WindowState.Normal, false); + + Window.Position = new Silk.NET.Maths.Vector2D( + instance.WindowX > -1 ? instance.WindowX : Window.Position.X, + instance.WindowY > -1 ? instance.WindowY : Window.Position.Y); + } + public override void Initialize() { Instance = this; Application.IsEditor = true; Application.IsPlaying = false; + // Set invariant culture for consistent number parsing/formatting in the editor (e.g. asset import settings) + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture; InitializeFont(); PaperInstance.TextMode = Prowl.Quill.TextRenderMode.Bitmap; @@ -129,6 +141,34 @@ public override void Initialize() // Set Windows title bar to match Darkest theme color ApplyDarkTitleBar(); + + // Attach to the window events to save the position and state of the window + Window.InternalWindow.Move += (position) => + { + EditorSettings.Instance.WindowX = position.X; + EditorSettings.Instance.WindowY = position.Y; + + EditorSettings.Instance.Save(); + }; + + Window.InternalWindow.Resize += (size) => + { + EditorSettings.Instance.WindowWidth = size.X; + EditorSettings.Instance.WindowHeight = size.Y; + EditorSettings.Instance.Save(); + }; + + Window.InternalWindow.StateChanged += (state) => + { + EditorSettings.Instance.WindowMaximized = state == Silk.NET.Windowing.WindowState.Maximized; + + EditorSettings.Instance.Save(); + }; + + Window.InternalWindow.Closing += () => + { + SaveEditorWindowState(); + }; } [DllImport("dwmapi.dll", PreserveSig = true)] @@ -909,10 +949,27 @@ private void RestoreAutoSavedScene(string path) // Project Switching // ================================================================ + /// + /// Saves the editor window position, size and maximization state. + /// + public void SaveEditorWindowState() + { + EditorSettings.Instance.WindowX = Window.Position.X; + EditorSettings.Instance.WindowY = Window.Position.Y; + + EditorSettings.Instance.WindowWidth = Window.Size.X; + EditorSettings.Instance.WindowHeight = Window.Size.Y; + + EditorSettings.Instance.WindowMaximized = Window.InternalWindow.WindowState == Silk.NET.Windowing.WindowState.Maximized; + + EditorSettings.Instance.Save(); + } + /// Save layout and settings for the current project. public void SaveProjectState() { if (Project.Current == null) return; + SaveEditorWindowState(); Docking.LayoutSerializer.Save(_dockSpace); ProjectSettingsRegistry.SaveAll(); } diff --git a/Prowl.Editor/Settings/EditorSettings.cs b/Prowl.Editor/Settings/EditorSettings.cs index a6dc255fe..3808712a7 100644 --- a/Prowl.Editor/Settings/EditorSettings.cs +++ b/Prowl.Editor/Settings/EditorSettings.cs @@ -28,6 +28,16 @@ public class EditorSettings public bool ReimportOnFocusOnly { get; set; } = true; public int ThumbnailSize { get; set; } = 32; + public int WindowX { get; set; } = -1; + + public int WindowY { get; set; } = -1; + + public int WindowWidth { get; set; } = 1280; + + public int WindowHeight { get; set; } = 800; + + public bool WindowMaximized { get; set; } = false; + // Shortcuts — only user-overridden bindings are stored public Dictionary ShortcutOverrides { get; set; } = new(); diff --git a/Prowl.Runtime/Game.cs b/Prowl.Runtime/Game.cs index a8bc58bed..34bbe53c5 100644 --- a/Prowl.Runtime/Game.cs +++ b/Prowl.Runtime/Game.cs @@ -39,9 +39,18 @@ public abstract class Game public bool DrawGizmos { get; set; } - public void Run(string title, int width, int height) + /// + /// Added a separate method to initialize the window as it might be needed to restore the latest saved state of the window (size, position, etc.) when the game is launched again. + /// This allows for better user experience by remembering their preferences. + /// + public virtual void InitializeWindow(string title, int width, int height) { Window.InitWindow(title, width, height, Silk.NET.Windowing.WindowState.Normal, false); + } + + public void Run(string title, int width, int height) + { + InitializeWindow(title, width, height); Window.Load += () => { diff --git a/Prowl.Runtime/Window.cs b/Prowl.Runtime/Window.cs index 55ba65912..7927ed936 100644 --- a/Prowl.Runtime/Window.cs +++ b/Prowl.Runtime/Window.cs @@ -28,6 +28,12 @@ public static class Window public static event Action? StateChanged; public static event Action? FileDrop; + public static Vector2D Position + { + get { return InternalWindow.Position; } + set { InternalWindow.Position = value; } + } + public static Vector2D Size { get { return InternalWindow.Size; }