actually sane sensor handling
This commit is contained in:
@@ -1,11 +1,29 @@
|
||||
use crate::{HashMap, Ui, UiRegion, util::Id};
|
||||
use crate::{HashMap, Ui, UiRegion, Vec2, WidgetId, util::Id};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum Sense {
|
||||
Press,
|
||||
Held,
|
||||
Hover,
|
||||
NoHover,
|
||||
PressStart,
|
||||
Pressing,
|
||||
PressEnd,
|
||||
HoverStart,
|
||||
Hovering,
|
||||
HoverEnd,
|
||||
NotHovering,
|
||||
}
|
||||
|
||||
pub struct CursorState {
|
||||
pub pos: Vec2,
|
||||
pub exists: bool,
|
||||
pub pressed: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq)]
|
||||
pub enum ActivationState {
|
||||
Start,
|
||||
On,
|
||||
End,
|
||||
#[default]
|
||||
Off,
|
||||
}
|
||||
|
||||
pub struct Sensor<Ctx> {
|
||||
@@ -13,20 +31,8 @@ pub struct Sensor<Ctx> {
|
||||
pub f: Box<dyn SenseFn<Ctx>>,
|
||||
}
|
||||
|
||||
pub struct ActiveSensor<Ctx> {
|
||||
pub trigger: SenseTrigger,
|
||||
pub f: Box<dyn SenseFn<Ctx>>,
|
||||
}
|
||||
impl<Ctx: 'static> Clone for ActiveSensor<Ctx> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
trigger: self.trigger.clone(),
|
||||
f: self.f.box_clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type SensorMap<Ctx> = HashMap<Id, Vec<Sensor<Ctx>>>;
|
||||
pub type ActiveSensors<Ctx> = Vec<Vec<ActiveSensor<Ctx>>>;
|
||||
pub type SensorMap<Ctx> = HashMap<Id, SensorGroup<Ctx>>;
|
||||
pub type ActiveSensors = Vec<(SenseShape, Id)>;
|
||||
pub trait SenseFn_<Ctx> = FnMut(&mut Ui<Ctx>, &mut Ctx) + 'static;
|
||||
pub type SenseShape = UiRegion;
|
||||
#[derive(Clone)]
|
||||
@@ -34,6 +40,11 @@ pub struct SenseTrigger {
|
||||
pub shape: SenseShape,
|
||||
pub sense: Sense,
|
||||
}
|
||||
pub struct SensorGroup<Ctx> {
|
||||
pub hover: ActivationState,
|
||||
pub cursor: ActivationState,
|
||||
pub sensors: Vec<Sensor<Ctx>>,
|
||||
}
|
||||
pub trait SenseFn<Ctx>: SenseFn_<Ctx> {
|
||||
fn box_clone(&self) -> Box<dyn SenseFn<Ctx>>;
|
||||
}
|
||||
@@ -42,3 +53,110 @@ impl<F: SenseFn_<Ctx> + Clone, Ctx> SenseFn<Ctx> for F {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx> Ui<Ctx> {
|
||||
pub fn add_sensor<W>(&mut self, id: &WidgetId<W>, f: Sensor<Ctx>) {
|
||||
self.sensor_map
|
||||
.entry(id.id.duplicate())
|
||||
.or_default()
|
||||
.sensors
|
||||
.push(f);
|
||||
}
|
||||
|
||||
pub fn run_sensors(&mut self, ctx: &mut Ctx, cursor: &CursorState, window_size: Vec2)
|
||||
where
|
||||
Ctx: 'static,
|
||||
{
|
||||
let mut active = std::mem::take(&mut self.active_sensors);
|
||||
let mut map = std::mem::take(&mut self.sensor_map);
|
||||
for (shape, id) in active.iter_mut().rev() {
|
||||
let group = &mut 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);
|
||||
group.cursor.update(cursor.pressed && in_shape);
|
||||
|
||||
for sensor in &mut group.sensors {
|
||||
if should_run(sensor.sense, group.cursor, group.hover) {
|
||||
(sensor.f.box_clone())(self, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.sensor_map = map;
|
||||
self.active_sensors = active;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn should_run(sense: Sense, cursor: ActivationState, hover: ActivationState) -> bool {
|
||||
match sense {
|
||||
Sense::PressStart => cursor.is_start(),
|
||||
Sense::Pressing => cursor.is_on(),
|
||||
Sense::PressEnd => cursor.is_end(),
|
||||
Sense::HoverStart => hover.is_start(),
|
||||
Sense::Hovering => hover.is_on(),
|
||||
Sense::HoverEnd => hover.is_end(),
|
||||
Sense::NotHovering => hover.is_off(),
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx> Default for SensorGroup<Ctx> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
hover: Default::default(),
|
||||
cursor: Default::default(),
|
||||
sensors: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<Ctx: 'static> Clone for SensorGroup<Ctx> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
hover: self.hover,
|
||||
cursor: self.cursor,
|
||||
sensors: self.sensors.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<Ctx: 'static> Clone for Sensor<Ctx> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
sense: self.sense,
|
||||
f: self.f.box_clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user