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