1use std::collections::VecDeque;
2use std::sync::atomic::Ordering;
3use std::time::{Duration, Instant};
4
5use anathema_backend::{Backend, WidgetCycle};
6use anathema_geometry::Size;
7use anathema_state::{Changes, StateId, States, clear_all_changes, clear_all_subs, drain_changes};
8use anathema_store::tree::root_node;
9use anathema_templates::blueprints::Blueprint;
10use anathema_templates::{Document, Expression, Variables};
11use anathema_value_resolver::{AttributeStorage, FunctionTable, Scope};
12use anathema_widgets::components::deferred::{CommandKind, DeferredComponents};
13use anathema_widgets::components::events::{Event, EventType};
14use anathema_widgets::components::{
15 AnyComponentContext, AssociatedEvents, ComponentKind, ComponentRegistry, Emitter, MessageReceiver, Recipient,
16 ViewMessage,
17};
18use anathema_widgets::layout::{LayoutCtx, Viewport};
19use anathema_widgets::query::Children;
20use anathema_widgets::tabindex::{Index, TabIndex};
21use anathema_widgets::{
22 Component, Components, DirtyWidgets, Factory, FloatingWidgets, GlyphMap, WidgetContainer, WidgetId, WidgetKind,
23 WidgetTree, eval_blueprint, update_widget,
24};
25use flume::Receiver;
26use notify::RecommendedWatcher;
27
28pub(crate) use self::error::show_error;
29use crate::builder::Builder;
30pub use crate::error::Result;
31use crate::events::GlobalEventHandler;
32use crate::{Error, REBUILD};
33
34mod error;
35mod testing;
36
37pub struct Runtime<G> {
39 pub(super) blueprint: Blueprint,
40 pub(super) variables: Variables,
41 pub(super) factory: Factory,
42 pub(super) states: States,
43 pub(super) component_registry: ComponentRegistry,
44 pub(super) components: Components,
45 pub(super) document: Document,
46 pub(super) floating_widgets: FloatingWidgets,
47 pub(super) assoc_events: AssociatedEvents,
48 pub(super) glyph_map: GlyphMap,
49 pub(super) changes: Changes,
50 pub(super) viewport: Viewport,
51 pub(super) emitter: Emitter,
52 pub(super) sleep_micros: u64,
53 pub(super) message_receiver: flume::Receiver<ViewMessage>,
54 pub(super) dt: Instant,
55 pub(super) _watcher: Option<RecommendedWatcher>,
56 pub(super) deferred_components: DeferredComponents,
57 pub(super) global_event_handler: G,
58 pub(super) function_table: FunctionTable,
59 pub(super) hot_reload: bool,
60}
61
62impl Runtime<()> {
63 pub fn builder<B: Backend>(doc: Document, backend: &B) -> Builder<()> {
65 Builder::new(doc, backend.size(), ())
66 }
67
68 pub fn register_global(&mut self, key: impl Into<String>, value: impl Into<Expression>) -> Result<()> {
69 self.variables.define_global(key, value).map_err(|e| e.to_error(None))?;
70 Ok(())
71 }
72
73 pub fn with_receiver<B: Backend>(
75 message_receiver: MessageReceiver,
76 emitter: Emitter,
77 doc: Document,
78 backend: &B,
79 ) -> Builder<()> {
80 Builder::with_receiver(message_receiver, emitter, doc, backend.size(), ())
81 }
82}
83
84impl<G: GlobalEventHandler> Runtime<G> {
85 pub(crate) fn new(
86 blueprint: Blueprint,
87 variables: Variables,
88 component_registry: ComponentRegistry,
89 document: Document,
90 factory: Factory,
91 message_receiver: Receiver<ViewMessage>,
92 emitter: Emitter,
93 watcher: Option<RecommendedWatcher>,
94 size: Size,
95 fps: u32,
96 global_event_handler: G,
97 function_table: FunctionTable,
98 hot_reload: bool,
99 ) -> Self {
100 let sleep_micros: u64 = ((1.0 / fps as f64) * 1000.0 * 1000.0) as u64;
101
102 Self {
103 component_registry,
104 components: Components::new(),
105 document,
106 factory,
107 states: States::new(),
108 floating_widgets: FloatingWidgets::empty(),
109 assoc_events: AssociatedEvents::new(),
110 glyph_map: GlyphMap::empty(),
111 blueprint,
112 variables,
113 changes: Changes::empty(),
114 viewport: Viewport::new(size),
115 message_receiver,
116 emitter,
117 dt: Instant::now(),
118 _watcher: watcher,
119 deferred_components: DeferredComponents::new(),
120 sleep_micros,
121 global_event_handler,
122 function_table,
123 hot_reload,
124 }
125 }
126
127 pub fn with_frame<B, F>(&mut self, backend: &mut B, mut f: F) -> Result<()>
131 where
132 B: Backend,
133 F: FnMut(&mut B, Frame<'_, '_, G>) -> Result<()>,
134 {
135 let mut tree = WidgetTree::empty();
136 let mut attribute_storage = AttributeStorage::empty();
137 let mut frame = self.next_frame(&mut tree, &mut attribute_storage)?;
138 frame.init_tree()?;
139 f(backend, frame)
140 }
141
142 pub fn run<B: Backend>(&mut self, backend: &mut B) -> Result<()> {
143 let sleep_micros = self.sleep_micros;
144
145 loop {
146 let res = self.with_frame(backend, |backend, mut frame| {
147 _ = frame.tick(backend);
151 TabIndex::new(&mut frame.tabindex, frame.tree.view()).next();
152
153 if let Some(current) = frame.tabindex.as_ref() {
154 frame.with_component(current.widget_id, current.state_id, |comp, children, ctx| {
155 comp.dyn_component.any_focus(children, ctx)
156 });
157 }
158
159 loop {
160 if REBUILD.swap(false, Ordering::Relaxed) {
161 frame.force_unmount_return();
162 backend.clear();
163 break Err(Error::Reload);
164 }
165
166 match frame.tick(backend) {
167 Ok(_duration) => (),
168 Err(err) => match err {
169 err @ (Error::Template(_) | Error::Widget(_)) => {
170 match show_error(err, backend, frame.document) {
171 Err(Error::Stop) => return Err(Error::Stop),
172 Err(Error::Reload) => continue,
175 _ => unreachable!("show_error only return stop or rebuild"),
176 }
177 }
178 err => return Err(err),
179 },
180 }
181
182 if frame.layout_ctx.stop_runtime {
183 return Err(Error::Stop);
184 }
185
186 if frame.needs_paint {
187 frame.present(backend);
188 frame.needs_paint = false;
189 }
190
191 frame.cleanup();
192 std::thread::sleep(Duration::from_micros(sleep_micros));
193 }
194 });
195
196 match res {
197 Ok(()) => panic!(),
198 Err(e) => match e {
199 Error::Template(_) | Error::Widget(_) => {
200 unreachable!("these error variants are handled inside the tick loop")
201 }
202 Error::Stop => return Err(Error::Stop),
203
204 Error::Reload => loop {
205 match self.reload() {
207 Ok(()) => break,
208 Err(e) => {
209 if let Err(Error::Stop) = show_error(e, backend, &self.document) {
210 return Err(Error::Stop);
211 }
212 }
213 }
214 },
215 e => return Err(e),
216 },
217 }
218
219 if !self.hot_reload {
220 break;
221 }
222 }
223 Ok(())
224 }
225
226 pub fn next_frame<'frame, 'bp>(
227 &'bp mut self,
228 tree: &'frame mut WidgetTree<'bp>,
229 attribute_storage: &'frame mut AttributeStorage<'bp>,
230 ) -> Result<Frame<'frame, 'bp, G>> {
231 let layout_ctx = LayoutCtx::new(
232 &self.variables,
233 &self.factory,
234 &mut self.states,
235 attribute_storage,
236 &mut self.components,
237 &mut self.component_registry,
238 &mut self.floating_widgets,
239 &mut self.glyph_map,
240 &mut self.viewport,
241 &self.function_table,
242 );
243
244 let inst = Frame {
245 document: &self.document,
246 blueprint: &self.blueprint,
247 tree,
248 layout_ctx,
249 changes: &mut self.changes,
250 sleep_micros: self.sleep_micros,
251
252 assoc_events: &mut self.assoc_events,
253 deferred_components: &mut self.deferred_components,
254
255 emitter: &self.emitter,
256 message_receiver: &self.message_receiver,
257
258 dt: &mut self.dt,
259 force_layout: true,
260 needs_paint: true,
261 post_cycle_events: VecDeque::new(),
262
263 global_event_handler: &self.global_event_handler,
264 tabindex: None,
265 dirty_widgets: DirtyWidgets::empty(),
266 };
267
268 Ok(inst)
269 }
270
271 pub(super) fn reload(&mut self) -> Result<()> {
272 clear_all_changes();
273 clear_all_subs();
274
275 self.components = Components::new();
276 self.floating_widgets = FloatingWidgets::empty();
277
278 self.document.reload_templates()?;
280
281 let blueprint = self.document.compile(&mut self.variables)?;
282 self.blueprint = blueprint;
283
284 Ok(())
285 }
286}
287
288pub struct Frame<'rt, 'bp, G> {
289 document: &'bp Document,
290 blueprint: &'bp Blueprint,
291 pub tree: &'rt mut WidgetTree<'bp>,
292 deferred_components: &'rt mut DeferredComponents,
293 layout_ctx: LayoutCtx<'rt, 'bp>,
294 changes: &'rt mut Changes,
295 assoc_events: &'rt mut AssociatedEvents,
296 sleep_micros: u64,
297 emitter: &'rt Emitter,
298 message_receiver: &'rt flume::Receiver<ViewMessage>,
299 dt: &'rt mut Instant,
300 force_layout: bool,
301 needs_paint: bool,
302 post_cycle_events: VecDeque<Event>,
303 dirty_widgets: DirtyWidgets,
304
305 global_event_handler: &'rt G,
306 pub tabindex: Option<Index>,
307}
308
309impl<'rt, 'bp, G: GlobalEventHandler> Frame<'rt, 'bp, G> {
310 pub fn force_unmount_return(mut self) {
312 for i in 0..self.layout_ctx.components.len() {
314 let Some((widget_id, state_id)) = self.layout_ctx.components.get_ticking(i) else { continue };
315 let event = Event::Unmount;
316 self.send_event_to_component(event, widget_id, state_id);
317 }
318
319 self.return_state_and_component();
320 }
321
322 pub fn handle_global_event(&mut self, event: Event) -> Option<Event> {
323 let mut tabindex = TabIndex::new(&mut self.tabindex, self.tree.view());
324
325 let event = self
326 .global_event_handler
327 .handle(event, &mut tabindex, self.deferred_components);
328
329 if tabindex.changed {
330 let prev = tabindex.consume();
331 if let Some(prev) = prev {
332 self.with_component(prev.widget_id, prev.state_id, |comp, children, ctx| {
333 comp.dyn_component.any_blur(children, ctx)
334 });
335 }
336
337 if let Some(current) = self.tabindex.as_ref() {
338 self.with_component(current.widget_id, current.state_id, |comp, children, ctx| {
339 comp.dyn_component.any_focus(children, ctx)
340 });
341 }
342 }
343
344 event
345 }
346
347 pub fn event(&mut self, event: Event) {
348 #[cfg(feature = "profile")]
349 puffin::profile_function!();
350
351 let Some(event) = self.handle_global_event(event) else { return };
352 if let Event::Stop = event {
353 self.layout_ctx.stop_runtime = true;
354 return;
355 }
356
357 match event {
358 Event::Noop => (),
359 Event::Stop => todo!(),
360
361 Event::Blur | Event::Focus | Event::Key(_) => {
363 let Some(Index {
364 widget_id, state_id, ..
365 }) = self.tabindex
366 else {
367 return;
368 };
369 self.send_event_to_component(event, widget_id, state_id);
370 }
371 Event::Mouse(_) | Event::Resize(_) => {
372 for i in 0..self.layout_ctx.components.len() {
373 let Some((widget_id, state_id)) = self.layout_ctx.components.get(i) else { continue };
374 self.send_event_to_component(event, widget_id, state_id);
375 }
376 }
377 Event::Tick(_) | Event::Mount | Event::Unmount => panic!("this event should never be sent to the runtime"),
378 }
379 }
380
381 pub fn init_tree(&mut self) -> Result<()> {
383 let mut ctx = self.layout_ctx.eval_ctx(None, None);
384 eval_blueprint(
385 self.blueprint,
386 &mut ctx,
387 &Scope::root(),
388 root_node(),
389 &mut self.tree.view(),
390 )?;
391
392 Ok(())
393 }
394
395 pub fn tick<B: Backend>(&mut self, backend: &mut B) -> Result<Duration> {
396 #[cfg(feature = "profile")]
397 puffin::GlobalProfiler::lock().new_frame();
398
399 let now = Instant::now();
400 let elapsed = self.handle_messages(now);
401 self.poll_events(elapsed, now, backend);
402 self.drain_deferred_commands();
403 self.drain_assoc_events();
404 self.tick_components(self.dt.elapsed());
405
406 self.apply_changes()?;
410 self.apply_changes()?;
411
412 self.cycle(backend)?;
413
414 self.init_new_components();
415 self.post_cycle_events();
416
417 *self.dt = Instant::now();
418
419 match self.layout_ctx.stop_runtime {
420 false => Ok(now.elapsed()),
421 true => Err(Error::Stop),
422 }
423 }
424
425 pub fn present<B: Backend>(&mut self, backend: &mut B) {
426 #[cfg(feature = "profile")]
427 puffin::profile_function!();
428
429 backend.render(self.layout_ctx.glyph_map);
430 backend.clear();
431 }
432
433 pub fn cleanup(&mut self) {
434 #[cfg(feature = "profile")]
435 puffin::profile_function!();
436 for key in self.tree.drain_removed() {
437 self.layout_ctx.attribute_storage.try_remove(key);
438 self.layout_ctx.floating_widgets.try_remove(key);
439 self.layout_ctx.components.try_remove(key);
440 if let Some(Index { widget_id, .. }) = self.tabindex {
441 if widget_id == key {
442 self.tabindex.take();
443 }
444 }
445 }
446 }
447
448 fn handle_messages(&mut self, fps_now: Instant) -> Duration {
449 #[cfg(feature = "profile")]
450 puffin::profile_function!();
451
452 while let Ok(msg) = self.message_receiver.try_recv() {
453 let (widget_id, state_id) = match msg.recipient() {
454 Recipient::ComponentId(id) => {
455 let val = self
456 .layout_ctx
457 .components
458 .get_by_component_id(id)
459 .map(|e| (e.widget_id, e.state_id));
460 let Some(id_and_state) = val else { continue };
461 id_and_state
462 }
463 Recipient::WidgetId(id) => {
464 let state_id = self.layout_ctx.components.get_by_widget_id(id).map(|(_, state)| state);
465 let Some(state_id) = state_id else { continue };
466 (id, state_id)
467 }
468 };
469
470 self.with_component(widget_id, state_id, |comp, elements, ctx| {
471 comp.dyn_component.any_message(elements, ctx, msg.payload())
472 });
473
474 if fps_now.elapsed().as_micros() as u64 >= self.sleep_micros / 2 {
476 break;
477 }
478 }
479
480 fps_now.elapsed()
481 }
482
483 fn poll_events<B: Backend>(&mut self, remaining: Duration, fps_now: Instant, backend: &mut B) {
484 while let Some(event) = backend.next_event(remaining) {
485 if let Event::Resize(size) = event {
486 self.layout_ctx.viewport.resize(size);
487 self.force_layout = true;
488 backend.resize(size, self.layout_ctx.glyph_map);
489 }
490
491 if let Event::Stop = event {
492 self.layout_ctx.stop_runtime = true;
493 break;
494 }
495
496 match event.into() {
497 EventType::PreCycle => {
498 self.event(event);
500 }
501 EventType::PostCycle => {
502 self.post_cycle_events.push_back(event);
504 }
505 }
506
507 if fps_now.elapsed().as_micros() as u64 > self.sleep_micros {
509 break;
510 }
511 }
512 }
513
514 fn drain_deferred_commands(&mut self) {
515 #[cfg(feature = "profile")]
516 puffin::profile_function!();
517
518 let commands = self.deferred_components.drain().collect::<Vec<_>>();
523 for mut cmd in commands {
524 for index in 0..self.layout_ctx.components.len() {
525 let Some((widget_id, state_id)) = self.layout_ctx.components.get(index) else { continue };
526 let Some(comp) = self.tree.get_ref(widget_id) else { continue };
527 let WidgetContainer {
528 kind: WidgetKind::Component(comp),
529 ..
530 } = comp
531 else {
532 continue;
533 };
534 let attributes = self.layout_ctx.attribute_storage.get(widget_id);
535 if !cmd.filter_component(comp, attributes) {
536 continue;
537 }
538
539 if let CommandKind::Focus = cmd.kind {
546 if let Some(index) = self.tabindex.as_ref() {
548 if index.widget_id == widget_id {
549 continue;
550 }
551 }
552
553 let new_index = self
555 .with_component(widget_id, state_id, |comp, children, ctx| {
556 if comp.dyn_component.any_accept_focus() {
557 let index = Index {
558 path: children.parent_path().into(),
559 index: comp.tabindex,
560 widget_id,
561 state_id,
562 };
563
564 comp.dyn_component.any_focus(children, ctx);
565
566 Some(index)
567 } else {
568 None
569 }
570 })
571 .flatten();
572
573 if let Some(index) = new_index {
574 if let Some(old) = self.tabindex.replace(index) {
577 self.with_component(old.widget_id, old.state_id, |comp, children, ctx| {
578 comp.dyn_component.any_blur(children, ctx)
579 });
580 }
581 }
582 }
583
584 if let CommandKind::SendMessage(msg) = cmd.kind {
588 self.with_component(widget_id, state_id, |comp, children, ctx| {
589 comp.dyn_component.any_message(children, ctx, msg);
590 });
591 break;
592 }
593 }
594 }
595 }
596
597 fn drain_assoc_events(&mut self) {
598 #[cfg(feature = "profile")]
599 puffin::profile_function!();
600
601 while let Some(assoc_event) = self.assoc_events.next() {
602 let mut parent = assoc_event.parent;
603 let external_ident = self.document.strings.get_ref_unchecked(assoc_event.external());
604 let internal_ident = self.document.strings.get_ref_unchecked(assoc_event.internal());
605 let sender = self.document.strings.get_ref_unchecked(assoc_event.sender);
606 let sender_id = assoc_event.sender_id;
607 let mut event = assoc_event.to_event(internal_ident, external_ident, sender, sender_id);
608
609 loop {
610 let Some((widget_id, state_id)) = self.layout_ctx.components.get_by_widget_id(parent.into()) else {
611 return;
612 };
613
614 let stop_propagation = self
615 .with_component(widget_id, state_id, |comp, children, ctx| {
616 let next_parent = ctx.parent();
617 comp.dyn_component.any_component_event(children, ctx, &mut event);
618
619 parent = match next_parent {
620 Some(p) => p,
621 None => return true,
622 };
623
624 event.should_stop_propagation()
625 })
626 .unwrap_or(true);
627
628 if stop_propagation {
629 break;
630 }
631 }
632 }
633 }
634
635 fn cycle<B: Backend>(&mut self, backend: &mut B) -> Result<()> {
636 #[cfg(feature = "profile")]
637 puffin::profile_function!();
638
639 if !self.force_layout && self.dirty_widgets.is_empty() {
640 return Ok(());
641 }
642
643 let mut cycle = WidgetCycle::new(backend, self.tree.view(), self.layout_ctx.viewport.constraints());
644 cycle.run(&mut self.layout_ctx, self.force_layout, &mut self.dirty_widgets)?;
645
646 self.force_layout = false;
647 self.needs_paint = true;
648
649 Ok(())
650 }
651
652 fn apply_changes(&mut self) -> Result<()> {
653 #[cfg(feature = "profile")]
654 puffin::profile_function!();
655
656 drain_changes(self.changes);
657
658 if self.changes.is_empty() {
659 return Ok(());
660 }
661
662 let mut tree = self.tree.view();
664
665 self.changes.iter().try_for_each(|(sub, change)| {
666 sub.iter().try_for_each(|value_id| {
667 let widget_id = value_id.key();
668
669 if !tree.contains(widget_id) {
671 return Result::Ok(());
672 }
673
674 tree.with_value_mut(widget_id, |_path, widget, tree| {
675 update_widget(
676 widget,
677 value_id,
678 change,
679 tree,
680 &mut self.layout_ctx,
681 &mut self.dirty_widgets,
682 )
683 })
684 .unwrap_or(Ok(()))?;
685
686 Result::Ok(())
687 })?;
688
689 Result::Ok(())
690 })?;
691
692 self.changes.clear();
693
694 Ok(())
695 }
696
697 fn send_event_to_component(&mut self, event: Event, widget_id: WidgetId, state_id: StateId) {
698 self.with_component(widget_id, state_id, |comp, elements, ctx| {
699 comp.dyn_component.any_event(elements, ctx, event);
700 });
701 }
702
703 fn with_component<F, U>(&mut self, widget_id: WidgetId, state_id: StateId, f: F) -> Option<U>
704 where
705 F: FnOnce(&mut Component<'_>, Children<'_, '_>, AnyComponentContext<'_, '_>) -> U,
706 {
707 let mut tree = self.tree.view();
708
709 tree.with_value_mut(widget_id, |_path, container, children| {
710 let WidgetKind::Component(component) = &mut container.kind else {
711 panic!("this is always a component")
712 };
713
714 let Some(state) = self.layout_ctx.states.get_mut(state_id) else {
715 panic!("a component always has a state")
716 };
717
718 self.layout_ctx
719 .attribute_storage
720 .with_mut(widget_id, |attributes, storage| {
721 let elements = Children::new(children, storage, &mut self.dirty_widgets);
722
723 let ctx = AnyComponentContext::new(
724 component.parent.map(Into::into),
725 component.name_id,
726 widget_id,
727 state_id,
728 component.assoc_functions,
729 self.assoc_events,
730 self.deferred_components,
731 attributes,
732 Some(state),
733 self.emitter,
734 self.layout_ctx.viewport,
735 &mut self.layout_ctx.stop_runtime,
736 &self.document.strings,
737 );
738
739 f(component, elements, ctx)
740 })
741 })?
742 }
743
744 fn tick_components(&mut self, dt: Duration) {
745 #[cfg(feature = "profile")]
746 puffin::profile_function!();
747
748 for i in 0..self.layout_ctx.components.len() {
749 let Some((widget_id, state_id)) = self.layout_ctx.components.get_ticking(i) else { continue };
750 let event = Event::Tick(dt);
751 self.send_event_to_component(event, widget_id, state_id);
752 }
753 }
754
755 fn init_new_components(&mut self) {
756 while let Some((widget_id, state_id)) = self.layout_ctx.new_components.pop() {
757 self.with_component(widget_id, state_id, |comp, elements, ctx| {
758 comp.dyn_component.any_event(elements, ctx, Event::Mount);
759 });
760 }
761 }
762
763 fn return_state_and_component(self) {
765 let mut tree = WidgetTree::empty();
767 std::mem::swap(&mut tree, self.tree);
768
769 for (_, widget) in tree.values().into_iter() {
770 let WidgetKind::Component(comp) = widget.kind else { continue };
771 let ComponentKind::Instance = comp.kind else { continue };
772 let state = self.layout_ctx.states.remove(comp.state_id).take();
773 self.layout_ctx
774 .component_registry
775 .return_component(comp.component_id, comp.dyn_component, state);
776 }
777 }
778
779 fn post_cycle_events(&mut self) {
780 while let Some(event) = self.post_cycle_events.pop_front() {
781 self.event(event);
782 }
783 }
784}