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