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