1use std::sync::atomic::Ordering;
2use std::time::{Duration, Instant};
3
4use anathema_backend::{Backend, WidgetCycle};
5use anathema_geometry::Size;
6use anathema_state::{Changes, StateId, States, clear_all_changes, clear_all_subs, drain_changes};
7use anathema_store::tree::root_node;
8use anathema_templates::blueprints::Blueprint;
9use anathema_templates::{Document, Globals};
10use anathema_value_resolver::{AttributeStorage, Scope};
11use anathema_widgets::components::deferred::{CommandKind, DeferredComponents};
12use anathema_widgets::components::events::Event;
13use anathema_widgets::components::{
14 AnyComponentContext, AssociatedEvents, ComponentKind, ComponentRegistry, Emitter, ViewMessage,
15};
16use anathema_widgets::layout::{LayoutCtx, Viewport};
17use anathema_widgets::query::Children;
18use anathema_widgets::tabindex::{Index, TabIndex};
19use anathema_widgets::{
20 Component, Components, Factory, FloatingWidgets, GlyphMap, WidgetContainer, WidgetId, WidgetKind, WidgetTree,
21 eval_blueprint, update_widget,
22};
23use flume::Receiver;
24use notify::RecommendedWatcher;
25
26use crate::builder::Builder;
27pub use crate::error::Result;
28use crate::events::GlobalEventHandler;
29use crate::{Error, REBUILD};
30
31mod testing;
32
33pub struct Runtime<G> {
34 pub(super) blueprint: Blueprint,
35 pub(super) globals: Globals,
36 pub(super) factory: Factory,
37 pub(super) states: States,
38 pub(super) component_registry: ComponentRegistry,
39 pub(super) components: Components,
40 pub(super) document: Document,
41 pub(super) floating_widgets: FloatingWidgets,
42 pub(super) assoc_events: AssociatedEvents,
43 pub(super) glyph_map: GlyphMap,
44 pub(super) changes: Changes,
45 pub(super) viewport: Viewport,
46 pub(super) emitter: Emitter,
47 pub(super) sleep_micros: u64,
48 pub(super) message_receiver: flume::Receiver<ViewMessage>,
49 pub(super) dt: Instant,
50 pub(super) _watcher: Option<RecommendedWatcher>,
51 pub(super) deferred_components: DeferredComponents,
52 pub(super) global_event_handler: G,
53}
54
55impl Runtime<()> {
56 pub fn builder<B: Backend>(doc: Document, backend: &B) -> Builder<()> {
57 Builder::new(doc, backend.size(), ())
58 }
59}
60
61impl<G: GlobalEventHandler> Runtime<G> {
62 pub(crate) fn new(
63 component_registry: ComponentRegistry,
64 mut document: Document,
65 mut err_document: Document,
66 factory: Factory,
67 message_receiver: Receiver<ViewMessage>,
68 emitter: Emitter,
69 watcher: Option<RecommendedWatcher>,
70 size: Size,
71 fps: u32,
72 global_event_handler: G,
73 ) -> Result<Self> {
74 let (blueprint, globals) = document.compile()?;
75 let Ok((_err_blueprint, _err_globals)) = err_document.compile() else {
76 panic!("the error display failed to compile")
77 };
78
79 let sleep_micros: u64 = ((1.0 / fps as f64) * 1000.0 * 1000.0) as u64;
80
81 let inst = Self {
82 component_registry,
83 components: Components::new(),
84 document,
85 factory,
86 states: States::new(),
87 floating_widgets: FloatingWidgets::empty(),
88 assoc_events: AssociatedEvents::new(),
89 glyph_map: GlyphMap::empty(),
90 blueprint,
91 globals,
92 changes: Changes::empty(),
93 viewport: Viewport::new(size),
94 message_receiver,
95 emitter,
96 dt: Instant::now(),
97 _watcher: watcher,
98 deferred_components: DeferredComponents::new(),
99 sleep_micros,
100 global_event_handler,
101 };
102 Ok(inst)
103 }
104
105 pub fn with_frame<B, F>(&mut self, backend: &mut B, mut f: F) -> Result<()>
109 where
110 B: Backend,
111 F: FnMut(&mut B, Frame<'_, '_, G>) -> Result<()>,
112 {
113 let mut tree = WidgetTree::empty();
114 let mut attribute_storage = AttributeStorage::empty();
115 let mut frame = self.next_frame(&mut tree, &mut attribute_storage)?;
116 frame.init_tree()?;
117 f(backend, frame)
118 }
119
120 pub fn run<B: Backend>(&mut self, backend: &mut B) -> Result<()> {
121 let sleep_micros = self.sleep_micros;
122 self.with_frame(backend, |backend, mut frame| {
123 frame.tick(backend)?;
127
128 let mut tabindex = TabIndex::new(&mut frame.tabindex, frame.tree.view_mut());
129 tabindex.next();
130
131 if let Some(current) = frame.tabindex.as_ref() {
132 frame.with_component(current.widget_id, current.state_id, |comp, children, ctx| {
133 comp.dyn_component.any_focus(children, ctx)
134 });
135 }
136
137 loop {
138 frame.tick(backend)?;
139 if frame.stop {
140 return Err(Error::Stop);
141 }
142
143 frame.present(backend);
144 frame.cleanup();
145 std::thread::sleep(Duration::from_micros(sleep_micros));
146
147 if REBUILD.swap(false, Ordering::Relaxed) {
148 frame.return_state();
149 backend.clear();
150 break Ok(());
151 }
152 }
153 })?;
154
155 Ok(())
156 }
157
158 pub fn next_frame<'frame, 'bp>(
159 &'bp mut self,
160 tree: &'frame mut WidgetTree<'bp>,
161 attribute_storage: &'frame mut AttributeStorage<'bp>,
162 ) -> Result<Frame<'frame, 'bp, G>> {
163 let layout_ctx = LayoutCtx::new(
164 &self.globals,
165 &self.factory,
166 &mut self.states,
167 attribute_storage,
168 &mut self.components,
169 &mut self.component_registry,
170 &mut self.floating_widgets,
171 &mut self.glyph_map,
172 &mut self.viewport,
173 );
174
175 let inst = Frame {
176 document: &self.document,
177 blueprint: &self.blueprint,
178 tree,
179 layout_ctx,
180 changes: &mut self.changes,
181 sleep_micros: self.sleep_micros,
182
183 assoc_events: &mut self.assoc_events,
184 deferred_components: &mut self.deferred_components,
185
186 emitter: &self.emitter,
187 message_receiver: &self.message_receiver,
188
189 dt: &mut self.dt,
190 needs_layout: true,
191 stop: false,
192
193 global_event_handler: &self.global_event_handler,
194 tabindex: None,
195 };
196
197 Ok(inst)
198 }
199
200 pub(super) fn reload(&mut self) -> Result<()> {
201 clear_all_changes();
202 clear_all_subs();
203
204 self.components = Components::new();
205 self.floating_widgets = FloatingWidgets::empty();
206
207 self.document.reload_templates()?;
209
210 let (blueprint, globals) = self.document.compile()?;
211 self.blueprint = blueprint;
212 self.globals = globals;
213
214 Ok(())
215 }
216}
217
218pub struct Frame<'rt, 'bp, G> {
219 document: &'bp Document,
220 blueprint: &'bp Blueprint,
221 pub tree: &'rt mut WidgetTree<'bp>,
222 deferred_components: &'rt mut DeferredComponents,
223 layout_ctx: LayoutCtx<'rt, 'bp>,
224 changes: &'rt mut Changes,
225 assoc_events: &'rt mut AssociatedEvents,
226 sleep_micros: u64,
227 emitter: &'rt Emitter,
228 message_receiver: &'rt flume::Receiver<ViewMessage>,
229 dt: &'rt mut Instant,
230 needs_layout: bool,
231 stop: bool,
232 global_event_handler: &'rt G,
233 pub tabindex: Option<Index>,
234}
235
236impl<'rt, 'bp, G: GlobalEventHandler> Frame<'rt, 'bp, G> {
237 pub fn handle_global_event(&mut self, event: Event) -> Option<Event> {
238 let mut tabindex = TabIndex::new(&mut self.tabindex, self.tree.view_mut());
239
240 let event = self
241 .global_event_handler
242 .handle(event, &mut tabindex, self.deferred_components);
243
244 if tabindex.changed {
245 let prev = tabindex.consume();
246 if let Some(prev) = prev {
247 self.with_component(prev.widget_id, prev.state_id, |comp, children, ctx| {
248 comp.dyn_component.any_blur(children, ctx)
249 });
250 }
251
252 if let Some(current) = self.tabindex.as_ref() {
253 self.with_component(current.widget_id, current.state_id, |comp, children, ctx| {
254 comp.dyn_component.any_focus(children, ctx)
255 });
256 }
257 }
258
259 event
260 }
261
262 pub fn event(&mut self, event: Event) {
263 #[cfg(feature = "profile")]
264 puffin::profile_function!();
265
266 let Some(event) = self.handle_global_event(event) else { return };
267 if let Event::Stop = event {
268 self.stop = true;
269 return;
270 }
271
272 match event {
273 Event::Noop => (),
274 Event::Stop => todo!(),
275
276 Event::Blur | Event::Focus | Event::Key(_) => {
278 let Some(Index {
279 widget_id, state_id, ..
280 }) = self.tabindex
281 else {
282 return;
283 };
284 self.send_event_to_component(event, widget_id, state_id);
285 }
286 Event::Mouse(_) | Event::Resize(_) => {
287 for i in 0..self.layout_ctx.components.len() {
288 let Some((widget_id, state_id)) = self.layout_ctx.components.get(i) else { continue };
289 self.send_event_to_component(event, widget_id, state_id);
290 }
291 }
292 Event::Tick(_) => panic!("this event should never be sent to the runtime"),
293 }
294 }
295
296 pub fn init_tree(&mut self) -> Result<()> {
298 let mut ctx = self.layout_ctx.eval_ctx(None);
299 eval_blueprint(
300 self.blueprint,
301 &mut ctx,
302 &Scope::root(),
303 root_node(),
304 &mut self.tree.view_mut(),
305 )?;
306
307 Ok(())
308 }
309
310 pub fn tick<B: Backend>(&mut self, backend: &mut B) -> Result<Duration> {
311 #[cfg(feature = "profile")]
312 puffin::GlobalProfiler::lock().new_frame();
313
314 let now = Instant::now();
315 self.cycle(backend)?;
316 self.tick_components(self.dt.elapsed());
317 let elapsed = self.handle_messages(now);
318 self.poll_events(elapsed, now, backend);
319 self.drain_deferred_commands();
320 self.drain_assoc_events();
321 self.apply_changes()?;
322 self.apply_changes()?;
325
326 *self.dt = Instant::now();
327 Ok(now.elapsed())
328 }
329
330 pub fn present<B: Backend>(&mut self, backend: &mut B) -> Duration {
331 #[cfg(feature = "profile")]
332 puffin::profile_function!();
333
334 let now = Instant::now();
335 backend.render(self.layout_ctx.glyph_map);
336 backend.clear();
337 now.elapsed()
338 }
339
340 pub fn cleanup(&mut self) {
341 #[cfg(feature = "profile")]
342 puffin::profile_function!();
343 for key in self.tree.drain_removed() {
344 self.layout_ctx.attribute_storage.try_remove(key);
345 self.layout_ctx.floating_widgets.try_remove(key);
346 self.layout_ctx.components.try_remove(key);
347 if let Some(Index { widget_id, .. }) = self.tabindex {
348 if widget_id == key {
349 self.tabindex.take();
350 }
351 }
352 }
353 }
354
355 fn handle_messages(&mut self, fps_now: Instant) -> Duration {
356 #[cfg(feature = "profile")]
357 puffin::profile_function!();
358
359 while let Ok(msg) = self.message_receiver.try_recv() {
360 if let Some((widget_id, state_id)) = self
361 .layout_ctx
362 .components
363 .get_by_component_id(msg.recipient())
364 .map(|e| (e.widget_id, e.state_id))
365 {
366 self.with_component(widget_id, state_id, |comp, elements, ctx| {
367 comp.dyn_component.any_message(elements, ctx, msg.payload())
368 });
369 }
370
371 if fps_now.elapsed().as_micros() as u64 >= self.sleep_micros / 2 {
373 break;
374 }
375 }
376
377 fps_now.elapsed()
378 }
379
380 fn poll_events<B: Backend>(&mut self, remaining: Duration, fps_now: Instant, backend: &mut B) {
381 while let Some(event) = backend.next_event(remaining) {
382 if let Event::Resize(size) = event {
383 self.layout_ctx.viewport.resize(size);
384 self.needs_layout = true;
385 backend.resize(size, self.layout_ctx.glyph_map);
386 }
387
388 self.event(event);
389
390 if fps_now.elapsed().as_micros() as u64 > self.sleep_micros {
392 break;
393 }
394 }
395 }
396
397 fn drain_deferred_commands(&mut self) {
398 #[cfg(feature = "profile")]
399 puffin::profile_function!();
400
401 let commands = self.deferred_components.drain().collect::<Vec<_>>();
406 for mut cmd in commands {
407 for index in 0..self.layout_ctx.components.len() {
408 let Some((widget_id, state_id)) = self.layout_ctx.components.get(index) else { continue };
409 let Some(comp) = self.tree.get_ref(widget_id) else { continue };
410 let WidgetContainer {
411 kind: WidgetKind::Component(comp),
412 ..
413 } = comp
414 else {
415 continue;
416 };
417 let attributes = self.layout_ctx.attribute_storage.get(widget_id);
418 if !cmd.filter_component(comp, attributes) {
419 continue;
420 }
421
422 if let CommandKind::Focus = cmd.kind {
429 if let Some(index) = self.tabindex.as_ref() {
431 if index.widget_id == widget_id {
432 continue;
433 }
434 }
435
436 let new_index = self
438 .with_component(widget_id, state_id, |comp, children, ctx| {
439 if comp.dyn_component.any_accept_focus() {
440 let index = Index {
441 path: children.parent_path().into(),
442 index: comp.tabindex,
443 widget_id,
444 state_id,
445 };
446
447 comp.dyn_component.any_focus(children, ctx);
448
449 Some(index)
450 } else {
451 None
452 }
453 })
454 .flatten();
455
456 if let Some(index) = new_index {
457 if let Some(old) = self.tabindex.replace(index) {
460 self.with_component(old.widget_id, old.state_id, |comp, children, ctx| {
461 comp.dyn_component.any_blur(children, ctx)
462 });
463 }
464 }
465 }
466
467 if let CommandKind::SendMessage(msg) = cmd.kind {
471 self.with_component(widget_id, state_id, |comp, children, ctx| {
472 comp.dyn_component.any_message(children, ctx, msg);
473 });
474 }
475 break;
476 }
477 }
478 }
479
480 fn drain_assoc_events(&mut self) {
481 #[cfg(feature = "profile")]
482 puffin::profile_function!();
483
484 while let Some(assoc_event) = self.assoc_events.next() {
485 let mut parent = assoc_event.parent;
486 let external_ident = self.document.strings.get_ref_unchecked(assoc_event.external());
487 let internal_ident = self.document.strings.get_ref_unchecked(assoc_event.internal());
488 let sender = self.document.strings.get_ref_unchecked(assoc_event.sender);
489 let mut event = assoc_event.to_event(internal_ident, external_ident, sender);
490
491 loop {
492 let Some((widget_id, state_id)) = self.layout_ctx.components.get_by_widget_id(parent.into()) else {
493 return;
494 };
495
496 let stop_propagation = self
497 .with_component(widget_id, state_id, |comp, children, ctx| {
498 let next_parent = ctx.parent();
499 comp.dyn_component.any_component_event(children, ctx, &mut event);
500
501 parent = match next_parent {
502 Some(p) => p,
503 None => return true,
504 };
505
506 event.should_stop_propagation()
507 })
508 .unwrap_or(true);
509
510 if stop_propagation {
511 break;
512 }
513 }
514 }
515 }
516
517 fn cycle<B: Backend>(&mut self, backend: &mut B) -> Result<()> {
518 #[cfg(feature = "profile")]
519 puffin::profile_function!();
520
521 let mut cycle = WidgetCycle::new(backend, self.tree.view_mut(), self.layout_ctx.viewport.constraints());
522 cycle.run(&mut self.layout_ctx, self.needs_layout)?;
523
524 self.needs_layout = false;
525 Ok(())
526 }
527
528 fn apply_changes(&mut self) -> Result<()> {
529 #[cfg(feature = "profile")]
530 puffin::profile_function!();
531
532 drain_changes(self.changes);
533
534 if self.changes.is_empty() {
535 return Ok(());
536 }
537
538 self.needs_layout = true;
539 let mut tree = self.tree.view_mut();
540
541 self.changes.iter().try_for_each(|(sub, change)| {
542 sub.iter().try_for_each(|value_id| {
543 let widget_id = value_id.key();
544
545 if let Some(widget) = tree.get_mut(widget_id) {
546 let kind = &widget.kind;
547 match kind {
548 WidgetKind::Element(_element) => {}
549 WidgetKind::For(_forloop) => {}
550 WidgetKind::Iteration(_) => {}
551 _ => (), }
556 if let WidgetKind::Element(element) = &mut widget.kind {
557 element.invalidate_cache();
558 }
559 }
560
561 if !tree.contains(widget_id) {
563 return Result::Ok(());
564 }
565
566 tree.with_value_mut(widget_id, |_path, widget, tree| {
567 update_widget(widget, value_id, change, tree, self.layout_ctx.attribute_storage)
568 })
569 .unwrap_or(Ok(()))?;
570
571 Ok(())
572 })?;
573
574 Result::Ok(())
575 })?;
576
577 self.changes.clear();
578
579 Ok(())
580 }
581
582 fn send_event_to_component(&mut self, event: Event, widget_id: WidgetId, state_id: StateId) {
583 self.with_component(widget_id, state_id, |comp, elements, ctx| {
584 comp.dyn_component.any_event(elements, ctx, event);
585 });
586 }
587
588 fn with_component<F, U>(&mut self, widget_id: WidgetId, state_id: StateId, f: F) -> Option<U>
589 where
590 F: FnOnce(&mut Component<'_>, Children<'_, '_>, AnyComponentContext<'_, '_>) -> U,
591 {
592 let mut tree = self.tree.view_mut();
593
594 tree.with_value_mut(widget_id, |_path, container, children| {
595 let WidgetKind::Component(component) = &mut container.kind else {
596 panic!("this is always a component")
597 };
598
599 let Some(state) = self.layout_ctx.states.get_mut(state_id) else {
600 panic!("a component always has a state")
601 };
602
603 self.layout_ctx
604 .attribute_storage
605 .with_mut(widget_id, |attributes, storage| {
606 let elements = Children::new(children, storage, &mut self.needs_layout);
607
608 let ctx = AnyComponentContext::new(
609 component.parent.map(Into::into),
610 component.name_id,
611 state_id,
612 component.assoc_functions,
613 self.assoc_events,
614 self.deferred_components,
615 attributes,
616 Some(state),
617 self.emitter,
618 self.layout_ctx.viewport,
619 &self.document.strings,
620 );
621
622 f(component, elements, ctx)
623 })
624 })?
625 }
626
627 fn tick_components(&mut self, dt: Duration) {
628 #[cfg(feature = "profile")]
629 puffin::profile_function!();
630
631 for i in 0..self.layout_ctx.components.len() {
632 let Some((widget_id, state_id)) = self.layout_ctx.components.get_ticking(i) else { continue };
633 let event = Event::Tick(dt);
634 self.send_event_to_component(event, widget_id, state_id);
635 }
636 }
637
638 fn return_state(self) {
640 let mut tree = WidgetTree::empty();
642 std::mem::swap(&mut tree, self.tree);
643
644 for (_, widget) in tree.values().into_iter() {
645 let WidgetKind::Component(comp) = widget.kind else { continue };
646 let ComponentKind::Instance = comp.kind else { continue };
647 let state = self.layout_ctx.states.remove(comp.state_id).take();
648 self.layout_ctx
649 .component_registry
650 .return_component(comp.component_id, comp.dyn_component, state);
651 }
652 }
653
654 }