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