makepad_widgets/
designer_outline_tree.rs

1use {
2    std::{
3        collections::{HashSet},
4    },
5    crate::{
6        makepad_derive_widget::*,
7        makepad_draw::*,
8        widget::*,
9        fold_button::*,
10        scroll_shadow::DrawScrollShadow,
11        scroll_bars::ScrollBars
12    }
13};
14
15live_design!{
16    use link::theme::*;
17    use makepad_draw::shader::std::*;
18    use link::widgets::*;
19    use crate::designer_theme::*;
20        
21    DrawNodeQuad = {{DrawNodeQuad}} {}
22    DrawNodeText = {{DrawNodeText}} {}
23    DrawNodeIcon = {{DrawNodeIcon}} {}
24    
25    pub DesignerOutlineTreeNodeBase = {{DesignerOutlineTreeNode}} {}
26    pub DesignerOutlineTreeBase = {{DesignerOutlineTree}} {}
27    
28    pub DesignerOutlineTreeNode = <DesignerOutlineTreeNodeBase> {
29        align: { y: 0.5 }
30        padding: { left: (THEME_SPACE_1) },
31        
32        indent_width: 10.0
33        min_drag_distance: 10.0
34        button_open_width: 24.0,
35        draw_eye: false,
36        
37        draw_bg: {
38            instance selected: 0.0
39            instance hover: 0.0
40            instance focussed: 0.0
41            
42            fn pixel(self) -> vec4 {
43                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
44                sdf.box(
45                    0.,
46                    -2.,
47                    self.rect_size.x,
48                    self.rect_size.y + 3.0,
49                    1.
50                )
51                sdf.fill_keep(
52                    mix(
53                        mix(
54                            THEME_COLOR_BG_EVEN,
55                            THEME_COLOR_BG_ODD,
56                            self.is_even
57                        ),
58                        THEME_COLOR_OUTSET_ACTIVE,
59                        self.selected
60                    )
61                )
62                return sdf.result
63            }
64        }
65        icon_walk:{
66            margin:{top:3,left:3,right:5}
67            width:12,
68            height:12,
69        }
70        draw_icon: {
71            instance selected: 0.0
72            instance hover: 0.0
73            instance focussed: 0.0
74            fn get_color(self) -> vec4 {
75                return self.color * self.scale;
76            }
77        }
78        
79        draw_text: {
80            instance selected: 0.0
81            instance hover: 0.0
82            instance focussed: 0.0
83            fn get_color(self) -> vec4 {
84                return mix(
85                    THEME_COLOR_LABEL_OUTER * self.scale,
86                    THEME_COLOR_LABEL_OUTER_ACTIVE,
87                    self.selected
88                )
89            }
90            
91            text_style: <THEME_FONT_REGULAR> {
92                font_size: (THEME_FONT_SIZE_P)
93                //top_drop: 1.2,
94            }
95        }
96        
97        button_open: <FoldButton> {
98            height: 25, width: 15,
99            margin: { left: (THEME_SPACE_2) }
100            animator: { active = { default: off } },
101            draw_bg: {
102                uniform size: 3.75;
103                instance open: 0.0
104                
105                fn pixel(self) -> vec4 {
106                    let sdf = Sdf2d::viewport(self.pos * self.rect_size)
107                    let left = 2;
108                    let sz = self.size;
109                    let c = vec2(left + sz, self.rect_size.y * 0.5);
110                    
111                    // PLUS
112                    sdf.box(0.5, sz * 3.0, sz * 2.5, sz * 0.7, 1.0); // rounding = 3rd value
113                    // vertical
114                    sdf.fill_keep(mix(#8F, #FF, self.hover));
115                    sdf.box(sz * 1.0, sz * 2.125, sz * 0.7, sz * 2.5, 1.0); // rounding = 3rd value
116                    
117                    sdf.fill_keep(mix(mix(#8F, #FF, self.hover), #FFF0, self.active))
118                    
119                    return sdf.result
120                }
121            }
122        }
123        
124        animator: {
125            hover = {
126                default: off
127                off = {
128                    from: {all: Forward {duration: 0.2}}
129                    apply: {
130                        hover: 0.0
131                        draw_bg: {hover: 0.0}
132                        draw_text: {hover: 0.0}
133                        draw_icon: {hover: 0.0}
134                    }
135                }
136                
137                on = {
138                    cursor: Hand
139                    from: {all: Snap}
140                    apply: {
141                        hover: 1.0
142                        draw_bg: {hover: 1.0}
143                        draw_text: {hover: 1.0}
144                        draw_icon: {hover: 1.0}
145                    },
146                }
147            }
148            
149            focus = {
150                default: on
151                on = {
152                    from: {all: Snap}
153                    apply: {focussed: 1.0}
154                }
155                
156                off = {
157                    from: {all: Forward {duration: 0.1}}
158                    apply: {focussed: 0.0}
159                }
160            }
161            
162            select = {
163                default: off
164                off = {
165                    from: {all: Forward {duration: 0.1}}
166                    apply: {
167                        selected: 0.0
168                        draw_bg: {selected: 0.0}
169                        draw_text: {selected: 0.0}
170                        draw_icon: {selected: 0.0}
171                    }
172                }
173                on = {
174                    from: {all: Snap}
175                    apply: {
176                        selected: 1.0
177                        draw_bg: {selected: 1.0}
178                        draw_text: {selected: 1.0}
179                        draw_icon: {selected: 1.0}
180                    }
181                }
182                
183            }
184        }
185    }
186    
187    STUDIO_PALETTE_1 = #B2FF64
188    STUDIO_PALETTE_2 = #80FFBF
189    STUDIO_PALETTE_3 = #80BFFF
190    STUDIO_PALETTE_4 = #BF80FF
191    STUDIO_PALETTE_5 = #FF80BF
192    STUDIO_PALETTE_6 = #FFB368
193    STUDIO_PALETTE_7 = #FFD864
194    
195    STUDIO_COLOR_FILE = (THEME_COLOR_LABEL_OUTER)
196    STUDIO_COLOR_FOLDER = (THEME_COLOR_LABEL_OUTER)
197    STUDIO_COLOR_LAYOUT = (STUDIO_PALETTE_6)
198    STUDIO_COLOR_WIDGET = (STUDIO_PALETTE_2)
199    STUDIO_COLOR_ASSET = (STUDIO_PALETTE_5)
200    STUDIO_COLOR_TEXT = (STUDIO_PALETTE_1)
201    
202    pub DesignerOutlineTree = <DesignerOutlineTreeBase> {
203        flow: Down,
204        
205        scroll_bars: <ScrollBars> {}
206        scroll_bars: {}
207        node_height: (THEME_DATA_ITEM_HEIGHT),
208        clip_x: true,
209        clip_y: true
210        
211        File = <DesignerOutlineTreeNode> {
212            draw_eye: true,
213            draw_icon: {
214                color: (STUDIO_COLOR_FILE)
215                svg_file: dep("crate://self/resources/icons/icon_file.svg"),
216            }
217        }
218        
219        Folder = <DesignerOutlineTreeNode> {
220            draw_icon: {
221                color: (STUDIO_COLOR_FOLDER)
222                svg_file: dep("crate://self/resources/icons/icon_folder.svg"),
223            }
224        }
225        
226        Layout = <DesignerOutlineTreeNode> {
227            draw_icon: {
228                color: (STUDIO_COLOR_LAYOUT)
229                svg_file: dep("crate://self/resources/icons/icon_layout.svg"),
230            }
231        }
232        
233        Widget = <DesignerOutlineTreeNode> {
234            draw_icon: {
235                color: (STUDIO_COLOR_WIDGET)
236                svg_file: dep("crate://self/resources/icons/icon_widget.svg"),
237            }
238        }
239        
240        Asset = <DesignerOutlineTreeNode> {
241            draw_icon: {
242                color: (STUDIO_COLOR_ASSET)
243                svg_file: dep("crate://self/resources/icons/icon_image.svg"),
244            }
245        }
246        
247        Text = <DesignerOutlineTreeNode> {
248            draw_icon: {
249                color: (STUDIO_COLOR_TEXT)
250                svg_file: dep("crate://self/resources/icons/icon_text.svg"),
251            }
252        }
253        
254        filler: {
255            fn pixel(self) -> vec4 {
256                return mix(
257                    THEME_COLOR_BG_EVEN,
258                    THEME_COLOR_BG_ODD,
259                    self.is_even
260                );
261            }
262        }
263    }
264}
265
266// TODO support a shared 'inputs' struct on drawshaders
267#[derive(Live, LiveHook, LiveRegister)]#[repr(C)]
268struct DrawNodeQuad {
269    #[deref] draw_super: DrawQuad,
270    #[live] is_even: f32,
271    #[live] scale: f32,
272}
273
274// TODO support a shared 'inputs' struct on drawshaders
275#[derive(Live, LiveHook, LiveRegister)]#[repr(C)]
276struct DrawNodeIcon {
277    #[deref] draw_super: DrawIcon,
278    #[live] scale: f32,
279}
280
281// TODO support a shared 'inputs' struct on drawshaders
282#[derive(Live, LiveHook, LiveRegister)]#[repr(C)]
283struct DrawNodeText {
284    #[deref] draw_super: DrawText,
285    #[live] scale: f32,
286}
287
288#[derive(Live, LiveHook, LiveRegister)]
289pub struct DesignerOutlineTreeNode {
290    #[live] draw_bg: DrawNodeQuad,
291    #[live] button_open: FoldButton,
292    #[live] draw_icon: DrawNodeIcon,
293    #[live] draw_text: DrawNodeText,
294    #[live] icon_walk: Walk,
295    #[live] button_open_width: f64,
296    #[live] draw_eye: bool,
297    #[layout] layout: Layout,
298    
299    #[animator] animator: Animator,
300    
301    #[live] min_drag_distance: f64,
302    #[live] indent_width: f64,
303    #[live] indent_shift: f64,
304    
305    #[live] selected: f64,
306    #[live] opened: f64,
307    #[live] hover: f64,
308    #[live] focussed: f64
309}
310
311#[derive(Live, Widget)]
312pub struct DesignerOutlineTree {
313    #[redraw] #[live] scroll_bars: ScrollBars,
314    
315    #[rust] templates: ComponentMap<LiveId, LivePtr>,
316        
317    #[walk] walk: Walk,
318    #[layout] layout: Layout,
319    #[live] filler: DrawNodeQuad,
320    
321    #[live] node_height: f64,
322    
323    #[live] draw_scroll_shadow: DrawScrollShadow,
324    
325    #[rust] draw_state: DrawStateWrap<()>,
326    
327    #[rust] dragging_node_id: Option<LiveId>,
328    #[rust] selected_node_id: Option<LiveId>,
329    #[rust] open_nodes: HashSet<LiveId>,
330    #[rust] scroll_into_view_id: Option<LiveId>,
331    #[rust] scroll_into_view_rect: Option<Rect>,
332        
333    #[rust] tree_nodes: ComponentMap<LiveId, (DesignerOutlineTreeNode, LiveId)>,
334    
335    #[rust] count: usize,
336    #[rust] stack: Vec<f64>,
337}
338
339impl LiveHook for DesignerOutlineTree {
340    fn before_apply(&mut self, _cx: &mut Cx, apply: &mut Apply, _index: usize, _nodes: &[LiveNode]) {
341        if let ApplyFrom::UpdateFromDoc {..} = apply.from {
342            self.templates.clear();
343        }
344    }
345        
346    // hook the apply flow to collect our templates and apply to instanced childnodes
347    fn apply_value_instance(&mut self, cx: &mut Cx, apply: &mut Apply, index: usize, nodes: &[LiveNode]) -> usize {
348        if nodes[index].is_instance_prop() {
349            if let Some(live_ptr) = apply.from.to_live_ptr(cx, index){
350                let id = nodes[index].id;
351                self.templates.insert(id, live_ptr);
352                for (_, (node, templ_id)) in self.tree_nodes.iter_mut() {
353                    if *templ_id == id {
354                        let opened = node.opened;
355                        node.apply(cx, apply, index, nodes);
356                        node.opened = opened;
357                    }
358                }
359            }
360        }
361        else {
362            cx.apply_error_no_matching_field(live_error_origin!(), index, nodes);
363        }
364        nodes.skip_node(index)
365    }
366    
367}
368
369#[derive(Clone, Debug, DefaultNone)]
370pub enum OutlineTreeAction {
371    None,
372    Selected(LiveId, KeyModifiers),
373    EyeClicked(LiveId, bool),
374    ShouldStartDrag(LiveId),
375}
376
377pub enum OutlineTreeNodeAction {
378    Selected(KeyModifiers),
379    Opening,
380    Closing,
381    ShouldStartDrag
382}
383
384impl DesignerOutlineTreeNode {
385    pub fn draw(&mut self, cx: &mut Cx2d, name: &str, is_even: f32, node_height: f64, depth: usize, scale: f64, draw_open_button:bool) {
386        self.draw_bg.is_even = is_even;
387        self.draw_bg.scale = scale as f32;
388        self.draw_icon.scale = scale as f32;
389        self.draw_text.scale = scale as f32;
390                        
391        
392        self.draw_bg.begin(cx, Walk::size(Size::Fill, Size::Fixed(scale * node_height)), self.layout);
393                
394        cx.walk_turtle(self.indent_walk(depth));
395        if draw_open_button{
396            self.button_open.draw_all(cx, &mut Scope::empty());
397        }
398        else{
399            cx.walk_turtle(Walk::fixed(self.button_open_width,0.0));
400        }
401        self.draw_icon.draw_walk(cx, self.icon_walk);
402        self.draw_text.draw_walk(cx, Walk::fit(), Align::default(), name);
403        self.draw_bg.end(cx);
404    }
405    
406    fn indent_walk(&self, depth: usize) -> Walk {
407        Walk {
408            abs_pos: None,
409            width: Size::Fixed(depth as f64 * self.indent_width + self.indent_shift),
410            height: Size::Fixed(0.0),
411            margin: Margin::default()
412        }
413    }
414    
415    fn set_is_selected(&mut self, cx: &mut Cx, is: bool, animate: Animate) {
416        self.animator_toggle(cx, is, animate, id!(select.on), id!(select.off))
417    }
418    
419    fn set_is_focussed(&mut self, cx: &mut Cx, is: bool, animate: Animate) {
420        self.animator_toggle(cx, is, animate, id!(focus.on), id!(focus.off))
421    }
422    
423    pub fn set_is_open(&mut self, cx: &mut Cx, is: bool, animate: Animate) {
424        if is{
425            self.opened = 1.0
426        }
427        else{
428            self.opened = 0.0
429        }
430        self.button_open.animator_toggle(cx, is, animate, id!(active.on), id!(active.off));
431    }
432    
433    pub fn set_folder_is_open(&mut self, cx: &mut Cx, is: bool, animate: Animate) {
434        self.animator_toggle(cx, is, animate, id!(active.on), id!(active.off));
435    }
436    
437    pub fn handle_event(
438        &mut self,
439        cx: &mut Cx,
440        event: &Event,
441        node_id: LiveId,
442        scope: &mut Scope,
443        actions_out: &mut Vec<(LiveId, OutlineTreeNodeAction)>,
444    ) {
445        let actions = cx.capture_actions(|cx|{
446            self.button_open.handle_event(cx, event, scope);
447        });
448        
449        /*if let Some(km) = self.button_name.pressed_modifiers(&actions){
450            actions_out.push((node_id, OutlineTreeNodeAction::NamePressed(km)));
451        }*/
452        
453        if let Some(anim) = self.button_open.animating(&actions){
454            self.opened = anim;
455            self.draw_bg.redraw(cx);
456        }
457        if self.button_open.opening(&actions){
458            actions_out.push((node_id, OutlineTreeNodeAction::Opening));
459        }
460        if self.button_open.closing(&actions){
461            actions_out.push((node_id, OutlineTreeNodeAction::Closing));
462        }
463        
464        if self.animator_handle_event(cx, event).must_redraw() {
465            self.draw_bg.redraw(cx);
466        }
467        
468        match event.hits(cx, self.draw_bg.area()) {
469            Hit::FingerHoverIn(_) => {
470               self.animator_play(cx, id!(hover.on));
471            }
472            Hit::FingerHoverOut(_) => {
473                self.animator_play(cx, id!(hover.off));
474            }
475            Hit::FingerMove(f) => {
476                if f.abs.distance(&f.abs_start) >= self.min_drag_distance {
477                    actions_out.push((node_id, OutlineTreeNodeAction::ShouldStartDrag));
478                }
479            }
480            Hit::FingerDown(e) => {
481                self.animator_play(cx, id!(active.on));
482                actions_out.push((node_id, OutlineTreeNodeAction::Selected(e.modifiers)));
483                /*
484                if self.is_folder {
485                    if self.animator_in_state(cx, id!(active.on)) {
486                        self.animator_play(cx, id!(active.off));
487                        actions.push((node_id, OutlineTreeNodeAction::Closing));
488                    }
489                    else {
490                        self.animator_play(cx, id!(active.on));
491                        actions.push((node_id, OutlineTreeNodeAction::Opening));
492                    }
493                }
494                actions.push((node_id, OutlineTreeNodeAction::WasClicked));*/
495            }
496            _ => {}
497        }
498    }
499}
500
501impl DesignerOutlineTree {
502    
503    pub fn begin(&mut self, cx: &mut Cx2d, walk: Walk) {
504        self.scroll_bars.begin(cx, walk, self.layout);
505        self.count = 0;
506    }
507    
508    pub fn end(&mut self, cx: &mut Cx2d) {
509        // lets fill the space left with blanks
510        let height_left = cx.turtle().height_left();
511        let mut walk = 0.0;
512        while walk < height_left {
513            self.count += 1;
514            self.filler.is_even = Self::is_even_as_f32(self.count);
515            self.filler.draw_walk(cx, Walk::size(Size::Fill, Size::Fixed(self.node_height.min(height_left - walk))));
516            walk += self.node_height.max(1.0);
517        }
518        
519        self.draw_scroll_shadow.draw(cx, dvec2(0., 0.));
520        self.scroll_bars.end(cx);
521        
522        if let Some(rect) = self.scroll_into_view_rect.take(){
523            let rect = rect.add_margin(dvec2(0.0,self.node_height*3.0)).translate(self.scroll_bars.get_scroll_pos());
524            self.scroll_bars.scroll_into_view_abs(cx, rect);
525        }
526        
527        let selected_node_id = self.selected_node_id;
528        self.tree_nodes.retain_visible_and( | node_id, _ | Some(*node_id) == selected_node_id);
529    }
530    
531    pub fn is_even_as_f32(count: usize) -> f32 {
532        if count % 2 == 1 {0.0}else {1.0}
533    }
534    
535    pub fn should_node_draw(&mut self, node_id: LiveId, cx: &mut Cx2d) -> bool {
536        let scale = self.stack.last().cloned().unwrap_or(1.0);
537        let height = self.node_height * scale;
538        let walk = Walk::size(Size::Fill, Size::Fixed(height));
539        if scale > 0.01 && cx.walk_turtle_would_be_visible(walk) {
540            if let Some(view_id) = &self.scroll_into_view_id{
541                if *view_id == node_id{
542                    self.scroll_into_view_id.take();
543                }
544            }
545            return true
546        }
547        else {
548            // alright so the node is NOT visible. what if we should be
549            let rect = cx.walk_turtle(walk);
550            if let Some(view_id) = &self.scroll_into_view_id{
551                if *view_id == node_id{
552                    self.scroll_into_view_id.take();
553                    self.scroll_into_view_rect = Some(rect);
554                }
555            }
556            return false
557        }
558    }
559    
560    pub fn begin_node(
561        &mut self,
562        cx: &mut Cx2d,
563        node_id: LiveId,
564        name: &str,
565        template: LiveId,
566    ) -> Result<(), ()> {
567        let scale = self.stack.last().cloned().unwrap_or(1.0);
568        
569        if scale > 0.2 {
570            self.count += 1;
571        }
572        
573        let is_open = self.open_nodes.contains(&node_id);
574        let is_selected = self.selected_node_id == Some(node_id);
575        if self.should_node_draw(node_id, cx) {
576            // lets create the node
577            if let Some(ptr) = self.templates.get(&template){
578                let (tree_node, _) = self.tree_nodes.get_or_insert(cx, node_id, | cx | {
579                    let mut tree_node = DesignerOutlineTreeNode::new_from_ptr(cx, Some(*ptr));
580                    if is_open {
581                        tree_node.set_is_open(cx, true, Animate::No)
582                    }
583                    if is_selected{
584                        tree_node.set_is_selected(cx, true, Animate::No)
585                    }
586                    (tree_node, template)
587                });
588                tree_node.draw(cx, name, Self::is_even_as_f32(self.count), self.node_height, self.stack.len(), scale, true);
589                self.stack.push(tree_node.opened as f64 * scale);
590                if tree_node.opened <= 0.001 {
591                    self.end_node();
592                    return Err(());
593                }
594            }
595            else{
596                return Err(());
597            }
598        }
599        else {
600            if is_open {
601                self.stack.push(scale * 1.0);
602            }
603            else {
604                return Err(());
605            }
606        }
607        Ok(())
608    }
609    
610    pub fn end_node(&mut self) {
611        self.stack.pop();
612    }
613    
614    pub fn node(&mut self, cx: &mut Cx2d, node_id: LiveId, name: &str, template: LiveId) {
615        let scale = self.stack.last().cloned().unwrap_or(1.0);
616        
617        if scale > 0.2 {
618            self.count += 1;
619        }
620        let is_selected = self.selected_node_id == Some(node_id);
621        if self.should_node_draw(node_id, cx) {
622            if let Some(ptr) = self.templates.get(&template){
623                let (tree_node, _) = self.tree_nodes.get_or_insert(cx, node_id, | cx | {
624                    let mut tree_node = DesignerOutlineTreeNode::new_from_ptr(cx, Some(*ptr));
625                    if is_selected{
626                        tree_node.set_is_selected(cx, true, Animate::No)
627                    }
628                    (tree_node, template)
629                    
630                });
631                tree_node.draw(cx, name, Self::is_even_as_f32(self.count), self.node_height, self.stack.len(), scale, false);
632            }
633        }
634    }
635    
636    pub fn forget(&mut self) {
637        self.tree_nodes.clear();
638    }
639    
640    pub fn forget_node(&mut self, file_node_id: LiveId) {
641        self.tree_nodes.remove(&file_node_id);
642    }
643    
644    pub fn select_and_show_node(&mut self, cx:&mut Cx, id_path:&[LiveId])  {
645        if id_path.len() == 0{
646            return
647        }
648        for i in 0..id_path.len()-1{
649            let id = id_path[i];
650            self.open_nodes.insert(id);
651            if let Some((tree_node,_)) = self.tree_nodes.get_mut(&id){
652                tree_node.set_is_open(cx, true, Animate::No);
653            }
654        }
655        let last = *id_path.last().unwrap();
656        self.scroll_into_view_id = Some(last);
657        self.selected_node_id = Some(last);
658        
659        for (id,(tree_node,_)) in self.tree_nodes.iter_mut(){
660            if *id == last{
661                tree_node.set_is_selected(cx, true, Animate::No);
662            }
663            else{
664                tree_node.set_is_selected(cx, false, Animate::No);
665            }
666        }
667        self.redraw(cx);
668    }
669    
670    pub fn start_dragging_file_node(
671        &mut self,
672        cx: &mut Cx,
673        node_id: LiveId,
674        items: Vec<DragItem>,
675    ) {
676        self.dragging_node_id = Some(node_id);
677
678        log!("makepad: start_dragging_file_node");
679
680        cx.start_dragging(items);
681    }
682    
683    pub fn set_folder_is_open(
684        &mut self,
685        cx: &mut Cx,
686        node_id: LiveId,
687        is_open: bool,
688        animate: Animate,
689    ) {
690        if is_open {
691            self.open_nodes.insert(node_id);
692        }
693        else {
694            self.open_nodes.remove(&node_id);
695        }
696        if let Some((tree_node, _)) = self.tree_nodes.get_mut(&node_id) {
697            tree_node.set_folder_is_open(cx, is_open, animate);
698        }
699    }
700    /*
701    pub fn set_open_by_path(
702        &mut self,
703        cx: &mut Cx,
704        path: &str,
705        is_open: bool,
706        animate: Animate,
707    ) {
708        for (idx,_) in path.match_indices('/'){
709            let slice = &path[0..idx+1];
710            let hash =  LiveId::from_str(slice).into();
711            self.set_folder_is_open(cx, hash, is_open, animate);
712        }
713    }*/
714/*    
715    let folder1 =  LiveId::from_str("examples/").into();
716    file_tree.set_folder_is_open(cx, folder1, true, Animate::No);
717    let folder1 =  LiveId::from_str("examples/ironfish/").into();
718    file_tree.set_folder_is_open(cx, folder1, true, Animate::No);
719    let folder1 =  LiveId::from_str("examples/ironfish/src/app_desktop.rs/").into();
720    file_tree.set_folder_is_open(cx, folder1, true, Animate::No);
721*/    
722}
723
724//pub type LiveId = LiveId;
725//#[derive(Clone, Debug, Default, Eq, Hash, Copy, PartialEq, FromLiveId)]
726//pub struct LiveId(pub LiveId);
727
728impl Widget for DesignerOutlineTree {
729
730    fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
731        let uid = self.widget_uid();
732        
733        self.scroll_bars.handle_event(cx, event, scope);
734                
735        match event {
736            Event::DragEnd => self.dragging_node_id = None,
737            _ => ()
738        }
739        
740        let mut node_actions = Vec::new();
741                
742        for (node_id, (node, _)) in self.tree_nodes.iter_mut() {
743            node.handle_event(cx, event, *node_id, scope, &mut node_actions);
744        }
745                
746        for (node_id, node_action) in node_actions {
747            match node_action {
748                OutlineTreeNodeAction::Opening => {
749                    self.open_nodes.insert(node_id);
750                }
751                OutlineTreeNodeAction::Closing => {
752                    self.open_nodes.remove(&node_id);
753                }
754                /*OutlineTreeNodeAction::EyeClicked(_checked) => {
755                    
756                }*/
757                OutlineTreeNodeAction::Selected(km) => {
758                    cx.widget_action(uid, &scope.path, OutlineTreeAction::Selected(node_id, km));
759                    cx.set_key_focus(self.scroll_bars.area());
760                    if let Some(last_selected) = self.selected_node_id {
761                        if last_selected != node_id {
762                            if let Some(node) = self.tree_nodes.get_mut(&last_selected){
763                                node.0.set_is_selected(cx, false, Animate::Yes);
764                            }
765                        }
766                    }
767                    self.selected_node_id = Some(node_id);
768                    //cx.widget_action(uid, &scope.path, OutlineTreeAction::LinkClicked(node_id));
769                }
770                OutlineTreeNodeAction::ShouldStartDrag => {
771                    if self.dragging_node_id.is_none() {
772                        cx.widget_action(uid, &scope.path, OutlineTreeAction::ShouldStartDrag(node_id));
773                    }
774                }
775            }
776        }
777                
778        match event.hits(cx, self.scroll_bars.area()) {
779            Hit::KeyFocus(_) => {
780                if let Some(node_id) = self.selected_node_id {
781                    self.tree_nodes.get_mut(&node_id).unwrap().0.set_is_focussed(cx, true, Animate::Yes);
782                }
783            }
784            Hit::KeyFocusLost(_) => {
785                if let Some(node_id) = self.selected_node_id {
786                    self.tree_nodes.get_mut(&node_id).unwrap().0.set_is_focussed(cx, false, Animate::Yes);
787                }
788            }
789            _ => ()
790        }
791    }
792    
793    fn draw_walk(&mut self, cx: &mut Cx2d, _scope:&mut Scope,walk: Walk) -> DrawStep {
794        if self.draw_state.begin(cx, ()) {
795            self.begin(cx, walk);
796            return DrawStep::make_step()
797        }
798        if let Some(()) = self.draw_state.get() {
799            self.end(cx);
800            self.draw_state.end();
801        }
802        DrawStep::done()
803    }
804}
805
806impl DesignerOutlineTreeRef{
807    pub fn should_file_start_drag(&self, actions: &Actions) -> Option<LiveId> {
808        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
809            if let OutlineTreeAction::ShouldStartDrag(file_id) = item.cast() {
810                return Some(file_id)
811            }
812        }
813        None
814    }
815    /*
816    pub fn file_c/licked(&self, actions: &Actions) -> Option<LiveId> {
817        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
818            if let OutlineTreeAction::FileClicked(file_id) = item.cast() {
819                return Some(file_id)
820            }
821        }
822        None
823    }*/
824    
825        
826    pub fn select_and_show_node(&self, cx:&mut Cx, id_path:&[LiveId])  {
827        if let Some(mut inner) = self.borrow_mut(){
828            inner.select_and_show_node(cx, id_path);
829        }
830    }
831        
832    
833    pub fn selected(&self, actions: &Actions) -> Option<(LiveId,KeyModifiers)> {
834        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
835            if let OutlineTreeAction::Selected(file_id, km) = item.cast() {
836                return Some((file_id,km))
837            }
838        }
839        None
840    }
841    
842    
843    pub fn start_drag(&self, cx: &mut Cx, _file_id: LiveId, item: DragItem) {
844        cx.start_dragging(vec![item]);
845    }
846}