1use std::sync::atomic::Ordering;
2
3use anathema_backend::Backend;
4use anathema_default_widgets::register_default_widgets;
5use anathema_geometry::Size;
6use anathema_templates::{Document, Expression, ToSourceKind, Variables};
7use anathema_value_resolver::{Function, FunctionTable};
8use anathema_widgets::components::deferred::DeferredComponents;
9use anathema_widgets::components::events::Event;
10use anathema_widgets::components::{Component, ComponentId, ComponentRegistry, Emitter, ViewMessage};
11use anathema_widgets::tabindex::TabIndex;
12use anathema_widgets::{Factory, Widget};
13use notify::{Event as NotifyEvent, RecommendedWatcher, RecursiveMode, Watcher, recommended_watcher};
14
15use crate::REBUILD;
16pub use crate::error::{Error, Result};
17use crate::events::GlobalEventHandler;
18use crate::runtime::{Runtime, show_error};
19
20pub struct Builder<G> {
21 factory: Factory,
22 document: Document,
23 component_registry: ComponentRegistry,
24 emitter: Emitter,
25 message_receiver: flume::Receiver<ViewMessage>,
26 fps: u32,
27 size: Size,
28 global_event_handler: G,
29 hot_reload: bool,
30 function_table: FunctionTable,
31 variables: Variables,
32}
33
34impl<G: GlobalEventHandler> Builder<G> {
35 pub(super) fn with_receiver(
38 message_receiver: flume::Receiver<ViewMessage>,
39 emitter: Emitter,
40 document: Document,
41 size: Size,
42 global_event_handler: G,
43 ) -> Self {
44 let mut factory = Factory::new();
45 register_default_widgets(&mut factory);
46
47 Self {
48 factory,
49 document,
50 component_registry: ComponentRegistry::new(),
51 emitter,
52 message_receiver,
53 fps: 30,
54 size,
55 global_event_handler,
56 hot_reload: true,
57 function_table: FunctionTable::new(),
58 variables: Variables::new(),
59 }
60 }
61
62 pub(super) fn new(document: Document, size: Size, global_event_handler: G) -> Self {
64 let (tx, rx) = flume::unbounded();
65 let emitter = Emitter::from(tx);
66 Self::with_receiver(rx, emitter.clone(), document, size, global_event_handler)
67 }
68
69 pub fn hot_reload(&mut self, value: bool) {
71 self.hot_reload = value;
72 }
73
74 pub fn register_widget<T: Widget + Default + 'static>(&mut self, ident: &'static str) {
76 self.factory.register_default::<T>(ident);
77 }
78
79 pub fn fps(&mut self, fps: u32) {
81 self.fps = fps;
82 }
83
84 pub fn emitter(&self) -> Emitter {
86 self.emitter.clone()
87 }
88
89 pub fn template(&mut self, ident: impl Into<String>, template: impl ToSourceKind) -> Result<()> {
93 self.prototype(ident, template, || (), || ())
94 }
95
96 pub fn component<C: Component>(
103 &mut self,
104 ident: impl Into<String>,
105 template: impl ToSourceKind,
106 component: C,
107 state: C::State,
108 ) -> Result<ComponentId<C::Message>> {
109 let id = self.document.add_component(ident, template.to_source_kind())?;
110 self.component_registry.add_component(id, component, state);
111 Ok(id.into())
112 }
113
114 pub fn default<C>(
118 &mut self,
119 ident: impl Into<String>,
120 template: impl ToSourceKind,
121 ) -> Result<ComponentId<C::Message>>
122 where
123 C: Component + Default,
124 C::State: Default,
125 {
126 let component = C::default();
127 let state = C::State::default();
128 let id = self.document.add_component(ident, template.to_source_kind())?;
129 self.component_registry.add_component(id, component, state);
130 Ok(id.into())
131 }
132
133 pub fn prototype<FC, FS, C>(
136 &mut self,
137 ident: impl Into<String>,
138 template: impl ToSourceKind,
139 proto: FC,
140 state: FS,
141 ) -> Result<()>
142 where
143 FC: 'static + Fn() -> C,
144 FS: 'static + FnMut() -> C::State,
145 C: Component + 'static,
146 {
147 let id = self.document.add_component(ident, template.to_source_kind())?;
148 self.component_registry.add_prototype(id, proto, state);
149 Ok(())
150 }
151
152 pub fn with_global_event_handler<Eh>(self, global_event_handler: Eh) -> Builder<Eh>
155 where
156 Eh: Fn(Event, &mut TabIndex<'_, '_>, &mut DeferredComponents) -> Option<Event>,
157 {
158 Builder {
159 factory: self.factory,
160 document: self.document,
161 component_registry: self.component_registry,
162 emitter: self.emitter,
163 message_receiver: self.message_receiver,
164 fps: self.fps,
165 size: self.size,
166 global_event_handler,
167 hot_reload: self.hot_reload,
168 function_table: self.function_table,
169 variables: Variables::new(),
170 }
171 }
172
173 pub fn register_global(&mut self, key: impl Into<String>, value: impl Into<Expression>) -> Result<()> {
174 self.variables.define_global(key, value).map_err(|e| e.to_error(None))?;
175 Ok(())
176 }
177
178 pub fn finish<F, B>(mut self, backend: &mut B, mut f: F) -> Result<()>
179 where
180 F: FnMut(&mut Runtime<G>, &mut B) -> Result<()>,
181 B: Backend,
182 {
183 #[cfg(feature = "profile")]
184 let _puffin_server = {
185 let server_addr = format!("127.0.0.1:{}", puffin_http::DEFAULT_PORT);
186 let server = puffin_http::Server::new(&server_addr).unwrap();
187 puffin::set_scopes_on(true);
188 server
189 };
190
191 let blueprint = loop {
192 match self.document.compile(&mut self.variables) {
193 Ok(val) => break val,
194 Err(error) => match show_error(error.into(), backend, &self.document) {
197 Ok(()) => return Err(Error::Stop),
198 Err(Error::Reload) if self.hot_reload => {
199 _ = self.document.reload_templates();
200 }
201 err => err?,
202 },
203 }
204 };
205
206 let watcher = self.set_watcher(self.hot_reload)?;
207
208 let mut inst = Runtime::new(
209 blueprint,
210 self.variables,
211 self.component_registry,
212 self.document,
213 self.factory,
214 self.message_receiver,
215 self.emitter,
216 watcher,
217 self.size,
218 self.fps,
219 self.global_event_handler,
220 self.function_table,
221 self.hot_reload,
222 );
223
224 f(&mut inst, backend)
225 }
226
227 fn set_watcher(&mut self, hot_reload: bool) -> Result<Option<RecommendedWatcher>> {
228 if !hot_reload {
229 return Ok(None);
230 }
231
232 let paths = self
233 .document
234 .template_paths()
235 .filter_map(|p| p.canonicalize().ok())
236 .collect::<Vec<_>>();
237
238 let mut watcher = recommended_watcher(move |event: std::result::Result<NotifyEvent, _>| match event {
239 Ok(event) => match event.kind {
240 notify::EventKind::Create(_) | notify::EventKind::Remove(_) | notify::EventKind::Modify(_) => {
241 if paths.iter().any(|p| event.paths.contains(p)) {
242 REBUILD.store(true, Ordering::Relaxed);
243 }
244 }
245 notify::EventKind::Any | notify::EventKind::Access(_) | notify::EventKind::Other => (),
246 },
247 Err(_err) => (),
248 })?;
249
250 for path in self.document.template_paths() {
251 let path = path.canonicalize().unwrap();
252
253 if let Some(parent) = path.parent() {
254 watcher.watch(parent, RecursiveMode::NonRecursive)?;
255 }
256 }
257
258 Ok(Some(watcher))
259 }
260
261 pub fn register_function(&mut self, ident: impl Into<String>, f: impl Into<Function>) -> Result<()> {
262 Ok(self.function_table.insert(ident, f)?)
263 }
264}