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