# bevy-persistent-windows A [Bevy](https://bevyengine.org/) plugin to easily create and manage windows that remember where they were. ## Background When you're developing a game, thus frequently restarting it, you may (understandably) desire that the windows just stay where they were in the last run. Implementing this manually in every project you create is error-prone and time-consuming (trust me, I know). This plugin aims to make it as seamless as possible! ## Installation We'll be using [bevy-persistent](https://github.com/umut-sahin/bevy-persistent/) to store window states persistently, so let's add it first: ```shell cargo add bevy-persistent --features all # you probably don't need all features, see installation section of bevy-persistent to learn more ``` Now let's add [bevy-persistent-windows](https://github.com/umut-sahin/bevy-persistent-windows/) to make our windows persistent: ```shell cargo add bevy-persistent-windows ``` ## Usage ### Prelude As mentioned before, we'll be using [bevy-persistent](https://github.com/umut-sahin/bevy-persistent/) to store the window state persistently, so lets prelude it first: ```rust use bevy_persistent::prelude::*; ``` We need [WindowState](https://docs.rs/bevy-persistent-windows/latest/bevy_persistent_windows/components/struct.WindowState.html), [PersistentWindowBundle](https://docs.rs/bevy-persistent-windows/latest/bevy_persistent_windows/bundles/struct.PersistentWindowBundle.html) and [PersistentWindowsPlugin](https://docs.rs/bevy-persistent-windows/latest/bevy_persistent_windows/plugins/struct.PersistentWindowsPlugin.html) types to use the library, and they are exported from the prelude module: ```rust use bevy_persistent_windows::prelude::*; ``` ### Setup Let's start by creating an `App` within `main`: ```rust let mut app = App::new(); ``` We'll add the default plugins to this app, but we should edit the window plugin to avoid creating a default primary window: ```rust let window_plugin = WindowPlugin { primary_window: None, ..Default::default() }; app.add_plugins(DefaultPlugins.set(window_plugin).build()); ``` We need somewhere to store the window state, to restore the window later: ```rust let state_directory = dirs::data_dir() .expect("failed to get the platforms data directory") .join("your-amazing-game") .join("state"); ``` Time to create the primary window: ```rust app.world_mut().spawn(( PrimaryWindow, PersistentWindowBundle { window: Window { title: "I am the primary window!".to_owned(), ..Default::default() }, state: Persistent::::builder() .name("primary window state") .format(StorageFormat::Toml) .path(state_directory.join("primary-window.toml")) .default(WindowState::windowed(1280, 720)) .revertible(true) .revert_to_default_on_deserialization_errors(true) .build() .expect("failed to create the persistent primary window state"), }, )); ``` Feel free to spawn additional windows, without the `PrimaryWindow` component of course! Once, you're done, you can add `PersistentWindowsPlugin` plugin to the app: ```rust app.add_plugins(PersistentWindowsPlugin); ``` And run your game: ```rust app.run(); ``` You'll see a `1280x720` window appear in the center of your best monitor, move it around, resize, and play with it. Now close the application, and run it again. You'll see that the window will open in the exact same monitor, with the exact same resolution, and the exact same position! See [examples/setup.rs](https://github.com/umut-sahin/bevy-persistent-windows/blob/main/examples/setup.rs) for the full example! ### Controlling You may wish to control the persistent windows programmatically. You can edit the window itself, but if you want your changes to persist, you should modify the window state directly! Say you want to toggle fullscreen when space bar is pressed, you can add this system to your app: ```rust fn fullscreen_toggle( keyboard_input: Res>, mut query: Query<&mut Persistent, With>, ) { if keyboard_input.just_pressed(KeyCode::Space) { let mut primary_window_state = query.get_single_mut().unwrap(); if primary_window_state.mode == WindowMode::Windowed { primary_window_state.mode = WindowMode::Fullscreen; } else { primary_window_state.mode = WindowMode::Windowed; } primary_window_state.persist().ok(); } } ``` Or if you want to move the window with arrow keys, and resize it with ctrl + arrow keys, you can use this system: ```rust fn movement( time: Res