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