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, ToSourceKind};
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}
32
33impl<G: GlobalEventHandler> Builder<G> {
34 pub(super) fn with_receiver(
37 message_receiver: flume::Receiver<ViewMessage>,
38 emitter: Emitter,
39 document: Document,
40 size: Size,
41 global_event_handler: G,
42 ) -> Self {
43 let mut factory = Factory::new();
44 register_default_widgets(&mut factory);
45
46 Self {
47 factory,
48 document,
49 component_registry: ComponentRegistry::new(),
50 emitter,
51 message_receiver,
52 fps: 30,
53 size,
54 global_event_handler,
55 hot_reload: true,
56 function_table: FunctionTable::new(),
57 }
58 }
59
60 pub(super) fn new(document: Document, size: Size, global_event_handler: G) -> Self {
62 let (tx, rx) = flume::unbounded();
63 let emitter = Emitter::from(tx);
64 Self::with_receiver(rx, emitter.clone(), document, size, global_event_handler)
65 }
66
67 pub fn hot_reload(&mut self, value: bool) {
69 self.hot_reload = value;
70 }
71
72 pub fn register_widget<T: Widget + Default + 'static>(&mut self, ident: &'static str) {
74 self.factory.register_default::<T>(ident);
75 }
76
77 pub fn fps(&mut self, fps: u32) {
79 self.fps = fps;
80 }
81
82 pub fn emitter(&self) -> Emitter {
84 self.emitter.clone()
85 }
86
87 pub fn template(&mut self, ident: impl Into<String>, template: impl ToSourceKind) -> Result<()> {
91 self.prototype(ident, template, || (), || ())
92 }
93
94 pub fn component<C: Component>(
101 &mut self,
102 ident: impl Into<String>,
103 template: impl ToSourceKind,
104 component: C,
105 state: C::State,
106 ) -> Result<ComponentId<C::Message>> {
107 let id = self.document.add_component(ident, template.to_source_kind())?;
108 self.component_registry.add_component(id, component, state);
109 Ok(id.into())
110 }
111
112 pub fn default<C>(
116 &mut self,
117 ident: impl Into<String>,
118 template: impl ToSourceKind,
119 ) -> Result<ComponentId<C::Message>>
120 where
121 C: Component + Default,
122 C::State: Default,
123 {
124 let component = C::default();
125 let state = C::State::default();
126 let id = self.document.add_component(ident, template.to_source_kind())?;
127 self.component_registry.add_component(id, component, state);
128 Ok(id.into())
129 }
130
131 pub fn prototype<FC, FS, C>(
134 &mut self,
135 ident: impl Into<String>,
136 template: impl ToSourceKind,
137 proto: FC,
138 state: FS,
139 ) -> Result<()>
140 where
141 FC: 'static + Fn() -> C,
142 FS: 'static + FnMut() -> C::State,
143 C: Component + 'static,
144 {
145 let id = self.document.add_component(ident, template.to_source_kind())?;
146 self.component_registry.add_prototype(id, proto, state);
147 Ok(())
148 }
149
150 pub fn with_global_event_handler<Eh>(self, global_event_handler: Eh) -> Builder<Eh>
153 where
154 Eh: Fn(Event, &mut TabIndex<'_, '_>, &mut DeferredComponents) -> Option<Event>,
155 {
156 Builder {
157 factory: self.factory,
158 document: self.document,
159 component_registry: self.component_registry,
160 emitter: self.emitter,
161 message_receiver: self.message_receiver,
162 fps: self.fps,
163 size: self.size,
164 global_event_handler,
165 hot_reload: self.hot_reload,
166 function_table: self.function_table,
167 }
168 }
169
170 pub fn finish<F, B>(mut self, backend: &mut B, mut f: F) -> Result<()>
171 where
172 F: FnMut(&mut Runtime<G>, &mut B) -> Result<()>,
173 B: Backend,
174 {
175 #[cfg(feature = "profile")]
176 let _puffin_server = {
177 let server_addr = format!("127.0.0.1:{}", puffin_http::DEFAULT_PORT);
178 let server = puffin_http::Server::new(&server_addr).unwrap();
179 puffin::set_scopes_on(true);
180 server
181 };
182
183 let (blueprint, globals) = loop {
184 match self.document.compile() {
185 Ok(val) => break val,
186 Err(error) => match show_error(error.into(), backend, &self.document) {
189 Ok(()) => return Err(Error::Stop),
190 Err(Error::Reload) if self.hot_reload => {
191 _ = self.document.reload_templates();
192 }
193 err => err?,
194 },
195 }
196 };
197
198 let watcher = self.set_watcher(self.hot_reload)?;
199
200 let mut inst = Runtime::new(
201 blueprint,
202 globals,
203 self.component_registry,
204 self.document,
205 self.factory,
206 self.message_receiver,
207 self.emitter,
208 watcher,
209 self.size,
210 self.fps,
211 self.global_event_handler,
212 self.function_table,
213 self.hot_reload,
214 );
215
216 f(&mut inst, backend)
217 }
218
219 fn set_watcher(&mut self, hot_reload: bool) -> Result<Option<RecommendedWatcher>> {
220 if !hot_reload {
221 return Ok(None);
222 }
223
224 let paths = self
225 .document
226 .template_paths()
227 .filter_map(|p| p.canonicalize().ok())
228 .collect::<Vec<_>>();
229
230 let mut watcher = recommended_watcher(move |event: std::result::Result<NotifyEvent, _>| match event {
231 Ok(event) => match event.kind {
232 notify::EventKind::Create(_) | notify::EventKind::Remove(_) | notify::EventKind::Modify(_) => {
233 if paths.iter().any(|p| event.paths.contains(p)) {
234 REBUILD.store(true, Ordering::Relaxed);
235 }
236 }
237 notify::EventKind::Any | notify::EventKind::Access(_) | notify::EventKind::Other => (),
238 },
239 Err(_err) => (),
240 })?;
241
242 for path in self.document.template_paths() {
243 let path = path.canonicalize().unwrap();
244
245 if let Some(parent) = path.parent() {
246 watcher.watch(parent, RecursiveMode::NonRecursive)?;
247 }
248 }
249
250 Ok(Some(watcher))
251 }
252
253 pub fn register_function(&mut self, ident: impl Into<String>, f: impl Into<Function>) -> Result<()> {
254 Ok(self.function_table.insert(ident, f)?)
255 }
256}