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