persisting_window_settings/
persisting_window_settings.rs1use std::time::Duration;
9
10use bevy::{
11 prelude::*,
12 settings::{
13 ReflectSettingsGroup, SaveSettingsDeferred, SaveSettingsSync, SettingsGroup, SettingsPlugin,
14 },
15 window::{ExitCondition, WindowCloseRequested, WindowMode, WindowResized, WindowResolution},
16};
17
18fn main() {
19 App::new()
20 .add_plugins(DefaultPlugins.set(WindowPlugin {
21 exit_condition: ExitCondition::DontExit,
23 primary_window: Some(Window {
24 title: "Settings Window".into(),
25 ..default()
26 }),
27 ..default()
28 }))
29 .add_plugins(SettingsPlugin::new(
30 "org.bevy.examples.persisting_window_settings",
31 ))
32 .add_systems(Startup, setup)
33 .add_systems(Update, (on_window_close, update_window_settings))
34 .add_plugins(init_window_pos)
35 .run();
36}
37
38#[derive(Resource, SettingsGroup, Reflect, Default, Clone, PartialEq)]
40#[reflect(Resource, SettingsGroup, Default)]
41#[settings_group(group = "window")]
42struct WindowSettings {
43 position: Option<IVec2>,
44 size: Option<UVec2>,
45 fullscreen: bool,
46}
47
48fn init_window_pos(app: &mut App) {
50 let world = app.world_mut();
51 let Some(window_settings) = world.get_resource::<WindowSettings>() else {
52 return;
53 };
54 let window_settings = window_settings.clone();
55
56 let Ok(mut window) = world.query::<&mut Window>().single_mut(world) else {
57 warn!("window not found");
58 return;
59 };
60
61 if let Some(position) = window_settings.position {
62 window.position = WindowPosition::new(position);
63 }
64
65 if let Some(size) = window_settings.size {
66 window.resolution = WindowResolution::new(size.x, size.y);
67 }
68
69 window.mode = if window_settings.fullscreen {
70 WindowMode::BorderlessFullscreen(MonitorSelection::Current)
71 } else {
72 WindowMode::Windowed
73 };
74}
75
76fn setup(mut commands: Commands) {
77 commands.spawn((Camera::default(), Camera2d));
78 commands.spawn(Node {
79 width: percent(100),
80 height: percent(100),
81 display: Display::Flex,
82 flex_direction: FlexDirection::Column,
83 align_items: AlignItems::Center,
84 justify_content: JustifyContent::Center,
85 ..default()
86 });
87}
88
89fn update_window_settings(
91 mut move_events: MessageReader<WindowMoved>,
92 mut resize_events: MessageReader<WindowResized>,
93 windows: Query<&mut Window>,
94 window_settings: ResMut<WindowSettings>,
95 mut commands: Commands,
96) {
97 let Ok(window) = windows.single() else {
98 return;
99 };
100
101 let mut window_changed = false;
102 for _ in move_events.read() {
103 window_changed = true;
104 }
105
106 for _ in resize_events.read() {
107 window_changed = true;
108 }
109
110 if window_changed && store_window_settings(window_settings, window) {
111 commands.queue(SaveSettingsDeferred(Duration::from_secs_f32(0.5)));
112 }
113}
114
115fn store_window_settings(mut window_settings: ResMut<WindowSettings>, window: &Window) -> bool {
116 window_settings.set_if_neq(WindowSettings {
117 position: match window.position {
118 WindowPosition::At(pos) => Some(pos),
119 _ => None,
120 },
121 size: Some(UVec2::new(
122 window.resolution.width() as u32,
123 window.resolution.height() as u32,
124 )),
125 fullscreen: window.mode != WindowMode::Windowed,
126 })
127}
128
129fn on_window_close(mut close: MessageReader<WindowCloseRequested>, mut commands: Commands) {
130 if let Some(_close_event) = close.read().next() {
132 commands.queue(SaveSettingsSync::IfChanged);
133 commands.write_message(AppExit::Success);
134 }
135}