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