use crate::context::LocalizationContext;
use crate::prelude::*;
use std::{
any::{Any, TypeId},
marker::PhantomData,
};
pub struct Handle<'a, V> {
pub(crate) current: Entity,
pub(crate) entity: Entity,
pub(crate) p: PhantomData<V>,
pub(crate) cx: &'a mut Context,
}
impl<'a, V> DataContext for Handle<'a, V> {
fn data<T: 'static>(&self) -> Option<&T> {
if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
return Some(t);
}
for entity in self.entity.parent_iter(&self.cx.tree) {
if let Some(model_data_store) = self.cx.data.get(&entity) {
if let Some(model) = model_data_store.models.get(&TypeId::of::<T>()) {
return model.downcast_ref::<T>();
}
}
if let Some(view_handler) = self.cx.views.get(&entity) {
if let Some(data) = view_handler.downcast_ref::<T>() {
return Some(data);
}
}
}
None
}
fn as_context(&self) -> Option<LocalizationContext<'_>> {
Some(LocalizationContext::from_context(self.cx))
}
}
impl<'a, V> Handle<'a, V> {
pub fn entity(&self) -> Entity {
self.entity
}
pub(crate) fn current(&self) -> Entity {
self.current
}
pub fn context(&mut self) -> &mut Context {
self.cx
}
pub fn parent(&self) -> Entity {
self.cx.tree.get_parent(self.entity).unwrap_or(Entity::root())
}
pub(crate) fn ignore(self) -> Self {
self.cx.tree.set_ignored(self.entity, true);
self.focusable(false)
}
pub fn lock_focus_to_within(self) -> Self {
self.cx.tree.set_lock_focus_within(self.entity, true);
self.cx.focus_stack.push(self.cx.focused);
if !self.cx.focused.is_descendant_of(&self.cx.tree, self.entity) {
let new_focus = vizia_storage::TreeIterator::subtree(&self.cx.tree, self.entity)
.find(|node| {
crate::tree::is_navigatable(
&self.cx.tree,
&self.cx.style,
*node,
Entity::root(),
)
})
.unwrap_or(self.cx.focus_stack.pop().unwrap());
self.cx.with_current(new_focus, |cx| cx.focus());
}
self
}
pub fn modify<F>(self, f: F) -> Self
where
F: FnOnce(&mut V),
V: 'static,
{
if let Some(view) = self
.cx
.views
.get_mut(&self.entity)
.and_then(|view_handler| view_handler.downcast_mut::<V>())
{
(f)(view);
}
self
}
pub fn on_build<F>(self, callback: F) -> Self
where
F: Fn(&mut EventContext),
{
let mut event_context = EventContext::new(self.cx);
event_context.current = self.entity;
(callback)(&mut event_context);
self
}
pub fn bind<R, T, F>(self, res: R, closure: F) -> Self
where
R: Res<T>,
F: 'static + Clone + Fn(Handle<'_, V>, R),
{
let entity = self.entity();
let current = self.current();
self.cx.with_current(current, |cx| {
res.set_or_bind(cx, entity, move |cx, r| {
let new_handle = Handle { entity, current: cx.current, p: Default::default(), cx };
(closure)(new_handle, r);
});
});
self
}
pub fn needs_relayout(&mut self) {
self.cx.needs_relayout();
}
pub fn needs_restyle(&mut self) {
self.cx.needs_restyle(self.entity);
}
pub fn needs_redraw(&mut self) {
self.cx.needs_redraw(self.entity);
}
pub fn bounds(&self) -> BoundingBox {
self.cx.cache.get_bounds(self.entity)
}
pub fn scale_factor(&self) -> f32 {
self.cx.scale_factor()
}
}
impl<'a, V> AsMut<Context> for Handle<'a, V> {
fn as_mut(&mut self) -> &mut Context {
self.context()
}
}