1use crate::{
2 makepad_draw::*,
3 widget::*,
4 makepad_platform::studio::DesignerComponentPosition,
5 };
7use std::collections::HashMap;
8use std::fmt::Write;
9
10pub enum OutlineNode{
11 Virtual{
12 name: String,
13 children: SmallVec<[LiveId;4]>
14 },
15 File{
16 file_id: LiveFileId,
17 name: String,
18 children: SmallVec<[LiveId;4]>
19 },
20 Folder{
21 name: String,
22 children: SmallVec<[LiveId;4]>
23 },
24 Component{
25 name: String,
26 id: LiveId,
27 class: LiveId,
28 prop_type: LivePropType,
29 ptr: LivePtr,
31 children: SmallVec<[LiveId;4]>
32 }
33}
34
35impl OutlineNode{
36 fn children(&self)->&[LiveId]{
37 match self{
38 Self::Virtual{children,..}=>children,
39 Self::File{children,..}=>children,
40 Self::Folder{children,..}=>children,
41 Self::Component{children,..}=>children,
42 }
43 }
44
45 fn name(&self)->&str{
46 match self{
47 Self::Virtual{name,..}=>name,
48 Self::File{name,..}=>name,
49 Self::Folder{name,..}=>name,
50 Self::Component{name,..}=>name,
51 }
52 }
53}
54
55
56#[derive(Default)]
57pub struct DesignerDataToWidget{
58 pub positions: Vec<DesignerComponentPosition>,
59 pub live_ptr_to_widget: HashMap<LivePtr, WidgetRef>,
60}
61
62impl DesignerDataToWidget{
63 pub fn find_ptr_by_widget_ref(&self, widget:&WidgetRef)->Option<LivePtr>{
64 for (ptr, wref) in &self.live_ptr_to_widget{
65 if wref == widget{
66 return Some(*ptr)
67 }
68 }
69 None
70 }
71}
72
73#[derive(Default)]
74pub struct DesignerData{
75 pub pending_revision: bool,
76 pub root: LiveId,
77 pub node_map: HashMap<LiveId, OutlineNode>,
78 pub selected: Option<LiveId>,
79 pub to_widget: DesignerDataToWidget,
80}
81
82impl DesignerData{
83 pub fn get_node_by_path(&self, root:LiveId, path:&str)->Option<LiveId>{
84 let mut current = root;
85 let mut split = path.split("/");
86 'outer: while let Some(node) = self.node_map.get(¤t){
87 if let Some(next_name) = split.next(){
88 for child in node.children(){
89 let node = self.node_map.get(&child).unwrap();
90 if node.name().starts_with(next_name){
91 current = *child;
92 continue 'outer;
93 }
94 }
95 return None
96 }
97 else{
98 return Some(current)
99 }
100 }
101 None
102 }
103
104 pub fn update_from_live_registry(&mut self, cx:&mut Cx){
105 self.node_map.clear();
106 self.to_widget.live_ptr_to_widget.clear();
107 let root_uid = live_id!(designer_root).into();
108 self.root = root_uid;
109 self.node_map.insert(root_uid, OutlineNode::Virtual{
110 name: "root".into(),
111 children: SmallVec::new()
112 });
113
114 let live_registry_rc = cx.live_registry.clone();
116 let live_registry = &*live_registry_rc.borrow();
117 let main_module_lti = live_registry.main_module.as_ref().unwrap().clone();
118 let mut path_hash = String::new();
119 for (file_path, file_id) in live_registry.file_ids(){
120 let file = live_registry.file_id_to_file(*file_id);
123 let nodes = &file.expanded.nodes;
124 fn recur_walk_components(
127 main_module_lti:&LiveTypeInfo,
128 live_registry: &LiveRegistry,
129 hash_id:LiveId,
130 base_ptr: LivePtr,
131 mut index: usize,
132 nodes: &[LiveNode],
133 map: &mut HashMap<LiveId, OutlineNode>,
134 parent_children: &mut SmallVec<[LiveId;4]>) -> usize {
135
136 while index < nodes.len().saturating_sub(1) {
137 if let LiveValue::Class {live_type, class_parent, ..} = &nodes[index].value {
138 let wr = live_registry.components.get::<WidgetRegistry>();
140 if main_module_lti.live_type == *live_type || wr.map.get(live_type).is_some(){
141
142 let id = nodes[index].id;
144 let class = live_registry.ptr_to_node(*class_parent).id;
145
146 if class == live_id!(Designer) || class == live_id!(PerformanceView) ||
148 id == live_id!(caption_bar) && class == live_id!(SolidView) ||
149 id == live_id!(window_menu) && class == live_id!(WindowMenu){
150 index = nodes.skip_node(index);
151 continue;
152 }
153
154 let ptr = base_ptr.with_index(index);
155 let prop_type = nodes[index].origin.prop_type();
156 let uid = hash_id.bytes_append(&id.0.to_be_bytes());
158 let mut children = SmallVec::new();
159
160 index = recur_walk_components(
161 main_module_lti,
162 live_registry,
163 uid,
164 base_ptr,
165 index + 1,
166 nodes,
167 map,
168 &mut children
169 );
170
171 let uid = uid.into();
172 parent_children.push(uid);
173
174 let mut name = String::new();
175
176 if !id.is_unique(){
177 if let LivePropType::Field = prop_type {
178 write!(name, "{}: <{}>", id, class).unwrap();
179 }
180 else {
181 write!(name, "{}=<{}>", id, class).unwrap();
182 }
183 }
184 else {
185 write!(name, "<{}>", class).unwrap();
186 }
187
188 map.insert(uid, OutlineNode::Component {
189 id,
190 name,
191 prop_type,
192 class,
193 ptr,
194 children
195 });
196
197 }
200 else{
201 index = nodes.skip_node(index);
203 }
204 }
205 else if nodes[index].value.is_close() {
206 return index + 1;
207 }
208 else {
209 index = nodes.skip_node(index);
210 }
211 }
212 index
213 }
214 let base_ptr = live_registry.file_id_index_to_live_ptr(*file_id, 0);
217
218 path_hash.clear();
219
220
221 let base_id = LiveId(0).bytes_append(&file_id.0.to_be_bytes());
222
223 let mut children_out = SmallVec::new();
224 recur_walk_components(
225 &main_module_lti,
226 live_registry,
227 base_id,
228 base_ptr,
229 1,
230 nodes,
231 &mut self.node_map,
232 &mut children_out
233 );
234 if children_out.len() == 0{
235 continue
236 }
237 let parent_id = path_split(self.root, &mut path_hash, file_path, &mut self.node_map, *file_id);
238 if let Some(OutlineNode::File{children,..}) = self.node_map.get_mut(&parent_id){
239 *children = children_out;
240 }
241
242 fn path_split<'a>(parent_id: LiveId, path_hash:&mut String, name:&str, map:&mut HashMap<LiveId, OutlineNode>, file_id:LiveFileId)->LiveId{
243 if let Some((folder,rest)) = name.split_once("/"){
244
245 if folder == "src"{ return path_split(parent_id, path_hash, rest, map, file_id)
247 }
248
249 path_hash.push_str(folder);
250 path_hash.push_str("/");
251
252 let what_uid = LiveId::from_str(&path_hash).into();
253
254 if let Some(OutlineNode::Folder{children, ..}) | Some(OutlineNode::Virtual{children, ..})= map.get_mut(&parent_id){
256 if !children.contains(&what_uid){
257 children.push(what_uid);
258 }
259 }
260
261 if map.get_mut(&what_uid).is_some(){
262 return path_split(what_uid, path_hash, rest, map, file_id)
263 }
264
265 map.insert(what_uid, OutlineNode::Folder{
266 name: folder.to_string(),
267 children: SmallVec::new()
268 });
269
270 return path_split(what_uid, path_hash, rest, map, file_id)
271 }
272 else{ path_hash.push_str(name);
274 path_hash.push_str("/");
275 let what_uid = LiveId::from_str(&path_hash).into();
276 if let Some(OutlineNode::Folder{children, ..}) | Some(OutlineNode::Virtual{children, ..})= map.get_mut(&parent_id){
277 if !children.contains(&what_uid){
278 children.push(what_uid);
279 }
280 }
281 map.insert(what_uid, OutlineNode::File{
282 file_id,
283 name: name.to_string(),
284 children: SmallVec::new()
285 });
286
287 return what_uid
288 }
289 }
290 }
291 }
292
293 pub fn swap_child_refs(&mut self,parent:&WidgetRef, index:usize, index2:usize){
294 if let Some(id) = self.find_component_by_widget_ref(parent){
295 if let Some(OutlineNode::Component{children,..}) = self.node_map.get_mut(&id){
296 children.swap(index, index2);
297 }
298 }
299 }
300
301 pub fn find_component_by_ptr(&mut self, find_ptr:LivePtr)->Option<LiveId>{
302 for (node_id, node) in &self.node_map{
303 if let OutlineNode::Component{ptr,..} = node{
304 if *ptr == find_ptr{
305 return Some(*node_id)
306 }
307 }
308 }
309 None
310 }
311
312
313 pub fn find_component_by_widget_ref(&mut self, wref:&WidgetRef)->Option<LiveId>{
314 if let Some(ptr) = self.to_widget.find_ptr_by_widget_ref(wref){
315 return self.find_component_by_ptr(ptr);
316 }
317 None
318 }
319
320 pub fn construct_path_ids(&self, find_node:LiveId)->Vec<LiveId>{
321 let mut result = Vec::new();
322 result.push(find_node);
323 let mut iter = find_node;
324 while let Some(parent) = self.find_parent(iter){
325 result.insert(0, parent);
326 iter = parent;
327 }
328 result
329 }
330
331 pub fn path_ids_to_string(&self, path:&[LiveId])->String{
332 let mut path_str= String::new();
333 for node_id in path{
334 if let Some(node) = self.node_map.get(&node_id){
335 match node{
336 OutlineNode::Folder{name,..} | OutlineNode::File{name,..}=>{
337 path_str.push_str(name);
338 path_str.push_str("/");
339 }
340 _=>()
341 }
342 }
343 }
344 path_str
345 }
346
347 pub fn path_str_to_path_ids(path:&str)->Vec<LiveId>{
348 let mut path_id = Vec::new();
349 for (idx,_) in path.match_indices('/'){
350 let slice = &path[0..idx+1];
351 let hash = LiveId::from_str(slice).into();
352 path_id.push(hash);
353 }
354 path_id
355 }
356
357 pub fn find_parent(&self, find_node:LiveId)->Option<LiveId>{
358 for (node_id, node) in &self.node_map{
359 match node{
360 OutlineNode::Component{children,..} | OutlineNode::Virtual{children,..} | OutlineNode::File{children,..} | OutlineNode::Folder{children, ..} =>{
361 if children.iter().position(|v| *v == find_node).is_some(){
362 return Some(*node_id)
363 }
364 }
365 }
366 }
367 None
368 }
369
370 pub fn find_file_parent(&mut self, find_node:LiveId)->Option<LiveId>{
371 let mut iter = find_node;
372 while let Some(parent) = self.find_parent(iter){
373 if let Some(OutlineNode::File{..}) = self.node_map.get(&parent){
374 return Some(parent);
375 }
376 iter = parent;
377 }
378 None
379 }
380
381 pub fn _remove_child(&mut self, find_node:LiveId){
382 for node in &mut self.node_map.values_mut(){
383 match node{
384 OutlineNode::Component{children,..} | OutlineNode::Virtual{children,..} | OutlineNode::File{children,..} | OutlineNode::Folder{children, ..} =>{
385 if let Some(i) = children.iter().position(|v| *v == find_node){
386 children.remove(i);
387 break;
388 }
389 }
390 }
391 }
392 }
393
394 pub fn _find_component_by_path(&self, path:&[LiveId])->Option<LiveId>{
395 fn get_node(node:LiveId, path:&[LiveId], map:&HashMap<LiveId, OutlineNode>)->Option<LiveId>{
396 match map.get(&node).as_ref(){
397 Some(OutlineNode::Virtual{children,..}) |
398 Some(OutlineNode::Folder{children,..}) |
399 Some(OutlineNode::File{children,..}) =>{
400 for child in children{
401 if let Some(v) = get_node(*child, path, map){
402 return Some(v)
403 }
404 }
405 }
406 Some(OutlineNode::Component{children, id, ..}) => {
407 if *id == path[0]{
408 if path.len()>1{
409 for child in children{
410 if let Some(v) = get_node(*child, &path[1..], map){
411 return Some(v)
412 }
413 }
414 }
415 else{
416 return Some(node)
417 }
418 }
419 for child in children{
420 if let Some(v) = get_node(*child, path, map){
421 return Some(v)
422 }
423 }
424 }
425 _=>()
426 }
427 None
428 }
429 get_node(self.root, path, &self.node_map)
430 }
431}