make run sensors sane and adjust on_edit to just use ui as ctx (so two run calls needed)
This commit is contained in:
@@ -3,7 +3,7 @@ use crate::prelude::*;
|
|||||||
use std::ops::{BitOr, Deref, DerefMut};
|
use std::ops::{BitOr, Deref, DerefMut};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::{UiModule, UiRegion, Vec2, WidgetId},
|
layout::{UiModule, UiRegion, Vec2},
|
||||||
util::{HashMap, Id},
|
util::{HashMap, Id},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -123,61 +123,65 @@ impl<Ctx: 'static> UiModule for SensorModule<Ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<Ctx> SensorModule<Ctx> {
|
impl<Ctx> SensorModule<Ctx> {
|
||||||
pub fn set<W>(&mut self, id: WidgetId<W>, sensor: Sensor<Ctx>) {
|
pub fn merge(&mut self, other: Self) {
|
||||||
// TODO: currently does not add to active if it exists
|
for (id, group) in other.map {
|
||||||
self.map.entry(id.key()).or_default().sensors.push(sensor);
|
for sensor in group.sensors {
|
||||||
|
self.map
|
||||||
|
.entry(id.duplicate())
|
||||||
|
.or_default()
|
||||||
|
.sensors
|
||||||
|
.push(sensor);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_sensors<Ctx: UiCtx + 'static>(ctx: &mut Ctx, cursor: &CursorState, window_size: Vec2) {
|
impl<Ctx: UiCtx + 'static> SensorModule<Ctx> {
|
||||||
let mut layers = std::mem::take(&mut ctx.ui().layers);
|
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::<Self>());
|
||||||
|
|
||||||
// TODO: temp, need to actually make reverse
|
// TODO: temp, need to actually make reverse
|
||||||
let mut layer_idxs = Vec::new();
|
let mut layer_idxs = Vec::new();
|
||||||
for (i, _) in layers.iter_mut() {
|
for (i, _) in layers.iter_mut() {
|
||||||
layer_idxs.push(i);
|
layer_idxs.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for l in &layer_idxs {
|
for l in &layer_idxs {
|
||||||
let m = ctx.ui().modules.get_mut::<SensorModule<Ctx>>();
|
let Some(list) = module.active.get_mut(l) else {
|
||||||
let Some(list) = m.active.get_mut(l) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let list = list.clone();
|
|
||||||
let mut ran = false;
|
|
||||||
for (id, shape) in list.iter() {
|
|
||||||
let m = ctx.ui().modules.get_mut::<SensorModule<Ctx>>();
|
|
||||||
let mut group = m.map.remove(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 {
|
|
||||||
// TODO: this does not merge if you happen to add a sensor to the widget itself
|
|
||||||
let m = ctx.ui().modules.get_mut::<SensorModule<Ctx>>();
|
|
||||||
m.map.insert(id.clone(), group);
|
|
||||||
continue;
|
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 {
|
for sensor in &mut group.sensors {
|
||||||
if should_run(&sensor.senses, &cursor.buttons, group.hover) {
|
if should_run(&sensor.senses, &cursor.buttons, group.hover) {
|
||||||
ran = true;
|
ran = true;
|
||||||
let sctx = SenseData {
|
let sctx = SenseData {
|
||||||
cursor: cursor.pos - region.top_left,
|
cursor: cursor.pos - region.top_left,
|
||||||
size: region.bot_right - region.top_left,
|
size: region.bot_right - region.top_left,
|
||||||
};
|
};
|
||||||
(sensor.f)(ctx, sctx);
|
(sensor.f)(ctx, sctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: this does not merge if you happen to add a sensor to the widget itself
|
if ran {
|
||||||
let m = ctx.ui().modules.get_mut::<SensorModule<Ctx>>();
|
break;
|
||||||
m.map.insert(id.clone(), group);
|
}
|
||||||
}
|
}
|
||||||
if ran {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.ui().layers = layers;
|
let ui_mod = ctx.ui().modules.get_mut::<Self>();
|
||||||
|
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 {
|
pub fn should_run(senses: &Senses, cursor: &CursorButtons, hover: ActivationState) -> bool {
|
||||||
@@ -260,6 +264,7 @@ impl<Ctx: 'static> Event<Ctx> for Sense {
|
|||||||
|
|
||||||
impl<Ctx: 'static> EventModule<Ctx, Sense> for SensorModule<Ctx> {
|
impl<Ctx: 'static> EventModule<Ctx, Sense> for SensorModule<Ctx> {
|
||||||
fn register(&mut self, id: Id, sense: Sense, f: impl EventFn<Ctx, SenseData>) {
|
fn register(&mut self, id: Id, sense: Sense, f: impl EventFn<Ctx, SenseData>) {
|
||||||
|
// TODO: does not add to active if currently active
|
||||||
self.map.entry(id).or_default().sensors.push(Sensor {
|
self.map.entry(id).or_default().sensors.push(Sensor {
|
||||||
senses: sense.into(),
|
senses: sense.into(),
|
||||||
f: Box::new(f),
|
f: Box::new(f),
|
||||||
|
|||||||
@@ -4,9 +4,13 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub trait UiCtx {
|
pub trait UiCtx {
|
||||||
fn ui(&mut self) -> &mut Ui
|
fn ui(&mut self) -> &mut Ui;
|
||||||
where
|
}
|
||||||
Self: Sized;
|
|
||||||
|
impl UiCtx for Ui {
|
||||||
|
fn ui(&mut self) -> &mut Ui {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Event<Ctx>: Sized {
|
pub trait Event<Ctx>: Sized {
|
||||||
@@ -21,48 +25,36 @@ pub trait EventModule<Ctx, E: Event<Ctx>> {
|
|||||||
pub trait EventFn<Ctx, Data>: FnMut(&mut Ctx, Data) + 'static {}
|
pub trait EventFn<Ctx, Data>: FnMut(&mut Ctx, Data) + 'static {}
|
||||||
impl<F: FnMut(&mut Ctx, Data) + 'static, Ctx, Data> EventFn<Ctx, Data> for F {}
|
impl<F: FnMut(&mut Ctx, Data) + 'static, Ctx, Data> EventFn<Ctx, Data> for F {}
|
||||||
|
|
||||||
pub trait Eventable<W, Ctx, Tag> {
|
pub trait Eventable<W, Tag> {
|
||||||
fn on<E: Event<Ctx>>(
|
fn on<E: Event<Ctx>, Ctx>(
|
||||||
self,
|
self,
|
||||||
event: E,
|
event: E,
|
||||||
f: impl EventFn<Ctx, E::Data>,
|
f: impl EventFn<Ctx, E::Data>,
|
||||||
) -> impl WidgetIdFn<W> + Eventable<W, Ctx, IdFnTag>;
|
) -> impl WidgetIdFn<W> + Eventable<W, IdFnTag>;
|
||||||
|
|
||||||
fn id_on<E: Event<Ctx>>(
|
fn id_on<E: Event<Ctx>, Ctx>(
|
||||||
self,
|
self,
|
||||||
event: E,
|
event: E,
|
||||||
f: impl FnMut(&WidgetId<W>, &mut Ctx, E::Data) + 'static,
|
f: impl FnMut(&WidgetId<W>, &mut Ctx, E::Data) + 'static,
|
||||||
) -> impl WidgetIdFn<W> + Eventable<W, Ctx, IdFnTag>
|
) -> impl WidgetIdFn<W> + Eventable<W, IdFnTag>
|
||||||
where
|
where
|
||||||
W: Widget;
|
W: Widget;
|
||||||
|
|
||||||
fn edit_on<E: Event<Ctx>>(
|
fn edit_on<E: Event<Ui>>(
|
||||||
self,
|
self,
|
||||||
event: E,
|
event: E,
|
||||||
f: impl FnMut(&mut W, E::Data) + 'static,
|
f: impl FnMut(&mut W, E::Data) + 'static,
|
||||||
) -> impl WidgetIdFn<W> + Eventable<W, Ctx, IdFnTag>
|
) -> impl WidgetIdFn<W> + Eventable<W, IdFnTag>
|
||||||
where
|
where
|
||||||
W: Widget,
|
W: Widget;
|
||||||
Ctx: UiCtx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Ctxable<W, Tag> {
|
impl<W: WidgetLike<Tag>, Tag> Eventable<W::Widget, Tag> for W {
|
||||||
/// sets context which lets event functions work without needing to specify generics
|
fn on<E: Event<Ctx>, Ctx>(
|
||||||
fn ctx<Ctx>(self) -> impl WidgetLike<Tag> + Eventable<W, Ctx, Tag>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W: WidgetLike<Tag>, Tag> Ctxable<W::Widget, Tag> for W {
|
|
||||||
fn ctx<Ctx>(self) -> impl WidgetLike<Tag> + Eventable<W::Widget, Ctx, Tag> {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W: WidgetLike<Tag>, Ctx, Tag> Eventable<W::Widget, Ctx, Tag> for W {
|
|
||||||
fn on<E: Event<Ctx>>(
|
|
||||||
self,
|
self,
|
||||||
event: E,
|
event: E,
|
||||||
f: impl EventFn<Ctx, E::Data>,
|
f: impl EventFn<Ctx, E::Data>,
|
||||||
) -> impl WidgetIdFn<W::Widget> + Eventable<W::Widget, Ctx, IdFnTag> {
|
) -> impl WidgetIdFn<W::Widget> {
|
||||||
move |ui| {
|
move |ui| {
|
||||||
let id = self.add(ui);
|
let id = self.add(ui);
|
||||||
ui.modules
|
ui.modules
|
||||||
@@ -72,11 +64,11 @@ impl<W: WidgetLike<Tag>, Ctx, Tag> Eventable<W::Widget, Ctx, Tag> for W {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn id_on<E: Event<Ctx>>(
|
fn id_on<E: Event<Ctx>, Ctx>(
|
||||||
self,
|
self,
|
||||||
event: E,
|
event: E,
|
||||||
mut f: impl FnMut(&WidgetId<W::Widget>, &mut Ctx, E::Data) + 'static,
|
mut f: impl FnMut(&WidgetId<W::Widget>, &mut Ctx, E::Data) + 'static,
|
||||||
) -> impl WidgetIdFn<W::Widget> + Eventable<W::Widget, Ctx, IdFnTag>
|
) -> impl WidgetIdFn<W::Widget>
|
||||||
where
|
where
|
||||||
W::Widget: Widget,
|
W::Widget: Widget,
|
||||||
{
|
{
|
||||||
@@ -86,15 +78,14 @@ impl<W: WidgetLike<Tag>, Ctx, Tag> Eventable<W::Widget, Ctx, Tag> for W {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn edit_on<E: Event<Ctx>>(
|
fn edit_on<E: Event<Ui>>(
|
||||||
self,
|
self,
|
||||||
event: E,
|
event: E,
|
||||||
mut f: impl FnMut(&mut W::Widget, E::Data) + 'static,
|
mut f: impl FnMut(&mut W::Widget, E::Data) + 'static,
|
||||||
) -> impl WidgetIdFn<W::Widget> + Eventable<W::Widget, Ctx, IdFnTag>
|
) -> impl WidgetIdFn<W::Widget>
|
||||||
where
|
where
|
||||||
W::Widget: Widget,
|
W::Widget: Widget,
|
||||||
Ctx: UiCtx,
|
|
||||||
{
|
{
|
||||||
self.id_on(event, move |id, ctx, pos| f(&mut ctx.ui()[id], pos))
|
self.id_on(event, move |id, ui, pos| f(&mut ui[id], pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,8 +155,7 @@ impl Client {
|
|||||||
|
|
||||||
let switch_button = |color, to, label| {
|
let switch_button = |color, to, label| {
|
||||||
let rect = rect(color)
|
let rect = rect(color)
|
||||||
.ctx::<Client>()
|
.id_on(Sense::click(), move |id, ctx: &mut Client, _| {
|
||||||
.id_on(Sense::click(), move |id, ctx, _| {
|
|
||||||
ctx.ui[main].inner.set_static(to);
|
ctx.ui[main].inner.set_static(to);
|
||||||
ctx.ui[id].color = color.darker(0.3);
|
ctx.ui[id].color = color.darker(0.3);
|
||||||
})
|
})
|
||||||
@@ -212,7 +211,8 @@ impl Client {
|
|||||||
}
|
}
|
||||||
if input_changed {
|
if input_changed {
|
||||||
let window_size = self.window_size();
|
let window_size = self.window_size();
|
||||||
run_sensors(self, &cursor_state, window_size);
|
SensorModule::run(&mut self.ui, &cursor_state, window_size);
|
||||||
|
SensorModule::run(self, &cursor_state, window_size);
|
||||||
}
|
}
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::CloseRequested => event_loop.exit(),
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/// intentionally does not implement copy or ~~clone~~ HEEELP
|
/// intentionally does not implement copy or clone
|
||||||
/// which should make it harder to misuse;
|
/// which should make it harder to misuse;
|
||||||
/// the idea is to generally try to guarantee all IDs
|
/// the idea is to generally try to guarantee all IDs
|
||||||
/// point to something valid, although duplicate
|
/// point to something valid, although duplicate
|
||||||
/// gets around this if needed
|
/// gets around this if needed
|
||||||
#[derive(Eq, Hash, PartialEq, Debug, Clone)]
|
#[derive(Eq, Hash, PartialEq, Debug)]
|
||||||
pub struct Id(u64);
|
pub struct Id(u64);
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|||||||
Reference in New Issue
Block a user