use crate::prelude::*; use std::{ ops::{BitOr, Deref, DerefMut}, rc::Rc, }; #[derive(Clone, Copy, PartialEq)] pub enum CursorButton { Left, Right, Middle, } #[derive(Clone, Copy, PartialEq)] pub enum CursorSense { PressStart(CursorButton), Pressing(CursorButton), PressEnd(CursorButton), HoverStart, Hovering, HoverEnd, Scroll, } #[derive(Clone)] pub struct CursorSenses(Vec); impl Event for CursorSenses { type Data<'a> = CursorData<'a>; type State = SensorState; fn should_run<'a>(&self, data: &Self::Data<'a>) -> Option> { if let Some(sense) = should_run(self, &data.cursor, data.hover) { let mut data = data.clone(); data.sense = sense; Some(data) } else { None } } } impl CursorSense { pub fn click() -> Self { Self::PressStart(CursorButton::Left) } pub fn click_or_drag() -> CursorSenses { Self::click() | Self::Pressing(CursorButton::Left) } pub fn unclick() -> Self { Self::PressEnd(CursorButton::Left) } pub fn is_dragging(&self) -> bool { matches!(self, CursorSense::Pressing(CursorButton::Left)) } } #[derive(Default, Clone)] pub struct CursorState { pub pos: Vec2, pub exists: bool, pub buttons: CursorButtons, pub scroll_delta: Vec2, } #[derive(Default, Clone)] pub struct CursorButtons { pub left: ActivationState, pub middle: ActivationState, pub right: ActivationState, } impl CursorButtons { pub fn select(&self, button: &CursorButton) -> &ActivationState { match button { CursorButton::Left => &self.left, CursorButton::Right => &self.right, CursorButton::Middle => &self.middle, } } pub fn end_frame(&mut self) { self.left.end_frame(); self.middle.end_frame(); self.right.end_frame(); } pub fn iter(&self) -> impl Iterator { [ CursorButton::Left, CursorButton::Middle, CursorButton::Right, ] .into_iter() .map(|b| (b, self.select(&b))) } } impl CursorState { pub fn end_frame(&mut self) { self.buttons.end_frame(); self.scroll_delta = Vec2::ZERO; } } #[derive(Debug, Clone, Copy, Default, PartialEq)] pub enum ActivationState { Start, On, End, #[default] Off, } /// this and other similar stuff has a generic /// because I kind of want to make CursorModule generic /// or basically have some way to have custom senses /// that depend on active widget positions /// but I'm not sure how or if worth it pub struct Sensor { pub senses: CursorSenses, pub f: Rc>, } pub type SenseShape = UiRegion; #[derive(Default, Debug)] pub struct SensorState { pub hover: ActivationState, } #[derive(Clone)] pub struct CursorData<'a> { /// where this widget was hit pub pos: Vec2, pub size: Vec2, pub scroll_delta: Vec2, pub hover: ActivationState, pub cursor: CursorState, /// the first sense that triggered this pub sense: CursorSense, pub render: &'a UiRenderState, } pub trait SensorUi { fn run_sensors( &self, rsc: &mut Rsc, state: &mut Rsc::State, cursor: CursorState, window_size: Vec2, ); } impl SensorUi for UiRenderState { fn run_sensors( &self, rsc: &mut Rsc, state: &mut Rsc::State, cursor: CursorState, window_size: Vec2, ) { // in order to remove this take, need to store active list in UiRenderState somehow // this would probably be done through a generic parameter that adds yet another rsc / // state like thing, but local to render state, and is passed to UiRsc events so you can // update it there? let mut active = std::mem::take(&mut rsc.events_mut().get_type::().active); for layer in self.layers.indices().rev() { let mut sensed = false; for (id, sensor) in active.get_mut(&layer).into_flat_iter() { let shape = self.active.get(id).unwrap().region; let region = shape.to_px(window_size); let in_shape = cursor.exists && region.contains(cursor.pos); sensor.hover.update(in_shape); if sensor.hover == ActivationState::Off { continue; } sensed = true; let cursor = cursor.clone(); let data = CursorData { pos: cursor.pos - region.top_left, size: region.bot_right - region.top_left, scroll_delta: cursor.scroll_delta, hover: sensor.hover, cursor, // this does not have any meaning; // might wanna set up Event to have a prepare stage sense: CursorSense::Hovering, render: self, }; rsc.run_event::(*id, data, state); } if sensed { break; } } rsc.events_mut().get_type::().active = active; } } pub fn should_run( senses: &CursorSenses, cursor: &CursorState, hover: ActivationState, ) -> Option { for sense in senses.iter() { if match sense { CursorSense::PressStart(button) => cursor.buttons.select(button).is_start(), CursorSense::Pressing(button) => cursor.buttons.select(button).is_on(), CursorSense::PressEnd(button) => cursor.buttons.select(button).is_end(), CursorSense::HoverStart => hover.is_start(), CursorSense::Hovering => hover.is_on(), CursorSense::HoverEnd => hover.is_end(), CursorSense::Scroll => cursor.scroll_delta != Vec2::ZERO, } { return Some(*sense); } } None } impl ActivationState { pub fn is_start(&self) -> bool { *self == Self::Start } pub fn is_on(&self) -> bool { *self == Self::Start || *self == Self::On } pub fn is_end(&self) -> bool { *self == Self::End } pub fn is_off(&self) -> bool { *self == Self::End || *self == Self::Off } pub fn update(&mut self, on: bool) { *self = match *self { Self::Start => match on { true => Self::On, false => Self::End, }, Self::On => match on { true => Self::On, false => Self::End, }, Self::End => match on { true => Self::Start, false => Self::Off, }, Self::Off => match on { true => Self::Start, false => Self::Off, }, } } pub fn end_frame(&mut self) { match self { Self::Start => *self = Self::On, Self::End => *self = Self::Off, _ => (), } } } impl EventLike for CursorSense { type Event = CursorSenses; fn into_event(self) -> Self::Event { self.into() } } impl Deref for CursorSenses { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for CursorSenses { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl From for CursorSenses { fn from(val: CursorSense) -> Self { CursorSenses(vec![val]) } } impl BitOr for CursorSense { type Output = CursorSenses; fn bitor(self, rhs: Self) -> Self::Output { CursorSenses(vec![self, rhs]) } } impl BitOr for CursorSenses { type Output = Self; fn bitor(mut self, rhs: CursorSense) -> Self::Output { self.0.push(rhs); self } }