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