vizia_core/context/
backend.rs

1use std::any::Any;
2
3use skia_safe::Surface;
4use vizia_storage::LayoutTreeIterator;
5use vizia_window::WindowDescription;
6
7use super::EventProxy;
8use crate::{cache::CachedData, prelude::*, systems::*};
9
10#[cfg(feature = "clipboard")]
11use copypasta::ClipboardProvider;
12
13/// Context used to integrate vizia with windowing backends such as winit and baseview.
14pub struct BackendContext(pub Context);
15
16impl BackendContext {
17    /// Creates a new instance of a backend context.
18    pub fn new(cx: Context) -> Self {
19        Self(cx)
20    }
21
22    pub fn init_accessibility_tree(&mut self) -> accesskit::TreeUpdate {
23        initial_accessibility_system(&mut self.0)
24    }
25
26    /// Helper function for mutating the state of a window.
27    pub fn mutate_window<W: Any, F: Fn(&mut BackendContext, &mut W)>(
28        &mut self,
29        window_entity: Entity,
30        f: F,
31    ) {
32        if let Some(mut window_event_handler) = self.0.views.remove(&window_entity) {
33            if let Some(window) = window_event_handler.downcast_mut::<W>() {
34                f(self, window);
35            }
36
37            self.0.views.insert(window_entity, window_event_handler);
38        }
39    }
40
41    /// Adds a root window view to the context.
42    pub fn add_window<W: View>(&mut self, window: W) {
43        self.0.views.insert(Entity::root(), Box::new(window));
44    }
45
46    /// Returns a mutable reference to the style data.
47    pub fn style(&mut self) -> &mut Style {
48        &mut self.0.style
49    }
50
51    /// Returns a mutable reference to the cache of computed properties data.
52    pub fn cache(&mut self) -> &mut CachedData {
53        &mut self.0.cache
54    }
55
56    /// Returns a reference to the keyboard modifiers state.
57    pub fn modifiers(&mut self) -> &mut Modifiers {
58        &mut self.0.modifiers
59    }
60
61    /// Returns the entity id of the currently focused view.
62    pub fn focused(&self) -> Entity {
63        self.0.focused
64    }
65
66    pub fn add_main_window(
67        &mut self,
68        window_entity: Entity,
69        window_description: &WindowDescription,
70        dpi_factor: f32,
71    ) {
72        let physical_width = window_description.inner_size.width as f32 * dpi_factor;
73        let physical_height = window_description.inner_size.height as f32 * dpi_factor;
74
75        self.0.style.dpi_factor = dpi_factor as f64;
76
77        self.0.cache.set_width(window_entity, physical_width);
78        self.0.cache.set_height(window_entity, physical_height);
79
80        self.0
81            .style
82            .width
83            .insert(window_entity, Units::Pixels(window_description.inner_size.width as f32));
84        self.0
85            .style
86            .height
87            .insert(window_entity, Units::Pixels(window_description.inner_size.height as f32));
88
89        self.0.style.disabled.insert(window_entity, false);
90
91        self.0.style.pseudo_classes.insert(window_entity, PseudoClassFlags::OVER);
92        self.0.style.restyle.insert(window_entity).unwrap();
93        self.0.style.reaccess.insert(window_entity).unwrap();
94
95        self.0.style.position_type.insert(window_entity, PositionType::Absolute);
96
97        self.0.tree.set_window(window_entity, true);
98
99        // let physical_x = window_description.position.unwrap_or_default().x as f32 * dpi_factor;
100        // let physical_y = window_description.position.unwrap_or_default().y as f32 * dpi_factor;
101
102        // self.set_window_position(window_entity, physical_x, physical_y);
103    }
104
105    /// Returns a reference to the [`Environment`] model.
106    pub fn environment(&self) -> &Environment {
107        self.0.data::<Environment>().unwrap()
108    }
109
110    /// Returns a mutable reference to the inner context.
111    pub fn context(&mut self) -> &mut Context {
112        &mut self.0
113    }
114
115    /// Calls the draw system.
116    pub fn draw(
117        &mut self,
118        window_entity: Entity,
119        surface: &mut Surface,
120        dirty_surface: &mut Surface,
121    ) -> bool {
122        draw_system(&mut self.0, window_entity, surface, dirty_surface)
123    }
124
125    /// Set the current entity. This is useful in user code when you're performing black magic and
126    /// want to trick other parts of the code into thinking you're processing some other part of the
127    /// tree.
128    pub fn set_current(&mut self, e: Entity) {
129        self.0.current = e;
130    }
131
132    /// Sets the scale factor used by the application.
133    pub fn set_scale_factor(&mut self, scale: f64) {
134        self.0.style.dpi_factor = scale;
135    }
136
137    /// Sets the size of the window.
138    pub fn set_window_size(
139        &mut self,
140        window_entity: Entity,
141        physical_width: f32,
142        physical_height: f32,
143    ) {
144        self.0.cache.set_bounds(
145            window_entity,
146            BoundingBox::from_min_max(0.0, 0.0, physical_width, physical_height),
147        );
148
149        let logical_width = self.0.style.physical_to_logical(physical_width);
150        let logical_height = self.0.style.physical_to_logical(physical_height);
151        self.0.style.width.insert(window_entity, Units::Pixels(logical_width));
152        self.0.style.height.insert(window_entity, Units::Pixels(logical_height));
153    }
154
155    /// Temporarily sets the current entity, calls the provided closure, and then resets the current entity back to previous.
156    pub fn with_current(&mut self, e: Entity, f: impl FnOnce(&mut Context)) {
157        let prev = self.0.current;
158        self.0.current = e;
159        f(&mut self.0);
160        self.0.current = prev;
161    }
162
163    /// Returns the scale factor.
164    pub fn scale_factor(&self) -> f32 {
165        self.0.scale_factor()
166    }
167
168    /// You should not call this method unless you are writing a windowing backend, in which case
169    /// you should consult the existing windowing backends for usage information.
170    pub fn set_event_proxy(&mut self, proxy: Box<dyn EventProxy>) {
171        if self.0.event_proxy.is_some() {
172            panic!("Set the event proxy twice. This should never happen.");
173        }
174
175        self.0.event_proxy = Some(proxy);
176    }
177
178    /// You should not call this method unless you are writing a windowing backend, in which case
179    /// you should consult the existing windowing backends for usage information.
180    #[cfg(feature = "clipboard")]
181    pub fn set_clipboard_provider(&mut self, clipboard: Box<dyn ClipboardProvider>) {
182        self.0.clipboard = clipboard;
183    }
184
185    /// Send an event with custom origin and propagation information.
186    pub fn send_event(&mut self, event: Event) {
187        self.0.event_queue.push_back(event);
188    }
189
190    /// Check whether there are any events in the queue waiting for the next event dispatch cycle.
191    pub fn has_queued_events(&self) -> bool {
192        !self.0.event_queue.is_empty()
193    }
194
195    pub fn renegotiate_language(&mut self) {
196        self.0.resource_manager.renegotiate_language();
197    }
198
199    /// Calls the accessibility system and updates the accesskit node tree.
200    pub fn process_tree_updates(&mut self) {
201        accessibility_system(&mut self.0);
202    }
203
204    /// Calls the style system to match entities with shared styles.
205    pub fn process_style_updates(&mut self) {
206        style_system(&mut self.0);
207
208        // Load any unloaded images and remove unused images.
209        image_system(&mut self.0);
210    }
211
212    // Returns true if animations are playing
213    pub fn process_animations(&mut self) -> bool {
214        animation_system(&mut self.0)
215    }
216
217    /// Massages the style system until everything is coherent
218    pub fn process_visual_updates(&mut self) {
219        // Perform layout.
220        layout_system(&mut self.0);
221    }
222
223    pub fn emit_origin<M: Send + Any>(&mut self, message: M) {
224        self.0.event_queue.push_back(
225            Event::new(message)
226                .target(self.0.current)
227                .origin(Entity::root())
228                .propagate(Propagation::Up),
229        );
230    }
231
232    pub fn emit_window_event<M: Send + Any>(&mut self, window_entity: Entity, message: M) {
233        self.0.event_queue.push_back(
234            Event::new(message)
235                .target(window_entity)
236                .origin(window_entity)
237                .propagate(Propagation::Up),
238        );
239    }
240
241    pub fn needs_refresh(&mut self, window_entity: Entity) {
242        self.0.cache.path.remove(window_entity);
243        self.0.style.system_flags = SystemFlags::all();
244        self.0.needs_redraw(window_entity);
245        self.0.style.needs_restyle(window_entity);
246        self.0.style.needs_relayout();
247        let iter = LayoutTreeIterator::full(&self.0.tree);
248        for entity in iter {
249            self.0.style.needs_text_layout(entity);
250            self.0.style.needs_text_update(entity);
251            self.0.style.needs_restyle(entity);
252        }
253    }
254
255    pub fn process_timers(&mut self) {
256        self.0.tick_timers();
257    }
258
259    pub fn get_next_timer_time(&self) -> Option<Instant> {
260        let timer_time = self.0.running_timers.peek().map(|timer_state| timer_state.time);
261        let scheduled_event_time = self.0.event_schedule.peek().map(|timed_event| timed_event.time);
262
263        match (timer_time, scheduled_event_time) {
264            (Some(t1), Some(t2)) => Some(t1.min(t2)),
265            (Some(t), None) => Some(t),
266            (None, Some(t)) => Some(t),
267            _ => None,
268        }
269    }
270
271    pub fn emit_scheduled_events(&mut self) {
272        let now = Instant::now();
273        while let Some(timed_event) = self.0.event_schedule.peek() {
274            if timed_event.time <= now {
275                self.0.event_queue.push_back(self.0.event_schedule.pop().unwrap().event);
276            } else {
277                break;
278            }
279        }
280    }
281}