senses are now bitflags

This commit is contained in:
2025-08-25 22:36:38 -04:00
parent e9037cdc14
commit 9780724126
7 changed files with 150 additions and 104 deletions

View File

@@ -1,27 +1,27 @@
use crate::prelude::*;
pub trait Sensable<W, Tag> {
fn on(self, sense: Sense, f: impl SenseFn) -> WidgetIdFnRet!(W);
fn on(self, sense: Senses, f: impl SenseFn) -> WidgetIdFnRet!(W);
fn id_on(
self,
sense: Sense,
senses: Senses,
f: impl FnMut(&WidgetId<W>, &mut Ui) + 'static + Clone,
) -> WidgetIdFnRet!(W)
where
W: Widget;
fn edit_on(self, sense: Sense, f: impl FnMut(&mut W) + 'static + Clone) -> WidgetIdFnRet!(W)
fn edit_on(self, senses: Senses, f: impl FnMut(&mut W) + 'static + Clone) -> WidgetIdFnRet!(W)
where
W: Widget;
}
impl<W: WidgetLike<Tag>, Tag> Sensable<W::Widget, Tag> for W {
fn on(self, sense: Sense, f: impl SenseFn) -> WidgetIdFnRet!(W::Widget) {
fn on(self, senses: Senses, f: impl SenseFn) -> WidgetIdFnRet!(W::Widget) {
move |ui| {
let id = self.add(ui);
ui.add_sensor(
&id,
Sensor {
sense,
senses,
f: Box::new(f),
},
);
@@ -30,7 +30,7 @@ impl<W: WidgetLike<Tag>, Tag> Sensable<W::Widget, Tag> for W {
}
fn id_on(
self,
sense: Sense,
senses: Senses,
mut f: impl FnMut(&WidgetId<W::Widget>, &mut Ui) + 'static + Clone,
) -> WidgetIdFnRet!(W::Widget)
where
@@ -38,17 +38,17 @@ impl<W: WidgetLike<Tag>, Tag> Sensable<W::Widget, Tag> for W {
{
self.with_id(move |ui, id| {
let id2 = id.clone();
ui.add(id.on(sense, move |ui| f(&id2, ui)))
ui.add(id.on(senses, move |ui| f(&id2, ui)))
})
}
fn edit_on(
self,
sense: Sense,
senses: Senses,
mut f: impl FnMut(&mut W::Widget) + 'static + Clone,
) -> WidgetIdFnRet!(W::Widget)
where
W::Widget: Widget,
{
self.id_on(sense, move |id, ui| f(&mut ui[id]))
self.id_on(senses, move |id, ui| f(&mut ui[id]))
}
}

View File

@@ -1,19 +1,17 @@
use crate::{
layout::{Ui, UiRegion, Vec2, WidgetId},
util::HashMap,
util::Id,
util::{HashMap, Id, bitflags},
};
#[derive(Clone, Copy, PartialEq)]
pub enum Sense {
PressStart,
Pressing,
PressEnd,
HoverStart,
Hovering,
HoverEnd,
NotHovering,
}
bitflags!(Sense, Senses, senses {
1 << 0; PressStart, PRESS_START,
1 << 1; Pressing, PRESSING,
1 << 2; PressEnd, PRESS_END,
1 << 3; HoverStart, HOVER_START,
1 << 4; Hovering, HOVERING,
1 << 5; HoverEnd, HOVER_END,
1 << 6; NotHovering, NOT_HOVERING,
});
pub struct CursorState {
pub pos: Vec2,
@@ -31,18 +29,13 @@ pub enum ActivationState {
}
pub struct Sensor {
pub sense: Sense,
pub senses: Senses,
pub f: Box<dyn SenseFn>,
}
pub type SensorMap = HashMap<Id, SensorGroup>;
pub type ActiveSensors = HashMap<Id, SenseShape>;
pub type SenseShape = UiRegion;
#[derive(Clone)]
pub struct SenseTrigger {
pub shape: SenseShape,
pub sense: Sense,
}
#[derive(Default)]
pub struct SensorGroup {
pub hover: ActivationState,
@@ -78,7 +71,7 @@ impl Ui {
group.cursor.update(cursor.pressed && in_shape);
for sensor in &mut group.sensors {
if should_run(sensor.sense, group.cursor, group.hover) {
if should_run(sensor.senses, group.cursor, group.hover) {
(sensor.f.box_clone())(self);
}
}
@@ -88,16 +81,21 @@ impl Ui {
}
}
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(),
pub fn should_run(senses: Senses, cursor: ActivationState, hover: ActivationState) -> bool {
for sense in senses.iter() {
if 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(),
} {
return true;
}
}
false
}
impl ActivationState {
@@ -147,7 +145,7 @@ impl Clone for SensorGroup {
impl Clone for Sensor {
fn clone(&self) -> Self {
Self {
sense: self.sense,
senses: self.senses,
f: self.f.box_clone(),
}
}

View File

@@ -2,6 +2,7 @@ use std::sync::Arc;
use app::App;
use render::Renderer;
use senses::*;
use ui::prelude::*;
use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::Window};
@@ -29,22 +30,19 @@ impl Client {
let mut ui = Ui::new();
let rect = Rect {
color: UiColor::WHITE,
color: Color::WHITE,
radius: 20.0,
thickness: 0.0,
inner_radius: 0.0,
};
let pad_test = ui.add_static(
(
rect.color(UiColor::BLUE),
rect.color(Color::BLUE),
(
rect.color(UiColor::RED).center((100.0, 100.0)),
(
rect.color(UiColor::ORANGE),
rect.color(UiColor::LIME).pad(10.0),
)
rect.color(Color::RED).center((100.0, 100.0)),
(rect.color(Color::ORANGE), rect.color(Color::LIME).pad(10.0))
.span(Dir::RIGHT, [1, 1]),
rect.color(UiColor::YELLOW),
rect.color(Color::YELLOW),
)
.span(Dir::RIGHT, [2, 2, 1])
.pad(10),
@@ -53,12 +51,12 @@ impl Client {
);
let span_test = ui.add_static(
(
rect.color(UiColor::GREEN),
rect.color(UiColor::ORANGE),
rect.color(UiColor::CYAN),
rect.color(UiColor::BLUE),
rect.color(UiColor::MAGENTA),
rect.color(UiColor::RED),
rect.color(Color::GREEN),
rect.color(Color::ORANGE),
rect.color(Color::CYAN),
rect.color(Color::BLUE),
rect.color(Color::MAGENTA),
rect.color(Color::RED),
)
.span(
Dir::LEFT,
@@ -77,17 +75,14 @@ impl Client {
let switch_button = |color, to, label| {
let rect = Rect::new(color)
.id_on(Sense::PressStart, move |id, ui| {
.id_on(PRESS_START, move |id, ui| {
ui[main].inner.set_static(to);
ui[id].color = color.add_rgb(-0.2);
})
.edit_on(Sense::HoverStart, move |r| {
.edit_on(HOVER_START | PRESS_END, move |r| {
r.color = color.add_rgb(0.4);
})
.edit_on(Sense::PressEnd, move |r| {
r.color = color.add_rgb(0.4);
})
.edit_on(Sense::HoverEnd, move |r| {
.edit_on(HOVER_END, move |r| {
r.color = color;
});
(rect, text(label).size(30)).stack()
@@ -95,15 +90,15 @@ impl Client {
let tabs = ui.add(
(
switch_button(UiColor::RED, pad_test, "pad test"),
switch_button(UiColor::GREEN, span_test, "span test"),
switch_button(UiColor::BLUE, span_add, "span add test"),
switch_button(Color::RED, pad_test, "pad test"),
switch_button(Color::GREEN, span_test, "span test"),
switch_button(Color::BLUE, span_add, "span add test"),
)
.span(Dir::RIGHT, [1, 1, 1]),
);
let add_button = Rect::new(Color::LIME)
.radius(30)
.on(Sense::PressStart, move |ui| {
.on(PRESS_START, move |ui| {
let child = ui
.add(image(include_bytes!("assets/sungals.png")))
.erase_type();
@@ -117,7 +112,7 @@ impl Client {
let del_button = Rect::new(Color::RED)
.radius(30)
.on(Sense::PressStart, move |ui| {
.on(PRESS_START, move |ui| {
ui[span_add].children.pop();
})
.region(

52
src/util/bitflags.rs Normal file
View File

@@ -0,0 +1,52 @@
macro_rules! bitflags {
($enum:ident, $struct:ident, $mod:ident {$($val:expr; $ename:ident, $sname:ident,)*}) => {
#[repr(u32)]
#[derive(Clone, Copy, PartialEq)]
pub enum $enum {
$($ename = $val,)*
}
#[derive(Clone, Copy, PartialEq)]
pub struct $struct(u32);
#[allow(non_upper_case_globals)]
impl $struct {
$(pub const $sname: Self = Self($enum::$ename as u32);)*
pub fn iter(&self) -> impl Iterator<Item = $enum> {
$crate::util::Biterator::new(self.0).map(|v| unsafe {std::mem::transmute(v)})
}
}
impl std::ops::BitOr for $struct {
type Output = Self;
fn bitor(self, rhs: $struct) -> Self {
Self(self.0 | rhs.0)
}
}
pub mod $mod {
use super::*;
$(pub const $sname: $struct = $struct::$sname;)*
}
};
}
pub(crate) use bitflags;
pub struct Biterator(u32);
impl Iterator for Biterator {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.0 == 0 {
return None;
}
let val = 1 << self.0.trailing_zeros();
self.0 &= !val;
Some(val)
}
}
impl Biterator {
pub fn new(val: u32) -> Self {
Self(val)
}
}

View File

@@ -1,10 +1,12 @@
mod id;
mod math;
mod refcount;
mod bitflags;
pub(crate) use id::*;
pub(crate) use math::*;
pub(crate) use refcount::*;
pub(crate) use bitflags::*;
pub type HashMap<K, V> = std::collections::HashMap<K, V>;
pub type HashSet<K> = std::collections::HashSet<K>;