use crate::context::Context;
use crate::error::GameError;
use crate::error::GameResult;
use std::collections::HashSet;
use winit::dpi;
pub use winit::event::MouseButton;
use winit::window::CursorGrabMode;
pub use winit::window::CursorIcon;
#[derive(Clone, Debug)]
pub struct MouseContext {
last_position: glam::Vec2,
last_delta: glam::Vec2,
delta: glam::Vec2,
buttons_pressed: HashSet<MouseButton>,
cursor_type: CursorIcon,
cursor_grabbed: bool,
cursor_hidden: bool,
previous_buttons_pressed: HashSet<MouseButton>,
}
impl MouseContext {
pub(crate) fn new() -> Self {
Self {
last_position: glam::Vec2::ZERO,
last_delta: glam::Vec2::ZERO,
delta: glam::Vec2::ZERO,
cursor_type: CursorIcon::Default,
buttons_pressed: HashSet::new(),
cursor_grabbed: false,
cursor_hidden: false,
previous_buttons_pressed: HashSet::new(),
}
}
pub fn cursor_type(&self) -> CursorIcon {
self.cursor_type
}
pub fn cursor_hidden(&self) -> bool {
self.cursor_hidden
}
pub fn position(&self) -> mint::Point2<f32> {
self.last_position.into()
}
pub fn delta(&self) -> mint::Point2<f32> {
self.delta.into()
}
pub fn button_pressed(&self, button: MouseButton) -> bool {
self.buttons_pressed.contains(&button)
}
pub fn button_just_pressed(&self, button: MouseButton) -> bool {
self.buttons_pressed.contains(&button) && !self.previous_buttons_pressed.contains(&button)
}
pub fn button_just_released(&self, button: MouseButton) -> bool {
!self.buttons_pressed.contains(&button) && self.previous_buttons_pressed.contains(&button)
}
pub fn handle_move(&mut self, new_x: f32, new_y: f32) {
let current_delta = self.delta();
let current_pos = self.position();
let diff = glam::Vec2::new(new_x - current_pos.x, new_y - current_pos.y);
self.set_delta(glam::Vec2::new(
current_delta.x + diff.x,
current_delta.y + diff.y,
));
self.set_last_delta(diff);
self.set_last_position(glam::Vec2::new(new_x, new_y));
}
pub fn reset_delta(&mut self) {
self.delta = glam::Vec2::ZERO;
}
pub fn save_mouse_state(&mut self) {
self.previous_buttons_pressed = self.buttons_pressed.clone();
}
pub(crate) fn set_last_position(&mut self, p: glam::Vec2) {
self.last_position = p;
}
pub(crate) fn set_last_delta(&mut self, p: glam::Vec2) {
self.last_delta = p;
}
pub(crate) fn set_delta(&mut self, p: glam::Vec2) {
self.delta = p;
}
pub(crate) fn set_button(&mut self, button: MouseButton, pressed: bool) {
if pressed {
let _ = self.buttons_pressed.insert(button);
} else {
let _ = self.buttons_pressed.remove(&button);
}
}
pub fn last_delta(&self) -> mint::Point2<f32> {
self.last_delta.into()
}
}
impl Default for MouseContext {
fn default() -> Self {
Self::new()
}
}
#[deprecated(since = "0.8.0", note = "Use `ctx.mouse.cursor_type` instead")]
pub fn cursor_type(ctx: &Context) -> CursorIcon {
ctx.mouse.cursor_type()
}
#[deprecated(since = "0.8.0", note = "Use `ctx.mouse.cursor_hidden` instead")]
pub fn cursor_hidden(ctx: &Context) -> bool {
ctx.mouse.cursor_hidden()
}
#[deprecated(since = "0.8.0", note = "Use `ctx.mouse.position` instead")]
pub fn position(ctx: &Context) -> mint::Point2<f32> {
ctx.mouse.position()
}
#[deprecated(since = "0.8.0", note = "Use `ctx.mouse.delta` instead")]
pub fn delta(ctx: &Context) -> mint::Point2<f32> {
ctx.mouse.delta()
}
#[deprecated(since = "0.8.0", note = "Use `ctx.mouse.button_pressed` instead")]
pub fn button_pressed(ctx: &Context, button: MouseButton) -> bool {
ctx.mouse.button_pressed(button)
}
#[deprecated(since = "0.8.0", note = "Use `ctx.mouse.button_just_pressed` instead")]
pub fn button_just_pressed(ctx: &Context, button: MouseButton) -> bool {
ctx.mouse.button_just_pressed(button)
}
#[deprecated(since = "0.8.0", note = "Use `ctx.mouse.button_just_released` instead")]
pub fn button_just_released(ctx: &Context, button: MouseButton) -> bool {
ctx.mouse.button_just_released(button)
}
#[deprecated(since = "0.8.0", note = "Use `ctx.mouse.handle_move` instead")]
pub fn handle_move(ctx: &mut Context, new_x: f32, new_y: f32) {
ctx.mouse.handle_move(new_x, new_y);
}
pub fn set_cursor_hidden(ctx: &mut Context, hidden: bool) {
ctx.mouse.cursor_hidden = hidden;
ctx.gfx.window.set_cursor_visible(!hidden);
}
pub fn set_cursor_type(ctx: &mut Context, cursor_type: CursorIcon) {
ctx.mouse.cursor_type = cursor_type;
ctx.gfx.window.set_cursor_icon(cursor_type);
}
pub fn cursor_grabbed(ctx: &Context) -> bool {
ctx.mouse.cursor_grabbed
}
#[allow(clippy::missing_errors_doc)]
pub fn set_cursor_grabbed(ctx: &mut Context, grabbed: bool) -> GameResult {
ctx.mouse.cursor_grabbed = grabbed;
ctx.gfx
.window
.set_cursor_grab(if grabbed {
if cfg!(target_os = "macos") {
CursorGrabMode::Locked
} else {
CursorGrabMode::Confined
}
} else {
CursorGrabMode::None
})
.map_err(|e| GameError::WindowError(e.to_string()))
}
pub fn set_position<P>(ctx: &mut Context, point: P) -> GameResult
where
P: Into<mint::Point2<f32>>,
{
let point = glam::Vec2::from(point.into());
ctx.mouse.last_position = point;
ctx.gfx
.window
.set_cursor_position(dpi::LogicalPosition {
x: f64::from(point.x),
y: f64::from(point.y),
})
.map_err(|_| GameError::WindowError("Couldn't set mouse cursor position!".to_owned()))
}