Skip to main content

anathema_widgets/components/
mod.rs

1use std::any::Any;
2use std::marker::PhantomData;
3use std::ops::{Deref, DerefMut};
4use std::time::Duration;
5
6use anathema_state::{State, StateId, Value as StateValue};
7use anathema_store::slab::Slab;
8use anathema_templates::strings::{StringId, Strings};
9use anathema_templates::{AssocEventMapping, ComponentBlueprintId};
10use anathema_value_resolver::{Attributes, ValueKind};
11use deferred::DeferredComponents;
12use flume::SendError;
13
14use self::events::{Event, KeyEvent, MouseEvent};
15use crate::WidgetId;
16use crate::layout::Viewport;
17use crate::query::Children;
18use crate::widget::Parent;
19
20pub mod deferred;
21pub mod events;
22
23pub type ComponentFn = dyn Fn() -> Box<dyn AnyComponent>;
24pub type StateFn = dyn FnMut() -> Box<dyn State>;
25
26enum ComponentType {
27    Component(Option<Box<dyn AnyComponent>>, Option<Box<dyn State>>),
28    Prototype(Box<ComponentFn>, Box<StateFn>),
29}
30
31/// Store component factories.
32/// This is how components are created.
33pub struct ComponentRegistry(Slab<ComponentBlueprintId, ComponentType>);
34
35impl ComponentRegistry {
36    pub fn new() -> Self {
37        Self(Slab::empty())
38    }
39
40    /// Both `add_component` and `add_prototype` are using `Slab::insert_at`.
41    ///
42    /// This is fine as the component ids are generated at the same time.
43    pub fn add_component<S: State>(&mut self, id: ComponentBlueprintId, component: impl Component + 'static, state: S) {
44        let comp_type = ComponentType::Component(Some(Box::new(component)), Some(Box::new(state)));
45        self.0.insert_at(id, comp_type);
46    }
47
48    pub fn add_prototype<FC, FS, C, S>(&mut self, id: ComponentBlueprintId, proto: FC, mut state: FS)
49    where
50        FC: 'static + Fn() -> C,
51        FS: 'static + FnMut() -> S,
52        C: Component + 'static,
53        S: State + 'static,
54    {
55        let comp_type =
56            ComponentType::Prototype(Box::new(move || Box::new(proto())), Box::new(move || Box::new(state())));
57
58        self.0.insert_at(id, comp_type);
59    }
60
61    // # Panics
62    //
63    // Panics if the component isn't registered.
64    // This shouldn't happen as the statement eval should catch this.
65    pub(super) fn get(
66        &mut self,
67        id: ComponentBlueprintId,
68    ) -> Option<(ComponentKind, Box<dyn AnyComponent>, Box<dyn State>)> {
69        match self.0.get_mut(id) {
70            Some(component) => match component {
71                ComponentType::Component(comp, state) => Some((ComponentKind::Instance, comp.take()?, state.take()?)),
72                ComponentType::Prototype(proto, state) => Some((ComponentKind::Prototype, proto(), state())),
73            },
74            None => panic!(),
75        }
76    }
77
78    /// Return a component back to the registry.
79    ///
80    /// # Panics
81    ///
82    /// Panics if the component entry doesn't exist or if the entry is for a prototype.
83    pub fn return_component(
84        &mut self,
85        id: ComponentBlueprintId,
86        current_component: Box<dyn AnyComponent>,
87        current_state: Box<dyn State>,
88    ) {
89        match self.0.get_mut(id) {
90            Some(component) => match component {
91                ComponentType::Component(comp, state) => {
92                    *comp = Some(current_component);
93                    *state = Some(current_state);
94                }
95                ComponentType::Prototype(..) => {
96                    // Can't return a prototype
97                }
98            },
99            None => panic!(),
100        }
101    }
102}
103
104#[derive(Debug)]
105pub struct ComponentId<T>(pub(crate) ComponentBlueprintId, pub(crate) PhantomData<T>);
106
107impl<T> From<ComponentBlueprintId> for ComponentId<T> {
108    fn from(value: ComponentBlueprintId) -> Self {
109        Self(value, PhantomData)
110    }
111}
112
113impl<T> Clone for ComponentId<T> {
114    fn clone(&self) -> Self {
115        *self
116    }
117}
118
119impl<T> Copy for ComponentId<T> {}
120
121pub struct ViewMessage {
122    pub(super) payload: Box<dyn Any + Send + Sync>,
123    pub(super) recipient: Recipient,
124}
125
126impl ViewMessage {
127    pub fn recipient(&self) -> Recipient {
128        self.recipient
129    }
130
131    pub fn payload(self) -> Box<dyn Any + Send + Sync> {
132        self.payload
133    }
134}
135
136#[derive(Debug, Copy, Clone)]
137pub enum Recipient {
138    ComponentId(ComponentBlueprintId),
139    WidgetId(WidgetId),
140}
141
142#[derive(Debug, Clone)]
143pub struct Emitter(pub(crate) flume::Sender<ViewMessage>);
144
145impl From<flume::Sender<ViewMessage>> for Emitter {
146    fn from(value: flume::Sender<ViewMessage>) -> Self {
147        Self(value)
148    }
149}
150
151pub type MessageReceiver = flume::Receiver<ViewMessage>;
152
153impl Emitter {
154    pub fn new() -> (Self, MessageReceiver) {
155        let (tx, rx) = flume::unbounded();
156        (Self(tx), rx)
157    }
158
159    /// Emit a message to a component via a `ComponentId<T>`
160    pub fn emit<T: 'static + Send + Sync>(
161        &self,
162        component_id: ComponentId<T>,
163        value: T,
164    ) -> Result<(), SendError<ViewMessage>> {
165        let msg = ViewMessage {
166            payload: Box::new(value),
167            recipient: Recipient::ComponentId(component_id.0),
168        };
169        self.0.send(msg)
170    }
171
172    /// Emit a message to a component via a `ComponentId<T>` asynchronously
173    pub async fn emit_async<T: 'static + Send + Sync>(
174        &self,
175        component_id: ComponentId<T>,
176        value: T,
177    ) -> Result<(), SendError<ViewMessage>> {
178        let msg = ViewMessage {
179            payload: Box::new(value),
180            recipient: Recipient::ComponentId(component_id.0),
181        };
182        self.0.send_async(msg).await
183    }
184
185    /// Try to emit a message to a component via its `WidgetId`.
186    /// Unlike the `emit` function there is no type associated with the widget id,
187    /// and the message will fail to deliver silently if the wrong type is used.
188    pub fn try_emit<T: 'static + Send + Sync>(
189        &self,
190        widget_id: WidgetId,
191        value: T,
192    ) -> Result<(), SendError<ViewMessage>> {
193        let msg = ViewMessage {
194            payload: Box::new(value),
195            recipient: Recipient::WidgetId(widget_id),
196        };
197        self.0.send(msg)
198    }
199
200    /// Async counterpart of `try_emit`.
201    pub async fn try_emit_async<T: 'static + Send + Sync>(
202        &self,
203        widget_id: WidgetId,
204        value: T,
205    ) -> Result<(), SendError<ViewMessage>> {
206        let msg = ViewMessage {
207            payload: Box::new(value),
208            recipient: Recipient::WidgetId(widget_id),
209        };
210        self.0.send_async(msg).await
211    }
212}
213
214pub struct Context<'frame, 'bp, T> {
215    inner: AnyComponentContext<'frame, 'bp>,
216    _p: PhantomData<T>,
217}
218
219impl<'frame, 'bp, T: 'static> Context<'frame, 'bp, T> {
220    pub fn new(inner: AnyComponentContext<'frame, 'bp>) -> Self {
221        Self { inner, _p: PhantomData }
222    }
223
224    /// Publish an event
225    ///
226    /// # Panics
227    ///
228    /// This will panic if the shared value is exclusively borrowed
229    /// at the time of the invocation.
230    pub fn publish<D: 'static>(&mut self, ident: &str, data: D) {
231        // If there is no parent there is no one to emit the event to.
232        let Some(parent) = self.parent else { return };
233
234        let Some(ident_id) = self.inner.strings.lookup(ident) else { return };
235
236        let ids = self.assoc_functions.iter().find(|assoc| assoc.internal == ident_id);
237
238        let Some(assoc_event_map) = ids else { return };
239
240        self.inner.assoc_events.push(
241            self.state_id,
242            parent,
243            *assoc_event_map,
244            self.ident_id,
245            self.widget_id,
246            data,
247        );
248    }
249
250    /// Get a value from the component attributes
251    pub fn attribute(&self, key: &str) -> Option<&ValueKind<'_>> {
252        self.attributes.get(key)
253    }
254
255    /// Send a message to a given component
256    pub fn emit<M: 'static + Send + Sync>(&self, recipient: ComponentId<M>, value: M) {
257        self.emitter
258            .emit(recipient, value)
259            .expect("this will not fail unless the runtime is dropped")
260    }
261}
262
263impl<'frame, 'bp, T> Deref for Context<'frame, 'bp, T> {
264    type Target = AnyComponentContext<'frame, 'bp>;
265
266    fn deref(&self) -> &Self::Target {
267        &self.inner
268    }
269}
270
271impl<'frame, 'bp, T> DerefMut for Context<'frame, 'bp, T> {
272    fn deref_mut(&mut self) -> &mut Self::Target {
273        &mut self.inner
274    }
275}
276
277pub struct AnyComponentContext<'frame, 'bp> {
278    parent: Option<Parent>,
279    ident_id: StringId,
280    pub widget_id: WidgetId,
281    state_id: StateId,
282    assoc_functions: &'frame [AssocEventMapping],
283    assoc_events: &'frame mut AssociatedEvents,
284    pub attributes: &'frame mut Attributes<'bp>,
285    state: Option<&'frame mut StateValue<Box<dyn State>>>,
286    pub emitter: &'frame Emitter,
287    pub viewport: &'frame Viewport,
288    pub strings: &'frame Strings,
289    pub components: &'frame mut DeferredComponents,
290    stop_runtime: &'frame mut bool,
291}
292
293impl<'frame, 'bp> AnyComponentContext<'frame, 'bp> {
294    pub fn new(
295        parent: Option<Parent>,
296        ident_id: StringId,
297        sender_id: WidgetId,
298        state_id: StateId,
299        assoc_functions: &'frame [AssocEventMapping],
300        assoc_events: &'frame mut AssociatedEvents,
301        components: &'frame mut DeferredComponents,
302        attributes: &'frame mut Attributes<'bp>,
303        state: Option<&'frame mut StateValue<Box<dyn State>>>,
304        emitter: &'frame Emitter,
305        viewport: &'frame Viewport,
306        stop_runtime: &'frame mut bool,
307        strings: &'frame Strings,
308    ) -> Self {
309        Self {
310            parent,
311            ident_id,
312            widget_id: sender_id,
313            state_id,
314            assoc_functions,
315            assoc_events,
316            attributes,
317            components,
318            state,
319            emitter,
320            viewport,
321            strings,
322            stop_runtime,
323        }
324    }
325
326    pub fn parent(&self) -> Option<Parent> {
327        self.parent
328    }
329
330    pub fn stop_runtime(&mut self) {
331        *self.stop_runtime = true;
332    }
333}
334
335pub struct AssociatedEvent {
336    pub state: StateId,
337    pub parent: Parent,
338    pub sender: StringId,
339    pub sender_id: WidgetId,
340    event_map: AssocEventMapping,
341    data: Box<dyn Any>,
342}
343
344impl AssociatedEvent {
345    pub fn to_event<'a>(
346        &'a self,
347        internal: &'a str,
348        external: &'a str,
349        sender: &'a str,
350        sender_id: WidgetId,
351    ) -> UserEvent<'a> {
352        UserEvent {
353            external_ident: external,
354            internal_ident: internal,
355            data: &*self.data,
356            sender,
357            sender_id,
358            stop_propagation: false,
359        }
360    }
361
362    pub fn external(&self) -> StringId {
363        self.event_map.external
364    }
365
366    pub fn internal(&self) -> StringId {
367        self.event_map.internal
368    }
369}
370
371#[derive(Debug, Copy, Clone)]
372pub struct UserEvent<'a> {
373    pub sender: &'a str,
374    pub sender_id: WidgetId,
375    pub external_ident: &'a str,
376    pub internal_ident: &'a str,
377    data: &'a dyn Any,
378    stop_propagation: bool,
379}
380
381impl<'a> UserEvent<'a> {
382    pub fn stop_propagation(&mut self) {
383        self.stop_propagation = true;
384    }
385
386    pub fn name(&self) -> &str {
387        self.external_ident
388    }
389
390    /// Cast the event payload to a specific type
391    ///
392    /// # Panics
393    ///
394    /// This will panic if the type is incorrect
395    pub fn data<T: 'static>(&self) -> &'a T {
396        match self.data.downcast_ref() {
397            Some(data) => data,
398            None => panic!("invalid type when casting event data"),
399        }
400    }
401
402    /// Try to cast the event payload to a specific type
403    pub fn data_checked<T: 'static>(&self) -> Option<&'a T> {
404        self.data.downcast_ref()
405    }
406
407    pub fn should_stop_propagation(&self) -> bool {
408        self.stop_propagation
409    }
410}
411
412// The reason the component can not have access
413// to the children during this event is because the parent is borrowing from the
414// child's state while this is happening.
415pub struct AssociatedEvents {
416    inner: Vec<AssociatedEvent>,
417}
418
419impl AssociatedEvents {
420    pub fn new() -> Self {
421        Self { inner: vec![] }
422    }
423
424    fn push<T: 'static>(
425        &mut self,
426        state: StateId,
427        parent: Parent,
428        assoc_event_map: AssocEventMapping,
429        sender: StringId,
430        sender_id: WidgetId,
431        data: T,
432    ) {
433        self.inner.push(AssociatedEvent {
434            state,
435            parent,
436            sender,
437            sender_id,
438            event_map: assoc_event_map,
439            data: Box::new(data),
440        })
441    }
442
443    pub fn next(&mut self) -> Option<AssociatedEvent> {
444        self.inner.pop()
445    }
446}
447
448pub trait Component: 'static {
449    type State: State;
450    type Message;
451
452    const TICKS: bool = true;
453
454    #[allow(unused_variables, unused_mut)]
455    fn on_key(
456        &mut self,
457        key: KeyEvent,
458        state: &mut Self::State,
459        mut children: Children<'_, '_>,
460        mut context: Context<'_, '_, Self::State>,
461    ) {
462    }
463
464    #[allow(unused_variables, unused_mut)]
465    fn on_mount(
466        &mut self,
467        state: &mut Self::State,
468        mut children: Children<'_, '_>,
469        mut context: Context<'_, '_, Self::State>,
470    ) {
471    }
472
473    #[allow(unused_variables, unused_mut)]
474    fn on_unmount(
475        &mut self,
476        state: &mut Self::State,
477        mut children: Children<'_, '_>,
478        mut context: Context<'_, '_, Self::State>,
479    ) {
480    }
481
482    #[allow(unused_variables, unused_mut)]
483    fn on_blur(
484        &mut self,
485        state: &mut Self::State,
486        mut children: Children<'_, '_>,
487        mut context: Context<'_, '_, Self::State>,
488    ) {
489    }
490
491    #[allow(unused_variables, unused_mut)]
492    fn on_focus(
493        &mut self,
494        state: &mut Self::State,
495        mut children: Children<'_, '_>,
496        mut context: Context<'_, '_, Self::State>,
497    ) {
498    }
499
500    #[allow(unused_variables, unused_mut)]
501    fn on_mouse(
502        &mut self,
503        mouse: MouseEvent,
504        state: &mut Self::State,
505        mut children: Children<'_, '_>,
506        mut context: Context<'_, '_, Self::State>,
507    ) {
508    }
509
510    #[allow(unused_variables, unused_mut)]
511    fn on_tick(
512        &mut self,
513        state: &mut Self::State,
514        mut children: Children<'_, '_>,
515        context: Context<'_, '_, Self::State>,
516        dt: Duration,
517    ) {
518    }
519
520    #[allow(unused_variables, unused_mut)]
521    fn on_message(
522        &mut self,
523        message: Self::Message,
524        state: &mut Self::State,
525        mut children: Children<'_, '_>,
526        mut context: Context<'_, '_, Self::State>,
527    ) {
528    }
529
530    #[allow(unused_variables, unused_mut)]
531    fn on_resize(
532        &mut self,
533        state: &mut Self::State,
534        mut children: Children<'_, '_>,
535        mut context: Context<'_, '_, Self::State>,
536    ) {
537    }
538
539    #[allow(unused_variables, unused_mut)]
540    fn on_event(
541        &mut self,
542        event: &mut UserEvent<'_>,
543        state: &mut Self::State,
544        mut children: Children<'_, '_>,
545        mut context: Context<'_, '_, Self::State>,
546    ) {
547    }
548
549    fn accept_focus(&self) -> bool {
550        true
551    }
552}
553
554impl Component for () {
555    type Message = ();
556    type State = ();
557
558    const TICKS: bool = false;
559
560    fn accept_focus(&self) -> bool {
561        false
562    }
563}
564
565#[derive(Debug)]
566pub enum ComponentKind {
567    Instance,
568    Prototype,
569}
570
571pub trait AnyComponent {
572    fn any_event(&mut self, children: Children<'_, '_>, ctx: AnyComponentContext<'_, '_>, ev: Event) -> Event;
573
574    fn any_message(&mut self, children: Children<'_, '_>, ctx: AnyComponentContext<'_, '_>, message: Box<dyn Any>);
575
576    fn any_tick(&mut self, children: Children<'_, '_>, ctx: AnyComponentContext<'_, '_>, dt: Duration);
577
578    fn any_focus(&mut self, children: Children<'_, '_>, ctx: AnyComponentContext<'_, '_>);
579
580    fn any_blur(&mut self, children: Children<'_, '_>, ctx: AnyComponentContext<'_, '_>);
581
582    fn any_resize(&mut self, children: Children<'_, '_>, ctx: AnyComponentContext<'_, '_>);
583
584    fn any_component_event(
585        &mut self,
586        children: Children<'_, '_>,
587        ctx: AnyComponentContext<'_, '_>,
588        value: &mut UserEvent<'_>,
589    );
590
591    fn any_accept_focus(&self) -> bool;
592
593    fn any_ticks(&self) -> bool;
594}
595
596impl<T> AnyComponent for T
597where
598    T: Component,
599    T: 'static,
600{
601    fn any_event(&mut self, children: Children<'_, '_>, mut ctx: AnyComponentContext<'_, '_>, event: Event) -> Event {
602        let mut state = ctx
603            .state
604            .take()
605            .map(|s| s.to_mut_cast::<T::State>())
606            .expect("components always have a state");
607        let context = Context::<T::State>::new(ctx);
608        match event {
609            Event::Blur | Event::Focus => (), // Application focus, not component focus.
610            Event::Key(ev) => self.on_key(ev, &mut *state, children, context),
611            Event::Mouse(ev) => self.on_mouse(ev, &mut *state, children, context),
612            Event::Tick(dt) => self.on_tick(&mut *state, children, context, dt),
613            Event::Resize(_) => self.on_resize(&mut *state, children, context),
614            Event::Mount => self.on_mount(&mut *state, children, context),
615            Event::Unmount => self.on_unmount(&mut *state, children, context),
616            Event::Noop | Event::Stop => (),
617        }
618        event
619    }
620
621    fn any_accept_focus(&self) -> bool {
622        self.accept_focus()
623    }
624
625    fn any_ticks(&self) -> bool {
626        T::TICKS
627    }
628
629    fn any_message(&mut self, children: Children<'_, '_>, mut ctx: AnyComponentContext<'_, '_>, message: Box<dyn Any>) {
630        let mut state = ctx
631            .state
632            .take()
633            .map(|s| s.to_mut_cast::<T::State>())
634            .expect("components always have a state");
635        let Ok(message) = message.downcast::<T::Message>() else { return };
636        let context = Context::<T::State>::new(ctx);
637        self.on_message(*message, &mut *state, children, context);
638    }
639
640    fn any_focus(&mut self, children: Children<'_, '_>, mut ctx: AnyComponentContext<'_, '_>) {
641        let mut state = ctx
642            .state
643            .take()
644            .map(|s| s.to_mut_cast::<T::State>())
645            .expect("components always have a state");
646        let context = Context::<T::State>::new(ctx);
647        self.on_focus(&mut *state, children, context);
648    }
649
650    fn any_blur(&mut self, children: Children<'_, '_>, mut ctx: AnyComponentContext<'_, '_>) {
651        let mut state = ctx
652            .state
653            .take()
654            .map(|s| s.to_mut_cast::<T::State>())
655            .expect("components always have a state");
656        let context = Context::<T::State>::new(ctx);
657        self.on_blur(&mut *state, children, context);
658    }
659
660    fn any_tick(&mut self, children: Children<'_, '_>, mut ctx: AnyComponentContext<'_, '_>, dt: Duration) {
661        let mut state = ctx
662            .state
663            .take()
664            .map(|s| s.to_mut_cast::<T::State>())
665            .expect("components always have a state");
666        let context = Context::<T::State>::new(ctx);
667        self.on_tick(&mut *state, children, context, dt);
668    }
669
670    fn any_resize(&mut self, children: Children<'_, '_>, mut ctx: AnyComponentContext<'_, '_>) {
671        let mut state = ctx
672            .state
673            .take()
674            .map(|s| s.to_mut_cast::<T::State>())
675            .expect("components always have a state");
676        let context = Context::<T::State>::new(ctx);
677        self.on_resize(&mut *state, children, context);
678    }
679
680    fn any_component_event(
681        &mut self,
682        children: Children<'_, '_>,
683        mut ctx: AnyComponentContext<'_, '_>,
684        event: &mut UserEvent<'_>,
685    ) {
686        let mut state = ctx
687            .state
688            .take()
689            .map(|s| s.to_mut_cast::<T::State>())
690            .expect("components always have a state");
691
692        let context = Context::<T::State>::new(ctx);
693
694        self.on_event(event, &mut *state, children, context);
695    }
696}
697
698impl std::fmt::Debug for dyn AnyComponent {
699    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
700        write!(f, "<dyn AnyComponent>")
701    }
702}