
# Objective - When spawning a window, it will be white until the GPU is ready to draw the app. To avoid this, we can make the window invisible and then make it visible once the gpu is ready. Unfortunately, the visible flag is not available to users. ## Solution - Let users change the visible flag ## Notes This is only user controlled. It would be nice if it was done automatically by bevy instead but I want to keep this PR simple.
185 lines
6.7 KiB
Rust
185 lines
6.7 KiB
Rust
//! Illustrates how to change window settings and shows how to affect
|
|
//! the mouse pointer in various ways.
|
|
|
|
use bevy::{
|
|
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
|
prelude::*,
|
|
window::{CursorGrabMode, PresentMode, WindowLevel, WindowTheme},
|
|
};
|
|
use bevy_internal::window::PrimaryWindow;
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins((
|
|
DefaultPlugins.set(WindowPlugin {
|
|
primary_window: Some(Window {
|
|
title: "I am a window!".into(),
|
|
resolution: (500., 300.).into(),
|
|
present_mode: PresentMode::AutoVsync,
|
|
// Tells wasm to resize the window according to the available canvas
|
|
fit_canvas_to_parent: true,
|
|
// Tells wasm not to override default event handling, like F5, Ctrl+R etc.
|
|
prevent_default_event_handling: false,
|
|
window_theme: Some(WindowTheme::Dark),
|
|
enabled_buttons: bevy::window::EnabledButtons {
|
|
maximize: false,
|
|
..Default::default()
|
|
},
|
|
// This will spawn an invisible window
|
|
// The window will be made visible in the setup() function
|
|
// This is useful when you want to avoid the white window that shows up before the GPU is ready to render the app.
|
|
visible: false,
|
|
..default()
|
|
}),
|
|
..default()
|
|
}),
|
|
LogDiagnosticsPlugin::default(),
|
|
FrameTimeDiagnosticsPlugin,
|
|
))
|
|
.add_systems(Startup, setup)
|
|
.add_systems(
|
|
Update,
|
|
(
|
|
change_title,
|
|
toggle_theme,
|
|
toggle_cursor,
|
|
toggle_vsync,
|
|
toggle_window_controls,
|
|
cycle_cursor_icon,
|
|
switch_level,
|
|
),
|
|
)
|
|
.run();
|
|
}
|
|
|
|
fn setup(mut primary_window: Query<&mut Window, With<PrimaryWindow>>) {
|
|
// At this point the gpu is ready to show the app so we can make the window visible
|
|
// There might still be a white frame when doing it in startup.
|
|
// Alternatively, you could have a system that waits a few seconds before making the window visible.
|
|
primary_window.single_mut().visible = true;
|
|
}
|
|
|
|
/// This system toggles the vsync mode when pressing the button V.
|
|
/// You'll see fps increase displayed in the console.
|
|
fn toggle_vsync(input: Res<Input<KeyCode>>, mut windows: Query<&mut Window>) {
|
|
if input.just_pressed(KeyCode::V) {
|
|
let mut window = windows.single_mut();
|
|
|
|
window.present_mode = if matches!(window.present_mode, PresentMode::AutoVsync) {
|
|
PresentMode::AutoNoVsync
|
|
} else {
|
|
PresentMode::AutoVsync
|
|
};
|
|
info!("PRESENT_MODE: {:?}", window.present_mode);
|
|
}
|
|
}
|
|
|
|
/// This system switches the window level when pressing the T button
|
|
/// You'll notice it won't be covered by other windows, or will be covered by all the other
|
|
/// windows depending on the level.
|
|
///
|
|
/// This feature only works on some platforms. Please check the
|
|
/// [documentation](https://docs.rs/bevy/latest/bevy/prelude/struct.Window.html#structfield.window_level)
|
|
/// for more details.
|
|
fn switch_level(input: Res<Input<KeyCode>>, mut windows: Query<&mut Window>) {
|
|
if input.just_pressed(KeyCode::T) {
|
|
let mut window = windows.single_mut();
|
|
|
|
window.window_level = match window.window_level {
|
|
WindowLevel::AlwaysOnBottom => WindowLevel::Normal,
|
|
WindowLevel::Normal => WindowLevel::AlwaysOnTop,
|
|
WindowLevel::AlwaysOnTop => WindowLevel::AlwaysOnBottom,
|
|
};
|
|
info!("WINDOW_LEVEL: {:?}", window.window_level);
|
|
}
|
|
}
|
|
|
|
/// This system toggles the window controls when pressing buttons 1, 2 and 3
|
|
///
|
|
/// This feature only works on some platforms. Please check the
|
|
/// [documentation](https://docs.rs/bevy/latest/bevy/prelude/struct.Window.html#structfield.enabled_buttons)
|
|
/// for more details.
|
|
fn toggle_window_controls(input: Res<Input<KeyCode>>, mut windows: Query<&mut Window>) {
|
|
let toggle_minimize = input.just_pressed(KeyCode::Key1);
|
|
let toggle_maximize = input.just_pressed(KeyCode::Key2);
|
|
let toggle_close = input.just_pressed(KeyCode::Key3);
|
|
|
|
if toggle_minimize || toggle_maximize || toggle_close {
|
|
let mut window = windows.single_mut();
|
|
|
|
if toggle_minimize {
|
|
window.enabled_buttons.minimize = !window.enabled_buttons.minimize;
|
|
}
|
|
if toggle_maximize {
|
|
window.enabled_buttons.maximize = !window.enabled_buttons.maximize;
|
|
}
|
|
if toggle_close {
|
|
window.enabled_buttons.close = !window.enabled_buttons.close;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// This system will then change the title during execution
|
|
fn change_title(mut windows: Query<&mut Window>, time: Res<Time>) {
|
|
let mut window = windows.single_mut();
|
|
window.title = format!(
|
|
"Seconds since startup: {}",
|
|
time.elapsed().as_secs_f32().round()
|
|
);
|
|
}
|
|
|
|
fn toggle_cursor(mut windows: Query<&mut Window>, input: Res<Input<KeyCode>>) {
|
|
if input.just_pressed(KeyCode::Space) {
|
|
let mut window = windows.single_mut();
|
|
|
|
window.cursor.visible = !window.cursor.visible;
|
|
window.cursor.grab_mode = match window.cursor.grab_mode {
|
|
CursorGrabMode::None => CursorGrabMode::Locked,
|
|
CursorGrabMode::Locked | CursorGrabMode::Confined => CursorGrabMode::None,
|
|
};
|
|
}
|
|
}
|
|
|
|
// This system will toggle the color theme used by the window
|
|
fn toggle_theme(mut windows: Query<&mut Window>, input: Res<Input<KeyCode>>) {
|
|
if input.just_pressed(KeyCode::F) {
|
|
let mut window = windows.single_mut();
|
|
|
|
if let Some(current_theme) = window.window_theme {
|
|
window.window_theme = match current_theme {
|
|
WindowTheme::Light => Some(WindowTheme::Dark),
|
|
WindowTheme::Dark => Some(WindowTheme::Light),
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
/// This system cycles the cursor's icon through a small set of icons when clicking
|
|
fn cycle_cursor_icon(
|
|
mut windows: Query<&mut Window>,
|
|
input: Res<Input<MouseButton>>,
|
|
mut index: Local<usize>,
|
|
) {
|
|
let mut window = windows.single_mut();
|
|
|
|
const ICONS: &[CursorIcon] = &[
|
|
CursorIcon::Default,
|
|
CursorIcon::Hand,
|
|
CursorIcon::Wait,
|
|
CursorIcon::Text,
|
|
CursorIcon::Copy,
|
|
];
|
|
|
|
if input.just_pressed(MouseButton::Left) {
|
|
*index = (*index + 1) % ICONS.len();
|
|
} else if input.just_pressed(MouseButton::Right) {
|
|
*index = if *index == 0 {
|
|
ICONS.len() - 1
|
|
} else {
|
|
*index - 1
|
|
};
|
|
}
|
|
|
|
window.cursor.icon = ICONS[*index];
|
|
}
|