vizia_core/view/
handle.rs

1use crate::context::LocalizationContext;
2use crate::prelude::*;
3use std::{
4    any::{Any, TypeId},
5    marker::PhantomData,
6};
7
8/// A handle to a view which has been built into the tree.
9pub struct Handle<'a, V> {
10    pub(crate) current: Entity,
11    pub(crate) entity: Entity,
12    pub(crate) p: PhantomData<V>,
13    pub(crate) cx: &'a mut Context,
14}
15
16impl<V> DataContext for Handle<'_, V> {
17    fn data<T: 'static>(&self) -> Option<&T> {
18        // Return data for the static model.
19        if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
20            return Some(t);
21        }
22
23        for entity in self.entity.parent_iter(&self.cx.tree) {
24            // Return any model data.
25            if let Some(models) = self.cx.models.get(&entity) {
26                if let Some(model) = models.get(&TypeId::of::<T>()) {
27                    return model.downcast_ref::<T>();
28                }
29            }
30
31            // Return any view data.
32            if let Some(view_handler) = self.cx.views.get(&entity) {
33                if let Some(data) = view_handler.downcast_ref::<T>() {
34                    return Some(data);
35                }
36            }
37        }
38
39        None
40    }
41
42    fn localization_context(&self) -> Option<LocalizationContext<'_>> {
43        Some(LocalizationContext::from_context(self.cx))
44    }
45}
46
47impl<V> Handle<'_, V> {
48    /// Returns the [`Entity`] id of the view.
49    pub fn entity(&self) -> Entity {
50        self.entity
51    }
52
53    pub(crate) fn current(&self) -> Entity {
54        self.current
55    }
56
57    /// Returns a mutable reference to the context.
58    pub fn context(&mut self) -> &mut Context {
59        self.cx
60    }
61
62    ///  Returns the entity id of the parent view.
63    pub fn parent(&self) -> Entity {
64        self.cx.tree.get_parent(self.entity).unwrap_or(Entity::root())
65    }
66
67    /// Marks the view as being ignored.
68    pub(crate) fn ignore(self) -> Self {
69        self.cx.tree.set_ignored(self.entity, true);
70        self.focusable(false)
71    }
72
73    /// Stop the user from tabbing out of a subtree, which is useful for modal dialogs.
74    pub fn lock_focus_to_within(self) -> Self {
75        self.cx.tree.set_lock_focus_within(self.entity, true);
76        self.cx.focus_stack.push(self.cx.focused);
77        if !self.cx.focused.is_descendant_of(&self.cx.tree, self.entity) {
78            let new_focus = vizia_storage::TreeIterator::subtree(&self.cx.tree, self.entity)
79                .find(|node| {
80                    crate::tree::is_navigatable(
81                        &self.cx.tree,
82                        &self.cx.style,
83                        *node,
84                        Entity::root(),
85                    )
86                })
87                .unwrap_or(self.cx.focus_stack.pop().unwrap());
88            self.cx.with_current(new_focus, |cx| cx.focus());
89        }
90        self
91    }
92
93    /// Mody the internal data of the view.
94    pub fn modify<F>(mut self, f: F) -> Self
95    where
96        F: FnOnce(&mut V),
97        V: 'static,
98    {
99        if let Some(view) = self
100            .cx
101            .views
102            .get_mut(&self.entity)
103            .and_then(|view_handler| view_handler.downcast_mut::<V>())
104        {
105            (f)(view);
106        }
107
108        // Send an event to force the modification to happen within the same event loop.
109        self.context().emit(WindowEvent::Redraw);
110
111        self
112    }
113
114    /// Callback which is run when the view is built/rebuilt.
115    pub fn on_build<F>(self, callback: F) -> Self
116    where
117        F: Fn(&mut EventContext),
118    {
119        let mut event_context = EventContext::new(self.cx);
120        event_context.current = self.entity;
121        (callback)(&mut event_context);
122
123        self
124    }
125
126    /// Creates a binding to the given lens and provides a closure which can be used to mutate the view through a handle.
127    pub fn bind<R, T, F>(self, res: R, closure: F) -> Self
128    where
129        R: Res<T>,
130        F: 'static + Fn(Handle<'_, V>, R),
131    {
132        let entity = self.entity();
133        let current = self.current();
134        self.cx.with_current(current, |cx| {
135            res.set_or_bind(cx, entity, move |cx, r| {
136                let new_handle = Handle { entity, current: cx.current, p: Default::default(), cx };
137                // new_handle.cx.set_current(new_handle.entity);
138                (closure)(new_handle, r);
139            });
140        });
141        self
142    }
143
144    /// Marks the view as needing a relayout.
145    pub fn needs_relayout(&mut self) {
146        self.cx.needs_relayout();
147    }
148
149    /// Marks the view as needing a restyle.
150    pub fn needs_restyle(&mut self) {
151        self.cx.needs_restyle(self.entity);
152    }
153
154    /// Marks the view as needing a redraw.
155    pub fn needs_redraw(&mut self) {
156        self.cx.needs_redraw(self.entity);
157    }
158
159    /// Returns the bounding box of the view.
160    pub fn bounds(&self) -> BoundingBox {
161        self.cx.cache.get_bounds(self.entity)
162    }
163
164    /// Returns the scale factor of the device.
165    pub fn scale_factor(&self) -> f32 {
166        self.cx.scale_factor()
167    }
168}
169
170impl<V> AsMut<Context> for Handle<'_, V> {
171    fn as_mut(&mut self) -> &mut Context {
172        self.context()
173    }
174}