use crate::types::Rect;
use serde::{Deserialize, Serialize};
use super::touch::TouchState;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
pub enum MouseButton {
#[default]
Left,
Right,
Middle,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub struct ModifierKeys {
pub shift: bool,
pub ctrl: bool,
pub alt: bool,
pub meta: bool,
}
impl ModifierKeys {
pub fn none() -> Self {
Self::default()
}
pub fn shift() -> Self {
Self {
shift: true,
..Default::default()
}
}
pub fn ctrl() -> Self {
Self {
ctrl: true,
..Default::default()
}
}
pub fn any(&self) -> bool {
self.shift || self.ctrl || self.alt || self.meta
}
#[inline]
pub fn ctrl_shift(&self) -> bool {
self.ctrl && self.shift && !self.alt && !self.meta
}
#[inline]
pub fn ctrl_alt(&self) -> bool {
self.ctrl && self.alt && !self.shift && !self.meta
}
#[inline]
pub fn command(&self) -> bool {
#[cfg(target_os = "macos")]
{
self.meta
}
#[cfg(not(target_os = "macos"))]
{
self.ctrl
}
}
}
#[derive(Clone, Debug, Default)]
pub struct PointerState {
pub pos: Option<(f64, f64)>,
pub button_down: Option<MouseButton>,
pub clicked: Option<MouseButton>,
pub double_clicked: Option<MouseButton>,
pub triple_clicked: Option<MouseButton>,
pub prev_pos: Option<(f64, f64)>,
}
impl PointerState {
pub fn delta(&self) -> (f64, f64) {
match (self.pos, self.prev_pos) {
(Some((x, y)), Some((px, py))) => (x - px, y - py),
_ => (0.0, 0.0),
}
}
pub fn is_present(&self) -> bool {
self.pos.is_some()
}
}
#[derive(Clone, Debug)]
pub struct DragState {
pub start: (f64, f64),
pub current: (f64, f64),
pub delta: (f64, f64),
pub total_delta: (f64, f64),
pub button: MouseButton,
pub initial_value: f64,
}
impl DragState {
pub fn new(start: (f64, f64), current: (f64, f64), button: MouseButton) -> Self {
let total_delta = (current.0 - start.0, current.1 - start.1);
Self {
start,
current,
delta: (0.0, 0.0),
total_delta,
button,
initial_value: 0.0,
}
}
pub fn update(&mut self, x: f64, y: f64) {
self.delta = (x - self.current.0, y - self.current.1);
self.current = (x, y);
self.total_delta = (self.current.0 - self.start.0, self.current.1 - self.start.1);
}
pub fn is_dragging(&self, _id: &crate::types::state::WidgetId) -> bool {
true
}
pub fn delta_tuple(&self) -> (f64, f64) {
self.delta
}
}
#[derive(Clone, Debug, Default)]
pub struct InputState {
pub pointer: PointerState,
pub modifiers: ModifierKeys,
pub scroll_delta: (f64, f64),
pub drag: Option<DragState>,
pub dt: f64,
pub time: f64,
pub multi_touch: Option<TouchState>,
}
impl InputState {
pub fn new() -> Self {
Self::default()
}
pub fn with_pointer_pos(mut self, x: f64, y: f64) -> Self {
self.pointer.pos = Some((x, y));
self
}
pub fn pointer_pos(&self) -> Option<(f64, f64)> {
self.pointer.pos
}
pub fn is_hovered(&self, rect: &Rect) -> bool {
if let Some((px, py)) = self.pointer.pos {
rect.contains(px, py)
} else {
false
}
}
pub fn is_clicked(&self) -> bool {
self.pointer.clicked == Some(MouseButton::Left)
}
pub fn is_double_clicked(&self) -> bool {
self.pointer.double_clicked == Some(MouseButton::Left)
}
pub fn is_middle_clicked(&self) -> bool {
self.pointer.clicked == Some(MouseButton::Middle)
}
pub fn is_right_clicked(&self) -> bool {
self.pointer.clicked == Some(MouseButton::Right)
}
pub fn is_mouse_down(&self) -> bool {
self.pointer.button_down == Some(MouseButton::Left)
}
pub fn is_dragging(&self) -> bool {
self.drag.is_some()
}
pub fn drag_delta(&self) -> Option<(f64, f64)> {
self.drag.as_ref().map(|d| d.delta)
}
pub fn shift(&self) -> bool {
self.modifiers.shift
}
pub fn ctrl(&self) -> bool {
self.modifiers.ctrl
}
pub fn alt(&self) -> bool {
self.modifiers.alt
}
pub fn consume_click(&mut self) -> bool {
if self.pointer.clicked.is_some() {
self.pointer.clicked = None;
true
} else {
false
}
}
pub fn consume_scroll(&mut self) -> (f64, f64) {
let delta = self.scroll_delta;
self.scroll_delta = (0.0, 0.0);
delta
}
pub fn touch_count(&self) -> usize {
self.multi_touch
.as_ref()
.map(|t| t.touch_count())
.unwrap_or(0)
}
pub fn primary_pointer(&self) -> Option<(f64, f64)> {
self.pointer.pos.or_else(|| {
self.multi_touch
.as_ref()
.and_then(|t| t.primary_touch())
.map(|t| t.pos)
})
}
pub fn end_frame(&mut self) {
self.pointer.clicked = None;
self.pointer.double_clicked = None;
self.pointer.triple_clicked = None;
self.pointer.prev_pos = self.pointer.pos;
if let Some(ref mut touch) = self.multi_touch {
touch.clear_deltas();
}
}
}