makepad_gen_plugin/model/widget/handler/
all.rs1use crate::{
2 compiler::{Context, WidgetPoll},
3 model::{
4 role::ForParent, widget::role::Role, AbsWidget, PropWidget, Widget, WidgetTemplate,
5 WidgetType,
6 },
7};
8
9use gen_analyzer::{
10 value::Bind, IdClass, Polls, Script, Style, StyleVisitor, SugarProps, Template,
11};
12use gen_utils::{common::Source, err_from_to, error::Error};
13use std::{
14 collections::HashMap,
15 sync::{Arc, RwLock},
16};
17
18pub type PropBinds = HashMap<String, Vec<PropWidget>>;
19pub type TemplatePtrs = Vec<WidgetTemplate>;
21
22pub fn all(
23 context: &mut Context,
24 source: Source,
25 template: Option<Template>,
26 script: Option<Script>,
27 style: Option<Style>,
28 is_entry: bool,
29 polls: Arc<RwLock<Polls>>,
30) -> Result<Widget, Error> {
31 let mut widget_poll: WidgetPoll = HashMap::new();
34 let mut template_ptrs: TemplatePtrs = vec![];
35 let template = if let Some(template) = template {
37 if let TemplateResult::Widget(template) = handle_template(
38 template,
39 style.as_ref(),
40 &mut template_ptrs,
41 &mut widget_poll,
42 &mut vec![],
43 0,
44 Role::Normal,
45 )? {
46 Some(template)
47 } else {
48 None
49 }
50 } else {
51 None
52 };
53 let script = if let Some(script) = script {
55 Some(crate::script::Script::new(
56 script,
57 context,
58 polls,
59 &widget_poll,
60 &template_ptrs,
61 template.as_ref(),
62 )?)
63 } else {
64 if let Some(ident) = template.as_ref().map(|t| t.root_name()) {
65 Some(crate::script::Script::default(ident))
66 } else {
67 None
68 }
69 };
70
71 let template_ptrs = if template_ptrs.is_empty() {
73 None
74 } else {
75 Some(template_ptrs)
76 };
77
78 let mut widget = Widget {
79 source,
80 template,
81 template_ptrs,
82 script,
83 is_entry,
84 has_plugin: context.plugins.is_some(),
85 };
86
87 let _ = widget.patch_or_default_script()?;
89 Ok(widget)
90}
91
92fn handle_template(
93 template: Template,
94 styles: Option<&Style>,
95 template_ptrs: &mut TemplatePtrs,
96 widget_poll: &mut WidgetPoll,
97 chain: &mut Vec<IdClass>,
98 index: usize,
99 father_role: Role,
100) -> Result<TemplateResult, Error> {
101 let is_static = template.is_static();
102 let is_define = template.is_component();
103 let Template {
104 id,
105 class,
106 as_prop,
107 name,
108 mut props,
109 callbacks,
110 inherits,
111 root,
112 children,
113 sugar_props,
114 parent,
115 binds,
116 ..
117 } = template;
118 let mut bind_props = HashMap::new();
120 if let Some(binds) = binds.as_ref() {
121 for (k, v) in binds {
122 bind_props.insert(v.as_bind()?.ident(), k.name.to_string());
123 }
124 }
125 let mut role = if let SugarProps::For(for_sign) = sugar_props {
128 if let Ok(Bind::For(bind)) = for_sign.as_bind() {
129 let mut parent: ForParent = parent.as_ref().unwrap().into();
130 parent.set_credential(father_role);
131 if let Some(id) = id.as_ref() {
132 Ok(Role::For {
133 parent,
134 creditial: bind,
135 origin_pos: index,
136 props: bind_props.clone(),
137 children: vec![],
138 id: id.to_string(),
139 name: name.to_string(),
140 })
141 } else {
142 Err(err_from_to!(
143 "GenUI Component" => "Makepad Widget, for widget need id!"
144 ))
145 }
146 } else {
147 Ok(Role::default())
148 }
149 } else {
150 Ok(Role::default())
151 }?;
152
153 let is_role_virtual = role.is_virtual();
154 if inherits.is_some() {
156 return Err(err_from_to!(
157 "GenUI Component" => "Makepad Widget, Static Widget has no inherits"
158 ));
159 }
160 if let Some(id) = id.as_ref() {
162 let widget = AbsWidget::new(&name, props.clone());
163 widget_poll.insert(id.to_string(), widget);
164 }
165 if callbacks.is_some() {
168 if as_prop.is_some() {
169 return Err(err_from_to!(
170 "GenUI Component" => "Makepad Widget, as_prop widget can't have callback!"
171 ));
172 }
173 if id.is_none() {
175 return Err(err_from_to!(
176 "GenUI Component" => "Makepad Widget, callback widget need id!"
177 ));
178 }
179 }
180 if let Some(styles) = styles.as_ref() {
182 let other_props = StyleVisitor::visit(styles, id.as_ref(), class.as_ref(), chain)?;
183 if !other_props.is_empty() {
185 if props.is_none() {
186 props = Some(HashMap::new());
187 }
188 if let Some(props) = props.as_mut() {
189 for p in other_props {
190 props.extend(p);
191 }
192 }
193 }
194 }
195
196 let ty = if !is_define {
197 WidgetType::try_from((name, props, root))?
198 } else {
199 WidgetType::Define((name, props, root).try_into()?)
200 };
201
202 let children = if let Some(children) = children {
203 let mut w_children = vec![];
204 chain.push(IdClass {
205 id: id.clone(),
206 class: class.clone(),
207 });
208 for (index, child) in children.into_iter().enumerate() {
209 let w = handle_template(
210 child,
211 styles,
212 template_ptrs,
213 widget_poll,
214 chain,
215 index,
216 role.clone(),
217 )?;
218 match w {
219 TemplateResult::Widget(widget_template) => {
220 w_children.push(widget_template);
221 }
222 TemplateResult::Role(child_role) => {
223 role.push_child(child_role);
224 }
225 }
226 }
227 if w_children.is_empty() {
228 None
229 } else {
230 Some(w_children)
231 }
232 } else {
233 None
234 };
235
236 let binds = if bind_props.is_empty() {
237 None
238 } else {
239 Some(bind_props)
240 };
241
242 let widget = WidgetTemplate {
243 id,
244 is_root: root,
245 as_prop,
246 is_static,
247 ty,
248 children,
249 role,
250 binds,
251 };
252 if is_role_virtual {
253 let role = widget.role.clone();
254 template_ptrs.push(widget);
255 Ok(TemplateResult::Role(role))
256 } else {
257 Ok(TemplateResult::Widget(widget))
258 }
259}
260
261pub enum TemplateResult {
262 Widget(WidgetTemplate),
263 Role(Role),
264}