use bevy::{
render::extract_resource::{ExtractResource, ExtractResourcePlugin},
window::PrimaryWindow,
};
use crate::{
filter::PxFilterAsset,
prelude::*,
screen::{screen_scale, Screen},
set::PxSet,
};
pub(crate) fn plug(app: &mut App) {
app.add_plugins((
ExtractResourcePlugin::<PxCursor>::default(),
ExtractResourcePlugin::<PxCursorPosition>::default(),
ExtractResourcePlugin::<CursorState>::default(),
))
.init_resource::<PxCursor>()
.init_resource::<PxCursorPosition>()
.add_systems(
PreUpdate,
update_cursor_position.in_set(PxSet::UpdateCursorPosition),
)
.add_systems(PostUpdate, change_cursor);
}
#[derive(ExtractResource, Resource, Clone, Default, Debug)]
pub enum PxCursor {
#[default]
Os,
Filter {
idle: Handle<PxFilterAsset>,
left_click: Handle<PxFilterAsset>,
right_click: Handle<PxFilterAsset>,
},
}
#[derive(ExtractResource, Resource, Deref, DerefMut, Clone, Default, Debug)]
pub struct PxCursorPosition(pub Option<UVec2>);
fn update_cursor_position(
mut move_events: EventReader<CursorMoved>,
mut leave_events: EventReader<CursorLeft>,
cameras: Query<(&Camera, &GlobalTransform)>,
screen: Res<Screen>,
mut position: ResMut<PxCursorPosition>,
windows: Query<&Window>,
) {
if leave_events.read().last().is_some() {
**position = None;
return;
}
let Some(event) = move_events.read().last() else {
return;
};
let Ok((camera, tf)) = cameras.get_single() else {
return;
};
let Ok(window) = windows.get_single() else {
return;
};
let Ok(new_position) = camera.viewport_to_world_2d(tf, event.position) else {
**position = None;
return;
};
let new_position = new_position
/ screen_scale(
screen.computed_size,
Vec2::new(window.width(), window.height()),
)
* screen.computed_size.as_vec2()
+ screen.computed_size.as_vec2() / 2.;
**position = (new_position.cmpge(Vec2::ZERO).all()
&& new_position.cmplt(screen.computed_size.as_vec2()).all())
.then(|| new_position.as_uvec2());
}
fn change_cursor(
mut windows: Query<&mut Window, With<PrimaryWindow>>,
cursor: Res<PxCursor>,
cursor_pos: Res<PxCursorPosition>,
) {
if !cursor.is_changed() && !cursor_pos.is_changed() {
return;
}
let Ok(mut window) = windows.get_single_mut() else {
return;
};
window.cursor_options.visible = cursor_pos.is_none()
|| match *cursor {
PxCursor::Os => true,
PxCursor::Filter { .. } => false,
};
}
#[derive(Resource)]
pub(crate) enum CursorState {
Idle,
Left,
Right,
}
impl ExtractResource for CursorState {
type Source = ButtonInput<MouseButton>;
fn extract_resource(source: &ButtonInput<MouseButton>) -> Self {
use CursorState::*;
if source.pressed(MouseButton::Left) {
Left
} else if source.pressed(MouseButton::Right) {
Right
} else {
Idle
}
}
}