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 background_executor(&self) -> &Arc<executor::Background> {
1721 &self.app.ctx.background
1722 }
1723
1724 pub fn debug_elements(&self) -> crate::json::Value {
1725 self.app.debug_elements(self.window_id).unwrap()
1726 }
1727
1728 pub fn focus<S>(&mut self, handle: S)
1729 where
1730 S: Into<AnyViewHandle>,
1731 {
1732 let handle = handle.into();
1733 self.app.pending_effects.push_back(Effect::Focus {
1734 window_id: handle.window_id,
1735 view_id: handle.view_id,
1736 });
1737 }
1738
1739 pub fn focus_self(&mut self) {
1740 self.app.pending_effects.push_back(Effect::Focus {
1741 window_id: self.window_id,
1742 view_id: self.view_id,
1743 });
1744 }
1745
1746 pub fn add_model<S, F>(&mut self, build_model: F) -> ModelHandle<S>
1747 where
1748 S: Entity,
1749 F: FnOnce(&mut ModelContext<S>) -> S,
1750 {
1751 self.app.add_model(build_model)
1752 }
1753
1754 pub fn add_view<S, F>(&mut self, build_view: F) -> ViewHandle<S>
1755 where
1756 S: View,
1757 F: FnOnce(&mut ViewContext<S>) -> S,
1758 {
1759 self.app.add_view(self.window_id, build_view)
1760 }
1761
1762 pub fn add_option_view<S, F>(&mut self, build_view: F) -> Option<ViewHandle<S>>
1763 where
1764 S: View,
1765 F: FnOnce(&mut ViewContext<S>) -> Option<S>,
1766 {
1767 self.app.add_option_view(self.window_id, build_view)
1768 }
1769
1770 pub fn subscribe_to_model<E, F>(&mut self, handle: &ModelHandle<E>, mut callback: F)
1771 where
1772 E: Entity,
1773 E::Event: 'static,
1774 F: 'static + FnMut(&mut T, ModelHandle<E>, &E::Event, &mut ViewContext<T>),
1775 {
1776 let emitter_handle = handle.downgrade();
1777 self.app
1778 .subscriptions
1779 .entry(handle.id())
1780 .or_default()
1781 .push(Subscription::FromView {
1782 window_id: self.window_id,
1783 view_id: self.view_id,
1784 callback: Box::new(move |view, payload, app, window_id, view_id| {
1785 if let Some(emitter_handle) = emitter_handle.upgrade(app.as_ref()) {
1786 let model = view.downcast_mut().expect("downcast is type safe");
1787 let payload = payload.downcast_ref().expect("downcast is type safe");
1788 let mut ctx = ViewContext::new(app, window_id, view_id);
1789 callback(model, emitter_handle, payload, &mut ctx);
1790 }
1791 }),
1792 });
1793 }
1794
1795 pub fn subscribe_to_view<V, F>(&mut self, handle: &ViewHandle<V>, mut callback: F)
1796 where
1797 V: View,
1798 V::Event: 'static,
1799 F: 'static + FnMut(&mut T, ViewHandle<V>, &V::Event, &mut ViewContext<T>),
1800 {
1801 let emitter_handle = handle.downgrade();
1802
1803 self.app
1804 .subscriptions
1805 .entry(handle.id())
1806 .or_default()
1807 .push(Subscription::FromView {
1808 window_id: self.window_id,
1809 view_id: self.view_id,
1810 callback: Box::new(move |view, payload, app, window_id, view_id| {
1811 if let Some(emitter_handle) = emitter_handle.upgrade(app.as_ref()) {
1812 let model = view.downcast_mut().expect("downcast is type safe");
1813 let payload = payload.downcast_ref().expect("downcast is type safe");
1814 let mut ctx = ViewContext::new(app, window_id, view_id);
1815 callback(model, emitter_handle, payload, &mut ctx);
1816 }
1817 }),
1818 });
1819 }
1820
1821 pub fn emit(&mut self, payload: T::Event) {
1822 self.app.pending_effects.push_back(Effect::Event {
1823 entity_id: self.view_id,
1824 payload: Box::new(payload),
1825 });
1826 }
1827
1828 pub fn observe<S, F>(&mut self, handle: &ModelHandle<S>, mut callback: F)
1829 where
1830 S: Entity,
1831 F: 'static + FnMut(&mut T, ModelHandle<S>, &mut ViewContext<T>),
1832 {
1833 self.app
1834 .observations
1835 .entry(handle.id())
1836 .or_default()
1837 .push(Observation::FromView {
1838 window_id: self.window_id,
1839 view_id: self.view_id,
1840 callback: Box::new(move |view, observed_id, app, window_id, view_id| {
1841 let view = view.downcast_mut().expect("downcast is type safe");
1842 let observed = ModelHandle::new(observed_id, &app.ctx.ref_counts);
1843 let mut ctx = ViewContext::new(app, window_id, view_id);
1844 callback(view, observed, &mut ctx);
1845 }),
1846 });
1847 }
1848
1849 pub fn notify(&mut self) {
1850 self.app.notify_view(self.window_id, self.view_id);
1851 }
1852
1853 pub fn propagate_action(&mut self) {
1854 self.halt_action_dispatch = false;
1855 }
1856
1857 pub fn halt_stream(&mut self) {
1858 self.halt_stream = true;
1859 }
1860
1861 pub fn spawn<S, F, U>(&mut self, future: S, callback: F) -> EntityTask<U>
1862 where
1863 S: 'static + Future,
1864 F: 'static + FnOnce(&mut T, S::Output, &mut ViewContext<T>) -> U,
1865 U: 'static,
1866 {
1867 let handle = self.handle();
1868 let task = self.app.spawn(future);
1869
1870 self.app.future_handlers.borrow_mut().insert(
1871 task.id,
1872 Box::new(move |output, app| {
1873 let output = *output.downcast().unwrap();
1874 handle.update(app, |view, ctx| Box::new(callback(view, output, ctx)))
1875 }),
1876 );
1877
1878 task
1879 }
1880
1881 pub fn spawn_stream<S, F, G, U>(
1882 &mut self,
1883 stream: S,
1884 mut item_callback: F,
1885 done_callback: G,
1886 ) -> EntityTask<U>
1887 where
1888 S: 'static + Stream + Unpin,
1889 F: 'static + FnMut(&mut T, S::Item, &mut ViewContext<T>),
1890 G: 'static + FnOnce(&mut T, &mut ViewContext<T>) -> U,
1891 U: 'static + Any,
1892 {
1893 let handle = self.handle();
1894 let task = self.app.spawn_stream(stream);
1895 self.app.stream_handlers.borrow_mut().insert(
1896 task.id,
1897 StreamHandler {
1898 item_callback: {
1899 let handle = handle.clone();
1900 Box::new(move |output, app| {
1901 let output = *output.downcast().unwrap();
1902 handle.update(app, |view, ctx| {
1903 item_callback(view, output, ctx);
1904 ctx.halt_stream
1905 })
1906 })
1907 },
1908 done_callback: Box::new(move |app| {
1909 handle.update(app, |view, ctx| Box::new(done_callback(view, ctx)))
1910 }),
1911 },
1912 );
1913 task
1914 }
1915}
1916
1917impl<M> AsRef<AppContext> for ViewContext<'_, M> {
1918 fn as_ref(&self) -> &AppContext {
1919 &self.app.ctx
1920 }
1921}
1922
1923impl<M> AsMut<MutableAppContext> for ViewContext<'_, M> {
1924 fn as_mut(&mut self) -> &mut MutableAppContext {
1925 self.app
1926 }
1927}
1928
1929impl<V> ReadModel for ViewContext<'_, V> {
1930 fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1931 self.app.read_model(handle)
1932 }
1933}
1934
1935impl<V: View> UpdateModel for ViewContext<'_, V> {
1936 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
1937 where
1938 T: Entity,
1939 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1940 {
1941 self.app.update_model(handle, update)
1942 }
1943}
1944
1945impl<V: View> ReadView for ViewContext<'_, V> {
1946 fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
1947 self.app.read_view(handle)
1948 }
1949}
1950
1951impl<V: View> UpdateView for ViewContext<'_, V> {
1952 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
1953 where
1954 T: View,
1955 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
1956 {
1957 self.app.update_view(handle, update)
1958 }
1959}
1960
1961pub trait Handle<T> {
1962 fn id(&self) -> usize;
1963 fn location(&self) -> EntityLocation;
1964}
1965
1966#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
1967pub enum EntityLocation {
1968 Model(usize),
1969 View(usize, usize),
1970}
1971
1972pub struct ModelHandle<T> {
1973 model_id: usize,
1974 model_type: PhantomData<T>,
1975 ref_counts: Weak<Mutex<RefCounts>>,
1976}
1977
1978impl<T: Entity> ModelHandle<T> {
1979 fn new(model_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
1980 ref_counts.lock().inc_entity(model_id);
1981 Self {
1982 model_id,
1983 model_type: PhantomData,
1984 ref_counts: Arc::downgrade(ref_counts),
1985 }
1986 }
1987
1988 fn downgrade(&self) -> WeakModelHandle<T> {
1989 WeakModelHandle::new(self.model_id)
1990 }
1991
1992 pub fn id(&self) -> usize {
1993 self.model_id
1994 }
1995
1996 pub fn read<'a, A: ReadModel>(&self, app: &'a A) -> &'a T {
1997 app.read_model(self)
1998 }
1999
2000 pub fn update<A, F, S>(&self, app: &mut A, update: F) -> S
2001 where
2002 A: UpdateModel,
2003 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
2004 {
2005 app.update_model(self, update)
2006 }
2007
2008 pub fn condition(
2009 &self,
2010 ctx: &TestAppContext,
2011 predicate: impl FnMut(&T, &AppContext) -> bool,
2012 ) -> impl Future<Output = ()> {
2013 self.condition_with_duration(Duration::from_millis(100), ctx, predicate)
2014 }
2015
2016 pub fn condition_with_duration(
2017 &self,
2018 duration: Duration,
2019 ctx: &TestAppContext,
2020 mut predicate: impl FnMut(&T, &AppContext) -> bool,
2021 ) -> impl Future<Output = ()> {
2022 let mut ctx = ctx.0.borrow_mut();
2023 let tx = ctx
2024 .async_observations
2025 .entry(self.id())
2026 .or_insert_with(|| postage::broadcast::channel(128).0);
2027 let mut rx = tx.subscribe();
2028 let ctx = ctx.weak_self.as_ref().unwrap().upgrade().unwrap();
2029 let handle = self.downgrade();
2030
2031 async move {
2032 timeout(duration, async move {
2033 loop {
2034 {
2035 let ctx = ctx.borrow();
2036 let ctx = ctx.as_ref();
2037 if predicate(
2038 handle
2039 .upgrade(ctx)
2040 .expect("model dropped with pending condition")
2041 .read(ctx),
2042 ctx,
2043 ) {
2044 break;
2045 }
2046 }
2047
2048 rx.recv()
2049 .await
2050 .expect("model dropped with pending condition");
2051 }
2052 })
2053 .await
2054 .expect("condition timed out");
2055 }
2056 }
2057}
2058
2059impl<T> Clone for ModelHandle<T> {
2060 fn clone(&self) -> Self {
2061 if let Some(ref_counts) = self.ref_counts.upgrade() {
2062 ref_counts.lock().inc_entity(self.model_id);
2063 }
2064
2065 Self {
2066 model_id: self.model_id,
2067 model_type: PhantomData,
2068 ref_counts: self.ref_counts.clone(),
2069 }
2070 }
2071}
2072
2073impl<T> PartialEq for ModelHandle<T> {
2074 fn eq(&self, other: &Self) -> bool {
2075 self.model_id == other.model_id
2076 }
2077}
2078
2079impl<T> Eq for ModelHandle<T> {}
2080
2081impl<T> Hash for ModelHandle<T> {
2082 fn hash<H: Hasher>(&self, state: &mut H) {
2083 self.model_id.hash(state);
2084 }
2085}
2086
2087impl<T> std::borrow::Borrow<usize> for ModelHandle<T> {
2088 fn borrow(&self) -> &usize {
2089 &self.model_id
2090 }
2091}
2092
2093impl<T> Debug for ModelHandle<T> {
2094 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2095 f.debug_tuple(&format!("ModelHandle<{}>", type_name::<T>()))
2096 .field(&self.model_id)
2097 .finish()
2098 }
2099}
2100
2101unsafe impl<T> Send for ModelHandle<T> {}
2102unsafe impl<T> Sync for ModelHandle<T> {}
2103
2104impl<T> Drop for ModelHandle<T> {
2105 fn drop(&mut self) {
2106 if let Some(ref_counts) = self.ref_counts.upgrade() {
2107 ref_counts.lock().dec_model(self.model_id);
2108 }
2109 }
2110}
2111
2112impl<T> Handle<T> for ModelHandle<T> {
2113 fn id(&self) -> usize {
2114 self.model_id
2115 }
2116
2117 fn location(&self) -> EntityLocation {
2118 EntityLocation::Model(self.model_id)
2119 }
2120}
2121
2122pub struct WeakModelHandle<T> {
2123 model_id: usize,
2124 model_type: PhantomData<T>,
2125}
2126
2127impl<T: Entity> WeakModelHandle<T> {
2128 fn new(model_id: usize) -> Self {
2129 Self {
2130 model_id,
2131 model_type: PhantomData,
2132 }
2133 }
2134
2135 pub fn upgrade(&self, app: &AppContext) -> Option<ModelHandle<T>> {
2136 if app.models.contains_key(&self.model_id) {
2137 Some(ModelHandle::new(self.model_id, &app.ref_counts))
2138 } else {
2139 None
2140 }
2141 }
2142}
2143
2144pub struct ViewHandle<T> {
2145 window_id: usize,
2146 view_id: usize,
2147 view_type: PhantomData<T>,
2148 ref_counts: Weak<Mutex<RefCounts>>,
2149}
2150
2151impl<T: View> ViewHandle<T> {
2152 fn new(window_id: usize, view_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
2153 ref_counts.lock().inc_entity(view_id);
2154 Self {
2155 window_id,
2156 view_id,
2157 view_type: PhantomData,
2158 ref_counts: Arc::downgrade(ref_counts),
2159 }
2160 }
2161
2162 pub fn downgrade(&self) -> WeakViewHandle<T> {
2163 WeakViewHandle::new(self.window_id, self.view_id)
2164 }
2165
2166 pub fn window_id(&self) -> usize {
2167 self.window_id
2168 }
2169
2170 pub fn id(&self) -> usize {
2171 self.view_id
2172 }
2173
2174 pub fn read<'a, A: ReadView>(&self, app: &'a A) -> &'a T {
2175 app.read_view(self)
2176 }
2177
2178 pub fn update<A, F, S>(&self, app: &mut A, update: F) -> S
2179 where
2180 A: UpdateView,
2181 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
2182 {
2183 app.update_view(self, update)
2184 }
2185
2186 pub fn is_focused(&self, app: &AppContext) -> bool {
2187 app.focused_view_id(self.window_id)
2188 .map_or(false, |focused_id| focused_id == self.view_id)
2189 }
2190
2191 pub fn condition(
2192 &self,
2193 ctx: &TestAppContext,
2194 mut predicate: impl 'static + FnMut(&T, &AppContext) -> bool,
2195 ) -> impl 'static + Future<Output = ()> {
2196 let mut ctx = ctx.0.borrow_mut();
2197 let tx = ctx
2198 .async_observations
2199 .entry(self.id())
2200 .or_insert_with(|| postage::broadcast::channel(128).0);
2201 let mut rx = tx.subscribe();
2202 let ctx = ctx.weak_self.as_ref().unwrap().upgrade().unwrap();
2203 let handle = self.downgrade();
2204
2205 async move {
2206 timeout(Duration::from_millis(200), async move {
2207 loop {
2208 {
2209 let ctx = ctx.borrow();
2210 let ctx = ctx.as_ref();
2211 if predicate(
2212 handle
2213 .upgrade(ctx)
2214 .expect("model dropped with pending condition")
2215 .read(ctx),
2216 ctx,
2217 ) {
2218 break;
2219 }
2220 }
2221
2222 rx.recv()
2223 .await
2224 .expect("model dropped with pending condition");
2225 }
2226 })
2227 .await
2228 .expect("condition timed out");
2229 }
2230 }
2231}
2232
2233impl<T> Clone for ViewHandle<T> {
2234 fn clone(&self) -> Self {
2235 if let Some(ref_counts) = self.ref_counts.upgrade() {
2236 ref_counts.lock().inc_entity(self.view_id);
2237 }
2238
2239 Self {
2240 window_id: self.window_id,
2241 view_id: self.view_id,
2242 view_type: PhantomData,
2243 ref_counts: self.ref_counts.clone(),
2244 }
2245 }
2246}
2247
2248impl<T> PartialEq for ViewHandle<T> {
2249 fn eq(&self, other: &Self) -> bool {
2250 self.window_id == other.window_id && self.view_id == other.view_id
2251 }
2252}
2253
2254impl<T> Eq for ViewHandle<T> {}
2255
2256impl<T> Debug for ViewHandle<T> {
2257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2258 f.debug_struct(&format!("ViewHandle<{}>", type_name::<T>()))
2259 .field("window_id", &self.window_id)
2260 .field("view_id", &self.view_id)
2261 .finish()
2262 }
2263}
2264
2265impl<T> Drop for ViewHandle<T> {
2266 fn drop(&mut self) {
2267 if let Some(ref_counts) = self.ref_counts.upgrade() {
2268 ref_counts.lock().dec_view(self.window_id, self.view_id);
2269 }
2270 }
2271}
2272
2273impl<T> Handle<T> for ViewHandle<T> {
2274 fn id(&self) -> usize {
2275 self.view_id
2276 }
2277
2278 fn location(&self) -> EntityLocation {
2279 EntityLocation::View(self.window_id, self.view_id)
2280 }
2281}
2282
2283#[derive(Clone)]
2284pub struct AnyViewHandle {
2285 window_id: usize,
2286 view_id: usize,
2287 view_type: TypeId,
2288 ref_counts: Weak<Mutex<RefCounts>>,
2289}
2290
2291impl AnyViewHandle {
2292 pub fn id(&self) -> usize {
2293 self.view_id
2294 }
2295
2296 pub fn is<T: 'static>(&self) -> bool {
2297 TypeId::of::<T>() == self.view_type
2298 }
2299
2300 pub fn downcast<T: View>(self) -> Option<ViewHandle<T>> {
2301 if self.is::<T>() {
2302 if let Some(ref_counts) = self.ref_counts.upgrade() {
2303 return Some(ViewHandle::new(self.window_id, self.view_id, &ref_counts));
2304 }
2305 }
2306 None
2307 }
2308}
2309
2310impl<T: View> From<&ViewHandle<T>> for AnyViewHandle {
2311 fn from(handle: &ViewHandle<T>) -> Self {
2312 if let Some(ref_counts) = handle.ref_counts.upgrade() {
2313 ref_counts.lock().inc_entity(handle.view_id);
2314 }
2315 AnyViewHandle {
2316 window_id: handle.window_id,
2317 view_id: handle.view_id,
2318 view_type: TypeId::of::<T>(),
2319 ref_counts: handle.ref_counts.clone(),
2320 }
2321 }
2322}
2323
2324impl<T: View> From<ViewHandle<T>> for AnyViewHandle {
2325 fn from(handle: ViewHandle<T>) -> Self {
2326 (&handle).into()
2327 }
2328}
2329
2330pub struct WeakViewHandle<T> {
2331 window_id: usize,
2332 view_id: usize,
2333 view_type: PhantomData<T>,
2334}
2335
2336impl<T: View> WeakViewHandle<T> {
2337 fn new(window_id: usize, view_id: usize) -> Self {
2338 Self {
2339 window_id,
2340 view_id,
2341 view_type: PhantomData,
2342 }
2343 }
2344
2345 pub fn upgrade(&self, app: &AppContext) -> Option<ViewHandle<T>> {
2346 if app
2347 .windows
2348 .get(&self.window_id)
2349 .and_then(|w| w.views.get(&self.view_id))
2350 .is_some()
2351 {
2352 Some(ViewHandle::new(
2353 self.window_id,
2354 self.view_id,
2355 &app.ref_counts,
2356 ))
2357 } else {
2358 None
2359 }
2360 }
2361}
2362
2363impl<T> Clone for WeakViewHandle<T> {
2364 fn clone(&self) -> Self {
2365 Self {
2366 window_id: self.window_id,
2367 view_id: self.view_id,
2368 view_type: PhantomData,
2369 }
2370 }
2371}
2372
2373pub struct ValueHandle<T> {
2374 value_type: PhantomData<T>,
2375 tag_type_id: TypeId,
2376 id: usize,
2377 ref_counts: Weak<Mutex<RefCounts>>,
2378}
2379
2380impl<T: 'static> ValueHandle<T> {
2381 fn new(tag_type_id: TypeId, id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
2382 ref_counts.lock().inc_value(tag_type_id, id);
2383 Self {
2384 value_type: PhantomData,
2385 tag_type_id,
2386 id,
2387 ref_counts: Arc::downgrade(ref_counts),
2388 }
2389 }
2390
2391 pub fn read<R>(&self, ctx: &AppContext, f: impl FnOnce(&T) -> R) -> R {
2392 f(ctx
2393 .values
2394 .read()
2395 .get(&(self.tag_type_id, self.id))
2396 .unwrap()
2397 .downcast_ref()
2398 .unwrap())
2399 }
2400
2401 pub fn update<R>(&self, ctx: &AppContext, f: impl FnOnce(&mut T) -> R) -> R {
2402 f(ctx
2403 .values
2404 .write()
2405 .get_mut(&(self.tag_type_id, self.id))
2406 .unwrap()
2407 .downcast_mut()
2408 .unwrap())
2409 }
2410}
2411
2412impl<T> Drop for ValueHandle<T> {
2413 fn drop(&mut self) {
2414 if let Some(ref_counts) = self.ref_counts.upgrade() {
2415 ref_counts.lock().dec_value(self.tag_type_id, self.id);
2416 }
2417 }
2418}
2419
2420#[derive(Default)]
2421struct RefCounts {
2422 entity_counts: HashMap<usize, usize>,
2423 value_counts: HashMap<(TypeId, usize), usize>,
2424 dropped_models: HashSet<usize>,
2425 dropped_views: HashSet<(usize, usize)>,
2426 dropped_values: HashSet<(TypeId, usize)>,
2427}
2428
2429impl RefCounts {
2430 fn inc_entity(&mut self, model_id: usize) {
2431 *self.entity_counts.entry(model_id).or_insert(0) += 1;
2432 }
2433
2434 fn inc_value(&mut self, tag_type_id: TypeId, id: usize) {
2435 *self.value_counts.entry((tag_type_id, id)).or_insert(0) += 1;
2436 }
2437
2438 fn dec_model(&mut self, model_id: usize) {
2439 let count = self.entity_counts.get_mut(&model_id).unwrap();
2440 *count -= 1;
2441 if *count == 0 {
2442 self.entity_counts.remove(&model_id);
2443 self.dropped_models.insert(model_id);
2444 }
2445 }
2446
2447 fn dec_view(&mut self, window_id: usize, view_id: usize) {
2448 let count = self.entity_counts.get_mut(&view_id).unwrap();
2449 *count -= 1;
2450 if *count == 0 {
2451 self.entity_counts.remove(&view_id);
2452 self.dropped_views.insert((window_id, view_id));
2453 }
2454 }
2455
2456 fn dec_value(&mut self, tag_type_id: TypeId, id: usize) {
2457 let key = (tag_type_id, id);
2458 let count = self.value_counts.get_mut(&key).unwrap();
2459 *count -= 1;
2460 if *count == 0 {
2461 self.value_counts.remove(&key);
2462 self.dropped_values.insert(key);
2463 }
2464 }
2465
2466 fn take_dropped(
2467 &mut self,
2468 ) -> (
2469 HashSet<usize>,
2470 HashSet<(usize, usize)>,
2471 HashSet<(TypeId, usize)>,
2472 ) {
2473 let mut dropped_models = HashSet::new();
2474 let mut dropped_views = HashSet::new();
2475 let mut dropped_values = HashSet::new();
2476 std::mem::swap(&mut self.dropped_models, &mut dropped_models);
2477 std::mem::swap(&mut self.dropped_views, &mut dropped_views);
2478 std::mem::swap(&mut self.dropped_values, &mut dropped_values);
2479 (dropped_models, dropped_views, dropped_values)
2480 }
2481}
2482
2483enum Subscription {
2484 FromModel {
2485 model_id: usize,
2486 callback: Box<dyn FnMut(&mut dyn Any, &dyn Any, &mut MutableAppContext, usize)>,
2487 },
2488 FromView {
2489 window_id: usize,
2490 view_id: usize,
2491 callback: Box<dyn FnMut(&mut dyn Any, &dyn Any, &mut MutableAppContext, usize, usize)>,
2492 },
2493}
2494
2495enum Observation {
2496 FromModel {
2497 model_id: usize,
2498 callback: Box<dyn FnMut(&mut dyn Any, usize, &mut MutableAppContext, usize)>,
2499 },
2500 FromView {
2501 window_id: usize,
2502 view_id: usize,
2503 callback: Box<dyn FnMut(&mut dyn Any, usize, &mut MutableAppContext, usize, usize)>,
2504 },
2505}
2506
2507type FutureHandler = Box<dyn FnOnce(Box<dyn Any>, &mut MutableAppContext) -> Box<dyn Any>>;
2508
2509struct StreamHandler {
2510 item_callback: Box<dyn FnMut(Box<dyn Any>, &mut MutableAppContext) -> bool>,
2511 done_callback: Box<dyn FnOnce(&mut MutableAppContext) -> Box<dyn Any>>,
2512}
2513
2514#[must_use]
2515pub struct EntityTask<T> {
2516 id: usize,
2517 task: Option<executor::Task<T>>,
2518 handler_map: TaskHandlerMap,
2519}
2520
2521enum TaskHandlerMap {
2522 Detached,
2523 Future(Rc<RefCell<HashMap<usize, FutureHandler>>>),
2524 Stream(Rc<RefCell<HashMap<usize, StreamHandler>>>),
2525}
2526
2527impl<T> EntityTask<T> {
2528 fn new(id: usize, task: executor::Task<T>, handler_map: TaskHandlerMap) -> Self {
2529 Self {
2530 id,
2531 task: Some(task),
2532 handler_map,
2533 }
2534 }
2535
2536 pub fn detach(mut self) {
2537 self.handler_map = TaskHandlerMap::Detached;
2538 self.task.take().unwrap().detach();
2539 }
2540
2541 pub async fn cancel(mut self) -> Option<T> {
2542 let task = self.task.take().unwrap();
2543 task.cancel().await
2544 }
2545}
2546
2547impl<T> Future for EntityTask<T> {
2548 type Output = T;
2549
2550 fn poll(
2551 self: std::pin::Pin<&mut Self>,
2552 ctx: &mut std::task::Context<'_>,
2553 ) -> std::task::Poll<Self::Output> {
2554 let task = unsafe { self.map_unchecked_mut(|task| task.task.as_mut().unwrap()) };
2555 task.poll(ctx)
2556 }
2557}
2558
2559impl<T> Drop for EntityTask<T> {
2560 fn drop(self: &mut Self) {
2561 match &self.handler_map {
2562 TaskHandlerMap::Detached => {
2563 return;
2564 }
2565 TaskHandlerMap::Future(map) => {
2566 map.borrow_mut().remove(&self.id);
2567 }
2568 TaskHandlerMap::Stream(map) => {
2569 map.borrow_mut().remove(&self.id);
2570 }
2571 }
2572 }
2573}
2574
2575#[cfg(test)]
2576mod tests {
2577 use super::*;
2578 use crate::elements::*;
2579 use smol::future::poll_once;
2580
2581 #[test]
2582 fn test_model_handles() {
2583 struct Model {
2584 other: Option<ModelHandle<Model>>,
2585 events: Vec<String>,
2586 }
2587
2588 impl Entity for Model {
2589 type Event = usize;
2590 }
2591
2592 impl Model {
2593 fn new(other: Option<ModelHandle<Self>>, ctx: &mut ModelContext<Self>) -> Self {
2594 if let Some(other) = other.as_ref() {
2595 ctx.observe(other, |me, _, _| {
2596 me.events.push("notified".into());
2597 });
2598 ctx.subscribe(other, |me, event, _| {
2599 me.events.push(format!("observed event {}", event));
2600 });
2601 }
2602
2603 Self {
2604 other,
2605 events: Vec::new(),
2606 }
2607 }
2608 }
2609
2610 App::test((), |app| {
2611 let handle_1 = app.add_model(|ctx| Model::new(None, ctx));
2612 let handle_2 = app.add_model(|ctx| Model::new(Some(handle_1.clone()), ctx));
2613 assert_eq!(app.ctx.models.len(), 2);
2614
2615 handle_1.update(app, |model, ctx| {
2616 model.events.push("updated".into());
2617 ctx.emit(1);
2618 ctx.notify();
2619 ctx.emit(2);
2620 });
2621 assert_eq!(handle_1.read(app).events, vec!["updated".to_string()]);
2622 assert_eq!(
2623 handle_2.read(app).events,
2624 vec![
2625 "observed event 1".to_string(),
2626 "notified".to_string(),
2627 "observed event 2".to_string(),
2628 ]
2629 );
2630
2631 handle_2.update(app, |model, _| {
2632 drop(handle_1);
2633 model.other.take();
2634 });
2635
2636 assert_eq!(app.ctx.models.len(), 1);
2637 assert!(app.subscriptions.is_empty());
2638 assert!(app.observations.is_empty());
2639 });
2640 }
2641
2642 #[test]
2643 fn test_subscribe_and_emit_from_model() {
2644 #[derive(Default)]
2645 struct Model {
2646 events: Vec<usize>,
2647 }
2648
2649 impl Entity for Model {
2650 type Event = usize;
2651 }
2652
2653 App::test((), |app| {
2654 let handle_1 = app.add_model(|_| Model::default());
2655 let handle_2 = app.add_model(|_| Model::default());
2656 let handle_2b = handle_2.clone();
2657
2658 handle_1.update(app, |_, c| {
2659 c.subscribe(&handle_2, move |model: &mut Model, event, c| {
2660 model.events.push(*event);
2661
2662 c.subscribe(&handle_2b, |model, event, _| {
2663 model.events.push(*event * 2);
2664 });
2665 });
2666 });
2667
2668 handle_2.update(app, |_, c| c.emit(7));
2669 assert_eq!(handle_1.read(app).events, vec![7]);
2670
2671 handle_2.update(app, |_, c| c.emit(5));
2672 assert_eq!(handle_1.read(app).events, vec![7, 10, 5]);
2673 })
2674 }
2675
2676 #[test]
2677 fn test_observe_and_notify_from_model() {
2678 #[derive(Default)]
2679 struct Model {
2680 count: usize,
2681 events: Vec<usize>,
2682 }
2683
2684 impl Entity for Model {
2685 type Event = ();
2686 }
2687
2688 App::test((), |app| {
2689 let handle_1 = app.add_model(|_| Model::default());
2690 let handle_2 = app.add_model(|_| Model::default());
2691 let handle_2b = handle_2.clone();
2692
2693 handle_1.update(app, |_, c| {
2694 c.observe(&handle_2, move |model, observed, c| {
2695 model.events.push(observed.read(c).count);
2696 c.observe(&handle_2b, |model, observed, c| {
2697 model.events.push(observed.read(c).count * 2);
2698 });
2699 });
2700 });
2701
2702 handle_2.update(app, |model, c| {
2703 model.count = 7;
2704 c.notify()
2705 });
2706 assert_eq!(handle_1.read(app).events, vec![7]);
2707
2708 handle_2.update(app, |model, c| {
2709 model.count = 5;
2710 c.notify()
2711 });
2712 assert_eq!(handle_1.read(app).events, vec![7, 10, 5])
2713 })
2714 }
2715
2716 #[test]
2717 fn test_spawn_from_model() {
2718 #[derive(Default)]
2719 struct Model {
2720 count: usize,
2721 }
2722
2723 impl Entity for Model {
2724 type Event = ();
2725 }
2726
2727 App::test_async((), |mut app| async move {
2728 let handle = app.add_model(|_| Model::default());
2729 handle
2730 .update(&mut app, |_, c| {
2731 c.spawn(async { 7 }, |model, output, _| {
2732 model.count = output;
2733 })
2734 })
2735 .await;
2736 app.read(|ctx| assert_eq!(handle.read(ctx).count, 7));
2737
2738 handle
2739 .update(&mut app, |_, c| {
2740 c.spawn(async { 14 }, |model, output, _| {
2741 model.count = output;
2742 })
2743 })
2744 .await;
2745 app.read(|ctx| assert_eq!(handle.read(ctx).count, 14));
2746 });
2747 }
2748
2749 #[test]
2750 fn test_spawn_stream_local_from_model() {
2751 #[derive(Default)]
2752 struct Model {
2753 events: Vec<Option<usize>>,
2754 }
2755
2756 impl Entity for Model {
2757 type Event = ();
2758 }
2759
2760 App::test_async((), |mut app| async move {
2761 let handle = app.add_model(|_| Model::default());
2762 handle
2763 .update(&mut app, |_, c| {
2764 c.spawn_stream(
2765 smol::stream::iter(vec![1, 2, 3]),
2766 |model, output, _| {
2767 model.events.push(Some(output));
2768 },
2769 |model, _| {
2770 model.events.push(None);
2771 },
2772 )
2773 })
2774 .await;
2775 app.read(|ctx| assert_eq!(handle.read(ctx).events, [Some(1), Some(2), Some(3), None]));
2776 })
2777 }
2778
2779 #[test]
2780 fn test_view_handles() {
2781 struct View {
2782 other: Option<ViewHandle<View>>,
2783 events: Vec<String>,
2784 }
2785
2786 impl Entity for View {
2787 type Event = usize;
2788 }
2789
2790 impl super::View for View {
2791 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2792 Empty::new().boxed()
2793 }
2794
2795 fn ui_name() -> &'static str {
2796 "View"
2797 }
2798 }
2799
2800 impl View {
2801 fn new(other: Option<ViewHandle<View>>, ctx: &mut ViewContext<Self>) -> Self {
2802 if let Some(other) = other.as_ref() {
2803 ctx.subscribe_to_view(other, |me, _, event, _| {
2804 me.events.push(format!("observed event {}", event));
2805 });
2806 }
2807 Self {
2808 other,
2809 events: Vec::new(),
2810 }
2811 }
2812 }
2813
2814 App::test((), |app| {
2815 let (window_id, _) = app.add_window(|ctx| View::new(None, ctx));
2816 let handle_1 = app.add_view(window_id, |ctx| View::new(None, ctx));
2817 let handle_2 = app.add_view(window_id, |ctx| View::new(Some(handle_1.clone()), ctx));
2818 assert_eq!(app.ctx.windows[&window_id].views.len(), 3);
2819
2820 handle_1.update(app, |view, ctx| {
2821 view.events.push("updated".into());
2822 ctx.emit(1);
2823 ctx.emit(2);
2824 });
2825 assert_eq!(handle_1.read(app).events, vec!["updated".to_string()]);
2826 assert_eq!(
2827 handle_2.read(app).events,
2828 vec![
2829 "observed event 1".to_string(),
2830 "observed event 2".to_string(),
2831 ]
2832 );
2833
2834 handle_2.update(app, |view, _| {
2835 drop(handle_1);
2836 view.other.take();
2837 });
2838
2839 assert_eq!(app.ctx.windows[&window_id].views.len(), 2);
2840 assert!(app.subscriptions.is_empty());
2841 assert!(app.observations.is_empty());
2842 })
2843 }
2844
2845 #[test]
2846 fn test_subscribe_and_emit_from_view() {
2847 #[derive(Default)]
2848 struct View {
2849 events: Vec<usize>,
2850 }
2851
2852 impl Entity for View {
2853 type Event = usize;
2854 }
2855
2856 impl super::View for View {
2857 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2858 Empty::new().boxed()
2859 }
2860
2861 fn ui_name() -> &'static str {
2862 "View"
2863 }
2864 }
2865
2866 struct Model;
2867
2868 impl Entity for Model {
2869 type Event = usize;
2870 }
2871
2872 App::test((), |app| {
2873 let (window_id, handle_1) = app.add_window(|_| View::default());
2874 let handle_2 = app.add_view(window_id, |_| View::default());
2875 let handle_2b = handle_2.clone();
2876 let handle_3 = app.add_model(|_| Model);
2877
2878 handle_1.update(app, |_, c| {
2879 c.subscribe_to_view(&handle_2, move |me, _, event, c| {
2880 me.events.push(*event);
2881
2882 c.subscribe_to_view(&handle_2b, |me, _, event, _| {
2883 me.events.push(*event * 2);
2884 });
2885 });
2886
2887 c.subscribe_to_model(&handle_3, |me, _, event, _| {
2888 me.events.push(*event);
2889 })
2890 });
2891
2892 handle_2.update(app, |_, c| c.emit(7));
2893 assert_eq!(handle_1.read(app).events, vec![7]);
2894
2895 handle_2.update(app, |_, c| c.emit(5));
2896 assert_eq!(handle_1.read(app).events, vec![7, 10, 5]);
2897
2898 handle_3.update(app, |_, c| c.emit(9));
2899 assert_eq!(handle_1.read(app).events, vec![7, 10, 5, 9]);
2900 })
2901 }
2902
2903 #[test]
2904 fn test_dropping_subscribers() {
2905 struct View;
2906
2907 impl Entity for View {
2908 type Event = ();
2909 }
2910
2911 impl super::View for View {
2912 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2913 Empty::new().boxed()
2914 }
2915
2916 fn ui_name() -> &'static str {
2917 "View"
2918 }
2919 }
2920
2921 struct Model;
2922
2923 impl Entity for Model {
2924 type Event = ();
2925 }
2926
2927 App::test((), |app| {
2928 let (window_id, _) = app.add_window(|_| View);
2929 let observing_view = app.add_view(window_id, |_| View);
2930 let emitting_view = app.add_view(window_id, |_| View);
2931 let observing_model = app.add_model(|_| Model);
2932 let observed_model = app.add_model(|_| Model);
2933
2934 observing_view.update(app, |_, ctx| {
2935 ctx.subscribe_to_view(&emitting_view, |_, _, _, _| {});
2936 ctx.subscribe_to_model(&observed_model, |_, _, _, _| {});
2937 });
2938 observing_model.update(app, |_, ctx| {
2939 ctx.subscribe(&observed_model, |_, _, _| {});
2940 });
2941
2942 app.update(|| {
2943 drop(observing_view);
2944 drop(observing_model);
2945 });
2946
2947 emitting_view.update(app, |_, ctx| ctx.emit(()));
2948 observed_model.update(app, |_, ctx| ctx.emit(()));
2949 })
2950 }
2951
2952 #[test]
2953 fn test_observe_and_notify_from_view() {
2954 #[derive(Default)]
2955 struct View {
2956 events: Vec<usize>,
2957 }
2958
2959 impl Entity for View {
2960 type Event = usize;
2961 }
2962
2963 impl super::View for View {
2964 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2965 Empty::new().boxed()
2966 }
2967
2968 fn ui_name() -> &'static str {
2969 "View"
2970 }
2971 }
2972
2973 #[derive(Default)]
2974 struct Model {
2975 count: usize,
2976 }
2977
2978 impl Entity for Model {
2979 type Event = ();
2980 }
2981
2982 App::test((), |app| {
2983 let (_, view) = app.add_window(|_| View::default());
2984 let model = app.add_model(|_| Model::default());
2985
2986 view.update(app, |_, c| {
2987 c.observe(&model, |me, observed, c| {
2988 me.events.push(observed.read(c).count)
2989 });
2990 });
2991
2992 model.update(app, |model, c| {
2993 model.count = 11;
2994 c.notify();
2995 });
2996 assert_eq!(view.read(app).events, vec![11]);
2997 })
2998 }
2999
3000 #[test]
3001 fn test_dropping_observers() {
3002 struct View;
3003
3004 impl Entity for View {
3005 type Event = ();
3006 }
3007
3008 impl super::View for View {
3009 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3010 Empty::new().boxed()
3011 }
3012
3013 fn ui_name() -> &'static str {
3014 "View"
3015 }
3016 }
3017
3018 struct Model;
3019
3020 impl Entity for Model {
3021 type Event = ();
3022 }
3023
3024 App::test((), |app| {
3025 let (window_id, _) = app.add_window(|_| View);
3026 let observing_view = app.add_view(window_id, |_| View);
3027 let observing_model = app.add_model(|_| Model);
3028 let observed_model = app.add_model(|_| Model);
3029
3030 observing_view.update(app, |_, ctx| {
3031 ctx.observe(&observed_model, |_, _, _| {});
3032 });
3033 observing_model.update(app, |_, ctx| {
3034 ctx.observe(&observed_model, |_, _, _| {});
3035 });
3036
3037 app.update(|| {
3038 drop(observing_view);
3039 drop(observing_model);
3040 });
3041
3042 observed_model.update(app, |_, ctx| ctx.notify());
3043 })
3044 }
3045
3046 #[test]
3047 fn test_focus() {
3048 #[derive(Default)]
3049 struct View {
3050 events: Vec<String>,
3051 }
3052
3053 impl Entity for View {
3054 type Event = String;
3055 }
3056
3057 impl super::View for View {
3058 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3059 Empty::new().boxed()
3060 }
3061
3062 fn ui_name() -> &'static str {
3063 "View"
3064 }
3065
3066 fn on_focus(&mut self, ctx: &mut ViewContext<Self>) {
3067 self.events.push("self focused".into());
3068 ctx.emit("focused".into());
3069 }
3070
3071 fn on_blur(&mut self, ctx: &mut ViewContext<Self>) {
3072 self.events.push("self blurred".into());
3073 ctx.emit("blurred".into());
3074 }
3075 }
3076
3077 App::test((), |app| {
3078 let (window_id, view_1) = app.add_window(|_| View::default());
3079 let view_2 = app.add_view(window_id, |_| View::default());
3080
3081 view_1.update(app, |_, ctx| {
3082 ctx.subscribe_to_view(&view_2, |view_1, _, event, _| {
3083 view_1.events.push(format!("view 2 {}", event));
3084 });
3085 ctx.focus(&view_2);
3086 });
3087
3088 view_1.update(app, |_, ctx| {
3089 ctx.focus(&view_1);
3090 });
3091
3092 assert_eq!(
3093 view_1.read(app).events,
3094 [
3095 "self focused".to_string(),
3096 "self blurred".to_string(),
3097 "view 2 focused".to_string(),
3098 "self focused".to_string(),
3099 "view 2 blurred".to_string(),
3100 ],
3101 );
3102 })
3103 }
3104
3105 #[test]
3106 fn test_spawn_from_view() {
3107 #[derive(Default)]
3108 struct View {
3109 count: usize,
3110 }
3111
3112 impl Entity for View {
3113 type Event = ();
3114 }
3115
3116 impl super::View for View {
3117 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3118 Empty::new().boxed()
3119 }
3120
3121 fn ui_name() -> &'static str {
3122 "View"
3123 }
3124 }
3125
3126 App::test_async((), |mut app| async move {
3127 let handle = app.add_window(|_| View::default()).1;
3128 handle
3129 .update(&mut app, |_, c| {
3130 c.spawn(async { 7 }, |me, output, _| {
3131 me.count = output;
3132 })
3133 })
3134 .await;
3135 app.read(|ctx| assert_eq!(handle.read(ctx).count, 7));
3136 handle
3137 .update(&mut app, |_, c| {
3138 c.spawn(async { 14 }, |me, output, _| {
3139 me.count = output;
3140 })
3141 })
3142 .await;
3143 app.read(|ctx| assert_eq!(handle.read(ctx).count, 14));
3144 });
3145 }
3146
3147 #[test]
3148 fn test_spawn_stream_local_from_view() {
3149 #[derive(Default)]
3150 struct View {
3151 events: Vec<Option<usize>>,
3152 }
3153
3154 impl Entity for View {
3155 type Event = ();
3156 }
3157
3158 impl super::View for View {
3159 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3160 Empty::new().boxed()
3161 }
3162
3163 fn ui_name() -> &'static str {
3164 "View"
3165 }
3166 }
3167
3168 App::test_async((), |mut app| async move {
3169 let (_, handle) = app.add_window(|_| View::default());
3170 handle
3171 .update(&mut app, |_, c| {
3172 c.spawn_stream(
3173 smol::stream::iter(vec![1_usize, 2, 3]),
3174 |me, output, _| {
3175 me.events.push(Some(output));
3176 },
3177 |me, _| {
3178 me.events.push(None);
3179 },
3180 )
3181 })
3182 .await;
3183
3184 app.read(|ctx| assert_eq!(handle.read(ctx).events, [Some(1), Some(2), Some(3), None]))
3185 });
3186 }
3187
3188 #[test]
3189 fn test_dispatch_action() {
3190 struct ViewA {
3191 id: usize,
3192 }
3193
3194 impl Entity for ViewA {
3195 type Event = ();
3196 }
3197
3198 impl View for ViewA {
3199 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3200 Empty::new().boxed()
3201 }
3202
3203 fn ui_name() -> &'static str {
3204 "View"
3205 }
3206 }
3207
3208 struct ViewB {
3209 id: usize,
3210 }
3211
3212 impl Entity for ViewB {
3213 type Event = ();
3214 }
3215
3216 impl View for ViewB {
3217 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3218 Empty::new().boxed()
3219 }
3220
3221 fn ui_name() -> &'static str {
3222 "View"
3223 }
3224 }
3225
3226 struct ActionArg {
3227 foo: String,
3228 }
3229
3230 App::test((), |app| {
3231 let actions = Rc::new(RefCell::new(Vec::new()));
3232
3233 let actions_clone = actions.clone();
3234 app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| {
3235 actions_clone.borrow_mut().push("global a".to_string());
3236 });
3237
3238 let actions_clone = actions.clone();
3239 app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| {
3240 actions_clone.borrow_mut().push("global b".to_string());
3241 });
3242
3243 let actions_clone = actions.clone();
3244 app.add_action("action", move |view: &mut ViewA, arg: &ActionArg, ctx| {
3245 assert_eq!(arg.foo, "bar");
3246 ctx.propagate_action();
3247 actions_clone.borrow_mut().push(format!("{} a", view.id));
3248 });
3249
3250 let actions_clone = actions.clone();
3251 app.add_action("action", move |view: &mut ViewA, _: &ActionArg, ctx| {
3252 if view.id != 1 {
3253 ctx.propagate_action();
3254 }
3255 actions_clone.borrow_mut().push(format!("{} b", view.id));
3256 });
3257
3258 let actions_clone = actions.clone();
3259 app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| {
3260 ctx.propagate_action();
3261 actions_clone.borrow_mut().push(format!("{} c", view.id));
3262 });
3263
3264 let actions_clone = actions.clone();
3265 app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| {
3266 ctx.propagate_action();
3267 actions_clone.borrow_mut().push(format!("{} d", view.id));
3268 });
3269
3270 let (window_id, view_1) = app.add_window(|_| ViewA { id: 1 });
3271 let view_2 = app.add_view(window_id, |_| ViewB { id: 2 });
3272 let view_3 = app.add_view(window_id, |_| ViewA { id: 3 });
3273 let view_4 = app.add_view(window_id, |_| ViewB { id: 4 });
3274
3275 app.dispatch_action(
3276 window_id,
3277 vec![view_1.id(), view_2.id(), view_3.id(), view_4.id()],
3278 "action",
3279 ActionArg { foo: "bar".into() },
3280 );
3281
3282 assert_eq!(
3283 *actions.borrow(),
3284 vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "1 b"]
3285 );
3286
3287 // Remove view_1, which doesn't propagate the action
3288 actions.borrow_mut().clear();
3289 app.dispatch_action(
3290 window_id,
3291 vec![view_2.id(), view_3.id(), view_4.id()],
3292 "action",
3293 ActionArg { foo: "bar".into() },
3294 );
3295
3296 assert_eq!(
3297 *actions.borrow(),
3298 vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "global b", "global a"]
3299 );
3300 })
3301 }
3302
3303 #[test]
3304 fn test_dispatch_keystroke() {
3305 use std::cell::Cell;
3306
3307 #[derive(Clone)]
3308 struct ActionArg {
3309 key: String,
3310 }
3311
3312 struct View {
3313 id: usize,
3314 keymap_context: keymap::Context,
3315 }
3316
3317 impl Entity for View {
3318 type Event = ();
3319 }
3320
3321 impl super::View for View {
3322 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3323 Empty::new().boxed()
3324 }
3325
3326 fn ui_name() -> &'static str {
3327 "View"
3328 }
3329
3330 fn keymap_context(&self, _: &AppContext) -> keymap::Context {
3331 self.keymap_context.clone()
3332 }
3333 }
3334
3335 impl View {
3336 fn new(id: usize) -> Self {
3337 View {
3338 id,
3339 keymap_context: keymap::Context::default(),
3340 }
3341 }
3342 }
3343
3344 App::test((), |app| {
3345 let mut view_1 = View::new(1);
3346 let mut view_2 = View::new(2);
3347 let mut view_3 = View::new(3);
3348 view_1.keymap_context.set.insert("a".into());
3349 view_2.keymap_context.set.insert("b".into());
3350 view_3.keymap_context.set.insert("c".into());
3351
3352 let (window_id, view_1) = app.add_window(|_| view_1);
3353 let view_2 = app.add_view(window_id, |_| view_2);
3354 let view_3 = app.add_view(window_id, |_| view_3);
3355
3356 // This keymap's only binding dispatches an action on view 2 because that view will have
3357 // "a" and "b" in its context, but not "c".
3358 let binding = keymap::Binding::new("a", "action", Some("a && b && !c"))
3359 .with_arg(ActionArg { key: "a".into() });
3360 app.add_bindings(vec![binding]);
3361
3362 let handled_action = Rc::new(Cell::new(false));
3363 let handled_action_clone = handled_action.clone();
3364 app.add_action("action", move |view: &mut View, arg: &ActionArg, _ctx| {
3365 handled_action_clone.set(true);
3366 assert_eq!(view.id, 2);
3367 assert_eq!(arg.key, "a");
3368 });
3369
3370 app.dispatch_keystroke(
3371 window_id,
3372 vec![view_1.id(), view_2.id(), view_3.id()],
3373 &Keystroke::parse("a").unwrap(),
3374 )
3375 .unwrap();
3376
3377 assert!(handled_action.get());
3378 });
3379 }
3380
3381 #[test]
3382 fn test_model_condition() {
3383 struct Counter(usize);
3384
3385 impl super::Entity for Counter {
3386 type Event = ();
3387 }
3388
3389 impl Counter {
3390 fn inc(&mut self, ctx: &mut ModelContext<Self>) {
3391 self.0 += 1;
3392 ctx.notify();
3393 }
3394 }
3395
3396 App::test_async((), |mut app| async move {
3397 let model = app.add_model(|_| Counter(0));
3398
3399 let condition1 = model.condition(&app, |model, _| model.0 == 2);
3400 let condition2 = model.condition(&app, |model, _| model.0 == 3);
3401 smol::pin!(condition1, condition2);
3402
3403 model.update(&mut app, |model, ctx| model.inc(ctx));
3404 assert_eq!(poll_once(&mut condition1).await, None);
3405 assert_eq!(poll_once(&mut condition2).await, None);
3406
3407 model.update(&mut app, |model, ctx| model.inc(ctx));
3408 assert_eq!(poll_once(&mut condition1).await, Some(()));
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 condition2).await, Some(()));
3413
3414 // Broadcast channel should be removed if no conditions remain on next notification.
3415 model.update(&mut app, |_, ctx| ctx.notify());
3416 app.update(|ctx| assert!(ctx.async_observations.get(&model.id()).is_none()));
3417 });
3418 }
3419
3420 #[test]
3421 #[should_panic]
3422 fn test_model_condition_timeout() {
3423 struct Model;
3424
3425 impl super::Entity for Model {
3426 type Event = ();
3427 }
3428
3429 App::test_async((), |mut app| async move {
3430 let model = app.add_model(|_| Model);
3431 model.condition(&app, |_, _| false).await;
3432 });
3433 }
3434
3435 #[test]
3436 #[should_panic(expected = "model dropped with pending condition")]
3437 fn test_model_condition_panic_on_drop() {
3438 struct Model;
3439
3440 impl super::Entity for Model {
3441 type Event = ();
3442 }
3443
3444 App::test_async((), |mut app| async move {
3445 let model = app.add_model(|_| Model);
3446 let condition = model.condition(&app, |_, _| false);
3447 app.update(|_| drop(model));
3448 condition.await;
3449 });
3450 }
3451
3452 #[test]
3453 fn test_view_condition() {
3454 struct Counter(usize);
3455
3456 impl super::Entity for Counter {
3457 type Event = ();
3458 }
3459
3460 impl super::View for Counter {
3461 fn ui_name() -> &'static str {
3462 "test view"
3463 }
3464
3465 fn render(&self, _: &AppContext) -> ElementBox {
3466 Empty::new().boxed()
3467 }
3468 }
3469
3470 impl Counter {
3471 fn inc(&mut self, ctx: &mut ViewContext<Self>) {
3472 self.0 += 1;
3473 ctx.notify();
3474 }
3475 }
3476
3477 App::test_async((), |mut app| async move {
3478 let (_, view) = app.add_window(|_| Counter(0));
3479
3480 let condition1 = view.condition(&app, |view, _| view.0 == 2);
3481 let condition2 = view.condition(&app, |view, _| view.0 == 3);
3482 smol::pin!(condition1, condition2);
3483
3484 view.update(&mut app, |view, ctx| view.inc(ctx));
3485 assert_eq!(poll_once(&mut condition1).await, None);
3486 assert_eq!(poll_once(&mut condition2).await, None);
3487
3488 view.update(&mut app, |view, ctx| view.inc(ctx));
3489 assert_eq!(poll_once(&mut condition1).await, Some(()));
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 condition2).await, Some(()));
3494
3495 // Broadcast channel should be removed if no conditions remain on next notification.
3496 view.update(&mut app, |_, ctx| ctx.notify());
3497 app.update(|ctx| assert!(ctx.async_observations.get(&view.id()).is_none()));
3498 });
3499 }
3500
3501 #[test]
3502 #[should_panic]
3503 fn test_view_condition_timeout() {
3504 struct View;
3505
3506 impl super::Entity for View {
3507 type Event = ();
3508 }
3509
3510 impl super::View for View {
3511 fn ui_name() -> &'static str {
3512 "test view"
3513 }
3514
3515 fn render(&self, _: &AppContext) -> ElementBox {
3516 Empty::new().boxed()
3517 }
3518 }
3519
3520 App::test_async((), |mut app| async move {
3521 let (_, view) = app.add_window(|_| View);
3522 view.condition(&app, |_, _| false).await;
3523 });
3524 }
3525
3526 #[test]
3527 #[should_panic(expected = "model dropped with pending condition")]
3528 fn test_view_condition_panic_on_drop() {
3529 struct View;
3530
3531 impl super::Entity for View {
3532 type Event = ();
3533 }
3534
3535 impl super::View for View {
3536 fn ui_name() -> &'static str {
3537 "test view"
3538 }
3539
3540 fn render(&self, _: &AppContext) -> ElementBox {
3541 Empty::new().boxed()
3542 }
3543 }
3544
3545 App::test_async((), |mut app| async move {
3546 let window_id = app.add_window(|_| View).0;
3547 let view = app.add_view(window_id, |_| View);
3548
3549 let condition = view.condition(&app, |_, _| false);
3550 app.update(|_| drop(view));
3551 condition.await;
3552 });
3553 }
3554
3555 // #[test]
3556 // fn test_ui_and_window_updates() {
3557 // struct View {
3558 // count: usize,
3559 // }
3560
3561 // impl Entity for View {
3562 // type Event = ();
3563 // }
3564
3565 // impl super::View for View {
3566 // fn render<'a>(&self, _: &AppContext) -> ElementBox {
3567 // Empty::new().boxed()
3568 // }
3569
3570 // fn ui_name() -> &'static str {
3571 // "View"
3572 // }
3573 // }
3574
3575 // App::test(|app| async move {
3576 // let (window_id, _) = app.add_window(|_| View { count: 3 });
3577 // let view_1 = app.add_view(window_id, |_| View { count: 1 });
3578 // let view_2 = app.add_view(window_id, |_| View { count: 2 });
3579
3580 // // Ensure that registering for UI updates after mutating the app still gives us all the
3581 // // updates.
3582 // let ui_updates = Rc::new(RefCell::new(Vec::new()));
3583 // let ui_updates_ = ui_updates.clone();
3584 // app.on_ui_update(move |update, _| ui_updates_.borrow_mut().push(update));
3585
3586 // assert_eq!(
3587 // ui_updates.borrow_mut().drain(..).collect::<Vec<_>>(),
3588 // vec![UiUpdate::OpenWindow {
3589 // window_id,
3590 // width: 1024.0,
3591 // height: 768.0,
3592 // }]
3593 // );
3594
3595 // let window_invalidations = Rc::new(RefCell::new(Vec::new()));
3596 // let window_invalidations_ = window_invalidations.clone();
3597 // app.on_window_invalidated(window_id, move |update, _| {
3598 // window_invalidations_.borrow_mut().push(update)
3599 // });
3600
3601 // let view_2_id = view_2.id();
3602 // view_1.update(app, |view, ctx| {
3603 // view.count = 7;
3604 // ctx.notify();
3605 // drop(view_2);
3606 // });
3607
3608 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3609 // assert_eq!(invalidation.updated.len(), 1);
3610 // assert!(invalidation.updated.contains(&view_1.id()));
3611 // assert_eq!(invalidation.removed, vec![view_2_id]);
3612
3613 // let view_3 = view_1.update(app, |_, ctx| ctx.add_view(|_| View { count: 8 }));
3614
3615 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3616 // assert_eq!(invalidation.updated.len(), 1);
3617 // assert!(invalidation.updated.contains(&view_3.id()));
3618 // assert!(invalidation.removed.is_empty());
3619
3620 // view_3
3621 // .update(app, |_, ctx| {
3622 // ctx.spawn_local(async { 9 }, |me, output, ctx| {
3623 // me.count = output;
3624 // ctx.notify();
3625 // })
3626 // })
3627 // .await;
3628
3629 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3630 // assert_eq!(invalidation.updated.len(), 1);
3631 // assert!(invalidation.updated.contains(&view_3.id()));
3632 // assert!(invalidation.removed.is_empty());
3633 // });
3634 // }
3635}