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