actually sane sensor handling
This commit is contained in:
107
:w
Normal file
107
:w
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
use crate::{HashMap, Ui, UiRegion, Vec2, WidgetId, util::Id};
|
||||||
|
|
||||||
|
pub trait SenseCtx: 'static {
|
||||||
|
fn cursor_state(&self) -> CursorState;
|
||||||
|
fn window_size(&self) -> Vec2;
|
||||||
|
fn active(&mut self, trigger: &SenseTrigger) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
pub enum Sense {
|
||||||
|
PressStart,
|
||||||
|
Pressing,
|
||||||
|
PressEnd,
|
||||||
|
HoverStart,
|
||||||
|
Hovering,
|
||||||
|
HoverEnd,
|
||||||
|
NotHovering,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CursorState {
|
||||||
|
pos: Vec2,
|
||||||
|
exists: bool,
|
||||||
|
primary: ActivationState,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
pub enum ActivationState {
|
||||||
|
Start,
|
||||||
|
On,
|
||||||
|
End,
|
||||||
|
#[default]
|
||||||
|
Off,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Sensor<Ctx> {
|
||||||
|
pub sense: Sense,
|
||||||
|
pub f: Box<dyn SenseFn<Ctx>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Ctx: 'static> Clone for SensorGroup<Ctx> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
shape: self.shape.clone(),
|
||||||
|
hover: self.hover.clone(),
|
||||||
|
f: self.f.box_clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub type SensorMap<Ctx> = HashMap<Id, Vec<Sensor<Ctx>>>;
|
||||||
|
pub type ActiveSensors<Ctx> = Vec<SensorGroup<Ctx>>;
|
||||||
|
pub trait SenseFn_<Ctx> = FnMut(&mut Ui<Ctx>, &mut Ctx) + 'static;
|
||||||
|
pub type SenseShape = UiRegion;
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SenseTrigger {
|
||||||
|
pub shape: SenseShape,
|
||||||
|
pub sense: Sense,
|
||||||
|
}
|
||||||
|
pub struct SensorGroup<Ctx> {
|
||||||
|
pub shape: SenseShape,
|
||||||
|
pub hover: ActivationState,
|
||||||
|
pub sensors: Vec<Sensor<Ctx>>,
|
||||||
|
}
|
||||||
|
pub trait SenseFn<Ctx>: SenseFn_<Ctx> {
|
||||||
|
fn box_clone(&self) -> Box<dyn SenseFn<Ctx>>;
|
||||||
|
}
|
||||||
|
impl<F: SenseFn_<Ctx> + Clone, Ctx> SenseFn<Ctx> for F {
|
||||||
|
fn box_clone(&self) -> Box<dyn SenseFn<Ctx>> {
|
||||||
|
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()
|
||||||
|
.push(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_sensors(&mut self, ctx: &mut Ctx, cursor: &CursorState, window_size: Vec2)
|
||||||
|
where
|
||||||
|
Ctx: SenseCtx + 'static,
|
||||||
|
{
|
||||||
|
let mut groups = std::mem::take(&mut self.active_sensors_swap);
|
||||||
|
groups.clone_from(&self.active_sensors);
|
||||||
|
for (hover, sensors) in groups.drain(..).rev() {
|
||||||
|
for mut sensor in sensors {
|
||||||
|
if should_run(sensor.trigger, cursor, hover, window_size) {
|
||||||
|
(sensor.f)(self, ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.active_sensors_swap = groups;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn should_run(
|
||||||
|
trigger: SenseTrigger,
|
||||||
|
cursor: &CursorState,
|
||||||
|
hover: ActivationState,
|
||||||
|
window_size: Vec2,
|
||||||
|
) -> bool {
|
||||||
|
let region = trigger.shape.to_screen(window_size);
|
||||||
|
if !cursor.exists || !region.contains(cursor.pos) {
|
||||||
|
return trigger.sense == Sense::NotHovering;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,28 +1,32 @@
|
|||||||
use crate::{Sense, SenseFn, SenseTrigger, Sensor, Ui, Widget, WidgetIdFn, WidgetLike};
|
use crate::{Sense, SenseFn, Sensor, Ui, Widget, WidgetId, WidgetIdFn, WidgetLike};
|
||||||
|
|
||||||
pub trait SenseCtx: 'static {
|
|
||||||
fn active(&mut self, trigger: &SenseTrigger) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Sensable<W, Ctx, Tag> {
|
pub trait Sensable<W, Ctx, Tag> {
|
||||||
fn sense(
|
fn on(
|
||||||
self,
|
self,
|
||||||
sense: Sense,
|
sense: Sense,
|
||||||
// trait copied here bc rust analyzer skill issue
|
// trait copied here bc rust analyzer skill issue
|
||||||
f: impl Fn(&mut Ui<Ctx>, &mut Ctx) + 'static + Clone,
|
f: impl FnMut(&mut Ui<Ctx>, &mut Ctx) + 'static + Clone,
|
||||||
) -> impl WidgetIdFn<W, Ctx>;
|
) -> impl WidgetIdFn<W, Ctx>;
|
||||||
fn sense_and_edit(
|
fn id_on(
|
||||||
self,
|
self,
|
||||||
sense: Sense,
|
sense: Sense,
|
||||||
// trait copied here bc rust analyzer skill issue
|
// trait copied here bc rust analyzer skill issue
|
||||||
f: impl Fn(&mut W, &mut Ctx) + 'static + Clone,
|
f: impl FnMut(&WidgetId<W>, &mut Ui<Ctx>, &mut Ctx) + 'static + Clone,
|
||||||
|
) -> impl WidgetIdFn<W, Ctx>
|
||||||
|
where
|
||||||
|
W: Widget<Ctx>;
|
||||||
|
fn edit_on(
|
||||||
|
self,
|
||||||
|
sense: Sense,
|
||||||
|
// trait copied here bc rust analyzer skill issue
|
||||||
|
f: impl FnMut(&mut W, &mut Ctx) + 'static + Clone,
|
||||||
) -> impl WidgetIdFn<W, Ctx>
|
) -> impl WidgetIdFn<W, Ctx>
|
||||||
where
|
where
|
||||||
W: Widget<Ctx>;
|
W: Widget<Ctx>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: WidgetLike<Ctx, Tag>, Ctx, Tag> Sensable<W::Widget, Ctx, Tag> for W {
|
impl<W: WidgetLike<Ctx, Tag>, Ctx, Tag> Sensable<W::Widget, Ctx, Tag> for W {
|
||||||
fn sense(self, sense: Sense, f: impl SenseFn<Ctx> + Clone) -> impl WidgetIdFn<W::Widget, Ctx> {
|
fn on(self, sense: Sense, f: impl SenseFn<Ctx> + Clone) -> impl WidgetIdFn<W::Widget, Ctx> {
|
||||||
move |ui| {
|
move |ui| {
|
||||||
let id = self.add(ui);
|
let id = self.add(ui);
|
||||||
ui.add_sensor(
|
ui.add_sensor(
|
||||||
@@ -35,18 +39,29 @@ impl<W: WidgetLike<Ctx, Tag>, Ctx, Tag> Sensable<W::Widget, Ctx, Tag> for W {
|
|||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn sense_and_edit(
|
fn id_on(
|
||||||
self,
|
self,
|
||||||
sense: Sense,
|
sense: Sense,
|
||||||
// trait copied here bc rust analyzer skill issue
|
// trait copied here bc rust analyzer skill issue
|
||||||
f: impl Fn(&mut W::Widget, &mut Ctx) + 'static + Clone,
|
mut f: impl FnMut(&WidgetId<W::Widget>, &mut Ui<Ctx>, &mut Ctx) + 'static + Clone,
|
||||||
) -> impl WidgetIdFn<W::Widget, Ctx>
|
) -> impl WidgetIdFn<W::Widget, Ctx>
|
||||||
where
|
where
|
||||||
W::Widget: Widget<Ctx>,
|
W::Widget: Widget<Ctx>,
|
||||||
{
|
{
|
||||||
self.with_id(move |ui, id| {
|
self.with_id(move |ui, id| {
|
||||||
let id2 = id.clone();
|
let id2 = id.clone();
|
||||||
ui.add(id.sense(sense, move |ui, ctx| f(&mut ui[&id2], ctx)))
|
ui.add(id.on(sense, move |ui, ctx| f(&id2, ui, ctx)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
fn edit_on(
|
||||||
|
self,
|
||||||
|
sense: Sense,
|
||||||
|
// trait copied here bc rust analyzer skill issue
|
||||||
|
mut f: impl FnMut(&mut W::Widget, &mut Ctx) + 'static + Clone,
|
||||||
|
) -> impl WidgetIdFn<W::Widget, Ctx>
|
||||||
|
where
|
||||||
|
W::Widget: Widget<Ctx>,
|
||||||
|
{
|
||||||
|
self.id_on(sense, move |id, ui, ctx| f(&mut ui[id], ctx))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ActiveSensor, ActiveSensors, SenseTrigger, SensorMap, UiRegion, WidgetId, Widgets,
|
ActiveSensors, SensorMap, UiRegion, WidgetId, Widgets,
|
||||||
primitive::{PrimitiveData, PrimitiveInstance, Primitives},
|
primitive::{PrimitiveData, PrimitiveInstance, Primitives},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ pub struct Painter<'a, Ctx: 'static> {
|
|||||||
nodes: &'a Widgets<Ctx>,
|
nodes: &'a Widgets<Ctx>,
|
||||||
ctx: &'a mut Ctx,
|
ctx: &'a mut Ctx,
|
||||||
sensors_map: &'a mut SensorMap<Ctx>,
|
sensors_map: &'a mut SensorMap<Ctx>,
|
||||||
active_sensors: &'a mut ActiveSensors<Ctx>,
|
active_sensors: &'a mut ActiveSensors,
|
||||||
primitives: Primitives,
|
primitives: Primitives,
|
||||||
pub region: UiRegion,
|
pub region: UiRegion,
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ impl<'a, Ctx> Painter<'a, Ctx> {
|
|||||||
nodes: &'a Widgets<Ctx>,
|
nodes: &'a Widgets<Ctx>,
|
||||||
ctx: &'a mut Ctx,
|
ctx: &'a mut Ctx,
|
||||||
sensors_map: &'a mut SensorMap<Ctx>,
|
sensors_map: &'a mut SensorMap<Ctx>,
|
||||||
active_sensors: &'a mut ActiveSensors<Ctx>,
|
active_sensors: &'a mut ActiveSensors,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
nodes,
|
nodes,
|
||||||
@@ -44,19 +44,8 @@ impl<'a, Ctx> Painter<'a, Ctx> {
|
|||||||
where
|
where
|
||||||
Ctx: 'static,
|
Ctx: 'static,
|
||||||
{
|
{
|
||||||
if let Some(sensors) = self.sensors_map.get(&id.id) {
|
if self.sensors_map.get(&id.id).is_some() {
|
||||||
self.active_sensors.push(
|
self.active_sensors.push((self.region, id.id.duplicate()));
|
||||||
sensors
|
|
||||||
.iter()
|
|
||||||
.map(|sensor| ActiveSensor {
|
|
||||||
trigger: SenseTrigger {
|
|
||||||
shape: self.region,
|
|
||||||
sense: sensor.sense,
|
|
||||||
},
|
|
||||||
f: sensor.f.box_clone(),
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
self.nodes.get_dyn(id).draw(self);
|
self.nodes.get_dyn(id).draw(self);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,9 +174,7 @@ impl UiRegion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn shifted(mut self, offset: impl Into<Vec2>) -> Self {
|
pub fn shifted(mut self, offset: impl Into<Vec2>) -> Self {
|
||||||
println!("before {:?}", self);
|
|
||||||
self.shift(offset);
|
self.shift(offset);
|
||||||
println!("after {:?}", self);
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,29 @@
|
|||||||
use crate::{HashMap, Ui, UiRegion, util::Id};
|
use crate::{HashMap, Ui, UiRegion, Vec2, WidgetId, util::Id};
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
pub enum Sense {
|
pub enum Sense {
|
||||||
Press,
|
PressStart,
|
||||||
Held,
|
Pressing,
|
||||||
Hover,
|
PressEnd,
|
||||||
NoHover,
|
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> {
|
pub struct Sensor<Ctx> {
|
||||||
@@ -13,20 +31,8 @@ pub struct Sensor<Ctx> {
|
|||||||
pub f: Box<dyn SenseFn<Ctx>>,
|
pub f: Box<dyn SenseFn<Ctx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ActiveSensor<Ctx> {
|
pub type SensorMap<Ctx> = HashMap<Id, SensorGroup<Ctx>>;
|
||||||
pub trigger: SenseTrigger,
|
pub type ActiveSensors = Vec<(SenseShape, Id)>;
|
||||||
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 trait SenseFn_<Ctx> = FnMut(&mut Ui<Ctx>, &mut Ctx) + 'static;
|
pub trait SenseFn_<Ctx> = FnMut(&mut Ui<Ctx>, &mut Ctx) + 'static;
|
||||||
pub type SenseShape = UiRegion;
|
pub type SenseShape = UiRegion;
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -34,6 +40,11 @@ pub struct SenseTrigger {
|
|||||||
pub shape: SenseShape,
|
pub shape: SenseShape,
|
||||||
pub sense: Sense,
|
pub sense: Sense,
|
||||||
}
|
}
|
||||||
|
pub struct SensorGroup<Ctx> {
|
||||||
|
pub hover: ActivationState,
|
||||||
|
pub cursor: ActivationState,
|
||||||
|
pub sensors: Vec<Sensor<Ctx>>,
|
||||||
|
}
|
||||||
pub trait SenseFn<Ctx>: SenseFn_<Ctx> {
|
pub trait SenseFn<Ctx>: SenseFn_<Ctx> {
|
||||||
fn box_clone(&self) -> Box<dyn 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())
|
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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ActiveSensors, HashMap, Painter, SenseCtx, Sensor, SensorMap, Widget, WidgetId, WidgetLike,
|
ActiveSensors, HashMap, Painter, SensorMap, Widget, WidgetId, WidgetLike,
|
||||||
primitive::Primitives,
|
primitive::Primitives,
|
||||||
util::{IDTracker, Id},
|
util::{IDTracker, Id},
|
||||||
};
|
};
|
||||||
@@ -13,8 +13,8 @@ pub struct Ui<Ctx> {
|
|||||||
base: Option<WidgetId>,
|
base: Option<WidgetId>,
|
||||||
widgets: Widgets<Ctx>,
|
widgets: Widgets<Ctx>,
|
||||||
updates: Vec<WidgetId>,
|
updates: Vec<WidgetId>,
|
||||||
active_sensors: ActiveSensors<Ctx>,
|
pub(super) active_sensors: ActiveSensors,
|
||||||
sensor_map: SensorMap<Ctx>,
|
pub(super) sensor_map: SensorMap<Ctx>,
|
||||||
primitives: Primitives,
|
primitives: Primitives,
|
||||||
full_redraw: bool,
|
full_redraw: bool,
|
||||||
}
|
}
|
||||||
@@ -85,26 +85,6 @@ impl<Ctx> Ui<Ctx> {
|
|||||||
self.primitives = painter.finish();
|
self.primitives = painter.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_sensor<W>(&mut self, id: &WidgetId<W>, f: Sensor<Ctx>) {
|
|
||||||
self.sensor_map
|
|
||||||
.entry(id.id.duplicate())
|
|
||||||
.or_default()
|
|
||||||
.push(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_sensors(&mut self, ctx: &mut Ctx)
|
|
||||||
where
|
|
||||||
Ctx: SenseCtx + 'static,
|
|
||||||
{
|
|
||||||
for sensors in self.active_sensors.clone().iter().rev() {
|
|
||||||
for sensor in sensors {
|
|
||||||
if ctx.active(&sensor.trigger) {
|
|
||||||
(sensor.f.box_clone())(self, ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update(&mut self, ctx: &mut Ctx) -> Option<&Primitives>
|
pub fn update(&mut self, ctx: &mut Ctx) -> Option<&Primitives>
|
||||||
where
|
where
|
||||||
Ctx: 'static,
|
Ctx: 'static,
|
||||||
|
|||||||
@@ -1,61 +1,44 @@
|
|||||||
use gui::{Sense, SenseCtx, SenseTrigger, Vec2};
|
use gui::{CursorState, Vec2};
|
||||||
use winit::event::WindowEvent;
|
use winit::event::WindowEvent;
|
||||||
|
|
||||||
use crate::testing::Client;
|
use crate::testing::Client;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Input {
|
pub struct Input {
|
||||||
size: Vec2,
|
|
||||||
mouse_pos: Vec2,
|
mouse_pos: Vec2,
|
||||||
mouse_pressed: bool,
|
mouse_pressed: bool,
|
||||||
mouse_just_pressed: bool,
|
mouse_exists: bool,
|
||||||
mouse_just_released: bool,
|
|
||||||
mouse_in: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
pub fn event(&mut self, event: &WindowEvent) {
|
pub fn event(&mut self, event: &WindowEvent) {
|
||||||
self.mouse_just_pressed = false;
|
|
||||||
self.mouse_just_released = false;
|
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::Resized(size) => {
|
|
||||||
self.size = Vec2::new(size.width as f32, size.height as f32);
|
|
||||||
}
|
|
||||||
WindowEvent::CursorMoved { position, .. } => {
|
WindowEvent::CursorMoved { position, .. } => {
|
||||||
self.mouse_pos = Vec2::new(position.x as f32, position.y as f32);
|
self.mouse_pos = Vec2::new(position.x as f32, position.y as f32);
|
||||||
self.mouse_in = true;
|
self.mouse_exists = true;
|
||||||
}
|
}
|
||||||
WindowEvent::MouseInput { state, button, .. } => match button {
|
WindowEvent::MouseInput { state, button, .. } => match button {
|
||||||
winit::event::MouseButton::Left => {
|
winit::event::MouseButton::Left => {
|
||||||
if state.is_pressed() {
|
self.mouse_pressed = state.is_pressed();
|
||||||
self.mouse_just_pressed = !self.mouse_pressed;
|
|
||||||
self.mouse_pressed = true;
|
|
||||||
} else {
|
|
||||||
self.mouse_just_released = self.mouse_pressed;
|
|
||||||
self.mouse_pressed = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn active(&mut self, trigger: &SenseTrigger) -> bool {
|
|
||||||
let region = trigger.shape.to_screen(self.size);
|
|
||||||
if !self.mouse_in || !region.contains(self.mouse_pos) {
|
|
||||||
return trigger.sense == Sense::NoHover;
|
|
||||||
}
|
|
||||||
match trigger.sense {
|
|
||||||
Sense::Press => self.mouse_just_pressed,
|
|
||||||
Sense::Held => self.mouse_pressed,
|
|
||||||
Sense::Hover => true,
|
|
||||||
Sense::NoHover => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SenseCtx for Client {
|
impl Client {
|
||||||
fn active(&mut self, trigger: &SenseTrigger) -> bool {
|
pub fn window_size(&self) -> Vec2 {
|
||||||
self.input.active(trigger)
|
let size = self.renderer.window().inner_size();
|
||||||
|
(size.width, size.height).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cursor_state(&self) -> CursorState {
|
||||||
|
CursorState {
|
||||||
|
pos: self.input.mouse_pos,
|
||||||
|
exists: self.input.mouse_exists,
|
||||||
|
pressed: self.input.mouse_pressed,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,17 +84,18 @@ impl Client {
|
|||||||
let main = main.clone();
|
let main = main.clone();
|
||||||
let to = to.clone().erase_type();
|
let to = to.clone().erase_type();
|
||||||
Rect::new(color)
|
Rect::new(color)
|
||||||
.sense(Sense::Press, move |ui, _| {
|
.id_on(Sense::PressStart, move |id, ui, _| {
|
||||||
ui[&main].inner = to.clone();
|
ui[&main].inner = to.clone();
|
||||||
|
ui[id].color = color.add_rgb(-0.2);
|
||||||
})
|
})
|
||||||
.sense_and_edit(Sense::Hover, move |r, _| {
|
.edit_on(Sense::HoverStart, move |r, _| {
|
||||||
r.color = color.add_rgb(0.1);
|
r.color = color.add_rgb(0.1);
|
||||||
})
|
})
|
||||||
.sense_and_edit(Sense::NoHover, move |r, _| {
|
.edit_on(Sense::PressEnd, move |r, _| {
|
||||||
r.color = color;
|
r.color = color.add_rgb(0.1);
|
||||||
})
|
})
|
||||||
.sense_and_edit(Sense::Held, move |r, _| {
|
.edit_on(Sense::HoverEnd, move |r, _| {
|
||||||
r.color = color.add_rgb(-0.1);
|
r.color = color;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +136,9 @@ impl Client {
|
|||||||
|
|
||||||
pub fn event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop, ui: &mut Ui<Self>) {
|
pub fn event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop, ui: &mut Ui<Self>) {
|
||||||
self.input.event(&event);
|
self.input.event(&event);
|
||||||
ui.run_sensors(self);
|
let cursor_state = self.cursor_state();
|
||||||
|
let window_size = self.window_size();
|
||||||
|
ui.run_sensors(self, &cursor_state, window_size);
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::CloseRequested => event_loop.exit(),
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
|
|||||||
@@ -13,10 +13,6 @@ pub struct IDTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IDTracker {
|
impl IDTracker {
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::should_implement_trait)]
|
#[allow(clippy::should_implement_trait)]
|
||||||
pub fn next(&mut self) -> Id {
|
pub fn next(&mut self) -> Id {
|
||||||
if let Some(id) = self.free.pop() {
|
if let Some(id) = self.free.pop() {
|
||||||
|
|||||||
Reference in New Issue
Block a user