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