1use crate::{
2 elements::ElementBox,
3 executor::{self, ForegroundTask},
4 keymap::{self, Keystroke},
5 platform::{self, App as _, WindowOptions},
6 presenter::Presenter,
7 util::post_inc,
8 AssetCache, AssetSource, FontCache,
9};
10use anyhow::{anyhow, Result};
11use keymap::MatchResult;
12use parking_lot::Mutex;
13use pathfinder_geometry::{rect::RectF, vector::vec2f};
14use platform::Event;
15use smol::{channel, prelude::*};
16use std::{
17 any::{type_name, Any, TypeId},
18 cell::RefCell,
19 collections::{HashMap, HashSet, VecDeque},
20 fmt::{self, Debug},
21 hash::{Hash, Hasher},
22 marker::PhantomData,
23 rc::{self, Rc},
24 sync::{Arc, Weak},
25};
26
27pub trait Entity: 'static + Send + Sync {
28 type Event;
29}
30
31pub trait View: Entity {
32 fn ui_name() -> &'static str;
33 fn render<'a>(&self, app: &AppContext) -> ElementBox;
34 fn on_focus(&mut self, _ctx: &mut ViewContext<Self>) {}
35 fn on_blur(&mut self, _ctx: &mut ViewContext<Self>) {}
36 fn keymap_context(&self, _: &AppContext) -> keymap::Context {
37 Self::default_keymap_context()
38 }
39 fn default_keymap_context() -> keymap::Context {
40 let mut ctx = keymap::Context::default();
41 ctx.set.insert(Self::ui_name().into());
42 ctx
43 }
44}
45
46pub trait ModelAsRef {
47 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T;
48}
49
50pub trait UpdateModel {
51 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
52 where
53 T: Entity,
54 F: FnOnce(&mut T, &mut ModelContext<T>) -> S;
55}
56
57pub trait ViewAsRef {
58 fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T;
59}
60
61pub trait UpdateView {
62 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
63 where
64 T: View,
65 F: FnOnce(&mut T, &mut ViewContext<T>) -> S;
66}
67
68#[derive(Clone)]
69pub struct App(Rc<RefCell<MutableAppContext>>);
70
71impl App {
72 pub fn test<T, A: AssetSource, F: Future<Output = T>, G: FnOnce(App) -> F>(
73 asset_source: A,
74 f: G,
75 ) -> T {
76 let platform = platform::current::app(); // TODO: Make a test platform app
77 let foreground = Rc::new(executor::Foreground::test());
78 let app = Self(Rc::new(RefCell::new(MutableAppContext::new(
79 foreground.clone(),
80 Arc::new(platform),
81 asset_source,
82 ))));
83 app.0.borrow_mut().weak_self = Some(Rc::downgrade(&app.0));
84 smol::block_on(foreground.run(f(app)))
85 }
86
87 pub fn new(asset_source: impl AssetSource) -> Result<Self> {
88 let platform = Arc::new(platform::current::app());
89 let foreground = Rc::new(executor::Foreground::platform(platform.dispatcher())?);
90 let app = Self(Rc::new(RefCell::new(MutableAppContext::new(
91 foreground,
92 platform,
93 asset_source,
94 ))));
95 app.0.borrow_mut().weak_self = Some(Rc::downgrade(&app.0));
96 Ok(app)
97 }
98
99 pub fn on_window_invalidated<F: 'static + FnMut(WindowInvalidation, &mut MutableAppContext)>(
100 &self,
101 window_id: usize,
102 callback: F,
103 ) {
104 self.0
105 .borrow_mut()
106 .on_window_invalidated(window_id, callback);
107 }
108
109 pub fn add_action<S, V, T, F>(&self, name: S, handler: F)
110 where
111 S: Into<String>,
112 V: View,
113 T: Any,
114 F: 'static + FnMut(&mut V, &T, &mut ViewContext<V>),
115 {
116 self.0.borrow_mut().add_action(name, handler);
117 }
118
119 pub fn add_global_action<S, T, F>(&self, name: S, handler: F)
120 where
121 S: Into<String>,
122 T: 'static + Any,
123 F: 'static + FnMut(&T, &mut MutableAppContext),
124 {
125 self.0.borrow_mut().add_global_action(name, handler);
126 }
127
128 pub fn dispatch_action<T: 'static + Any>(
129 &self,
130 window_id: usize,
131 responder_chain: Vec<usize>,
132 name: &str,
133 arg: T,
134 ) {
135 self.0.borrow_mut().dispatch_action(
136 window_id,
137 &responder_chain,
138 name,
139 Box::new(arg).as_ref(),
140 );
141 }
142
143 pub fn dispatch_global_action<T: 'static + Any>(&self, name: &str, arg: T) {
144 self.0
145 .borrow_mut()
146 .dispatch_global_action(name, Box::new(arg).as_ref());
147 }
148
149 pub fn add_bindings<T: IntoIterator<Item = keymap::Binding>>(&self, bindings: T) {
150 self.0.borrow_mut().add_bindings(bindings);
151 }
152
153 pub fn dispatch_keystroke(
154 &self,
155 window_id: usize,
156 responder_chain: Vec<usize>,
157 keystroke: &Keystroke,
158 ) -> Result<bool> {
159 let mut state = self.0.borrow_mut();
160 state.dispatch_keystroke(window_id, responder_chain, keystroke)
161 }
162
163 pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
164 where
165 T: Entity,
166 F: FnOnce(&mut ModelContext<T>) -> T,
167 {
168 let mut state = self.0.borrow_mut();
169 state.pending_flushes += 1;
170 let handle = state.add_model(build_model);
171 state.flush_effects();
172 handle
173 }
174
175 fn read_model<T, F, S>(&self, handle: &ModelHandle<T>, read: F) -> S
176 where
177 T: Entity,
178 F: FnOnce(&T, &AppContext) -> S,
179 {
180 let state = self.0.borrow();
181 read(state.model(handle), &state.ctx)
182 }
183
184 pub fn add_window<T, F>(&mut self, build_root_view: F) -> (usize, ViewHandle<T>)
185 where
186 T: View,
187 F: FnOnce(&mut ViewContext<T>) -> T,
188 {
189 self.0.borrow_mut().add_window(build_root_view)
190 }
191
192 pub fn window_ids(&self) -> Vec<usize> {
193 self.0.borrow().window_ids().collect()
194 }
195
196 pub fn root_view<T: View>(&self, window_id: usize) -> Option<ViewHandle<T>> {
197 self.0.borrow().root_view(window_id)
198 }
199
200 pub fn add_view<T, F>(&mut self, window_id: usize, build_view: F) -> ViewHandle<T>
201 where
202 T: View,
203 F: FnOnce(&mut ViewContext<T>) -> T,
204 {
205 let mut state = self.0.borrow_mut();
206 state.pending_flushes += 1;
207 let handle = state.add_view(window_id, build_view);
208 state.flush_effects();
209 handle
210 }
211
212 pub fn add_option_view<T, F>(
213 &mut self,
214 window_id: usize,
215 build_view: F,
216 ) -> Option<ViewHandle<T>>
217 where
218 T: View,
219 F: FnOnce(&mut ViewContext<T>) -> Option<T>,
220 {
221 let mut state = self.0.borrow_mut();
222 state.pending_flushes += 1;
223 let handle = state.add_option_view(window_id, build_view);
224 state.flush_effects();
225 handle
226 }
227
228 pub fn read<T, F: FnOnce(&AppContext) -> T>(&mut self, callback: F) -> T {
229 callback(self.0.borrow().downgrade())
230 }
231
232 pub fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
233 let mut state = self.0.borrow_mut();
234 state.pending_flushes += 1;
235 let result = callback(&mut *state);
236 state.flush_effects();
237 result
238 }
239
240 fn read_view<T, F, S>(&self, handle: &ViewHandle<T>, read: F) -> S
241 where
242 T: View,
243 F: FnOnce(&T, &AppContext) -> S,
244 {
245 let state = self.0.borrow();
246 read(state.view(handle), state.downgrade())
247 }
248
249 pub fn finish_pending_tasks(&self) -> impl Future<Output = ()> {
250 self.0.borrow().finish_pending_tasks()
251 }
252
253 pub fn font_cache(&self) -> Arc<FontCache> {
254 self.0.borrow().font_cache.clone()
255 }
256
257 pub fn platform(&self) -> Arc<dyn platform::App> {
258 self.0.borrow().platform.clone()
259 }
260}
261
262impl UpdateModel for App {
263 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
264 where
265 T: Entity,
266 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
267 {
268 let mut state = self.0.borrow_mut();
269 state.pending_flushes += 1;
270 let result = state.update_model(handle, update);
271 state.flush_effects();
272 result
273 }
274}
275
276impl UpdateView for App {
277 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
278 where
279 T: View,
280 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
281 {
282 let mut state = self.0.borrow_mut();
283 state.pending_flushes += 1;
284 let result = state.update_view(handle, update);
285 state.flush_effects();
286 result
287 }
288}
289
290type ActionCallback =
291 dyn FnMut(&mut dyn AnyView, &dyn Any, &mut MutableAppContext, usize, usize) -> bool;
292
293type GlobalActionCallback = dyn FnMut(&dyn Any, &mut MutableAppContext);
294
295pub struct MutableAppContext {
296 weak_self: Option<rc::Weak<RefCell<Self>>>,
297 platform: Arc<dyn platform::App>,
298 font_cache: Arc<FontCache>,
299 assets: Arc<AssetCache>,
300 ctx: AppContext,
301 actions: HashMap<TypeId, HashMap<String, Vec<Box<ActionCallback>>>>,
302 global_actions: HashMap<String, Vec<Box<GlobalActionCallback>>>,
303 keystroke_matcher: keymap::Matcher,
304 next_entity_id: usize,
305 next_window_id: usize,
306 next_task_id: usize,
307 subscriptions: HashMap<usize, Vec<Subscription>>,
308 observations: HashMap<usize, Vec<Observation>>,
309 window_invalidations: HashMap<usize, WindowInvalidation>,
310 invalidation_callbacks:
311 HashMap<usize, Box<dyn FnMut(WindowInvalidation, &mut MutableAppContext)>>,
312 foreground: Rc<executor::Foreground>,
313 background: Arc<executor::Background>,
314 future_handlers: HashMap<usize, FutureHandler>,
315 stream_handlers: HashMap<usize, StreamHandler>,
316 task_done: (channel::Sender<usize>, channel::Receiver<usize>),
317 pending_effects: VecDeque<Effect>,
318 pending_flushes: usize,
319 flushing_effects: bool,
320}
321
322impl MutableAppContext {
323 pub fn new(
324 foreground: Rc<executor::Foreground>,
325 platform: Arc<dyn platform::App>,
326 asset_source: impl AssetSource,
327 ) -> Self {
328 let fonts = platform.fonts();
329 Self {
330 weak_self: None,
331 platform,
332 font_cache: Arc::new(FontCache::new(fonts)),
333 assets: Arc::new(AssetCache::new(asset_source)),
334 ctx: AppContext {
335 models: HashMap::new(),
336 windows: HashMap::new(),
337 ref_counts: Arc::new(Mutex::new(RefCounts::default())),
338 },
339 actions: HashMap::new(),
340 global_actions: HashMap::new(),
341 keystroke_matcher: keymap::Matcher::default(),
342 next_entity_id: 0,
343 next_window_id: 0,
344 next_task_id: 0,
345 subscriptions: HashMap::new(),
346 observations: HashMap::new(),
347 window_invalidations: HashMap::new(),
348 invalidation_callbacks: HashMap::new(),
349 foreground,
350 background: Arc::new(executor::Background::new()),
351 future_handlers: HashMap::new(),
352 stream_handlers: HashMap::new(),
353 task_done: channel::unbounded(),
354 pending_effects: VecDeque::new(),
355 pending_flushes: 0,
356 flushing_effects: false,
357 }
358 }
359
360 pub fn upgrade(&self) -> App {
361 App(self.weak_self.as_ref().unwrap().upgrade().unwrap())
362 }
363
364 pub fn downgrade(&self) -> &AppContext {
365 &self.ctx
366 }
367
368 pub fn foreground_executor(&self) -> Rc<executor::Foreground> {
369 self.foreground.clone()
370 }
371
372 pub fn on_window_invalidated<F: 'static + FnMut(WindowInvalidation, &mut MutableAppContext)>(
373 &mut self,
374 window_id: usize,
375 callback: F,
376 ) {
377 self.invalidation_callbacks
378 .insert(window_id, Box::new(callback));
379 }
380
381 pub fn add_action<S, V, T, F>(&mut self, name: S, mut handler: F)
382 where
383 S: Into<String>,
384 V: View,
385 T: Any,
386 F: 'static + FnMut(&mut V, &T, &mut ViewContext<V>),
387 {
388 let name = name.into();
389 let name_clone = name.clone();
390 let handler = Box::new(
391 move |view: &mut dyn AnyView,
392 arg: &dyn Any,
393 app: &mut MutableAppContext,
394 window_id: usize,
395 view_id: usize| {
396 match arg.downcast_ref() {
397 Some(arg) => {
398 let mut ctx = ViewContext::new(app, window_id, view_id);
399 handler(
400 view.as_any_mut()
401 .downcast_mut()
402 .expect("downcast is type safe"),
403 arg,
404 &mut ctx,
405 );
406 ctx.halt_action_dispatch
407 }
408 None => {
409 log::error!("Could not downcast argument for action {}", name_clone);
410 false
411 }
412 }
413 },
414 );
415
416 self.actions
417 .entry(TypeId::of::<V>())
418 .or_default()
419 .entry(name)
420 .or_default()
421 .push(handler);
422 }
423
424 pub fn add_global_action<S, T, F>(&mut self, name: S, mut handler: F)
425 where
426 S: Into<String>,
427 T: 'static + Any,
428 F: 'static + FnMut(&T, &mut MutableAppContext),
429 {
430 let name = name.into();
431 let name_clone = name.clone();
432 let handler = Box::new(move |arg: &dyn Any, app: &mut MutableAppContext| {
433 if let Some(arg) = arg.downcast_ref() {
434 handler(arg, app);
435 } else {
436 log::error!("Could not downcast argument for action {}", name_clone);
437 }
438 });
439
440 self.global_actions.entry(name).or_default().push(handler);
441 }
442
443 pub fn window_ids(&self) -> impl Iterator<Item = usize> + '_ {
444 self.ctx.windows.keys().cloned()
445 }
446
447 pub fn root_view<T: View>(&self, window_id: usize) -> Option<ViewHandle<T>> {
448 self.ctx
449 .windows
450 .get(&window_id)
451 .and_then(|window| window.root_view.as_ref().unwrap().clone().downcast::<T>())
452 }
453
454 pub fn root_view_id(&self, window_id: usize) -> Option<usize> {
455 self.ctx.root_view_id(window_id)
456 }
457
458 pub fn focused_view_id(&self, window_id: usize) -> Option<usize> {
459 self.ctx.focused_view_id(window_id)
460 }
461
462 pub fn render_view(&self, window_id: usize, view_id: usize) -> Result<ElementBox> {
463 self.ctx.render_view(window_id, view_id)
464 }
465
466 pub fn render_views(&self, window_id: usize) -> Result<HashMap<usize, ElementBox>> {
467 self.ctx.render_views(window_id)
468 }
469
470 pub fn dispatch_action(
471 &mut self,
472 window_id: usize,
473 path: &[usize],
474 name: &str,
475 arg: &dyn Any,
476 ) -> bool {
477 self.pending_flushes += 1;
478 let mut halted_dispatch = false;
479
480 for view_id in path.iter().rev() {
481 if let Some(mut view) = self
482 .ctx
483 .windows
484 .get_mut(&window_id)
485 .and_then(|w| w.views.remove(view_id))
486 {
487 let type_id = view.as_any().type_id();
488
489 if let Some((name, mut handlers)) = self
490 .actions
491 .get_mut(&type_id)
492 .and_then(|h| h.remove_entry(name))
493 {
494 for handler in handlers.iter_mut().rev() {
495 let halt_dispatch = handler(view.as_mut(), arg, self, window_id, *view_id);
496 if halt_dispatch {
497 halted_dispatch = true;
498 break;
499 }
500 }
501 self.actions
502 .get_mut(&type_id)
503 .unwrap()
504 .insert(name, handlers);
505 }
506
507 self.ctx
508 .windows
509 .get_mut(&window_id)
510 .unwrap()
511 .views
512 .insert(*view_id, view);
513
514 if halted_dispatch {
515 break;
516 }
517 }
518 }
519
520 if !halted_dispatch {
521 self.dispatch_global_action(name, arg);
522 }
523
524 self.flush_effects();
525 halted_dispatch
526 }
527
528 fn dispatch_global_action(&mut self, name: &str, arg: &dyn Any) {
529 if let Some((name, mut handlers)) = self.global_actions.remove_entry(name) {
530 self.pending_flushes += 1;
531 for handler in handlers.iter_mut().rev() {
532 handler(arg, self);
533 }
534 self.global_actions.insert(name, handlers);
535 self.flush_effects();
536 }
537 }
538
539 fn add_bindings<T: IntoIterator<Item = keymap::Binding>>(&mut self, bindings: T) {
540 self.keystroke_matcher.add_bindings(bindings);
541 }
542
543 pub fn dispatch_keystroke(
544 &mut self,
545 window_id: usize,
546 responder_chain: Vec<usize>,
547 keystroke: &Keystroke,
548 ) -> Result<bool> {
549 let mut context_chain = Vec::new();
550 let mut context = keymap::Context::default();
551 for view_id in &responder_chain {
552 if let Some(view) = self
553 .ctx
554 .windows
555 .get(&window_id)
556 .and_then(|w| w.views.get(view_id))
557 {
558 context.extend(view.keymap_context(self.downgrade()));
559 context_chain.push(context.clone());
560 } else {
561 return Err(anyhow!(
562 "View {} in responder chain does not exist",
563 view_id
564 ));
565 }
566 }
567
568 let mut pending = false;
569 for (i, ctx) in context_chain.iter().enumerate().rev() {
570 match self
571 .keystroke_matcher
572 .push_keystroke(keystroke.clone(), responder_chain[i], ctx)
573 {
574 MatchResult::None => {}
575 MatchResult::Pending => pending = true,
576 MatchResult::Action { name, arg } => {
577 if self.dispatch_action(
578 window_id,
579 &responder_chain[0..=i],
580 &name,
581 arg.as_ref().map(|arg| arg.as_ref()).unwrap_or(&()),
582 ) {
583 return Ok(true);
584 }
585 }
586 }
587 }
588
589 Ok(pending)
590 }
591
592 pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
593 where
594 T: Entity,
595 F: FnOnce(&mut ModelContext<T>) -> T,
596 {
597 self.pending_flushes += 1;
598 let model_id = post_inc(&mut self.next_entity_id);
599 let mut ctx = ModelContext::new(self, model_id);
600 let model = build_model(&mut ctx);
601 self.ctx.models.insert(model_id, Box::new(model));
602 self.flush_effects();
603 ModelHandle::new(model_id, &self.ctx.ref_counts)
604 }
605
606 pub fn add_window<T, F>(&mut self, build_root_view: F) -> (usize, ViewHandle<T>)
607 where
608 T: View,
609 F: FnOnce(&mut ViewContext<T>) -> T,
610 {
611 let window_id = post_inc(&mut self.next_window_id);
612 self.ctx.windows.insert(window_id, Window::default());
613
614 let root_handle = self.add_view(window_id, build_root_view);
615 self.ctx.windows.get_mut(&window_id).unwrap().root_view = Some(root_handle.clone().into());
616 self.focus(window_id, root_handle.id());
617
618 match self.platform.open_window(
619 WindowOptions {
620 bounds: RectF::new(vec2f(0., 0.), vec2f(1024., 768.)),
621 title: "Zed".into(),
622 },
623 self.foreground.clone(),
624 ) {
625 Err(e) => log::error!("error opening window: {}", e),
626 Ok(mut window) => {
627 let presenter = Rc::new(RefCell::new(Presenter::new(
628 window_id,
629 self.font_cache.clone(),
630 self.platform.fonts(),
631 self.assets.clone(),
632 self,
633 )));
634
635 {
636 let mut app = self.upgrade();
637 let presenter = presenter.clone();
638 window.on_event(Box::new(move |event| {
639 app.update(|ctx| {
640 if let Event::KeyDown { keystroke, .. } = &event {
641 if ctx
642 .dispatch_keystroke(
643 window_id,
644 presenter.borrow().dispatch_path(ctx.downgrade()),
645 keystroke,
646 )
647 .unwrap()
648 {
649 return;
650 }
651 }
652
653 let actions = presenter
654 .borrow_mut()
655 .dispatch_event(event, ctx.downgrade());
656 for action in actions {
657 ctx.dispatch_action(
658 window_id,
659 &action.path,
660 action.name,
661 action.arg.as_ref(),
662 );
663 }
664 })
665 }));
666 }
667
668 {
669 let mut app = self.upgrade();
670 let presenter = presenter.clone();
671 window.on_resize(Box::new(move |window| {
672 app.update(|ctx| {
673 let scene = presenter.borrow_mut().build_scene(
674 window.size(),
675 window.scale_factor(),
676 ctx,
677 );
678 window.present_scene(scene);
679 })
680 }));
681 }
682
683 self.on_window_invalidated(window_id, move |invalidation, ctx| {
684 let mut presenter = presenter.borrow_mut();
685 presenter.invalidate(invalidation, ctx.downgrade());
686 let scene = presenter.build_scene(window.size(), window.scale_factor(), ctx);
687 window.present_scene(scene);
688 });
689 }
690 }
691
692 (window_id, root_handle)
693 }
694
695 pub fn add_view<T, F>(&mut self, window_id: usize, build_view: F) -> ViewHandle<T>
696 where
697 T: View,
698 F: FnOnce(&mut ViewContext<T>) -> T,
699 {
700 self.add_option_view(window_id, |ctx| Some(build_view(ctx)))
701 .unwrap()
702 }
703
704 pub fn add_option_view<T, F>(
705 &mut self,
706 window_id: usize,
707 build_view: F,
708 ) -> Option<ViewHandle<T>>
709 where
710 T: View,
711 F: FnOnce(&mut ViewContext<T>) -> Option<T>,
712 {
713 let view_id = post_inc(&mut self.next_entity_id);
714 self.pending_flushes += 1;
715 let mut ctx = ViewContext::new(self, window_id, view_id);
716 let handle = if let Some(view) = build_view(&mut ctx) {
717 if let Some(window) = self.ctx.windows.get_mut(&window_id) {
718 window.views.insert(view_id, Box::new(view));
719 } else {
720 panic!("Window does not exist");
721 }
722 self.window_invalidations
723 .entry(window_id)
724 .or_default()
725 .updated
726 .insert(view_id);
727 Some(ViewHandle::new(window_id, view_id, &self.ctx.ref_counts))
728 } else {
729 None
730 };
731 self.flush_effects();
732 handle
733 }
734
735 fn remove_dropped_entities(&mut self) {
736 loop {
737 let (dropped_models, dropped_views) = self.ctx.ref_counts.lock().take_dropped();
738 if dropped_models.is_empty() && dropped_views.is_empty() {
739 break;
740 }
741
742 for model_id in dropped_models {
743 self.ctx.models.remove(&model_id);
744 self.subscriptions.remove(&model_id);
745 self.observations.remove(&model_id);
746 }
747
748 for (window_id, view_id) in dropped_views {
749 self.subscriptions.remove(&view_id);
750 self.observations.remove(&view_id);
751 if let Some(window) = self.ctx.windows.get_mut(&window_id) {
752 self.window_invalidations
753 .entry(window_id)
754 .or_default()
755 .removed
756 .push(view_id);
757 window.views.remove(&view_id);
758 }
759 }
760 }
761 }
762
763 fn flush_effects(&mut self) {
764 self.pending_flushes -= 1;
765
766 if !self.flushing_effects && self.pending_flushes == 0 {
767 self.flushing_effects = true;
768
769 while let Some(effect) = self.pending_effects.pop_front() {
770 match effect {
771 Effect::Event { entity_id, payload } => self.emit_event(entity_id, payload),
772 Effect::ModelNotification { model_id } => self.notify_model_observers(model_id),
773 Effect::ViewNotification { window_id, view_id } => {
774 self.notify_view_observers(window_id, view_id)
775 }
776 Effect::Focus { window_id, view_id } => {
777 self.focus(window_id, view_id);
778 }
779 }
780 }
781
782 self.flushing_effects = false;
783 self.remove_dropped_entities();
784 self.update_windows();
785 }
786 }
787
788 fn update_windows(&mut self) {
789 let mut invalidations = HashMap::new();
790 std::mem::swap(&mut invalidations, &mut self.window_invalidations);
791
792 for (window_id, invalidation) in invalidations {
793 if let Some(mut callback) = self.invalidation_callbacks.remove(&window_id) {
794 callback(invalidation, self);
795 self.invalidation_callbacks.insert(window_id, callback);
796 }
797 }
798 }
799
800 fn emit_event(&mut self, entity_id: usize, payload: Box<dyn Any>) {
801 if let Some(subscriptions) = self.subscriptions.remove(&entity_id) {
802 for mut subscription in subscriptions {
803 let alive = match &mut subscription {
804 Subscription::FromModel { model_id, callback } => {
805 if let Some(mut model) = self.ctx.models.remove(model_id) {
806 callback(model.as_any_mut(), payload.as_ref(), self, *model_id);
807 self.ctx.models.insert(*model_id, model);
808 true
809 } else {
810 false
811 }
812 }
813 Subscription::FromView {
814 window_id,
815 view_id,
816 callback,
817 } => {
818 if let Some(mut view) = self
819 .ctx
820 .windows
821 .get_mut(&window_id)
822 .and_then(|window| window.views.remove(view_id))
823 {
824 callback(
825 view.as_any_mut(),
826 payload.as_ref(),
827 self,
828 *window_id,
829 *view_id,
830 );
831 self.ctx
832 .windows
833 .get_mut(&window_id)
834 .unwrap()
835 .views
836 .insert(*view_id, view);
837 true
838 } else {
839 false
840 }
841 }
842 };
843
844 if alive {
845 self.subscriptions
846 .entry(entity_id)
847 .or_default()
848 .push(subscription);
849 }
850 }
851 }
852 }
853
854 fn notify_model_observers(&mut self, observed_id: usize) {
855 if let Some(observations) = self.observations.remove(&observed_id) {
856 if self.ctx.models.contains_key(&observed_id) {
857 for mut observation in observations {
858 let alive = match &mut observation {
859 Observation::FromModel { model_id, callback } => {
860 if let Some(mut model) = self.ctx.models.remove(model_id) {
861 callback(model.as_any_mut(), observed_id, self, *model_id);
862 self.ctx.models.insert(*model_id, model);
863 true
864 } else {
865 false
866 }
867 }
868 Observation::FromView {
869 window_id,
870 view_id,
871 callback,
872 } => {
873 if let Some(mut view) = self
874 .ctx
875 .windows
876 .get_mut(window_id)
877 .and_then(|w| w.views.remove(view_id))
878 {
879 callback(
880 view.as_any_mut(),
881 observed_id,
882 self,
883 *window_id,
884 *view_id,
885 );
886 self.ctx
887 .windows
888 .get_mut(window_id)
889 .unwrap()
890 .views
891 .insert(*view_id, view);
892 true
893 } else {
894 false
895 }
896 }
897 };
898
899 if alive {
900 self.observations
901 .entry(observed_id)
902 .or_default()
903 .push(observation);
904 }
905 }
906 }
907 }
908 }
909
910 fn notify_view_observers(&mut self, window_id: usize, view_id: usize) {
911 self.window_invalidations
912 .entry(window_id)
913 .or_default()
914 .updated
915 .insert(view_id);
916 }
917
918 fn focus(&mut self, window_id: usize, focused_id: usize) {
919 if self
920 .ctx
921 .windows
922 .get(&window_id)
923 .and_then(|w| w.focused_view)
924 .map_or(false, |cur_focused| cur_focused == focused_id)
925 {
926 return;
927 }
928
929 self.pending_flushes += 1;
930
931 if let Some((blurred_id, mut blurred)) =
932 self.ctx.windows.get_mut(&window_id).and_then(|w| {
933 let blurred_view = w.focused_view;
934 w.focused_view = Some(focused_id);
935 blurred_view.and_then(|id| w.views.remove(&id).map(|view| (id, view)))
936 })
937 {
938 blurred.on_blur(self, window_id, blurred_id);
939 self.ctx
940 .windows
941 .get_mut(&window_id)
942 .unwrap()
943 .views
944 .insert(blurred_id, blurred);
945 }
946
947 if let Some(mut focused) = self
948 .ctx
949 .windows
950 .get_mut(&window_id)
951 .and_then(|w| w.views.remove(&focused_id))
952 {
953 focused.on_focus(self, window_id, focused_id);
954 self.ctx
955 .windows
956 .get_mut(&window_id)
957 .unwrap()
958 .views
959 .insert(focused_id, focused);
960 }
961
962 self.flush_effects();
963 }
964
965 fn spawn<F, T>(&mut self, future: F) -> (usize, ForegroundTask<Option<T>>)
966 where
967 F: 'static + Future,
968 T: 'static,
969 {
970 let task_id = post_inc(&mut self.next_task_id);
971 let app = self.weak_self.as_ref().unwrap().upgrade().unwrap();
972 let task = self.foreground.spawn(async move {
973 let output = future.await;
974 app.borrow_mut()
975 .handle_future_output(task_id, Box::new(output))
976 .map(|result| *result.downcast::<T>().unwrap())
977 });
978 (task_id, task)
979 }
980
981 fn spawn_stream<F, T>(&mut self, mut stream: F) -> (usize, ForegroundTask<Option<T>>)
982 where
983 F: 'static + Stream + Unpin,
984 T: 'static,
985 {
986 let task_id = post_inc(&mut self.next_task_id);
987 let app = self.weak_self.as_ref().unwrap().upgrade().unwrap();
988 let task = self.foreground.spawn(async move {
989 loop {
990 match stream.next().await {
991 Some(item) => {
992 let mut app = app.borrow_mut();
993 if app.handle_stream_item(task_id, Box::new(item)) {
994 break;
995 }
996 }
997 None => {
998 break;
999 }
1000 }
1001 }
1002
1003 app.borrow_mut()
1004 .stream_completed(task_id)
1005 .map(|result| *result.downcast::<T>().unwrap())
1006 });
1007
1008 (task_id, task)
1009 }
1010
1011 fn handle_future_output(
1012 &mut self,
1013 task_id: usize,
1014 output: Box<dyn Any>,
1015 ) -> Option<Box<dyn Any>> {
1016 self.pending_flushes += 1;
1017 let future_callback = self.future_handlers.remove(&task_id).unwrap();
1018
1019 let mut result = None;
1020
1021 match future_callback {
1022 FutureHandler::Model { model_id, callback } => {
1023 if let Some(mut model) = self.ctx.models.remove(&model_id) {
1024 result = Some(callback(model.as_any_mut(), output, self, model_id));
1025 self.ctx.models.insert(model_id, model);
1026 }
1027 self.task_done(task_id);
1028 }
1029 FutureHandler::View {
1030 window_id,
1031 view_id,
1032 callback,
1033 } => {
1034 if let Some(mut view) = self
1035 .ctx
1036 .windows
1037 .get_mut(&window_id)
1038 .and_then(|w| w.views.remove(&view_id))
1039 {
1040 result = Some(callback(view.as_mut(), output, self, window_id, view_id));
1041 self.ctx
1042 .windows
1043 .get_mut(&window_id)
1044 .unwrap()
1045 .views
1046 .insert(view_id, view);
1047 }
1048 self.task_done(task_id);
1049 }
1050 };
1051
1052 self.flush_effects();
1053 result
1054 }
1055
1056 fn handle_stream_item(&mut self, task_id: usize, output: Box<dyn Any>) -> bool {
1057 self.pending_flushes += 1;
1058
1059 let mut handler = self.stream_handlers.remove(&task_id).unwrap();
1060 let halt = match &mut handler {
1061 StreamHandler::Model {
1062 model_id,
1063 item_callback,
1064 ..
1065 } => {
1066 if let Some(mut model) = self.ctx.models.remove(&model_id) {
1067 let halt = item_callback(model.as_any_mut(), output, self, *model_id);
1068 self.ctx.models.insert(*model_id, model);
1069 self.stream_handlers.insert(task_id, handler);
1070 halt
1071 } else {
1072 true
1073 }
1074 }
1075 StreamHandler::View {
1076 window_id,
1077 view_id,
1078 item_callback,
1079 ..
1080 } => {
1081 if let Some(mut view) = self
1082 .ctx
1083 .windows
1084 .get_mut(&window_id)
1085 .and_then(|w| w.views.remove(&view_id))
1086 {
1087 let halt = item_callback(view.as_mut(), output, self, *window_id, *view_id);
1088 self.ctx
1089 .windows
1090 .get_mut(&window_id)
1091 .unwrap()
1092 .views
1093 .insert(*view_id, view);
1094 self.stream_handlers.insert(task_id, handler);
1095 halt
1096 } else {
1097 true
1098 }
1099 }
1100 };
1101
1102 self.flush_effects();
1103 halt
1104 }
1105
1106 fn stream_completed(&mut self, task_id: usize) -> Option<Box<dyn Any>> {
1107 let result = match self.stream_handlers.remove(&task_id).unwrap() {
1108 StreamHandler::Model {
1109 model_id,
1110 done_callback,
1111 ..
1112 } => {
1113 if let Some(mut model) = self.ctx.models.remove(&model_id) {
1114 let result = done_callback(model.as_any_mut(), self, model_id);
1115 self.ctx.models.insert(model_id, model);
1116 Some(result)
1117 } else {
1118 None
1119 }
1120 }
1121 StreamHandler::View {
1122 window_id,
1123 view_id,
1124 done_callback,
1125 ..
1126 } => {
1127 if let Some(mut view) = self
1128 .ctx
1129 .windows
1130 .get_mut(&window_id)
1131 .and_then(|w| w.views.remove(&view_id))
1132 {
1133 let result = done_callback(view.as_mut(), self, window_id, view_id);
1134 self.ctx
1135 .windows
1136 .get_mut(&window_id)
1137 .unwrap()
1138 .views
1139 .insert(view_id, view);
1140 Some(result)
1141 } else {
1142 None
1143 }
1144 }
1145 };
1146 self.task_done(task_id);
1147 result
1148 }
1149
1150 fn task_done(&self, task_id: usize) {
1151 let task_done = self.task_done.0.clone();
1152 self.foreground
1153 .spawn(async move {
1154 let _ = task_done.send(task_id).await;
1155 })
1156 .detach()
1157 }
1158
1159 pub fn finish_pending_tasks(&self) -> impl Future<Output = ()> {
1160 let mut pending_tasks = self.future_handlers.keys().cloned().collect::<HashSet<_>>();
1161 let task_done = self.task_done.1.clone();
1162
1163 async move {
1164 while !pending_tasks.is_empty() {
1165 if let Ok(task_id) = task_done.recv().await {
1166 pending_tasks.remove(&task_id);
1167 } else {
1168 break;
1169 }
1170 }
1171 }
1172 }
1173}
1174
1175impl ModelAsRef for MutableAppContext {
1176 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1177 if let Some(model) = self.ctx.models.get(&handle.model_id) {
1178 model
1179 .as_any()
1180 .downcast_ref()
1181 .expect("Downcast is type safe")
1182 } else {
1183 panic!("Circular model reference");
1184 }
1185 }
1186}
1187
1188impl UpdateModel for MutableAppContext {
1189 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
1190 where
1191 T: Entity,
1192 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1193 {
1194 if let Some(mut model) = self.ctx.models.remove(&handle.model_id) {
1195 self.pending_flushes += 1;
1196 let mut ctx = ModelContext::new(self, handle.model_id);
1197 let result = update(
1198 model
1199 .as_any_mut()
1200 .downcast_mut()
1201 .expect("Downcast is type safe"),
1202 &mut ctx,
1203 );
1204 self.ctx.models.insert(handle.model_id, model);
1205 self.flush_effects();
1206 result
1207 } else {
1208 panic!("Circular model update");
1209 }
1210 }
1211}
1212
1213impl ViewAsRef for MutableAppContext {
1214 fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
1215 if let Some(window) = self.ctx.windows.get(&handle.window_id) {
1216 if let Some(view) = window.views.get(&handle.view_id) {
1217 view.as_any().downcast_ref().expect("Downcast is type safe")
1218 } else {
1219 panic!("Circular view reference");
1220 }
1221 } else {
1222 panic!("Window does not exist");
1223 }
1224 }
1225}
1226
1227impl UpdateView for MutableAppContext {
1228 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
1229 where
1230 T: View,
1231 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
1232 {
1233 self.pending_flushes += 1;
1234 let mut view = if let Some(window) = self.ctx.windows.get_mut(&handle.window_id) {
1235 if let Some(view) = window.views.remove(&handle.view_id) {
1236 view
1237 } else {
1238 panic!("Circular view update");
1239 }
1240 } else {
1241 panic!("Window does not exist");
1242 };
1243
1244 let mut ctx = ViewContext::new(self, handle.window_id, handle.view_id);
1245 let result = update(
1246 view.as_any_mut()
1247 .downcast_mut()
1248 .expect("Downcast is type safe"),
1249 &mut ctx,
1250 );
1251 self.ctx
1252 .windows
1253 .get_mut(&handle.window_id)
1254 .unwrap()
1255 .views
1256 .insert(handle.view_id, view);
1257 self.flush_effects();
1258 result
1259 }
1260}
1261
1262pub struct AppContext {
1263 models: HashMap<usize, Box<dyn AnyModel>>,
1264 windows: HashMap<usize, Window>,
1265 ref_counts: Arc<Mutex<RefCounts>>,
1266}
1267
1268impl AppContext {
1269 pub fn root_view_id(&self, window_id: usize) -> Option<usize> {
1270 self.windows
1271 .get(&window_id)
1272 .and_then(|window| window.root_view.as_ref().map(|v| v.id()))
1273 }
1274
1275 pub fn focused_view_id(&self, window_id: usize) -> Option<usize> {
1276 self.windows
1277 .get(&window_id)
1278 .and_then(|window| window.focused_view)
1279 }
1280
1281 pub fn render_view(&self, window_id: usize, view_id: usize) -> Result<ElementBox> {
1282 self.windows
1283 .get(&window_id)
1284 .and_then(|w| w.views.get(&view_id))
1285 .map(|v| v.render(self))
1286 .ok_or(anyhow!("view not found"))
1287 }
1288
1289 pub fn render_views(&self, window_id: usize) -> Result<HashMap<usize, ElementBox>> {
1290 self.windows
1291 .get(&window_id)
1292 .map(|w| {
1293 w.views
1294 .iter()
1295 .map(|(id, view)| (*id, view.render(self)))
1296 .collect::<HashMap<_, ElementBox>>()
1297 })
1298 .ok_or(anyhow!("window not found"))
1299 }
1300}
1301
1302impl ModelAsRef for AppContext {
1303 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1304 if let Some(model) = self.models.get(&handle.model_id) {
1305 model
1306 .as_any()
1307 .downcast_ref()
1308 .expect("downcast should be type safe")
1309 } else {
1310 panic!("circular model reference");
1311 }
1312 }
1313}
1314
1315impl ViewAsRef for AppContext {
1316 fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
1317 if let Some(window) = self.windows.get(&handle.window_id) {
1318 if let Some(view) = window.views.get(&handle.view_id) {
1319 view.as_any()
1320 .downcast_ref()
1321 .expect("downcast should be type safe")
1322 } else {
1323 panic!("circular view reference");
1324 }
1325 } else {
1326 panic!("window does not exist");
1327 }
1328 }
1329}
1330
1331#[derive(Default)]
1332struct Window {
1333 views: HashMap<usize, Box<dyn AnyView>>,
1334 root_view: Option<AnyViewHandle>,
1335 focused_view: Option<usize>,
1336}
1337
1338#[derive(Default, Clone)]
1339pub struct WindowInvalidation {
1340 pub updated: HashSet<usize>,
1341 pub removed: Vec<usize>,
1342}
1343
1344pub enum Effect {
1345 Event {
1346 entity_id: usize,
1347 payload: Box<dyn Any>,
1348 },
1349 ModelNotification {
1350 model_id: usize,
1351 },
1352 ViewNotification {
1353 window_id: usize,
1354 view_id: usize,
1355 },
1356 Focus {
1357 window_id: usize,
1358 view_id: usize,
1359 },
1360}
1361
1362pub trait AnyModel: Send + Sync {
1363 fn as_any(&self) -> &dyn Any;
1364 fn as_any_mut(&mut self) -> &mut dyn Any;
1365}
1366
1367impl<T> AnyModel for T
1368where
1369 T: Entity,
1370{
1371 fn as_any(&self) -> &dyn Any {
1372 self
1373 }
1374
1375 fn as_any_mut(&mut self) -> &mut dyn Any {
1376 self
1377 }
1378}
1379
1380pub trait AnyView: Send + Sync {
1381 fn as_any(&self) -> &dyn Any;
1382 fn as_any_mut(&mut self) -> &mut dyn Any;
1383 fn ui_name(&self) -> &'static str;
1384 fn render<'a>(&self, app: &AppContext) -> ElementBox;
1385 fn on_focus(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize);
1386 fn on_blur(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize);
1387 fn keymap_context(&self, app: &AppContext) -> keymap::Context;
1388}
1389
1390impl<T> AnyView for T
1391where
1392 T: View,
1393{
1394 fn as_any(&self) -> &dyn Any {
1395 self
1396 }
1397
1398 fn as_any_mut(&mut self) -> &mut dyn Any {
1399 self
1400 }
1401
1402 fn ui_name(&self) -> &'static str {
1403 T::ui_name()
1404 }
1405
1406 fn render<'a>(&self, app: &AppContext) -> ElementBox {
1407 View::render(self, app)
1408 }
1409
1410 fn on_focus(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize) {
1411 let mut ctx = ViewContext::new(app, window_id, view_id);
1412 View::on_focus(self, &mut ctx);
1413 }
1414
1415 fn on_blur(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize) {
1416 let mut ctx = ViewContext::new(app, window_id, view_id);
1417 View::on_blur(self, &mut ctx);
1418 }
1419
1420 fn keymap_context(&self, app: &AppContext) -> keymap::Context {
1421 View::keymap_context(self, app)
1422 }
1423}
1424
1425pub struct ModelContext<'a, T: ?Sized> {
1426 app: &'a mut MutableAppContext,
1427 model_id: usize,
1428 model_type: PhantomData<T>,
1429 halt_stream: bool,
1430}
1431
1432impl<'a, T: Entity> ModelContext<'a, T> {
1433 fn new(app: &'a mut MutableAppContext, model_id: usize) -> Self {
1434 Self {
1435 app,
1436 model_id,
1437 model_type: PhantomData,
1438 halt_stream: false,
1439 }
1440 }
1441
1442 pub fn app(&self) -> &AppContext {
1443 &self.app.ctx
1444 }
1445
1446 pub fn app_mut(&mut self) -> &mut MutableAppContext {
1447 self.app
1448 }
1449
1450 pub fn background_executor(&self) -> &Arc<executor::Background> {
1451 &self.app.background
1452 }
1453
1454 pub fn halt_stream(&mut self) {
1455 self.halt_stream = true;
1456 }
1457
1458 pub fn model_id(&self) -> usize {
1459 self.model_id
1460 }
1461
1462 pub fn add_model<S, F>(&mut self, build_model: F) -> ModelHandle<S>
1463 where
1464 S: Entity,
1465 F: FnOnce(&mut ModelContext<S>) -> S,
1466 {
1467 self.app.add_model(build_model)
1468 }
1469
1470 pub fn subscribe<S: Entity, F>(&mut self, handle: &ModelHandle<S>, mut callback: F)
1471 where
1472 S::Event: 'static,
1473 F: 'static + FnMut(&mut T, &S::Event, &mut ModelContext<T>),
1474 {
1475 self.app
1476 .subscriptions
1477 .entry(handle.model_id)
1478 .or_default()
1479 .push(Subscription::FromModel {
1480 model_id: self.model_id,
1481 callback: Box::new(move |model, payload, app, model_id| {
1482 let model = model.downcast_mut().expect("downcast is type safe");
1483 let payload = payload.downcast_ref().expect("downcast is type safe");
1484 let mut ctx = ModelContext::new(app, model_id);
1485 callback(model, payload, &mut ctx);
1486 }),
1487 });
1488 }
1489
1490 pub fn emit(&mut self, payload: T::Event) {
1491 self.app.pending_effects.push_back(Effect::Event {
1492 entity_id: self.model_id,
1493 payload: Box::new(payload),
1494 });
1495 }
1496
1497 pub fn observe<S, F>(&mut self, handle: &ModelHandle<S>, mut callback: F)
1498 where
1499 S: Entity,
1500 F: 'static + FnMut(&mut T, ModelHandle<S>, &mut ModelContext<T>),
1501 {
1502 self.app
1503 .observations
1504 .entry(handle.model_id)
1505 .or_default()
1506 .push(Observation::FromModel {
1507 model_id: self.model_id,
1508 callback: Box::new(move |model, observed_id, app, model_id| {
1509 let model = model.downcast_mut().expect("downcast is type safe");
1510 let observed = ModelHandle::new(observed_id, &app.ctx.ref_counts);
1511 let mut ctx = ModelContext::new(app, model_id);
1512 callback(model, observed, &mut ctx);
1513 }),
1514 });
1515 }
1516
1517 pub fn notify(&mut self) {
1518 self.app
1519 .pending_effects
1520 .push_back(Effect::ModelNotification {
1521 model_id: self.model_id,
1522 });
1523 }
1524
1525 pub fn spawn<S, F, U>(&mut self, future: S, callback: F) -> ForegroundTask<Option<U>>
1526 where
1527 S: 'static + Future,
1528 F: 'static + FnOnce(&mut T, S::Output, &mut ModelContext<T>) -> U,
1529 U: 'static,
1530 {
1531 let (task_id, task) = self.app.spawn::<S, U>(future);
1532
1533 self.app.future_handlers.insert(
1534 task_id,
1535 FutureHandler::Model {
1536 model_id: self.model_id,
1537 callback: Box::new(move |model, output, app, model_id| {
1538 let model = model.downcast_mut().unwrap();
1539 let output = *output.downcast().unwrap();
1540 Box::new(callback(
1541 model,
1542 output,
1543 &mut ModelContext::new(app, model_id),
1544 ))
1545 }),
1546 },
1547 );
1548
1549 task
1550 }
1551
1552 pub fn spawn_stream<S, F, G, U>(
1553 &mut self,
1554 stream: S,
1555 mut item_callback: F,
1556 done_callback: G,
1557 ) -> ForegroundTask<Option<U>>
1558 where
1559 S: 'static + Stream + Unpin,
1560 F: 'static + FnMut(&mut T, S::Item, &mut ModelContext<T>),
1561 G: 'static + FnOnce(&mut T, &mut ModelContext<T>) -> U,
1562 U: 'static + Any,
1563 {
1564 let (task_id, task) = self.app.spawn_stream(stream);
1565 self.app.stream_handlers.insert(
1566 task_id,
1567 StreamHandler::Model {
1568 model_id: self.model_id,
1569 item_callback: Box::new(move |model, output, app, model_id| {
1570 let model = model.downcast_mut().unwrap();
1571 let output = *output.downcast().unwrap();
1572 let mut ctx = ModelContext::new(app, model_id);
1573 item_callback(model, output, &mut ctx);
1574 ctx.halt_stream
1575 }),
1576 done_callback: Box::new(
1577 move |model: &mut dyn Any, app: &mut MutableAppContext, model_id| {
1578 let model = model.downcast_mut().unwrap();
1579 let mut ctx = ModelContext::new(app, model_id);
1580 Box::new(done_callback(model, &mut ctx))
1581 },
1582 ),
1583 },
1584 );
1585
1586 task
1587 }
1588}
1589
1590impl<M> ModelAsRef for ModelContext<'_, M> {
1591 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1592 self.app.model(handle)
1593 }
1594}
1595
1596impl<M> UpdateModel for ModelContext<'_, M> {
1597 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
1598 where
1599 T: Entity,
1600 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1601 {
1602 self.app.update_model(handle, update)
1603 }
1604}
1605
1606pub struct ViewContext<'a, T: ?Sized> {
1607 app: &'a mut MutableAppContext,
1608 window_id: usize,
1609 view_id: usize,
1610 view_type: PhantomData<T>,
1611 halt_action_dispatch: bool,
1612 halt_stream: bool,
1613}
1614
1615impl<'a, T: View> ViewContext<'a, T> {
1616 fn new(app: &'a mut MutableAppContext, window_id: usize, view_id: usize) -> Self {
1617 Self {
1618 app,
1619 window_id,
1620 view_id,
1621 view_type: PhantomData,
1622 halt_action_dispatch: true,
1623 halt_stream: false,
1624 }
1625 }
1626
1627 pub fn handle(&self) -> WeakViewHandle<T> {
1628 WeakViewHandle::new(self.window_id, self.view_id)
1629 }
1630
1631 pub fn window_id(&self) -> usize {
1632 self.window_id
1633 }
1634
1635 pub fn app(&self) -> &AppContext {
1636 &self.app.ctx
1637 }
1638
1639 pub fn app_mut(&mut self) -> &mut MutableAppContext {
1640 self.app
1641 }
1642
1643 pub fn background_executor(&self) -> &Arc<executor::Background> {
1644 &self.app.background
1645 }
1646
1647 pub fn focus<S>(&mut self, handle: S)
1648 where
1649 S: Into<AnyViewHandle>,
1650 {
1651 let handle = handle.into();
1652 self.app.pending_effects.push_back(Effect::Focus {
1653 window_id: handle.window_id,
1654 view_id: handle.view_id,
1655 });
1656 }
1657
1658 pub fn focus_self(&mut self) {
1659 self.app.pending_effects.push_back(Effect::Focus {
1660 window_id: self.window_id,
1661 view_id: self.view_id,
1662 });
1663 }
1664
1665 pub fn add_model<S, F>(&mut self, build_model: F) -> ModelHandle<S>
1666 where
1667 S: Entity,
1668 F: FnOnce(&mut ModelContext<S>) -> S,
1669 {
1670 self.app.add_model(build_model)
1671 }
1672
1673 pub fn add_view<S, F>(&mut self, build_view: F) -> ViewHandle<S>
1674 where
1675 S: View,
1676 F: FnOnce(&mut ViewContext<S>) -> S,
1677 {
1678 self.app.add_view(self.window_id, build_view)
1679 }
1680
1681 pub fn add_option_view<S, F>(&mut self, build_view: F) -> Option<ViewHandle<S>>
1682 where
1683 S: View,
1684 F: FnOnce(&mut ViewContext<S>) -> Option<S>,
1685 {
1686 self.app.add_option_view(self.window_id, build_view)
1687 }
1688
1689 pub fn subscribe_to_model<E, F>(&mut self, handle: &ModelHandle<E>, mut callback: F)
1690 where
1691 E: Entity,
1692 E::Event: 'static,
1693 F: 'static + FnMut(&mut T, ModelHandle<E>, &E::Event, &mut ViewContext<T>),
1694 {
1695 let emitter_handle = handle.downgrade();
1696 self.app
1697 .subscriptions
1698 .entry(handle.id())
1699 .or_default()
1700 .push(Subscription::FromView {
1701 window_id: self.window_id,
1702 view_id: self.view_id,
1703 callback: Box::new(move |view, payload, app, window_id, view_id| {
1704 if let Some(emitter_handle) = emitter_handle.upgrade(app.downgrade()) {
1705 let model = view.downcast_mut().expect("downcast is type safe");
1706 let payload = payload.downcast_ref().expect("downcast is type safe");
1707 let mut ctx = ViewContext::new(app, window_id, view_id);
1708 callback(model, emitter_handle, payload, &mut ctx);
1709 }
1710 }),
1711 });
1712 }
1713
1714 pub fn subscribe_to_view<V, F>(&mut self, handle: &ViewHandle<V>, mut callback: F)
1715 where
1716 V: View,
1717 V::Event: 'static,
1718 F: 'static + FnMut(&mut T, ViewHandle<V>, &V::Event, &mut ViewContext<T>),
1719 {
1720 let emitter_handle = handle.downgrade();
1721
1722 self.app
1723 .subscriptions
1724 .entry(handle.id())
1725 .or_default()
1726 .push(Subscription::FromView {
1727 window_id: self.window_id,
1728 view_id: self.view_id,
1729 callback: Box::new(move |view, payload, app, window_id, view_id| {
1730 if let Some(emitter_handle) = emitter_handle.upgrade(app.downgrade()) {
1731 let model = view.downcast_mut().expect("downcast is type safe");
1732 let payload = payload.downcast_ref().expect("downcast is type safe");
1733 let mut ctx = ViewContext::new(app, window_id, view_id);
1734 callback(model, emitter_handle, payload, &mut ctx);
1735 }
1736 }),
1737 });
1738 }
1739
1740 pub fn emit(&mut self, payload: T::Event) {
1741 self.app.pending_effects.push_back(Effect::Event {
1742 entity_id: self.view_id,
1743 payload: Box::new(payload),
1744 });
1745 }
1746
1747 pub fn observe<S, F>(&mut self, handle: &ModelHandle<S>, mut callback: F)
1748 where
1749 S: Entity,
1750 F: 'static + FnMut(&mut T, ModelHandle<S>, &mut ViewContext<T>),
1751 {
1752 self.app
1753 .observations
1754 .entry(handle.id())
1755 .or_default()
1756 .push(Observation::FromView {
1757 window_id: self.window_id,
1758 view_id: self.view_id,
1759 callback: Box::new(move |view, observed_id, app, window_id, view_id| {
1760 let view = view.downcast_mut().expect("downcast is type safe");
1761 let observed = ModelHandle::new(observed_id, &app.ctx.ref_counts);
1762 let mut ctx = ViewContext::new(app, window_id, view_id);
1763 callback(view, observed, &mut ctx);
1764 }),
1765 });
1766 }
1767
1768 pub fn notify(&mut self) {
1769 self.app
1770 .pending_effects
1771 .push_back(Effect::ViewNotification {
1772 window_id: self.window_id,
1773 view_id: self.view_id,
1774 });
1775 }
1776
1777 pub fn propagate_action(&mut self) {
1778 self.halt_action_dispatch = false;
1779 }
1780
1781 pub fn halt_stream(&mut self) {
1782 self.halt_stream = true;
1783 }
1784
1785 pub fn spawn<S, F, U>(&mut self, future: S, callback: F) -> ForegroundTask<Option<U>>
1786 where
1787 S: 'static + Future,
1788 F: 'static + FnOnce(&mut T, S::Output, &mut ViewContext<T>) -> U,
1789 U: 'static,
1790 {
1791 let (task_id, task) = self.app.spawn(future);
1792
1793 self.app.future_handlers.insert(
1794 task_id,
1795 FutureHandler::View {
1796 window_id: self.window_id,
1797 view_id: self.view_id,
1798 callback: Box::new(move |view, output, app, window_id, view_id| {
1799 let view = view.as_any_mut().downcast_mut().unwrap();
1800 let output = *output.downcast().unwrap();
1801 Box::new(callback(
1802 view,
1803 output,
1804 &mut ViewContext::new(app, window_id, view_id),
1805 ))
1806 }),
1807 },
1808 );
1809
1810 task
1811 }
1812
1813 pub fn spawn_stream<S, F, G, U>(
1814 &mut self,
1815 stream: S,
1816 mut item_callback: F,
1817 done_callback: G,
1818 ) -> ForegroundTask<Option<U>>
1819 where
1820 S: 'static + Stream + Unpin,
1821 F: 'static + FnMut(&mut T, S::Item, &mut ViewContext<T>),
1822 G: 'static + FnOnce(&mut T, &mut ViewContext<T>) -> U,
1823 U: 'static + Any,
1824 {
1825 let (task_id, task) = self.app.spawn_stream(stream);
1826 self.app.stream_handlers.insert(
1827 task_id,
1828 StreamHandler::View {
1829 window_id: self.window_id,
1830 view_id: self.view_id,
1831 item_callback: Box::new(move |view, output, app, window_id, view_id| {
1832 let view = view.as_any_mut().downcast_mut().unwrap();
1833 let output = *output.downcast().unwrap();
1834 let mut ctx = ViewContext::new(app, window_id, view_id);
1835 item_callback(view, output, &mut ctx);
1836 ctx.halt_stream
1837 }),
1838 done_callback: Box::new(move |view, app, window_id, view_id| {
1839 let view = view.as_any_mut().downcast_mut().unwrap();
1840 let mut ctx = ViewContext::new(app, window_id, view_id);
1841 Box::new(done_callback(view, &mut ctx))
1842 }),
1843 },
1844 );
1845 task
1846 }
1847}
1848
1849impl<V> ModelAsRef for ViewContext<'_, V> {
1850 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1851 self.app.model(handle)
1852 }
1853}
1854
1855impl<V: View> UpdateModel for ViewContext<'_, V> {
1856 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
1857 where
1858 T: Entity,
1859 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1860 {
1861 self.app.update_model(handle, update)
1862 }
1863}
1864
1865impl<V: View> ViewAsRef for ViewContext<'_, V> {
1866 fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
1867 self.app.view(handle)
1868 }
1869}
1870
1871impl<V: View> UpdateView for ViewContext<'_, V> {
1872 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
1873 where
1874 T: View,
1875 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
1876 {
1877 self.app.update_view(handle, update)
1878 }
1879}
1880
1881pub trait Handle<T> {
1882 fn id(&self) -> usize;
1883 fn location(&self) -> EntityLocation;
1884}
1885
1886#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
1887pub enum EntityLocation {
1888 Model(usize),
1889 View(usize, usize),
1890}
1891
1892pub struct ModelHandle<T> {
1893 model_id: usize,
1894 model_type: PhantomData<T>,
1895 ref_counts: Weak<Mutex<RefCounts>>,
1896}
1897
1898impl<T: Entity> ModelHandle<T> {
1899 fn new(model_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
1900 ref_counts.lock().inc(model_id);
1901 Self {
1902 model_id,
1903 model_type: PhantomData,
1904 ref_counts: Arc::downgrade(ref_counts),
1905 }
1906 }
1907
1908 fn downgrade(&self) -> WeakModelHandle<T> {
1909 WeakModelHandle::new(self.model_id)
1910 }
1911
1912 pub fn id(&self) -> usize {
1913 self.model_id
1914 }
1915
1916 pub fn as_ref<'a, A: ModelAsRef>(&self, app: &'a A) -> &'a T {
1917 app.model(self)
1918 }
1919
1920 pub fn read<'a, S, F>(&self, app: &'a App, read: F) -> S
1921 where
1922 F: FnOnce(&T, &AppContext) -> S,
1923 {
1924 app.read_model(self, read)
1925 }
1926
1927 pub fn update<A, F, S>(&self, app: &mut A, update: F) -> S
1928 where
1929 A: UpdateModel,
1930 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1931 {
1932 app.update_model(self, update)
1933 }
1934}
1935
1936impl<T> Clone for ModelHandle<T> {
1937 fn clone(&self) -> Self {
1938 if let Some(ref_counts) = self.ref_counts.upgrade() {
1939 ref_counts.lock().inc(self.model_id);
1940 }
1941
1942 Self {
1943 model_id: self.model_id,
1944 model_type: PhantomData,
1945 ref_counts: self.ref_counts.clone(),
1946 }
1947 }
1948}
1949
1950impl<T> PartialEq for ModelHandle<T> {
1951 fn eq(&self, other: &Self) -> bool {
1952 self.model_id == other.model_id
1953 }
1954}
1955
1956impl<T> Eq for ModelHandle<T> {}
1957
1958impl<T> Hash for ModelHandle<T> {
1959 fn hash<H: Hasher>(&self, state: &mut H) {
1960 self.model_id.hash(state);
1961 }
1962}
1963
1964impl<T> std::borrow::Borrow<usize> for ModelHandle<T> {
1965 fn borrow(&self) -> &usize {
1966 &self.model_id
1967 }
1968}
1969
1970impl<T> Debug for ModelHandle<T> {
1971 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1972 f.debug_tuple(&format!("ModelHandle<{}>", type_name::<T>()))
1973 .field(&self.model_id)
1974 .finish()
1975 }
1976}
1977
1978unsafe impl<T> Send for ModelHandle<T> {}
1979unsafe impl<T> Sync for ModelHandle<T> {}
1980
1981impl<T> Drop for ModelHandle<T> {
1982 fn drop(&mut self) {
1983 if let Some(ref_counts) = self.ref_counts.upgrade() {
1984 ref_counts.lock().dec_model(self.model_id);
1985 }
1986 }
1987}
1988
1989impl<T> Handle<T> for ModelHandle<T> {
1990 fn id(&self) -> usize {
1991 self.model_id
1992 }
1993
1994 fn location(&self) -> EntityLocation {
1995 EntityLocation::Model(self.model_id)
1996 }
1997}
1998
1999pub struct WeakModelHandle<T> {
2000 model_id: usize,
2001 model_type: PhantomData<T>,
2002}
2003
2004impl<T: Entity> WeakModelHandle<T> {
2005 fn new(model_id: usize) -> Self {
2006 Self {
2007 model_id,
2008 model_type: PhantomData,
2009 }
2010 }
2011
2012 pub fn upgrade(&self, app: &AppContext) -> Option<ModelHandle<T>> {
2013 if app.models.contains_key(&self.model_id) {
2014 Some(ModelHandle::new(self.model_id, &app.ref_counts))
2015 } else {
2016 None
2017 }
2018 }
2019}
2020
2021pub struct ViewHandle<T> {
2022 window_id: usize,
2023 view_id: usize,
2024 view_type: PhantomData<T>,
2025 ref_counts: Weak<Mutex<RefCounts>>,
2026}
2027
2028impl<T: View> ViewHandle<T> {
2029 fn new(window_id: usize, view_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
2030 ref_counts.lock().inc(view_id);
2031 Self {
2032 window_id,
2033 view_id,
2034 view_type: PhantomData,
2035 ref_counts: Arc::downgrade(ref_counts),
2036 }
2037 }
2038
2039 fn downgrade(&self) -> WeakViewHandle<T> {
2040 WeakViewHandle::new(self.window_id, self.view_id)
2041 }
2042
2043 pub fn window_id(&self) -> usize {
2044 self.window_id
2045 }
2046
2047 pub fn id(&self) -> usize {
2048 self.view_id
2049 }
2050
2051 pub fn as_ref<'a, A: ViewAsRef>(&self, app: &'a A) -> &'a T {
2052 app.view(self)
2053 }
2054
2055 pub fn read<'a, F, S>(&self, app: &'a App, read: F) -> S
2056 where
2057 F: FnOnce(&T, &AppContext) -> S,
2058 {
2059 app.read_view(self, read)
2060 }
2061
2062 pub fn update<A, F, S>(&self, app: &mut A, update: F) -> S
2063 where
2064 A: UpdateView,
2065 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
2066 {
2067 app.update_view(self, update)
2068 }
2069
2070 pub fn is_focused(&self, app: &AppContext) -> bool {
2071 app.focused_view_id(self.window_id)
2072 .map_or(false, |focused_id| focused_id == self.view_id)
2073 }
2074}
2075
2076impl<T> Clone for ViewHandle<T> {
2077 fn clone(&self) -> Self {
2078 if let Some(ref_counts) = self.ref_counts.upgrade() {
2079 ref_counts.lock().inc(self.view_id);
2080 }
2081
2082 Self {
2083 window_id: self.window_id,
2084 view_id: self.view_id,
2085 view_type: PhantomData,
2086 ref_counts: self.ref_counts.clone(),
2087 }
2088 }
2089}
2090
2091impl<T> PartialEq for ViewHandle<T> {
2092 fn eq(&self, other: &Self) -> bool {
2093 self.window_id == other.window_id && self.view_id == other.view_id
2094 }
2095}
2096
2097impl<T> Eq for ViewHandle<T> {}
2098
2099impl<T> Debug for ViewHandle<T> {
2100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2101 f.debug_struct(&format!("ViewHandle<{}>", type_name::<T>()))
2102 .field("window_id", &self.window_id)
2103 .field("view_id", &self.view_id)
2104 .finish()
2105 }
2106}
2107
2108impl<T> Drop for ViewHandle<T> {
2109 fn drop(&mut self) {
2110 if let Some(ref_counts) = self.ref_counts.upgrade() {
2111 ref_counts.lock().dec_view(self.window_id, self.view_id);
2112 }
2113 }
2114}
2115
2116impl<T> Handle<T> for ViewHandle<T> {
2117 fn id(&self) -> usize {
2118 self.view_id
2119 }
2120
2121 fn location(&self) -> EntityLocation {
2122 EntityLocation::View(self.window_id, self.view_id)
2123 }
2124}
2125
2126#[derive(Clone)]
2127pub struct AnyViewHandle {
2128 window_id: usize,
2129 view_id: usize,
2130 view_type: TypeId,
2131 ref_counts: Weak<Mutex<RefCounts>>,
2132}
2133
2134impl AnyViewHandle {
2135 pub fn id(&self) -> usize {
2136 self.view_id
2137 }
2138
2139 pub fn is<T: 'static>(&self) -> bool {
2140 TypeId::of::<T>() == self.view_type
2141 }
2142
2143 pub fn downcast<T: View>(self) -> Option<ViewHandle<T>> {
2144 if self.is::<T>() {
2145 if let Some(ref_counts) = self.ref_counts.upgrade() {
2146 return Some(ViewHandle::new(self.window_id, self.view_id, &ref_counts));
2147 }
2148 }
2149 None
2150 }
2151}
2152
2153impl<T: View> From<&ViewHandle<T>> for AnyViewHandle {
2154 fn from(handle: &ViewHandle<T>) -> Self {
2155 if let Some(ref_counts) = handle.ref_counts.upgrade() {
2156 ref_counts.lock().inc(handle.view_id);
2157 }
2158 AnyViewHandle {
2159 window_id: handle.window_id,
2160 view_id: handle.view_id,
2161 view_type: TypeId::of::<T>(),
2162 ref_counts: handle.ref_counts.clone(),
2163 }
2164 }
2165}
2166
2167impl<T: View> From<ViewHandle<T>> for AnyViewHandle {
2168 fn from(handle: ViewHandle<T>) -> Self {
2169 (&handle).into()
2170 }
2171}
2172
2173pub struct WeakViewHandle<T> {
2174 window_id: usize,
2175 view_id: usize,
2176 view_type: PhantomData<T>,
2177}
2178
2179impl<T: View> WeakViewHandle<T> {
2180 fn new(window_id: usize, view_id: usize) -> Self {
2181 Self {
2182 window_id,
2183 view_id,
2184 view_type: PhantomData,
2185 }
2186 }
2187
2188 pub fn upgrade(&self, app: &AppContext) -> Option<ViewHandle<T>> {
2189 if app
2190 .windows
2191 .get(&self.window_id)
2192 .and_then(|w| w.views.get(&self.view_id))
2193 .is_some()
2194 {
2195 Some(ViewHandle::new(
2196 self.window_id,
2197 self.view_id,
2198 &app.ref_counts,
2199 ))
2200 } else {
2201 None
2202 }
2203 }
2204}
2205
2206impl<T> Clone for WeakViewHandle<T> {
2207 fn clone(&self) -> Self {
2208 Self {
2209 window_id: self.window_id,
2210 view_id: self.view_id,
2211 view_type: PhantomData,
2212 }
2213 }
2214}
2215
2216#[derive(Default)]
2217struct RefCounts {
2218 counts: HashMap<usize, usize>,
2219 dropped_models: HashSet<usize>,
2220 dropped_views: HashSet<(usize, usize)>,
2221}
2222
2223impl RefCounts {
2224 fn inc(&mut self, model_id: usize) {
2225 *self.counts.entry(model_id).or_insert(0) += 1;
2226 }
2227
2228 fn dec_model(&mut self, model_id: usize) {
2229 if let Some(count) = self.counts.get_mut(&model_id) {
2230 *count -= 1;
2231 if *count == 0 {
2232 self.counts.remove(&model_id);
2233 self.dropped_models.insert(model_id);
2234 }
2235 } else {
2236 panic!("Expected ref count to be positive")
2237 }
2238 }
2239
2240 fn dec_view(&mut self, window_id: usize, view_id: usize) {
2241 if let Some(count) = self.counts.get_mut(&view_id) {
2242 *count -= 1;
2243 if *count == 0 {
2244 self.counts.remove(&view_id);
2245 self.dropped_views.insert((window_id, view_id));
2246 }
2247 } else {
2248 panic!("Expected ref count to be positive")
2249 }
2250 }
2251
2252 fn take_dropped(&mut self) -> (HashSet<usize>, HashSet<(usize, usize)>) {
2253 let mut dropped_models = HashSet::new();
2254 let mut dropped_views = HashSet::new();
2255 std::mem::swap(&mut self.dropped_models, &mut dropped_models);
2256 std::mem::swap(&mut self.dropped_views, &mut dropped_views);
2257 (dropped_models, dropped_views)
2258 }
2259}
2260
2261enum Subscription {
2262 FromModel {
2263 model_id: usize,
2264 callback: Box<dyn FnMut(&mut dyn Any, &dyn Any, &mut MutableAppContext, usize)>,
2265 },
2266 FromView {
2267 window_id: usize,
2268 view_id: usize,
2269 callback: Box<dyn FnMut(&mut dyn Any, &dyn Any, &mut MutableAppContext, usize, usize)>,
2270 },
2271}
2272
2273enum Observation {
2274 FromModel {
2275 model_id: usize,
2276 callback: Box<dyn FnMut(&mut dyn Any, usize, &mut MutableAppContext, usize)>,
2277 },
2278 FromView {
2279 window_id: usize,
2280 view_id: usize,
2281 callback: Box<dyn FnMut(&mut dyn Any, usize, &mut MutableAppContext, usize, usize)>,
2282 },
2283}
2284
2285enum FutureHandler {
2286 Model {
2287 model_id: usize,
2288 callback: Box<
2289 dyn FnOnce(&mut dyn Any, Box<dyn Any>, &mut MutableAppContext, usize) -> Box<dyn Any>,
2290 >,
2291 },
2292 View {
2293 window_id: usize,
2294 view_id: usize,
2295 callback: Box<
2296 dyn FnOnce(
2297 &mut dyn AnyView,
2298 Box<dyn Any>,
2299 &mut MutableAppContext,
2300 usize,
2301 usize,
2302 ) -> Box<dyn Any>,
2303 >,
2304 },
2305}
2306
2307enum StreamHandler {
2308 Model {
2309 model_id: usize,
2310 item_callback:
2311 Box<dyn FnMut(&mut dyn Any, Box<dyn Any>, &mut MutableAppContext, usize) -> bool>,
2312 done_callback: Box<dyn FnOnce(&mut dyn Any, &mut MutableAppContext, usize) -> Box<dyn Any>>,
2313 },
2314 View {
2315 window_id: usize,
2316 view_id: usize,
2317 item_callback: Box<
2318 dyn FnMut(&mut dyn AnyView, Box<dyn Any>, &mut MutableAppContext, usize, usize) -> bool,
2319 >,
2320 done_callback:
2321 Box<dyn FnOnce(&mut dyn AnyView, &mut MutableAppContext, usize, usize) -> Box<dyn Any>>,
2322 },
2323}
2324
2325#[cfg(test)]
2326mod tests {
2327 use super::*;
2328 use crate::elements::*;
2329
2330 #[test]
2331 fn test_model_handles() {
2332 struct Model {
2333 other: Option<ModelHandle<Model>>,
2334 events: Vec<String>,
2335 }
2336
2337 impl Entity for Model {
2338 type Event = usize;
2339 }
2340
2341 impl Model {
2342 fn new(other: Option<ModelHandle<Self>>, ctx: &mut ModelContext<Self>) -> Self {
2343 if let Some(other) = other.as_ref() {
2344 ctx.observe(other, |me, _, _| {
2345 me.events.push("notified".into());
2346 });
2347 ctx.subscribe(other, |me, event, _| {
2348 me.events.push(format!("observed event {}", event));
2349 });
2350 }
2351
2352 Self {
2353 other,
2354 events: Vec::new(),
2355 }
2356 }
2357 }
2358
2359 App::test((), |mut app| async move {
2360 let app = &mut app;
2361
2362 let handle_1 = app.add_model(|ctx| Model::new(None, ctx));
2363 let handle_2 = app.add_model(|ctx| Model::new(Some(handle_1.clone()), ctx));
2364 assert_eq!(app.0.borrow().ctx.models.len(), 2);
2365
2366 handle_1.update(app, |model, ctx| {
2367 model.events.push("updated".into());
2368 ctx.emit(1);
2369 ctx.notify();
2370 ctx.emit(2);
2371 });
2372 handle_1.read(app, |model, _| {
2373 assert_eq!(model.events, vec!["updated".to_string()]);
2374 });
2375 handle_2.read(app, |model, _| {
2376 assert_eq!(
2377 model.events,
2378 vec![
2379 "observed event 1".to_string(),
2380 "notified".to_string(),
2381 "observed event 2".to_string(),
2382 ]
2383 );
2384 });
2385
2386 handle_2.update(app, |model, _| {
2387 drop(handle_1);
2388 model.other.take();
2389 });
2390
2391 let app_state = app.0.borrow();
2392 assert_eq!(app_state.ctx.models.len(), 1);
2393 assert!(app_state.subscriptions.is_empty());
2394 assert!(app_state.observations.is_empty());
2395 })
2396 }
2397
2398 #[test]
2399 fn test_subscribe_and_emit_from_model() {
2400 #[derive(Default)]
2401 struct Model {
2402 events: Vec<usize>,
2403 }
2404
2405 impl Entity for Model {
2406 type Event = usize;
2407 }
2408
2409 App::test((), |mut app| async move {
2410 let app = &mut app;
2411 let handle_1 = app.add_model(|_| Model::default());
2412 let handle_2 = app.add_model(|_| Model::default());
2413 let handle_2b = handle_2.clone();
2414
2415 handle_1.update(app, |_, c| {
2416 c.subscribe(&handle_2, move |model: &mut Model, event, c| {
2417 model.events.push(*event);
2418
2419 c.subscribe(&handle_2b, |model, event, _| {
2420 model.events.push(*event * 2);
2421 });
2422 });
2423 });
2424
2425 handle_2.update(app, |_, c| c.emit(7));
2426 handle_1.read(app, |model, _| assert_eq!(model.events, vec![7]));
2427
2428 handle_2.update(app, |_, c| c.emit(5));
2429 handle_1.read(app, |model, _| assert_eq!(model.events, vec![7, 10, 5]));
2430 })
2431 }
2432
2433 #[test]
2434 fn test_observe_and_notify_from_model() {
2435 #[derive(Default)]
2436 struct Model {
2437 count: usize,
2438 events: Vec<usize>,
2439 }
2440
2441 impl Entity for Model {
2442 type Event = ();
2443 }
2444
2445 App::test((), |mut app| async move {
2446 let app = &mut app;
2447 let handle_1 = app.add_model(|_| Model::default());
2448 let handle_2 = app.add_model(|_| Model::default());
2449 let handle_2b = handle_2.clone();
2450
2451 handle_1.update(app, |_, c| {
2452 c.observe(&handle_2, move |model, observed, c| {
2453 model.events.push(observed.as_ref(c).count);
2454 c.observe(&handle_2b, |model, observed, c| {
2455 model.events.push(observed.as_ref(c).count * 2);
2456 });
2457 });
2458 });
2459
2460 handle_2.update(app, |model, c| {
2461 model.count = 7;
2462 c.notify()
2463 });
2464 handle_1.read(app, |model, _| assert_eq!(model.events, vec![7]));
2465
2466 handle_2.update(app, |model, c| {
2467 model.count = 5;
2468 c.notify()
2469 });
2470 handle_1.read(app, |model, _| assert_eq!(model.events, vec![7, 10, 5]))
2471 })
2472 }
2473
2474 #[test]
2475 fn test_spawn_from_model() {
2476 #[derive(Default)]
2477 struct Model {
2478 count: usize,
2479 }
2480
2481 impl Entity for Model {
2482 type Event = ();
2483 }
2484
2485 App::test((), |mut app| async move {
2486 let handle = app.add_model(|_| Model::default());
2487 handle
2488 .update(&mut app, |_, c| {
2489 c.spawn(async { 7 }, |model, output, _| {
2490 model.count = output;
2491 })
2492 })
2493 .await;
2494 handle.read(&app, |model, _| assert_eq!(model.count, 7));
2495
2496 handle
2497 .update(&mut app, |_, c| {
2498 c.spawn(async { 14 }, |model, output, _| {
2499 model.count = output;
2500 })
2501 })
2502 .await;
2503 handle.read(&app, |model, _| assert_eq!(model.count, 14));
2504 });
2505 }
2506
2507 #[test]
2508 fn test_spawn_stream_local_from_model() {
2509 #[derive(Default)]
2510 struct Model {
2511 events: Vec<Option<usize>>,
2512 }
2513
2514 impl Entity for Model {
2515 type Event = ();
2516 }
2517
2518 App::test((), |mut app| async move {
2519 let handle = app.add_model(|_| Model::default());
2520 handle
2521 .update(&mut app, |_, c| {
2522 c.spawn_stream(
2523 smol::stream::iter(vec![1, 2, 3]),
2524 |model, output, _| {
2525 model.events.push(Some(output));
2526 },
2527 |model, _| {
2528 model.events.push(None);
2529 },
2530 )
2531 })
2532 .await;
2533
2534 handle.read(&app, |model, _| {
2535 assert_eq!(model.events, [Some(1), Some(2), Some(3), None])
2536 });
2537 })
2538 }
2539
2540 #[test]
2541 fn test_view_handles() {
2542 struct View {
2543 other: Option<ViewHandle<View>>,
2544 events: Vec<String>,
2545 }
2546
2547 impl Entity for View {
2548 type Event = usize;
2549 }
2550
2551 impl super::View for View {
2552 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2553 Empty::new().boxed()
2554 }
2555
2556 fn ui_name() -> &'static str {
2557 "View"
2558 }
2559 }
2560
2561 impl View {
2562 fn new(other: Option<ViewHandle<View>>, ctx: &mut ViewContext<Self>) -> Self {
2563 if let Some(other) = other.as_ref() {
2564 ctx.subscribe_to_view(other, |me, _, event, _| {
2565 me.events.push(format!("observed event {}", event));
2566 });
2567 }
2568 Self {
2569 other,
2570 events: Vec::new(),
2571 }
2572 }
2573 }
2574
2575 App::test((), |mut app| async move {
2576 let app = &mut app;
2577 let (window_id, _) = app.add_window(|ctx| View::new(None, ctx));
2578 let handle_1 = app.add_view(window_id, |ctx| View::new(None, ctx));
2579 let handle_2 = app.add_view(window_id, |ctx| View::new(Some(handle_1.clone()), ctx));
2580 assert_eq!(app.0.borrow().ctx.windows[&window_id].views.len(), 3);
2581
2582 handle_1.update(app, |view, ctx| {
2583 view.events.push("updated".into());
2584 ctx.emit(1);
2585 ctx.emit(2);
2586 });
2587 handle_1.read(app, |view, _| {
2588 assert_eq!(view.events, vec!["updated".to_string()]);
2589 });
2590 handle_2.read(app, |view, _| {
2591 assert_eq!(
2592 view.events,
2593 vec![
2594 "observed event 1".to_string(),
2595 "observed event 2".to_string(),
2596 ]
2597 );
2598 });
2599
2600 handle_2.update(app, |view, _| {
2601 drop(handle_1);
2602 view.other.take();
2603 });
2604
2605 let app_state = app.0.borrow();
2606 assert_eq!(app_state.ctx.windows[&window_id].views.len(), 2);
2607 assert!(app_state.subscriptions.is_empty());
2608 assert!(app_state.observations.is_empty());
2609 })
2610 }
2611
2612 #[test]
2613 fn test_subscribe_and_emit_from_view() {
2614 #[derive(Default)]
2615 struct View {
2616 events: Vec<usize>,
2617 }
2618
2619 impl Entity for View {
2620 type Event = usize;
2621 }
2622
2623 impl super::View for View {
2624 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2625 Empty::new().boxed()
2626 }
2627
2628 fn ui_name() -> &'static str {
2629 "View"
2630 }
2631 }
2632
2633 struct Model;
2634
2635 impl Entity for Model {
2636 type Event = usize;
2637 }
2638
2639 App::test((), |mut app| async move {
2640 let app = &mut app;
2641 let (window_id, handle_1) = app.add_window(|_| View::default());
2642 let handle_2 = app.add_view(window_id, |_| View::default());
2643 let handle_2b = handle_2.clone();
2644 let handle_3 = app.add_model(|_| Model);
2645
2646 handle_1.update(app, |_, c| {
2647 c.subscribe_to_view(&handle_2, move |me, _, event, c| {
2648 me.events.push(*event);
2649
2650 c.subscribe_to_view(&handle_2b, |me, _, event, _| {
2651 me.events.push(*event * 2);
2652 });
2653 });
2654
2655 c.subscribe_to_model(&handle_3, |me, _, event, _| {
2656 me.events.push(*event);
2657 })
2658 });
2659
2660 handle_2.update(app, |_, c| c.emit(7));
2661 handle_1.read(app, |view, _| assert_eq!(view.events, vec![7]));
2662
2663 handle_2.update(app, |_, c| c.emit(5));
2664 handle_1.read(app, |view, _| assert_eq!(view.events, vec![7, 10, 5]));
2665
2666 handle_3.update(app, |_, c| c.emit(9));
2667 handle_1.read(app, |view, _| assert_eq!(view.events, vec![7, 10, 5, 9]));
2668 })
2669 }
2670
2671 #[test]
2672 fn test_dropping_subscribers() {
2673 struct View;
2674
2675 impl Entity for View {
2676 type Event = ();
2677 }
2678
2679 impl super::View for View {
2680 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2681 Empty::new().boxed()
2682 }
2683
2684 fn ui_name() -> &'static str {
2685 "View"
2686 }
2687 }
2688
2689 struct Model;
2690
2691 impl Entity for Model {
2692 type Event = ();
2693 }
2694
2695 App::test((), |mut app| async move {
2696 let app = &mut app;
2697
2698 let (window_id, _) = app.add_window(|_| View);
2699 let observing_view = app.add_view(window_id, |_| View);
2700 let emitting_view = app.add_view(window_id, |_| View);
2701 let observing_model = app.add_model(|_| Model);
2702 let observed_model = app.add_model(|_| Model);
2703
2704 observing_view.update(app, |_, ctx| {
2705 ctx.subscribe_to_view(&emitting_view, |_, _, _, _| {});
2706 ctx.subscribe_to_model(&observed_model, |_, _, _, _| {});
2707 });
2708 observing_model.update(app, |_, ctx| {
2709 ctx.subscribe(&observed_model, |_, _, _| {});
2710 });
2711
2712 app.update(|_| {
2713 drop(observing_view);
2714 drop(observing_model);
2715 });
2716
2717 emitting_view.update(app, |_, ctx| ctx.emit(()));
2718 observed_model.update(app, |_, ctx| ctx.emit(()));
2719 })
2720 }
2721
2722 #[test]
2723 fn test_observe_and_notify_from_view() {
2724 #[derive(Default)]
2725 struct View {
2726 events: Vec<usize>,
2727 }
2728
2729 impl Entity for View {
2730 type Event = usize;
2731 }
2732
2733 impl super::View for View {
2734 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2735 Empty::new().boxed()
2736 }
2737
2738 fn ui_name() -> &'static str {
2739 "View"
2740 }
2741 }
2742
2743 #[derive(Default)]
2744 struct Model {
2745 count: usize,
2746 }
2747
2748 impl Entity for Model {
2749 type Event = ();
2750 }
2751
2752 App::test((), |mut app| async move {
2753 let app = &mut app;
2754 let (_, view) = app.add_window(|_| View::default());
2755 let model = app.add_model(|_| Model::default());
2756
2757 view.update(app, |_, c| {
2758 c.observe(&model, |me, observed, c| {
2759 me.events.push(observed.as_ref(c).count)
2760 });
2761 });
2762
2763 model.update(app, |model, c| {
2764 model.count = 11;
2765 c.notify();
2766 });
2767 view.read(app, |view, _| assert_eq!(view.events, vec![11]));
2768 })
2769 }
2770
2771 #[test]
2772 fn test_dropping_observers() {
2773 struct View;
2774
2775 impl Entity for View {
2776 type Event = ();
2777 }
2778
2779 impl super::View for View {
2780 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2781 Empty::new().boxed()
2782 }
2783
2784 fn ui_name() -> &'static str {
2785 "View"
2786 }
2787 }
2788
2789 struct Model;
2790
2791 impl Entity for Model {
2792 type Event = ();
2793 }
2794
2795 App::test((), |mut app| async move {
2796 let app = &mut app;
2797
2798 let (window_id, _) = app.add_window(|_| View);
2799 let observing_view = app.add_view(window_id, |_| View);
2800 let observing_model = app.add_model(|_| Model);
2801 let observed_model = app.add_model(|_| Model);
2802
2803 observing_view.update(app, |_, ctx| {
2804 ctx.observe(&observed_model, |_, _, _| {});
2805 });
2806 observing_model.update(app, |_, ctx| {
2807 ctx.observe(&observed_model, |_, _, _| {});
2808 });
2809
2810 app.update(|_| {
2811 drop(observing_view);
2812 drop(observing_model);
2813 });
2814
2815 observed_model.update(app, |_, ctx| ctx.notify());
2816 })
2817 }
2818
2819 #[test]
2820 fn test_focus() {
2821 #[derive(Default)]
2822 struct View {
2823 events: Vec<String>,
2824 }
2825
2826 impl Entity for View {
2827 type Event = String;
2828 }
2829
2830 impl super::View for View {
2831 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2832 Empty::new().boxed()
2833 }
2834
2835 fn ui_name() -> &'static str {
2836 "View"
2837 }
2838
2839 fn on_focus(&mut self, ctx: &mut ViewContext<Self>) {
2840 self.events.push("self focused".into());
2841 ctx.emit("focused".into());
2842 }
2843
2844 fn on_blur(&mut self, ctx: &mut ViewContext<Self>) {
2845 self.events.push("self blurred".into());
2846 ctx.emit("blurred".into());
2847 }
2848 }
2849
2850 App::test((), |mut app| async move {
2851 let app = &mut app;
2852 let (window_id, view_1) = app.add_window(|_| View::default());
2853 let view_2 = app.add_view(window_id, |_| View::default());
2854
2855 view_1.update(app, |_, ctx| {
2856 ctx.subscribe_to_view(&view_2, |view_1, _, event, _| {
2857 view_1.events.push(format!("view 2 {}", event));
2858 });
2859 ctx.focus(&view_2);
2860 });
2861
2862 view_1.update(app, |_, ctx| {
2863 ctx.focus(&view_1);
2864 });
2865
2866 view_1.read(app, |view_1, _| {
2867 assert_eq!(
2868 view_1.events,
2869 [
2870 "self focused".to_string(),
2871 "self blurred".to_string(),
2872 "view 2 focused".to_string(),
2873 "self focused".to_string(),
2874 "view 2 blurred".to_string(),
2875 ],
2876 );
2877 });
2878 })
2879 }
2880
2881 #[test]
2882 fn test_spawn_from_view() {
2883 #[derive(Default)]
2884 struct View {
2885 count: usize,
2886 }
2887
2888 impl Entity for View {
2889 type Event = ();
2890 }
2891
2892 impl super::View for View {
2893 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2894 Empty::new().boxed()
2895 }
2896
2897 fn ui_name() -> &'static str {
2898 "View"
2899 }
2900 }
2901
2902 App::test((), |mut app| async move {
2903 let (_, handle) = app.add_window(|_| View::default());
2904 handle
2905 .update(&mut app, |_, c| {
2906 c.spawn(async { 7 }, |me, output, _| {
2907 me.count = output;
2908 })
2909 })
2910 .await;
2911 handle.read(&app, |view, _| assert_eq!(view.count, 7));
2912 handle
2913 .update(&mut app, |_, c| {
2914 c.spawn(async { 14 }, |me, output, _| {
2915 me.count = output;
2916 })
2917 })
2918 .await;
2919 handle.read(&app, |view, _| assert_eq!(view.count, 14));
2920 });
2921 }
2922
2923 #[test]
2924 fn test_spawn_stream_local_from_view() {
2925 #[derive(Default)]
2926 struct View {
2927 events: Vec<Option<usize>>,
2928 }
2929
2930 impl Entity for View {
2931 type Event = ();
2932 }
2933
2934 impl super::View for View {
2935 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2936 Empty::new().boxed()
2937 }
2938
2939 fn ui_name() -> &'static str {
2940 "View"
2941 }
2942 }
2943
2944 App::test((), |mut app| async move {
2945 let (_, handle) = app.add_window(|_| View::default());
2946 handle
2947 .update(&mut app, |_, c| {
2948 c.spawn_stream(
2949 smol::stream::iter(vec![1_usize, 2, 3]),
2950 |me, output, _| {
2951 me.events.push(Some(output));
2952 },
2953 |me, _| {
2954 me.events.push(None);
2955 },
2956 )
2957 })
2958 .await;
2959
2960 handle.read(&app, |view, _| {
2961 assert_eq!(view.events, [Some(1), Some(2), Some(3), None])
2962 });
2963 });
2964 }
2965
2966 #[test]
2967 fn test_dispatch_action() {
2968 struct ViewA {
2969 id: usize,
2970 }
2971
2972 impl Entity for ViewA {
2973 type Event = ();
2974 }
2975
2976 impl View for ViewA {
2977 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2978 Empty::new().boxed()
2979 }
2980
2981 fn ui_name() -> &'static str {
2982 "View"
2983 }
2984 }
2985
2986 struct ViewB {
2987 id: usize,
2988 }
2989
2990 impl Entity for ViewB {
2991 type Event = ();
2992 }
2993
2994 impl View for ViewB {
2995 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2996 Empty::new().boxed()
2997 }
2998
2999 fn ui_name() -> &'static str {
3000 "View"
3001 }
3002 }
3003
3004 struct ActionArg {
3005 foo: String,
3006 }
3007
3008 App::test((), |mut app| async move {
3009 let actions = Rc::new(RefCell::new(Vec::new()));
3010
3011 let actions_clone = actions.clone();
3012 app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| {
3013 actions_clone.borrow_mut().push("global a".to_string());
3014 });
3015
3016 let actions_clone = actions.clone();
3017 app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| {
3018 actions_clone.borrow_mut().push("global b".to_string());
3019 });
3020
3021 let actions_clone = actions.clone();
3022 app.add_action("action", move |view: &mut ViewA, arg: &ActionArg, ctx| {
3023 assert_eq!(arg.foo, "bar");
3024 ctx.propagate_action();
3025 actions_clone.borrow_mut().push(format!("{} a", view.id));
3026 });
3027
3028 let actions_clone = actions.clone();
3029 app.add_action("action", move |view: &mut ViewA, _: &ActionArg, ctx| {
3030 if view.id != 1 {
3031 ctx.propagate_action();
3032 }
3033 actions_clone.borrow_mut().push(format!("{} b", view.id));
3034 });
3035
3036 let actions_clone = actions.clone();
3037 app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| {
3038 ctx.propagate_action();
3039 actions_clone.borrow_mut().push(format!("{} c", view.id));
3040 });
3041
3042 let actions_clone = actions.clone();
3043 app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| {
3044 ctx.propagate_action();
3045 actions_clone.borrow_mut().push(format!("{} d", view.id));
3046 });
3047
3048 let (window_id, view_1) = app.add_window(|_| ViewA { id: 1 });
3049 let view_2 = app.add_view(window_id, |_| ViewB { id: 2 });
3050 let view_3 = app.add_view(window_id, |_| ViewA { id: 3 });
3051 let view_4 = app.add_view(window_id, |_| ViewB { id: 4 });
3052
3053 app.dispatch_action(
3054 window_id,
3055 vec![view_1.id(), view_2.id(), view_3.id(), view_4.id()],
3056 "action",
3057 ActionArg { foo: "bar".into() },
3058 );
3059
3060 assert_eq!(
3061 *actions.borrow(),
3062 vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "1 b"]
3063 );
3064
3065 // Remove view_1, which doesn't propagate the action
3066 actions.borrow_mut().clear();
3067 app.dispatch_action(
3068 window_id,
3069 vec![view_2.id(), view_3.id(), view_4.id()],
3070 "action",
3071 ActionArg { foo: "bar".into() },
3072 );
3073
3074 assert_eq!(
3075 *actions.borrow(),
3076 vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "global b", "global a"]
3077 );
3078 })
3079 }
3080
3081 #[test]
3082 fn test_dispatch_keystroke() -> Result<()> {
3083 use std::cell::Cell;
3084
3085 #[derive(Clone)]
3086 struct ActionArg {
3087 key: String,
3088 }
3089
3090 struct View {
3091 id: usize,
3092 keymap_context: keymap::Context,
3093 }
3094
3095 impl Entity for View {
3096 type Event = ();
3097 }
3098
3099 impl super::View for View {
3100 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3101 Empty::new().boxed()
3102 }
3103
3104 fn ui_name() -> &'static str {
3105 "View"
3106 }
3107
3108 fn keymap_context(&self, _: &AppContext) -> keymap::Context {
3109 self.keymap_context.clone()
3110 }
3111 }
3112
3113 impl View {
3114 fn new(id: usize) -> Self {
3115 View {
3116 id,
3117 keymap_context: keymap::Context::default(),
3118 }
3119 }
3120 }
3121
3122 App::test((), |mut app| async move {
3123 let mut view_1 = View::new(1);
3124 let mut view_2 = View::new(2);
3125 let mut view_3 = View::new(3);
3126 view_1.keymap_context.set.insert("a".into());
3127 view_2.keymap_context.set.insert("b".into());
3128 view_3.keymap_context.set.insert("c".into());
3129
3130 let (window_id, view_1) = app.add_window(|_| view_1);
3131 let view_2 = app.add_view(window_id, |_| view_2);
3132 let view_3 = app.add_view(window_id, |_| view_3);
3133
3134 // This keymap's only binding dispatches an action on view 2 because that view will have
3135 // "a" and "b" in its context, but not "c".
3136 let binding = keymap::Binding::new("a", "action", Some("a && b && !c"))
3137 .with_arg(ActionArg { key: "a".into() });
3138 app.add_bindings(vec![binding]);
3139
3140 let handled_action = Rc::new(Cell::new(false));
3141 let handled_action_clone = handled_action.clone();
3142 app.add_action("action", move |view: &mut View, arg: &ActionArg, _ctx| {
3143 handled_action_clone.set(true);
3144 assert_eq!(view.id, 2);
3145 assert_eq!(arg.key, "a");
3146 });
3147
3148 app.dispatch_keystroke(
3149 window_id,
3150 vec![view_1.id(), view_2.id(), view_3.id()],
3151 &Keystroke::parse("a")?,
3152 )?;
3153
3154 assert!(handled_action.get());
3155 Ok(())
3156 })
3157 }
3158
3159 // #[test]
3160 // fn test_ui_and_window_updates() {
3161 // struct View {
3162 // count: usize,
3163 // }
3164
3165 // impl Entity for View {
3166 // type Event = ();
3167 // }
3168
3169 // impl super::View for View {
3170 // fn render<'a>(&self, _: &AppContext) -> ElementBox {
3171 // Empty::new().boxed()
3172 // }
3173
3174 // fn ui_name() -> &'static str {
3175 // "View"
3176 // }
3177 // }
3178
3179 // App::test(|mut app| async move {
3180 // let (window_id, _) = app.add_window(|_| View { count: 3 });
3181 // let view_1 = app.add_view(window_id, |_| View { count: 1 });
3182 // let view_2 = app.add_view(window_id, |_| View { count: 2 });
3183
3184 // // Ensure that registering for UI updates after mutating the app still gives us all the
3185 // // updates.
3186 // let ui_updates = Rc::new(RefCell::new(Vec::new()));
3187 // let ui_updates_ = ui_updates.clone();
3188 // app.on_ui_update(move |update, _| ui_updates_.borrow_mut().push(update));
3189
3190 // assert_eq!(
3191 // ui_updates.borrow_mut().drain(..).collect::<Vec<_>>(),
3192 // vec![UiUpdate::OpenWindow {
3193 // window_id,
3194 // width: 1024.0,
3195 // height: 768.0,
3196 // }]
3197 // );
3198
3199 // let window_invalidations = Rc::new(RefCell::new(Vec::new()));
3200 // let window_invalidations_ = window_invalidations.clone();
3201 // app.on_window_invalidated(window_id, move |update, _| {
3202 // window_invalidations_.borrow_mut().push(update)
3203 // });
3204
3205 // let view_2_id = view_2.id();
3206 // view_1.update(&mut app, |view, ctx| {
3207 // view.count = 7;
3208 // ctx.notify();
3209 // drop(view_2);
3210 // });
3211
3212 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3213 // assert_eq!(invalidation.updated.len(), 1);
3214 // assert!(invalidation.updated.contains(&view_1.id()));
3215 // assert_eq!(invalidation.removed, vec![view_2_id]);
3216
3217 // let view_3 = view_1.update(&mut app, |_, ctx| ctx.add_view(|_| View { count: 8 }));
3218
3219 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3220 // assert_eq!(invalidation.updated.len(), 1);
3221 // assert!(invalidation.updated.contains(&view_3.id()));
3222 // assert!(invalidation.removed.is_empty());
3223
3224 // view_3
3225 // .update(&mut app, |_, ctx| {
3226 // ctx.spawn_local(async { 9 }, |me, output, ctx| {
3227 // me.count = output;
3228 // ctx.notify();
3229 // })
3230 // })
3231 // .await;
3232
3233 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3234 // assert_eq!(invalidation.updated.len(), 1);
3235 // assert!(invalidation.updated.contains(&view_3.id()));
3236 // assert!(invalidation.removed.is_empty());
3237 // });
3238 // }
3239
3240 #[test]
3241 fn test_finish_pending_tasks() {
3242 struct View;
3243
3244 impl Entity for View {
3245 type Event = ();
3246 }
3247
3248 impl super::View for View {
3249 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3250 Empty::new().boxed()
3251 }
3252
3253 fn ui_name() -> &'static str {
3254 "View"
3255 }
3256 }
3257
3258 struct Model;
3259
3260 impl Entity for Model {
3261 type Event = ();
3262 }
3263
3264 App::test((), |mut app| async move {
3265 let model = app.add_model(|_| Model);
3266 let (_, view) = app.add_window(|_| View);
3267
3268 model.update(&mut app, |_, ctx| {
3269 let _ = ctx.spawn(async {}, |_, _, _| {});
3270 let _ = ctx.spawn(async {}, |_, _, _| {});
3271 let _ =
3272 ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {});
3273 });
3274
3275 view.update(&mut app, |_, ctx| {
3276 let _ = ctx.spawn(async {}, |_, _, _| {});
3277 let _ = ctx.spawn(async {}, |_, _, _| {});
3278 let _ =
3279 ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {});
3280 });
3281
3282 assert!(!app.0.borrow().future_handlers.is_empty());
3283 app.finish_pending_tasks().await;
3284 assert!(app.0.borrow().future_handlers.is_empty());
3285 app.finish_pending_tasks().await; // Don't block if there are no tasks
3286 });
3287 }
3288}