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