1use std::sync::atomic::Ordering;
2
3use anathema_default_widgets::register_default_widgets;
4use anathema_geometry::Size;
5use anathema_templates::{Document, ToSourceKind};
6use anathema_widgets::components::deferred::DeferredComponents;
7use anathema_widgets::components::events::Event;
8use anathema_widgets::components::{Component, ComponentId, ComponentRegistry, Emitter, ViewMessage};
9use anathema_widgets::tabindex::TabIndex;
10use anathema_widgets::{Factory, Widget};
11use notify::{Event as NotifyEvent, RecommendedWatcher, RecursiveMode, Watcher, recommended_watcher};
12
13use crate::REBUILD;
14pub use crate::error::{Error, Result};
15use crate::events::GlobalEventHandler;
16use crate::runtime::Runtime;
17
18fn error_doc() -> Document {
19 let template = "text 'you goofed up'";
20 Document::new(template)
21}
22
23pub struct Builder<G> {
24 factory: Factory,
25 document: Document,
26 component_registry: ComponentRegistry,
27 emitter: Emitter,
28 message_receiver: flume::Receiver<ViewMessage>,
29 fps: u32,
30 size: Size,
31 global_event_handler: G,
32}
33
34impl<G: GlobalEventHandler> Builder<G> {
35 pub(super) fn new(document: Document, size: Size, global_event_handler: G) -> Self {
37 let mut factory = Factory::new();
38 register_default_widgets(&mut factory);
39
40 let (tx, message_receiver) = flume::unbounded();
41 let emitter = tx.into();
42
43 Self {
44 factory,
45 document,
46 component_registry: ComponentRegistry::new(),
47 emitter,
48 message_receiver,
49 fps: 30,
50 size,
51 global_event_handler,
52 }
53 }
54
55 pub fn register_widget<T: Widget + Default + 'static>(&mut self, ident: &'static str) {
56 self.factory.register_default::<T>(ident);
57 }
58
59 pub fn fps(&mut self, fps: u32) {
60 self.fps = fps;
61 }
62
63 pub fn emitter(&self) -> Emitter {
65 self.emitter.clone()
66 }
67
68 pub fn template(&mut self, ident: impl Into<String>, template: impl ToSourceKind) -> Result<()> {
72 self.prototype(ident, template, || (), || ())
73 }
74
75 pub fn component<C: Component>(
82 &mut self,
83 ident: impl Into<String>,
84 template: impl ToSourceKind,
85 component: C,
86 state: C::State,
87 ) -> Result<ComponentId<C::Message>> {
88 let id = self.document.add_component(ident, template.to_source_kind())?;
89 self.component_registry.add_component(id, component, state);
90 Ok(id.into())
91 }
92
93 pub fn default<C>(
97 &mut self,
98 ident: impl Into<String>,
99 template: impl ToSourceKind,
100 ) -> Result<ComponentId<C::Message>>
101 where
102 C: Component + Default,
103 C::State: Default,
104 {
105 let component = C::default();
106 let state = C::State::default();
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 prototype<FC, FS, C>(
115 &mut self,
116 ident: impl Into<String>,
117 template: impl ToSourceKind,
118 proto: FC,
119 state: FS,
120 ) -> Result<()>
121 where
122 FC: 'static + Fn() -> C,
123 FS: 'static + FnMut() -> C::State,
124 C: Component + 'static,
125 {
126 let id = self.document.add_component(ident, template.to_source_kind())?;
127 self.component_registry.add_prototype(id, proto, state);
128 Ok(())
129 }
130
131 pub fn with_global_event_handler<Eh>(self, global_event_handler: Eh) -> Builder<Eh>
132 where
133 Eh: Fn(Event, &mut TabIndex<'_, '_>, &mut DeferredComponents) -> Option<Event>,
134 {
135 Builder {
136 factory: self.factory,
137 document: self.document,
138 component_registry: self.component_registry,
139 emitter: self.emitter,
140 message_receiver: self.message_receiver,
141 fps: self.fps,
142 size: self.size,
143 global_event_handler,
144 }
145 }
146
147 pub fn finish<F>(mut self, mut f: F) -> Result<()>
148 where
149 F: FnMut(&mut Runtime<G>) -> Result<()>,
150 {
151 #[cfg(feature = "profile")]
152 let _puffin_server = {
153 let server_addr = format!("127.0.0.1:{}", puffin_http::DEFAULT_PORT);
154 let server = puffin_http::Server::new(&server_addr).unwrap();
155 puffin::set_scopes_on(true);
156 server
157 };
158
159 let watcher = self.set_watcher()?;
160
161 let mut inst = Runtime::new(
162 self.component_registry,
163 self.document,
164 error_doc(),
165 self.factory,
166 self.message_receiver,
167 self.emitter,
168 Some(watcher),
169 self.size,
170 self.fps,
171 self.global_event_handler,
172 )?;
173
174 loop {
178 match f(&mut inst) {
179 Ok(()) => (),
180 e => match e {
181 Ok(_) => continue,
182 Err(Error::Stop) => break Ok(()),
183 Err(Error::Template(_error)) => todo!(),
184 Err(Error::Widget(err)) => panic!("this should not panic in the future: {err}"),
185 Err(e) => break Err(e),
186 },
187 }
188 match inst.reload() {
189 Ok(()) => continue,
190 Err(Error::Stop) => todo!(),
191 Err(Error::Template(_error)) => todo!(),
192 Err(Error::Widget(_error)) => todo!(),
193 Err(e) => break Err(e),
194 }
195 }
196 }
197
198 fn set_watcher(&mut self) -> Result<RecommendedWatcher> {
199 let paths = self
200 .document
201 .template_paths()
202 .filter_map(|p| p.canonicalize().ok())
203 .collect::<Vec<_>>();
204
205 let mut watcher = recommended_watcher(move |event: std::result::Result<NotifyEvent, _>| match event {
206 Ok(event) => match event.kind {
207 notify::EventKind::Create(_) | notify::EventKind::Remove(_) | notify::EventKind::Modify(_) => {
208 if paths.iter().any(|p| event.paths.contains(p)) {
209 REBUILD.store(true, Ordering::Relaxed);
210 }
211 }
212 notify::EventKind::Any | notify::EventKind::Access(_) | notify::EventKind::Other => (),
213 },
214 Err(_err) => (),
215 })?;
216
217 for path in self.document.template_paths() {
218 let path = path.canonicalize().unwrap();
219
220 if let Some(parent) = path.parent() {
221 watcher.watch(parent, RecursiveMode::NonRecursive)?;
222 }
223 }
224
225 Ok(watcher)
226 }
227}