1use super::custom_render::CustomRenderObject;
2use super::traits::{Lower, LowerDyn};
3use super::widgets::{
4 ActionScope, Align, Button, Checkbox, Clip, Column, Composite, Container, FocusScope,
5 GestureDetector, Grid, GridItem, Icon, Image, LazyColumn, Overlay, Positioned, Radio, RichText,
6 Row, SafeArea, Scroll, Slider, Spacer, Switch, Text, TextInput, Transform, Video, ZStack,
7};
8use crate::lowering::LoweringContext;
9use fission_ir::{NodeId, Op, StructuralOp};
10use serde::{Deserialize, Serialize};
11use std::sync::Arc;
12
13#[derive(Clone, Debug, Serialize, Deserialize)]
14pub enum Node {
15 ActionScope(ActionScope),
16 Row(Row),
17 Column(Column),
18 Align(Align),
19 FocusScope(FocusScope),
20 Clip(Clip),
21 Text(Text),
22 RichText(RichText),
23 Transform(Transform),
24 Button(Button),
25 TextInput(TextInput),
26 Scroll(Scroll),
27 Image(Image),
28 Video(Video),
29 ZStack(ZStack),
30 Overlay(Overlay),
31 Container(Container),
32 GestureDetector(GestureDetector),
33 Grid(Grid),
34 GridItem(GridItem),
35 Checkbox(Checkbox),
36 Switch(Switch),
37 Radio(Radio),
38 SafeArea(SafeArea),
39 Positioned(Positioned),
40 Spacer(Spacer),
41 Slider(Slider),
42 LazyColumn(LazyColumn),
43 Icon(Icon),
44 Composite(Composite),
45 Custom(CustomNode),
46}
47
48impl Node {
49 pub fn lower(&self, cx: &mut LoweringContext) -> NodeId {
50 match self {
51 Node::ActionScope(w) => w.lower(cx),
52 Node::Row(w) => w.lower(cx),
53 Node::Column(w) => w.lower(cx),
54 Node::Align(w) => w.lower(cx),
55 Node::FocusScope(w) => w.lower(cx),
56 Node::Clip(w) => w.lower(cx),
57 Node::Text(w) => w.lower(cx),
58 Node::RichText(w) => w.lower(cx),
59 Node::Transform(w) => w.lower(cx),
60 Node::Button(w) => w.lower(cx),
61 Node::TextInput(w) => w.lower(cx),
62 Node::Scroll(w) => w.lower(cx),
63 Node::Image(w) => w.lower(cx),
64 Node::Video(w) => w.lower(cx),
65 Node::ZStack(w) => w.lower(cx),
66 Node::Overlay(w) => w.lower(cx),
67 Node::Container(w) => w.lower(cx),
68 Node::GestureDetector(w) => w.lower(cx),
69 Node::Grid(w) => w.lower(cx),
70 Node::GridItem(w) => w.lower(cx),
71 Node::Checkbox(w) => w.lower(cx),
72 Node::Switch(w) => w.lower(cx),
73 Node::Radio(w) => w.lower(cx),
74 Node::SafeArea(w) => w.lower(cx),
75 Node::Positioned(w) => w.lower(cx),
76 Node::Spacer(w) => w.lower(cx),
77 Node::Slider(w) => w.lower(cx),
78 Node::LazyColumn(w) => w.lower(cx),
79 Node::Icon(w) => w.lower(cx),
80 Node::Composite(w) => w.lower(cx),
81 Node::Custom(w) => {
82 let lowerer = w.lowerer.as_ref().expect("CustomNode lowerer must be set");
83 let child_id = lowerer.lower_dyn(cx);
84 let wrapper = cx.next_node_id();
85 let mut builder = crate::lowering::NodeBuilder::new(
86 wrapper,
87 Op::Structural(StructuralOp::Group {
88 stable_hash: lowerer.stable_key(),
89 }),
90 );
91 builder.add_child(child_id);
92 let node_id = builder.build(cx);
93
94 if let Some(render_obj) = &w.render_object {
100 let holder = crate::ui::custom_render::RenderObjectHolder(render_obj.clone());
101 let erased: fission_ir::AnyRenderObject = Arc::new(holder);
102 cx.ir.custom_render_objects.insert(node_id, erased.clone());
106 fn register_subtree(
107 ir: &mut fission_ir::CoreIR,
108 node_id: fission_ir::NodeId,
109 erased: &fission_ir::AnyRenderObject,
110 ) {
111 ir.custom_render_objects.insert(node_id, erased.clone());
112 if let Some(children) = ir.nodes.get(&node_id).map(|n| n.children.clone()) {
113 for child_id in children {
114 register_subtree(ir, child_id, erased);
115 }
116 }
117 }
118 register_subtree(&mut cx.ir, child_id, &erased);
119 }
120
121 node_id
122 }
123 }
124 }
125}
126
127impl From<Row> for Node {
128 fn from(w: Row) -> Self {
129 Node::Row(w)
130 }
131}
132impl From<ActionScope> for Node {
133 fn from(w: ActionScope) -> Self {
134 Node::ActionScope(w)
135 }
136}
137impl From<Column> for Node {
138 fn from(w: Column) -> Self {
139 Node::Column(w)
140 }
141}
142impl From<Align> for Node {
143 fn from(w: Align) -> Self {
144 Node::Align(w)
145 }
146}
147impl From<FocusScope> for Node {
148 fn from(w: FocusScope) -> Self {
149 Node::FocusScope(w)
150 }
151}
152impl From<Clip> for Node {
153 fn from(w: Clip) -> Self {
154 Node::Clip(w)
155 }
156}
157impl From<Text> for Node {
158 fn from(w: Text) -> Self {
159 Node::Text(w)
160 }
161}
162impl From<RichText> for Node {
163 fn from(w: RichText) -> Self {
164 Node::RichText(w)
165 }
166}
167impl From<Transform> for Node {
168 fn from(w: Transform) -> Self {
169 Node::Transform(w)
170 }
171}
172impl From<Button> for Node {
173 fn from(w: Button) -> Self {
174 Node::Button(w)
175 }
176}
177impl From<TextInput> for Node {
178 fn from(w: TextInput) -> Self {
179 Node::TextInput(w)
180 }
181}
182impl From<Scroll> for Node {
183 fn from(w: Scroll) -> Self {
184 Node::Scroll(w)
185 }
186}
187impl From<Image> for Node {
188 fn from(w: Image) -> Self {
189 Node::Image(w)
190 }
191}
192impl From<ZStack> for Node {
193 fn from(w: ZStack) -> Self {
194 Node::ZStack(w)
195 }
196}
197impl From<Overlay> for Node {
198 fn from(w: Overlay) -> Self {
199 Node::Overlay(w)
200 }
201}
202impl From<Container> for Node {
203 fn from(w: Container) -> Self {
204 Node::Container(w)
205 }
206}
207impl From<GestureDetector> for Node {
208 fn from(w: GestureDetector) -> Self {
209 Node::GestureDetector(w)
210 }
211}
212impl From<Grid> for Node {
213 fn from(w: Grid) -> Self {
214 Node::Grid(w)
215 }
216}
217impl From<GridItem> for Node {
218 fn from(w: GridItem) -> Self {
219 Node::GridItem(w)
220 }
221}
222impl From<Checkbox> for Node {
223 fn from(w: Checkbox) -> Self {
224 Node::Checkbox(w)
225 }
226}
227impl From<Switch> for Node {
228 fn from(w: Switch) -> Self {
229 Node::Switch(w)
230 }
231}
232impl From<Radio> for Node {
233 fn from(w: Radio) -> Self {
234 Node::Radio(w)
235 }
236}
237impl From<SafeArea> for Node {
238 fn from(w: SafeArea) -> Self {
239 Node::SafeArea(w)
240 }
241}
242impl From<Composite> for Node {
243 fn from(w: Composite) -> Self {
244 Node::Composite(w)
245 }
246}
247impl From<Positioned> for Node {
248 fn from(w: Positioned) -> Self {
249 Node::Positioned(w)
250 }
251}
252impl From<Spacer> for Node {
253 fn from(w: Spacer) -> Self {
254 Node::Spacer(w)
255 }
256}
257impl From<Slider> for Node {
258 fn from(w: Slider) -> Self {
259 Node::Slider(w)
260 }
261}
262impl From<LazyColumn> for Node {
263 fn from(w: LazyColumn) -> Self {
264 Node::LazyColumn(w)
265 }
266}
267impl From<Icon> for Node {
268 fn from(w: Icon) -> Self {
269 Node::Icon(w)
270 }
271}
272
273#[derive(Clone, Debug, Serialize, Deserialize)]
274pub struct CustomNode {
275 pub debug_tag: String,
276 #[serde(skip)]
277 pub lowerer: Option<Arc<dyn LowerDyn>>,
278 #[serde(skip)]
282 pub render_object: Option<Arc<dyn CustomRenderObject>>,
283}