maycoon_core/
component.rs

1use crate::app::info::AppInfo;
2use crate::app::update::Update;
3use crate::layout::{LayoutNode, StyleNode};
4use crate::state::State;
5use crate::widget::Widget;
6use maycoon_theme::id::WidgetId;
7use maycoon_theme::theme::Theme;
8use std::marker::PhantomData;
9use std::ops::{Deref, DerefMut};
10use vello::Scene;
11
12/// The core trait for all components.
13///
14/// A [`Component`] is composed out of an already existing [`Widget`].
15/// The advantage of using a component is that you can easily create your own widgets
16/// with your own logic without handling rendering, updating and other things.
17///
18/// In order to make it usable, you'll need to call [`Component::build`] on it,
19/// to convert it into a real widget (more specifically the [`ComponentAdapter`]).
20/// This is required to not confuse the compiler with overlapping traits.
21pub trait Component<S: State> {
22    /// Returns a mutable reference to the inner [`Widget`].
23    fn get_widget(&mut self) -> &mut impl Widget<S>;
24
25    /// Get the ID of your component as a [`WidgetId`].
26    fn get_widget_id(&self) -> WidgetId;
27
28    /// Converts the component into a widget by wrapping it in a [`ComponentAdapter`].
29    fn build(self) -> ComponentAdapter<S, Self>
30    where
31        Self: Sized,
32    {
33        ComponentAdapter::new(self)
34    }
35}
36
37/// An adapter around a [`Component`] to make it usable as a [`Widget`].
38///
39/// You can still call methods of the inner [`Component`], due to [`Deref` coercion](Deref)
40pub struct ComponentAdapter<S: State, C: Component<S>> {
41    inner: C,
42    phantom: PhantomData<S>,
43}
44
45impl<S: State, C: Component<S>> ComponentAdapter<S, C> {
46    /// Creates a new [`ComponentAdapter`] by using the given [`Component`].
47    pub fn new(inner: C) -> Self {
48        Self {
49            inner,
50            phantom: PhantomData,
51        }
52    }
53}
54
55impl<S: State, C: Component<S>> Deref for ComponentAdapter<S, C> {
56    type Target = C;
57
58    fn deref(&self) -> &Self::Target {
59        &self.inner
60    }
61}
62
63impl<S: State, C: Component<S>> DerefMut for ComponentAdapter<S, C> {
64    fn deref_mut(&mut self) -> &mut Self::Target {
65        &mut self.inner
66    }
67}
68
69impl<S: State, C: Component<S>> Widget<S> for ComponentAdapter<S, C> {
70    fn render(
71        &mut self,
72        scene: &mut Scene,
73        theme: &mut dyn Theme,
74        info: &AppInfo,
75        layout_node: &LayoutNode,
76        state: &S,
77    ) {
78        self.inner
79            .get_widget()
80            .render(scene, theme, info, layout_node, state)
81    }
82
83    fn layout_style(&mut self, state: &S) -> StyleNode {
84        self.inner.get_widget().layout_style(state)
85    }
86
87    fn update(&mut self, layout: &LayoutNode, state: &mut S, info: &AppInfo) -> Update {
88        self.inner.get_widget().update(layout, state, info)
89    }
90
91    fn widget_id(&self) -> WidgetId {
92        self.inner.get_widget_id()
93    }
94}