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
13pub struct BackendContext(pub Context);
15
16impl BackendContext {
17 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 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 pub fn add_window<W: View>(&mut self, window: W) {
43 self.0.views.insert(Entity::root(), Box::new(window));
44 }
45
46 pub fn style(&mut self) -> &mut Style {
48 &mut self.0.style
49 }
50
51 pub fn cache(&mut self) -> &mut CachedData {
53 &mut self.0.cache
54 }
55
56 pub fn modifiers(&mut self) -> &mut Modifiers {
58 &mut self.0.modifiers
59 }
60
61 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 }
104
105 pub fn environment(&self) -> &Environment {
107 self.0.data::<Environment>().unwrap()
108 }
109
110 pub fn context(&mut self) -> &mut Context {
112 &mut self.0
113 }
114
115 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 pub fn set_current(&mut self, e: Entity) {
129 self.0.current = e;
130 }
131
132 pub fn set_scale_factor(&mut self, scale: f64) {
134 self.0.style.dpi_factor = scale;
135 }
136
137 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 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 pub fn scale_factor(&self) -> f32 {
165 self.0.scale_factor()
166 }
167
168 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 #[cfg(feature = "clipboard")]
181 pub fn set_clipboard_provider(&mut self, clipboard: Box<dyn ClipboardProvider>) {
182 self.0.clipboard = clipboard;
183 }
184
185 pub fn send_event(&mut self, event: Event) {
187 self.0.event_queue.push_back(event);
188 }
189
190 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 pub fn process_tree_updates(&mut self) {
201 accessibility_system(&mut self.0);
202 }
203
204 pub fn process_style_updates(&mut self) {
206 style_system(&mut self.0);
207
208 image_system(&mut self.0);
210 }
211
212 pub fn process_animations(&mut self) -> bool {
214 animation_system(&mut self.0)
215 }
216
217 pub fn process_visual_updates(&mut self) {
219 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}