use vizia_reactive::{Scope, SignalGet, UpdaterEffect};
use crate::{binding::BindingHandler, context::SIGNAL_REBUILDS, prelude::*};
pub struct Binding<T: 'static + Clone> {
entity: Entity,
content: Option<Box<dyn Fn(&mut Context)>>,
scope: Scope,
marker: std::marker::PhantomData<T>,
}
impl<T: 'static + Clone> Binding<T> {
#[allow(clippy::new_ret_no_self)]
pub fn new<S, F>(cx: &mut Context, signal: S, builder: F)
where
S: SignalGet<T> + 'static,
F: 'static + Fn(&mut Context),
{
let entity = cx.entity_manager.create();
cx.tree.add(entity, cx.current()).expect("Failed to add to tree");
cx.tree.set_ignored(entity, true);
let scope = Scope::new();
scope.enter(|| {
UpdaterEffect::new(
move || signal.get(),
move |_new_value| {
SIGNAL_REBUILDS.with_borrow_mut(|set| {
set.insert(entity);
});
},
)
});
let binding = Self {
entity,
content: Some(Box::new(builder)),
scope,
marker: std::marker::PhantomData,
};
if let Some(b) = &binding.content {
cx.with_current(entity, |cx| {
(b)(cx);
});
}
cx.bindings.insert(entity, Box::new(binding));
let _: Handle<Self> =
Handle { current: entity, entity, p: Default::default(), cx }.ignore();
}
}
impl<T: 'static + Clone> BindingHandler for Binding<T> {
fn update(&mut self, cx: &mut Context) {
cx.remove_children(cx.current());
if let Some(b) = &self.content {
cx.with_current(self.entity, |cx| {
(b)(cx);
});
}
}
fn remove(&self, _cx: &mut Context) {
self.scope.dispose();
}
fn debug(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("Binding")
}
}