use crate::prelude::*; use std::ops::{BitOr, Deref, DerefMut}; use crate::{ layout::{UiModule, UiRegion, Vec2}, util::{HashMap, Id}, }; pub trait CursorCtx { fn cursor_state(&self) -> &CursorState; } pub enum Button { Left, Right, Middle, } pub enum Sense { PressStart(Button), Pressing(Button), PressEnd(Button), HoverStart, Hovering, HoverEnd, } pub struct Senses(Vec); impl Sense { pub fn click() -> Self { Self::PressStart(Button::Left) } pub fn unclick() -> Self { Self::PressEnd(Button::Left) } } #[derive(Default, Clone)] pub struct CursorState { pub pos: Vec2, pub exists: bool, pub buttons: CursorButtons, } #[derive(Default, Clone)] pub struct CursorButtons { pub left: ActivationState, pub middle: ActivationState, pub right: ActivationState, } impl CursorButtons { pub fn select(&self, button: &Button) -> &ActivationState { match button { Button::Left => &self.left, Button::Right => &self.right, Button::Middle => &self.middle, } } pub fn end_frame(&mut self) { self.left.end_frame(); self.middle.end_frame(); self.right.end_frame(); } } #[derive(Debug, Clone, Copy, Default, PartialEq)] pub enum ActivationState { Start, On, End, #[default] Off, } pub struct Sensor { pub senses: Senses, pub f: Box>, } pub type SensorMap = HashMap>; pub type SenseShape = UiRegion; pub struct SensorGroup { pub hover: ActivationState, pub sensors: Vec>, } pub struct SenseData { pub cursor: Vec2, pub size: Vec2, } pub trait SenseFn: FnMut(&mut Ctx, SenseData) + 'static {} impl SenseFn for F {} pub struct SensorModule { map: SensorMap, active: HashMap>, } impl UiModule for SensorModule { fn on_draw(&mut self, inst: &WidgetInstance) { if self.map.contains_key(&inst.id) { self.active .entry(inst.layer) .or_default() .insert(inst.id.duplicate(), inst.region); } } fn on_undraw(&mut self, inst: &WidgetInstance) { if let Some(layer) = self.active.get_mut(&inst.layer) { layer.remove(&inst.id); } } fn on_remove(&mut self, id: &Id) { self.map.remove(id); } } impl SensorModule { pub fn merge(&mut self, other: Self) { for (id, group) in other.map { for sensor in group.sensors { self.map .entry(id.duplicate()) .or_default() .sensors .push(sensor); } } } } impl SensorModule { pub fn run(ctx: &mut Ctx, cursor: &CursorState, window_size: Vec2) { let mut layers = std::mem::take(&mut ctx.ui().layers); let mut module = std::mem::take(ctx.ui().modules.get_mut::()); // TODO: temp, need to actually make reverse let mut layer_idxs = Vec::new(); for (i, _) in layers.iter_mut() { layer_idxs.push(i); } for l in &layer_idxs { let Some(list) = module.active.get_mut(l) else { continue; }; let mut ran = false; for (id, shape) in list.iter() { let group = module.map.get_mut(id).unwrap(); let region = shape.to_screen(window_size); let in_shape = cursor.exists && region.contains(cursor.pos); group.hover.update(in_shape); if group.hover == ActivationState::Off { continue; } for sensor in &mut group.sensors { if should_run(&sensor.senses, &cursor.buttons, group.hover) { ran = true; let sctx = SenseData { cursor: cursor.pos - region.top_left, size: region.bot_right - region.top_left, }; (sensor.f)(ctx, sctx); } } } if ran { break; } } let ui_mod = ctx.ui().modules.get_mut::(); std::mem::swap(ui_mod, &mut module); ui_mod.merge(module); ctx.ui().layers = layers; } } pub fn should_run(senses: &Senses, cursor: &CursorButtons, hover: ActivationState) -> bool { for sense in senses.iter() { if match sense { Sense::PressStart(button) => cursor.select(button).is_start(), Sense::Pressing(button) => cursor.select(button).is_on(), Sense::PressEnd(button) => cursor.select(button).is_end(), Sense::HoverStart => hover.is_start(), Sense::Hovering => hover.is_on(), Sense::HoverEnd => hover.is_end(), } { return true; } } false } 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 Event for Senses { type Module = SensorModule; type Data = SenseData; } impl EventModule for SensorModule { fn register(&mut self, id: Id, senses: Senses, f: impl EventFn) { self.map.entry(id).or_default().sensors.push(Sensor { senses, f: Box::new(f), }); } } impl Event for Sense { type Module = SensorModule; type Data = SenseData; } impl EventModule for SensorModule { fn register(&mut self, id: Id, sense: Sense, f: impl EventFn) { // TODO: does not add to active if currently active self.map.entry(id).or_default().sensors.push(Sensor { senses: sense.into(), f: Box::new(f), }); } } impl Default for SensorGroup { fn default() -> Self { Self { hover: Default::default(), sensors: Default::default(), } } } impl Deref for Senses { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for Senses { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl From for Senses { fn from(val: Sense) -> Self { Senses(vec![val]) } } impl BitOr for Sense { type Output = Senses; fn bitor(self, rhs: Self) -> Self::Output { Senses(vec![self, rhs]) } } impl BitOr for Senses { type Output = Self; fn bitor(mut self, rhs: Sense) -> Self::Output { self.0.push(rhs); self } } impl Default for SensorModule { fn default() -> Self { Self { map: Default::default(), active: Default::default(), } } }