use bevy::{
prelude::*,
window::{CursorGrabMode, PrimaryWindow},
};
use leafwing_input_manager::prelude::*;
pub struct DollyCursorGrab;
impl Plugin for DollyCursorGrab {
fn build(&self, app: &mut App) {
app.init_resource::<DollyCursorGrabConfig>()
.add_systems(
Startup,
(initial_grab_cursor, dolly_cursor_grab_input_setup),
)
.add_systems(Update, cursor_grab.run_if(use_grab));
}
}
#[derive(Resource)]
pub struct DollyCursorGrabConfig {
pub enabled: bool,
pub visible: bool,
}
impl Default for DollyCursorGrabConfig {
fn default() -> Self {
DollyCursorGrabConfig {
enabled: true,
visible: false,
}
}
}
fn use_grab(config: Res<DollyCursorGrabConfig>) -> bool {
config.enabled
}
#[derive(Component)]
struct DollyCursorGrabAction;
fn dolly_cursor_grab_input_setup(mut commands: Commands) {
commands.spawn((DollyCursorGrabInputBundle::default(), DollyCursorGrabAction));
}
#[derive(Actionlike, PartialEq, Eq, Clone, Copy, Hash, Debug, Reflect)]
enum GrabAction {
Exit,
}
#[derive(Bundle)]
struct DollyCursorGrabInputBundle {
input_manager: InputManagerBundle<GrabAction>,
}
impl Default for DollyCursorGrabInputBundle {
fn default() -> Self {
use GrabAction::*;
let mut input_map = InputMap::default();
input_map.insert(Exit, KeyCode::Escape);
let input_manager = InputManagerBundle {
input_map,
action_state: ActionState::default(),
};
Self { input_manager }
}
}
fn toggle_grab_cursor(window: &mut Window) -> bool {
match window.cursor_options.grab_mode {
CursorGrabMode::None => {
window.cursor_options.grab_mode = CursorGrabMode::Confined;
window.cursor_options.visible = false;
false
}
_ => {
window.cursor_options.grab_mode = CursorGrabMode::None;
window.cursor_options.visible = true;
true
}
}
}
fn initial_grab_cursor(
mut windows: Query<&mut Window, With<PrimaryWindow>>,
mut config: ResMut<DollyCursorGrabConfig>,
) {
config.visible = if !config.enabled {
if let Ok(window) = &mut windows.get_single_mut() {
toggle_grab_cursor(window)
} else {
false
}
} else if let Ok(window) = &mut windows.get_single_mut() {
toggle_grab_cursor(window)
} else {
warn!("Primary window not found for `initial_grab_cursor`!");
false
};
}
fn cursor_grab(
mut windows: Query<&mut Window, With<PrimaryWindow>>,
keys: Res<ButtonInput<KeyCode>>,
mut config: ResMut<DollyCursorGrabConfig>,
) {
if let Ok(window) = &mut windows.get_single_mut() {
if keys.just_pressed(KeyCode::Escape) {
config.visible = toggle_grab_cursor(window);
}
}
}