use std::{ any::{Any, TypeId}, collections::HashMap, sync::{Arc, Mutex}, }; use crate::{ engine::{Command, CommandExecutor}, render::DrawContext, state::{use_effect, HookDependency}, View, ViewWrapper, }; pub type Component = Arc) -> View + Send + Sync>; pub type EventHandler = Arc, &dyn Any) + Send + Sync>>; pub struct Scope { pub children: Mutex, Option)>>, executor: Arc, } pub struct Context { component: Mutex, event_handlers: Mutex>>, view: Mutex, pub(crate) scopes: Mutex>>, executor: Arc, } impl Context { pub fn new) -> View + Send + Sync + 'static>( component: F, executor: Arc, ) -> Arc { Arc::new(Self { component: Mutex::new(Arc::new(component)), event_handlers: Mutex::new(HashMap::new()), view: Mutex::new(Arc::new(|_| {})), scopes: Mutex::new(Vec::new()), executor, }) } pub fn refresh(self: &Arc) { let s = self.clone(); std::thread::spawn({ move || { s.event_handlers.lock().unwrap().clear(); let c = s.component.lock().unwrap().clone(); *s.view.lock().unwrap() = (c)(&s); } }); } pub fn refresh_atomic(self: &Arc) -> Arc> { let s = self.clone(); let done = Arc::new(Mutex::new(false)); std::thread::spawn({ let done = done.clone(); move || { s.event_handlers.lock().unwrap().clear(); let c = s.component.lock().unwrap().clone(); *s.view.lock().unwrap() = (c)(&s); *done.lock().unwrap() = true; } }); done } pub fn get_view(self: &Arc) -> View { self.view.lock().unwrap().clone() } pub fn on_event, &T) + Send + Sync + 'static>( self: &Arc, handler: F, ) { self.event_handlers .lock() .unwrap() .entry(TypeId::of::()) .or_insert_with(|| Vec::new()) .push(Arc::new(Mutex::new( move |ctx: &Arc, event: &dyn Any| { if let Some(e) = event.downcast_ref::() { (handler)(ctx, e); } }, ))); } pub fn emit_event(self: &Arc, event: &E) { if let Some(v) = self.event_handlers.lock().unwrap().get(&TypeId::of::()) { for i in v { (i.lock().unwrap())(self, event); } } for scope in self.scopes.lock().unwrap().iter() { for (child, _) in scope.children.lock().unwrap().iter() { child.emit_event(event); } } } pub fn emit_event_threaded( self: &Arc, event: &E, ) { if let Some(v) = self.event_handlers.lock().unwrap().get(&TypeId::of::()) { for i in v { let i = i.clone(); let event = event.clone(); let s = self.clone(); std::thread::spawn(move || { (i.lock().unwrap())(&s, &event); }); } } for scope in self.scopes.lock().unwrap().iter() { for (child, _) in scope.children.lock().unwrap().iter() { child.emit_event_threaded(event); } } } pub fn scope(self: &Arc) -> Arc { let scope = Scope::new(self.executor.clone()); self.scopes.lock().unwrap().push(scope.clone()); scope } pub fn dyn_scope) + Send + Sync + 'static>( self: &Arc, drawer: F, dependencies: &[&dyn HookDependency], ) -> Arc { let scope = Scope::new(self.executor.clone()); self.scopes.lock().unwrap().push(scope.clone()); drawer(&scope); use_effect( { let scope = scope.clone(); move || { drawer(&scope); } }, dependencies, ); scope } pub fn draw_children(self: &Arc, ctx: &mut DrawContext) { for scope in self.scopes.lock().unwrap().iter() { for (child, view_wrapper) in scope.children.lock().unwrap().iter() { let view = child.get_view(); if let Some(view_wrapper) = view_wrapper { view_wrapper(ctx, view) } else { ctx.draw_view(ctx.area.clone(), view); } } } } pub fn get_executor(self: &Arc) -> Arc { self.executor.clone() } pub fn execute(self: &Arc, command: T) -> crate::Result<()> { self.executor .execute_command(&(Arc::new(command) as Arc)) } pub fn stop(self: &Arc) -> crate::Result<()> { self.execute(crate::engine::commands::Stop) } } impl Scope { pub fn new(executor: Arc) -> Arc { Arc::new(Self { children: Mutex::new(Vec::new()), executor, }) } pub fn child) -> View + Send + Sync + 'static>( self: &Arc, child: F, view_wrapper: Option, ) { let ctx = Context::new(child, self.executor.clone()); ctx.refresh(); self.children.lock().unwrap().push((ctx, view_wrapper)); } pub fn view(self: &Arc, view: View) { let ctx = Context::new(move |_| view.clone(), self.executor.clone()); ctx.refresh(); self.children.lock().unwrap().push((ctx, None)); } }