add offset / scrolling + clipboard support

This commit is contained in:
2025-09-27 21:13:00 -04:00
parent 95f049acb4
commit 5445008528
16 changed files with 386 additions and 99 deletions

View File

@@ -29,6 +29,7 @@ pub enum Sense {
HoverStart,
Hovering,
HoverEnd,
Scroll,
}
pub struct Senses(Vec<Sense>);
@@ -47,6 +48,7 @@ pub struct CursorState {
pub pos: Vec2,
pub exists: bool,
pub buttons: CursorButtons,
pub scroll_delta: Vec2,
}
#[derive(Default, Clone)]
@@ -72,6 +74,13 @@ impl CursorButtons {
}
}
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,
@@ -81,29 +90,27 @@ pub enum ActivationState {
Off,
}
pub struct Sensor<Ctx> {
pub struct Sensor<Ctx, Data> {
pub senses: Senses,
pub f: Rc<dyn SenseFn<Ctx>>,
pub f: Rc<dyn EventFn<Ctx, Data>>,
}
pub type SensorMap<Ctx> = HashMap<Id, SensorGroup<Ctx>>;
pub type SensorMap<Ctx, Data> = HashMap<Id, SensorGroup<Ctx, Data>>;
pub type SenseShape = UiRegion;
pub struct SensorGroup<Ctx> {
pub struct SensorGroup<Ctx, Data> {
pub hover: ActivationState,
pub sensors: Vec<Sensor<Ctx>>,
pub sensors: Vec<Sensor<Ctx, Data>>,
}
#[derive(Clone)]
pub struct SenseData {
pub struct CursorData {
pub cursor: Vec2,
pub size: Vec2,
pub scroll_delta: Vec2,
}
pub trait SenseFn<Ctx>: Fn(&mut Ctx, SenseData) + 'static {}
impl<F: Fn(&mut Ctx, SenseData) + 'static, Ctx> SenseFn<Ctx> for F {}
pub struct SensorModule<Ctx> {
map: SensorMap<Ctx>,
map: SensorMap<Ctx, CursorData>,
active: HashMap<usize, HashMap<Id, SenseShape>>,
}
@@ -125,6 +132,9 @@ impl<Ctx: 'static> UiModule for SensorModule<Ctx> {
fn on_remove(&mut self, id: &Id) {
self.map.remove(id);
for layer in self.active.values_mut() {
layer.remove(id);
}
}
fn on_move(&mut self, inst: &WidgetInstance) {
@@ -165,7 +175,7 @@ impl<Ctx: UiCtx + 'static> SensorModule<Ctx> {
let Some(list) = module.active.get_mut(&i) else {
continue;
};
let mut ran = false;
let mut sensed = false;
for (id, shape) in list.iter() {
let group = module.map.get_mut(id).unwrap();
let region = shape.to_screen(window_size);
@@ -174,19 +184,20 @@ impl<Ctx: UiCtx + 'static> SensorModule<Ctx> {
if group.hover == ActivationState::Off {
continue;
}
sensed = true;
for sensor in &mut group.sensors {
if should_run(&sensor.senses, &cursor.buttons, group.hover) {
ran = true;
let sctx = SenseData {
if should_run(&sensor.senses, cursor, group.hover) {
let data = CursorData {
cursor: cursor.pos - region.top_left,
size: region.bot_right - region.top_left,
scroll_delta: cursor.scroll_delta,
};
(sensor.f)(ctx, sctx);
(sensor.f)(ctx, data);
}
}
}
if ran {
if sensed {
break;
}
}
@@ -198,15 +209,16 @@ impl<Ctx: UiCtx + 'static> SensorModule<Ctx> {
}
}
pub fn should_run(senses: &Senses, cursor: &CursorButtons, hover: ActivationState) -> bool {
pub fn should_run(senses: &Senses, cursor: &CursorState, 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::PressStart(button) => cursor.buttons.select(button).is_start(),
Sense::Pressing(button) => cursor.buttons.select(button).is_on(),
Sense::PressEnd(button) => cursor.buttons.select(button).is_end(),
Sense::HoverStart => hover.is_start(),
Sense::Hovering => hover.is_on(),
Sense::HoverEnd => hover.is_end(),
Sense::Scroll => cursor.scroll_delta != Vec2::ZERO,
} {
return true;
}
@@ -259,12 +271,12 @@ impl ActivationState {
impl Event for Senses {
type Module<Ctx: 'static> = SensorModule<Ctx>;
type Data = SenseData;
type Data = CursorData;
}
impl Event for Sense {
type Module<Ctx: 'static> = SensorModule<Ctx>;
type Data = SenseData;
type Data = CursorData;
}
impl<E: Event<Data = <Senses as Event>::Data> + Into<Senses>, Ctx: 'static> EventModule<E, Ctx>
@@ -292,7 +304,7 @@ impl<E: Event<Data = <Senses as Event>::Data> + Into<Senses>, Ctx: 'static> Even
}
})
.collect();
Some(move |ctx: &mut Ctx, data: SenseData| {
Some(move |ctx: &mut Ctx, data: CursorData| {
for f in &fs {
f(ctx, data.clone());
}
@@ -303,7 +315,7 @@ impl<E: Event<Data = <Senses as Event>::Data> + Into<Senses>, Ctx: 'static> Even
}
}
impl<Ctx> Default for SensorGroup<Ctx> {
impl<Ctx, Data> Default for SensorGroup<Ctx, Data> {
fn default() -> Self {
Self {
hover: Default::default(),