use crate::{ AnyView, AnyWindowHandle, AppCell, AppContext, BackgroundExecutor, Context, DismissEvent, FocusableView, ForegroundExecutor, Model, ModelContext, Render, Result, Task, View, ViewContext, VisualContext, WindowContext, WindowHandle, }; use anyhow::{anyhow, Context as _}; use derive_more::{Deref, DerefMut}; use std::{future::Future, rc::Weak}; #[derive(Clone)] pub struct AsyncAppContext { pub(crate) app: Weak, pub(crate) background_executor: BackgroundExecutor, pub(crate) foreground_executor: ForegroundExecutor, } impl Context for AsyncAppContext { type Result = Result; fn new_model( &mut self, build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T, ) -> Self::Result> where T: 'static, { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let mut app = app.borrow_mut(); Ok(app.new_model(build_model)) } fn update_model( &mut self, handle: &Model, update: impl FnOnce(&mut T, &mut ModelContext<'_, T>) -> R, ) -> Self::Result { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let mut app = app.borrow_mut(); Ok(app.update_model(handle, update)) } fn read_model( &self, handle: &Model, callback: impl FnOnce(&T, &AppContext) -> R, ) -> Self::Result where T: 'static, { let app = self.app.upgrade().context("app was released")?; let lock = app.borrow(); Ok(lock.read_model(handle, callback)) } fn update_window(&mut self, window: AnyWindowHandle, f: F) -> Result where F: FnOnce(AnyView, &mut WindowContext<'_>) -> T, { let app = self.app.upgrade().context("app was released")?; let mut lock = app.borrow_mut(); lock.update_window(window, f) } fn read_window( &self, window: &WindowHandle, read: impl FnOnce(View, &AppContext) -> R, ) -> Result where T: 'static, { let app = self.app.upgrade().context("app was released")?; let lock = app.borrow(); lock.read_window(window, read) } } impl AsyncAppContext { pub fn refresh(&mut self) -> Result<()> { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let mut lock = app.borrow_mut(); lock.refresh(); Ok(()) } pub fn background_executor(&self) -> &BackgroundExecutor { &self.background_executor } pub fn foreground_executor(&self) -> &ForegroundExecutor { &self.foreground_executor } pub fn update(&self, f: impl FnOnce(&mut AppContext) -> R) -> Result { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let mut lock = app.borrow_mut(); Ok(f(&mut lock)) } pub fn open_window( &self, options: crate::WindowOptions, build_root_view: impl FnOnce(&mut WindowContext) -> View, ) -> Result> where V: 'static + Render, { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let mut lock = app.borrow_mut(); Ok(lock.open_window(options, build_root_view)) } pub fn spawn(&self, f: impl FnOnce(AsyncAppContext) -> Fut) -> Task where Fut: Future + 'static, R: 'static, { self.foreground_executor.spawn(f(self.clone())) } pub fn has_global(&self) -> Result { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let app = app.borrow_mut(); Ok(app.has_global::()) } pub fn read_global(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let app = app.borrow_mut(); Ok(read(app.global(), &app)) } pub fn try_read_global( &self, read: impl FnOnce(&G, &AppContext) -> R, ) -> Option { let app = self.app.upgrade()?; let app = app.borrow_mut(); Some(read(app.try_global()?, &app)) } pub fn update_global( &mut self, update: impl FnOnce(&mut G, &mut AppContext) -> R, ) -> Result { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let mut app = app.borrow_mut(); Ok(app.update_global(update)) } } #[derive(Clone, Deref, DerefMut)] pub struct AsyncWindowContext { #[deref] #[deref_mut] app: AsyncAppContext, window: AnyWindowHandle, } impl AsyncWindowContext { pub fn window_handle(&self) -> AnyWindowHandle { self.window } pub(crate) fn new(app: AsyncAppContext, window: AnyWindowHandle) -> Self { Self { app, window } } pub fn update( &mut self, update: impl FnOnce(AnyView, &mut WindowContext) -> R, ) -> Result { self.app.update_window(self.window, update) } pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + 'static) { self.window.update(self, |_, cx| cx.on_next_frame(f)).ok(); } pub fn read_global( &mut self, read: impl FnOnce(&G, &WindowContext) -> R, ) -> Result { self.window.update(self, |_, cx| read(cx.global(), cx)) } pub fn update_global( &mut self, update: impl FnOnce(&mut G, &mut WindowContext) -> R, ) -> Result where G: 'static, { self.window.update(self, |_, cx| cx.update_global(update)) } pub fn spawn(&self, f: impl FnOnce(AsyncWindowContext) -> Fut) -> Task where Fut: Future + 'static, R: 'static, { self.foreground_executor.spawn(f(self.clone())) } } impl Context for AsyncWindowContext { type Result = Result; fn new_model( &mut self, build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T, ) -> Result> where T: 'static, { self.window.update(self, |_, cx| cx.new_model(build_model)) } fn update_model( &mut self, handle: &Model, update: impl FnOnce(&mut T, &mut ModelContext<'_, T>) -> R, ) -> Result { self.window .update(self, |_, cx| cx.update_model(handle, update)) } fn update_window(&mut self, window: AnyWindowHandle, update: F) -> Result where F: FnOnce(AnyView, &mut WindowContext<'_>) -> T, { self.app.update_window(window, update) } fn read_model( &self, handle: &Model, read: impl FnOnce(&T, &AppContext) -> R, ) -> Self::Result where T: 'static, { self.app.read_model(handle, read) } fn read_window( &self, window: &WindowHandle, read: impl FnOnce(View, &AppContext) -> R, ) -> Result where T: 'static, { self.app.read_window(window, read) } } impl VisualContext for AsyncWindowContext { fn new_view( &mut self, build_view_state: impl FnOnce(&mut ViewContext<'_, V>) -> V, ) -> Self::Result> where V: 'static + Render, { self.window .update(self, |_, cx| cx.new_view(build_view_state)) } fn update_view( &mut self, view: &View, update: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R, ) -> Self::Result { self.window .update(self, |_, cx| cx.update_view(view, update)) } fn replace_root_view( &mut self, build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V, ) -> Self::Result> where V: 'static + Render, { self.window .update(self, |_, cx| cx.replace_root_view(build_view)) } fn focus_view(&mut self, view: &View) -> Self::Result<()> where V: FocusableView, { self.window.update(self, |_, cx| { view.read(cx).focus_handle(cx).clone().focus(cx); }) } fn dismiss_view(&mut self, view: &View) -> Self::Result<()> where V: crate::ManagedView, { self.window .update(self, |_, cx| view.update(cx, |_, cx| cx.emit(DismissEvent))) } }