maycoon_core/
component.rs1use crate::app::context::AppContext;
2use crate::app::info::AppInfo;
3use crate::app::update::Update;
4use crate::layout::{LayoutNode, LayoutStyle, StyleNode};
5use crate::signal::MaybeSignal;
6use crate::vgi::Scene;
7use crate::widget::{BoxedWidget, Widget, WidgetChildExt, WidgetChildrenExt, WidgetLayoutExt};
8use maycoon_theme::id::WidgetId;
9use maycoon_theme::theme::Theme;
10use std::fmt::Debug;
11use std::ops::{Deref, DerefMut};
12
13pub trait Component {
17 fn build(&self, context: AppContext) -> impl Widget + 'static;
19
20 fn widget_id(&self) -> WidgetId;
22
23 #[inline(always)]
25 fn compose(self) -> Composed<Self>
26 where
27 Self: Sized,
28 {
29 Composed {
30 component: self,
31 widget: None,
32 }
33 }
34}
35
36pub struct Composed<C: Component> {
38 component: C,
39 widget: Option<BoxedWidget>,
40}
41
42impl<C: Component> Composed<C> {
43 #[inline(always)]
45 pub fn new(component: C) -> Self {
46 Self {
47 component,
48 widget: None,
49 }
50 }
51}
52
53impl<C: Component> Widget for Composed<C> {
54 #[inline(always)]
55 fn render(
56 &mut self,
57 scene: &mut dyn Scene,
58 theme: &mut dyn Theme,
59 layout_node: &LayoutNode,
60 info: &AppInfo,
61 context: AppContext,
62 ) {
63 if let Some(widget) = &mut self.widget {
64 widget.render(scene, theme, layout_node, info, context)
65 } else {
66 self.widget = Some(Box::new(self.component.build(context.clone())));
67 }
68 }
69
70 #[inline(always)]
71 fn layout_style(&self) -> StyleNode {
72 if let Some(widget) = &self.widget {
73 widget.layout_style()
74 } else {
75 StyleNode {
76 style: LayoutStyle::default(),
77 children: Vec::new(),
78 }
79 }
80 }
81
82 #[inline(always)]
83 fn update(&mut self, layout: &LayoutNode, context: AppContext, info: &AppInfo) -> Update {
84 if let Some(widget) = &mut self.widget {
85 widget.update(layout, context, info)
86 } else {
87 self.widget = Some(Box::new(self.component.build(context.clone())));
88 Update::FORCE
89 }
90 }
91
92 #[inline(always)]
93 fn widget_id(&self) -> WidgetId {
94 self.component.widget_id()
95 }
96}
97
98impl<C: Component + WidgetChildrenExt> WidgetChildrenExt for Composed<C> {
99 #[inline(always)]
100 fn set_children(&mut self, children: Vec<BoxedWidget>) {
101 self.component.set_children(children)
102 }
103
104 #[inline(always)]
105 fn with_children(self, children: Vec<BoxedWidget>) -> Self
106 where
107 Self: Sized,
108 {
109 self.component.with_children(children).compose()
110 }
111
112 #[inline(always)]
113 fn add_child(&mut self, child: impl Widget + 'static) {
114 self.component.add_child(child)
115 }
116
117 #[inline(always)]
118 fn with_child(self, child: impl Widget + 'static) -> Self
119 where
120 Self: Sized,
121 {
122 self.component.with_child(child).compose()
123 }
124}
125
126impl<C: Component + WidgetChildExt> WidgetChildExt for Composed<C> {
127 #[inline(always)]
128 fn set_child(&mut self, child: impl Widget + 'static) {
129 self.component.set_child(child)
130 }
131
132 #[inline(always)]
133 fn with_child(self, child: impl Widget + 'static) -> Self
134 where
135 Self: Sized,
136 {
137 self.component.with_child(child).compose()
138 }
139}
140
141impl<C: Component + WidgetLayoutExt> WidgetLayoutExt for Composed<C> {
142 #[inline(always)]
143 fn set_layout_style(&mut self, layout_style: impl Into<MaybeSignal<LayoutStyle>>) {
144 self.component.set_layout_style(layout_style)
145 }
146
147 #[inline(always)]
148 fn with_layout_style(self, layout_style: impl Into<MaybeSignal<LayoutStyle>>) -> Self
149 where
150 Self: Sized,
151 {
152 self.component.with_layout_style(layout_style).compose()
153 }
154}
155
156impl<C: Component + Clone> Clone for Composed<C> {
157 #[inline(always)]
158 fn clone(&self) -> Self {
159 Self {
160 component: self.component.clone(),
161 widget: None,
162 }
163 }
164}
165
166impl<C: Component + Debug> Debug for Composed<C> {
167 #[inline(always)]
168 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169 f.debug_struct("ComposedWidget")
170 .field("component", &self.component)
171 .field("widget", &self.widget.as_ref().map(|_| "?".to_string()))
172 .finish()
173 }
174}
175
176impl<C: Component> Deref for Composed<C> {
177 type Target = C;
178
179 #[inline(always)]
180 fn deref(&self) -> &Self::Target {
181 &self.component
182 }
183}
184
185impl<C: Component> DerefMut for Composed<C> {
186 #[inline(always)]
187 fn deref_mut(&mut self) -> &mut Self::Target {
188 &mut self.component
189 }
190}