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