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