makepad_widgets/
designer_view.rs

1use crate::{
2    makepad_derive_widget::*,
3    makepad_draw::*,
4    makepad_platform::studio::*,
5    designer_data::*,
6    turtle_step::*,
7    view::*,
8    widget::*,
9};
10use std::collections::BTreeMap;
11
12live_design!{
13    use link::theme::*;
14    use makepad_draw::shader::std::*;
15    use link::widgets::*;
16    
17    pub DesignerViewBase = {{DesignerView}}{
18    }
19    
20    pub DesignerContainerBase = {{DesignerContainer}}{
21    }
22    
23    pub DesignerContainer = <DesignerContainerBase>{
24        width: 1200,
25        height: 1200,
26        flow: Overlay,
27        clip_x: false,
28        clip_y: false,
29        align: {x:1.0},
30        animator: {
31            select = {
32                default: off
33                off = {
34                    from: {all: Forward {duration: 0.1}}
35                    apply: {
36                        view = {draw_bg:{border_color:#5}}
37                    }
38                }
39                on = {
40                    from: {all: Snap}
41                    apply: {
42                        view = {draw_bg:{border_color:#c}}
43                    }
44                }
45                
46            }
47        }
48        view = <RoundedView>{
49            draw_bg:{
50                color:#4,
51                border_size:2
52                border_color:#5
53            }
54            padding: 10
55            inner = <BareStep>{}
56        }
57        
58        widget_label = <RoundedShadowView>{
59            margin: { top: -35., right: 0. }
60            padding: 0.
61            width: Fit, height: Fit,
62            spacing: 0.,
63            align: { x: 1.0, y: 0.0 }
64            flow: Down,
65            clip_x: false, clip_y: false,
66            
67            draw_bg: {
68                border_size: 1.0
69                border_color: (THEME_COLOR_BEVEL_OUTSET_1)
70                shadow_color: (THEME_COLOR_D_3)
71                shadow_radius: 5.0,
72                shadow_offset: vec2(0.0, 0.0)
73                border_radius: 2.5
74                color: (THEME_COLOR_FG_APP),
75            }
76            
77            label = <Button> {
78                padding: <THEME_MSPACE_2> {}
79                text:"Hello world"
80                
81                draw_bg: {
82                    instance hover: 0.0
83                    instance down: 0.0
84                    uniform border_radius: (THEME_CORNER_RADIUS)
85                    instance color: (THEME_COLOR_FG_APP)
86                    instance color_down: #f00
87                    fn pixel(self) -> vec4 {
88                        let sdf = Sdf2d::viewport(self.pos * self.rect_size);
89                        let grad_top = 5.0;
90                        let grad_bot = 2.0;
91                        let body = mix(mix(self.color, self.color_down, self.hover), THEME_COLOR_OUTSET_DOWN, self.down);
92                        
93                        let body_transp = vec4(body.xyz, 0.0);
94                        let top_gradient = mix(
95                            body_transp,
96                            mix(THEME_COLOR_BEVEL_OUTSET_1, THEME_COLOR_BEVEL_OUTSET_1_DOWN, self.down),
97                            max(0.0, grad_top - sdf.pos.y) / grad_top
98                        );
99                        let bot_gradient = mix(
100                            mix(THEME_COLOR_BEVEL_OUTSET_2, THEME_COLOR_BEVEL_OUTSET_2_DOWN, self.down),
101                            top_gradient,
102                            clamp((self.rect_size.y - grad_bot - sdf.pos.y - 1.0) / grad_bot, 0.0, 1.0)
103                        );
104                        
105                        sdf.box(
106                            1.,
107                            1.,
108                            self.rect_size.x - 2.0,
109                            self.rect_size.y - 2.0,
110                            self.border_radius
111                        )
112                        sdf.fill_keep(body)
113                        
114                        sdf.stroke(
115                            bot_gradient,
116                            THEME_BEVELING
117                        )
118                        
119                        return sdf.result
120                    }
121                }
122            }
123        }
124    }
125    
126    pub DesignerView = <DesignerViewBase>{
127        clear_color: #3
128        draw_outline:{
129            fn pixel(self) -> vec4 {
130                let p = self.pos * self.rect_size;
131                let sdf = Sdf2d::viewport(p)
132                sdf.rect(0., 0., self.rect_size.x, self.rect_size.y);
133                                
134                let line_width = 0.58;
135                let dash_length = 10;
136                let pos = p.x + p.y;//+self.time*10.0 ;
137                let dash_pattern = fract(pos / dash_length);
138                let alpha = step(dash_pattern, line_width);
139                                
140                let c = vec4(mix(#c, #555f, alpha))
141                                
142                sdf.stroke(c, 2.5);
143                return sdf.result;
144                //return vec4(self.color.xyz * self.color.w, self.color.w)
145            }
146        }
147                
148        draw_bg: {
149            texture image: texture2d
150            varying scale: vec2
151            varying shift: vec2
152            fn vertex(self) -> vec4 {
153                
154                let dpi = self.dpi_factor;
155                let ceil_size = ceil(self.rect_size * dpi) / dpi
156                let floor_pos = floor(self.rect_pos * dpi) / dpi
157                self.scale = self.rect_size / ceil_size;
158                self.shift = (self.rect_pos - floor_pos) / ceil_size;
159                return self.clip_and_transform_vertex(self.rect_pos, self.rect_size)
160            }
161            fn pixel(self) -> vec4 {
162                return sample2d(self.image, self.pos * self.scale + self.shift);
163            }
164        }
165        container: <DesignerContainer>{
166        }
167    }
168    
169}
170
171#[derive(Clone, Debug, DefaultNone)]
172pub enum DesignerViewAction {
173    None,
174    SwapComponents{
175        comp: LiveId,
176        next_comp: LiveId,
177    },
178    Selected{
179        id:LiveId, 
180        km:KeyModifiers,
181        tap_count: u32,
182    }
183}
184
185
186struct ContainerData{
187    ptr: LivePtr,
188    component: WidgetRef,
189    container: WidgetRef,
190    rect: Rect
191}
192
193enum Edge{
194    Left,
195    Right,
196    Bottom,
197    Top,
198    Body
199}
200
201impl ContainerData{
202    fn get_edge(&self, rel:DVec2, zoom:f64, pan: DVec2)->Option<Edge>{
203        let cp = rel * zoom + pan;
204        let edge_outer:f64 = 5.0 * zoom ;
205        let edge_inner:f64  = 5.0 * zoom ;
206                
207        if cp.x >= self.rect.pos.x - edge_outer && 
208        cp.x <= self.rect.pos.x + edge_inner && 
209        cp.y >= self.rect.pos.y && 
210        cp.y <= self.rect.pos.y + self.rect.size.y{
211            // left edge
212            return Some(Edge::Left);
213        }
214        if cp.x >= self.rect.pos.x + self.rect.size.x- edge_outer && 
215        cp.x <= self.rect.pos.x + self.rect.size.x+ edge_inner && 
216        cp.y >= self.rect.pos.y && 
217        cp.y <= self.rect.pos.y + self.rect.size.y{
218            return Some(Edge::Right);
219        }
220        else if cp.y >= self.rect.pos.y - edge_outer && 
221        cp.y <= self.rect.pos.y + edge_inner &&
222        cp.x >= self.rect.pos.x && 
223        cp.x <= self.rect.pos.x + self.rect.size.x{
224            // top edge
225            return Some(Edge::Top);
226        }
227        else if cp.y >= self.rect.pos.y + self.rect.size.y- edge_outer && 
228        cp.y <= self.rect.pos.y + self.rect.size.y + edge_inner &&
229        cp.x >= self.rect.pos.x && 
230        cp.x <= self.rect.pos.x + self.rect.size.x{
231            // bottom edge
232            return Some(Edge::Bottom);
233        }
234        else if self.rect.contains(cp){
235            // bottom edge
236            return Some(Edge::Body);
237        }
238        None
239    }
240}
241
242#[derive(Live, Widget, LiveHook)]
243pub struct DesignerContainer {
244    #[deref] view: View
245}
246
247impl Widget for DesignerContainer {
248    fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope){
249        self.view.handle_event(cx, event, scope);
250    }
251                
252    fn draw_walk(&mut self, cx: &mut Cx2d, scope:&mut Scope, _walk: Walk) -> DrawStep {
253        let data = scope.props.get::<ContainerData>().unwrap();
254        // alright lets draw the container, then the child
255        let _turtle_step = self.view.turtle_step(id!(inner));
256        self.walk = Walk{
257            abs_pos: Some(data.rect.pos),
258            width: Size::Fixed(data.rect.size.x),
259            height: Size::Fixed(data.rect.size.y),
260            margin: Default::default()
261        };
262        while let Some(_next) = self.view.draw(cx, &mut Scope::empty()).step() {
263            data.component.draw_all(cx, &mut Scope::empty());
264        }
265        
266        DrawStep::done()
267    }
268}
269
270#[allow(unused)]
271enum FingerMove{
272    Pan{start_pan: DVec2},
273    DragBody{ptr: LivePtr},
274    DragEdge{edge: Edge, rect:Rect, id: LiveId},
275    DragAll{rects:BTreeMap<LiveId,Rect>},
276    DragSubComponentOrder(SelectedSubcomponent)
277}
278
279#[derive(Live, Widget)]
280pub struct DesignerView {
281    #[walk] walk:Walk,
282    #[area]
283    #[rust] area:Area,
284    #[rust] reapply: bool,
285    #[rust(1.5)] zoom: f64,
286    #[rust] undo_group: u64,
287    #[rust] pan: DVec2,
288    #[live] clear_color: Vec4,
289    #[rust] finger_move: Option<FingerMove>,
290    #[live] container: Option<LivePtr>,
291    #[live] draw_bg: DrawColor,
292    #[live] draw_outline: DrawQuad,
293    #[rust] view_file: Option<LiveId>,
294    #[rust] selected_component: Option<LiveId>,
295    #[rust] selected_subcomponent: Option<SelectedSubcomponent>,
296    #[rust] containers: ComponentMap<LiveId, ContainerData>,
297    #[redraw] #[rust(DrawList2d::new(cx))] draw_list: DrawList2d,
298    #[rust(Pass::new(cx))] pass: Pass,
299    #[rust] color_texture: Option<Texture>,
300}
301
302#[derive(Clone, Debug)]
303struct SelectedSubcomponent{
304    parent:Option<WidgetRef>,
305    component:WidgetRef
306}
307
308impl LiveHook for DesignerView {
309fn after_update_from_doc(&mut self, _cx: &mut Cx){
310        // find a bit cleaner way to do this
311        self.reapply = true;
312    }
313}
314
315impl DesignerView{
316    fn draw_container(&mut self, cx:&mut Cx2d, id:LiveId, ptr: LivePtr, name:&str, to_widget: &mut DesignerDataToWidget){
317        
318        let rect = if let Some(v) = to_widget.positions.iter().find(|v| v.id == id){
319            rect(v.left, v.top, v.width, v.height)
320        }
321        else{
322            to_widget.positions.push(DesignerComponentPosition{
323                id,
324                left: 50.0,
325                top: 50.0,
326                width: 200.0,
327                height: 200.00
328            });
329            return self.draw_container(cx, id, ptr, name, to_widget);
330        };
331        // lets put on our scope a reference map
332        
333        let container_ptr = self.container.unwrap();
334        let mut is_new = false;
335        
336        let mut scope = Scope::with_data(to_widget);
337        let cd = self.containers.get_or_insert(cx, id, | cx | {
338            
339            is_new = true;
340            ContainerData{
341                ptr,
342                component :WidgetRef::new_from_ptr_with_scope(cx, Some(ptr), &mut scope),
343                container: WidgetRef::new_from_ptr_with_scope(cx, Some(container_ptr), &mut scope),
344                rect
345            }
346        });
347        cd.rect = rect;
348        cd.ptr = ptr;
349        // fix up the livecoding of the
350        if self.reapply{
351            cd.component.update_from_ptr_with_scope(cx, Some(ptr), &mut scope);
352            cd.container.update_from_ptr_with_scope(cx, Some(container_ptr), &mut scope);
353            // alright here the component is created
354        }
355        if self.reapply || is_new{
356            cd.container.apply_over(cx, live!{
357                widget_label = { label = {text:(name)}}
358            });
359            //self.reapply = false;
360        }
361        // ok so we're going to draw the container with the widget inside
362        cd.container.draw_all(cx, &mut Scope::with_props(cd))
363    }
364    
365    fn select_component(&mut self, cx:&mut Cx, what_id:Option<LiveId>){
366        /*for (id, comp) in self.containers.iter_mut(){
367            if what_id == Some(*id){
368                comp.container.as_designer_container().borrow_mut().unwrap()
369                    .animator_cut(cx, id!(active.on));
370            }
371            else{
372                comp.container.as_designer_container().borrow_mut().unwrap()
373                    .animator_cut(cx, id!(active.off));
374            }
375        }
376        */
377        self.redraw(cx);
378        self.selected_component = what_id;
379    }
380    
381    fn sync_zoom_pan(&self, _cx:&mut Cx){
382        Cx::send_studio_message(AppToStudio::DesignerZoomPan(
383            DesignerZoomPan{
384                zoom: self.zoom,
385                pan_x: self.pan.x,
386                pan_y: self.pan.y
387            }
388        ));
389    }
390    
391    fn get_component_rect(&self, cx:&mut Cx, comp:&WidgetRef)->Rect{
392        let mut rect = self.area().rect(cx);
393        let cr = comp.area().rect(cx);
394        rect.pos += (cr.pos - self.pan)/self.zoom;
395        rect.size = cr.size;
396        rect.size /= self.zoom;
397        rect
398    }
399    
400    fn update_rect(&mut self, cx:&mut Cx, id: LiveId, rect:Rect, pos:&mut Vec<DesignerComponentPosition>){
401        if let Some(container) = self.containers.get_mut(&id){
402            container.container.redraw(cx);
403            container.rect = rect;
404            // lets send the info over
405            if let Some(v) = pos.iter_mut().find(|v| v.id == id){
406                v.left = rect.pos.x;
407                v.top = rect.pos.y;
408                v.width = rect.size.x;
409                v.height = rect.size.y;
410                // alright lets send it over
411                Cx::send_studio_message(AppToStudio::DesignerComponentMoved(v.clone()));
412            }
413            // ok first we have to build a
414            
415            /*
416            // alright lets send over the rect to the editor
417            // we need to find out the text position
418            let registry = cx.live_registry.clone();
419            let mut registry = registry.borrow_mut();
420            //let replace = format!("dx:{:.1} dy:{:.1} dw:{:.1} dh:{:.1}", r.pos.x, r.pos.y, r.size.x, r.size.y);
421            let design_info = LiveDesignInfo{
422                span: Default::default(),
423                dx: rect.pos.x,
424                dy: rect.pos.y,
425                dw: rect.size.x,
426                dh: rect.size.y,
427            };
428            // lets find the ptr
429                                        
430            if let Some((replace, file_name, range)) =  registry.patch_design_info(container.ptr, design_info){
431                                                
432                Cx::send_studio_message(AppToStudio::PatchFile(PatchFile{
433                    file_name: file_name.into(),
434                    line: range.line,
435                    undo_group: self.undo_group,
436                    column_start: range.start_column,
437                    column_end: range.end_column,
438                    replace
439                }));
440                //self.finger_move = Some(FingerMove::Pan{start_pan:dvec2(0.0,0.0)});
441            }*/
442        }
443    }
444}
445
446impl Widget for DesignerView {
447    fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope){
448        let uid = self.widget_uid();
449        // alright so. our widgets dont have any 'event' flow here
450        // so what can we do.
451        // 
452        let data = scope.data.get_mut::<DesignerData>().unwrap();
453        match event.hits(cx, self.area) {
454            Hit::FingerHoverOver(fe) =>{
455                // lets poll our widget structure with a special event
456                // alright so we hover over. lets determine the mouse cursor
457                //let corner_inner:f64  = 10.0 * self.zoom;
458                //let corner_outer:f64  = 10.0 * self.zoom;
459                // lets send a designer pick into all our widgets
460                self.selected_subcomponent = None;
461                for (_id, cd) in self.containers.iter(){
462                    // ok BUT our mouse pick is not dependent on the container
463                    // ok so we are in a pass. meaning 0,0 origin
464                    let abs = (fe.abs - fe.rect.pos) * self.zoom + self.pan;
465                    // lets capture the actions
466                    let actions = cx.capture_actions(|cx|{
467                        cd.component.handle_event(cx, &Event::DesignerPick(DesignerPickEvent{
468                            abs: abs
469                        }), &mut Scope::empty())
470                    });
471                    for action in actions{
472                        if let Some(action) = action.as_widget_action(){
473                            match action.cast(){
474                                WidgetDesignAction::PickedBody=>{
475                                    // alright so lets draw a quad on top
476                                    // alright our widget got clicked.
477                                    let mut cs = action.widgets.iter();
478                                    // scan for the parent with more than one child node
479                                    // and then make our subcomponent/parent those widgets
480                                    
481                                    // scan upwards
482                                    let mut component = cs.next();
483                                    let mut parent = cs.next();
484                                    while parent.is_some(){
485                                        let p = parent.unwrap();
486                                        if let Some(p) = p.as_view().borrow(){
487                                            if p.child_count()>1{
488                                                break;
489                                            }
490                                        }
491                                        component = parent;
492                                        parent = cs.next();
493                                    }
494                                    // lets find the LivePtr that belongs to this widget
495                                    if let Some(id)  = data.find_component_by_widget_ref(component.as_ref().unwrap()){
496                                        cx.widget_action(uid, &scope.path, DesignerViewAction::Selected{
497                                            id, 
498                                            tap_count: 1 , 
499                                            km:fe.modifiers
500                                        });
501                                    }
502                                    
503                                    self.selected_subcomponent = Some(
504                                        SelectedSubcomponent{
505                                            component: component.unwrap().clone(),
506                                            parent: parent.cloned(),
507                                        }
508                                    );
509                                    // alright. now we also need to sync the selection to the tree.
510                                    
511                                    //println!("{:?}", self.selected_subcomponent);
512                                    break
513                                }
514                                _=>()
515                            }
516                        }
517                    }
518                    self.draw_list.redraw(cx);
519                }
520                
521                let mut cursor = None;
522                for cd in self.containers.values(){
523                    match cd.get_edge(fe.abs - fe.rect.pos, self.zoom, self.pan){
524                        Some(edge)=> {
525                            cursor = Some(match edge{
526                                Edge::Left|Edge::Right=>MouseCursor::EwResize,
527                                Edge::Top|Edge::Bottom=>MouseCursor::NsResize,
528                                Edge::Body=>MouseCursor::Move
529                            });
530                            break;
531                        }
532                        None=>{}
533                    }
534                }
535                if let Some(cursor) = cursor{
536                    cx.set_cursor(cursor);
537                }
538                else{
539                    cx.set_cursor(MouseCursor::Default);
540                }
541            }
542            Hit::FingerHoverOut(_fh)=>{
543            }
544            Hit::FingerDown(fe) => {
545                self.undo_group += 1;
546                if !fe.modifiers.shift{
547                    if fe.modifiers.control && fe.modifiers.alt{
548                        let mut rects = BTreeMap::new();
549                        for (id, cd) in self.containers.iter(){
550                            rects.insert(*id, cd.rect);
551                        }
552                        self.finger_move = Some(FingerMove::DragAll{rects})
553                    }
554                    else{
555                        if fe.modifiers.logo || self.selected_subcomponent.is_none(){
556                            for (id, cd) in self.containers.iter(){
557                                match cd.get_edge(fe.abs -fe.rect.pos, self.zoom, self.pan){
558                                    Some(edge)=>{
559                                        self.finger_move = Some(FingerMove::DragEdge{
560                                            rect: cd.rect,
561                                            id: *id,
562                                            edge
563                                        });
564                                        // lets send out a click on this containter
565                                        cx.widget_action(uid, &scope.path, DesignerViewAction::Selected{
566                                            id:*id, 
567                                            tap_count: fe.tap_count , 
568                                            km:fe.modifiers
569                                        });
570                                        // set selected component
571                                        // unselect all other components
572                                        self.select_component(cx, Some(*id));
573                                        break;
574                                    }
575                                    None=>()
576                                }
577                            }
578                        }
579                        else{
580                            if let Some(sc) = &self.selected_subcomponent{
581                                self.finger_move = Some(FingerMove::DragSubComponentOrder(sc.clone()));
582                            }
583                        }
584                    }
585                }
586                
587                if self.finger_move.is_none(){
588                    self.finger_move = Some(FingerMove::Pan{
589                        start_pan: self.pan
590                    });
591                }
592            },
593            Hit::KeyDown(_k)=>{
594            }
595            Hit::FingerScroll(fs)=>{
596                let last_zoom = self.zoom;
597                
598                if fs.scroll.y < 0.0{
599                    let step = (-fs.scroll.y).min(200.0) / 500.0;
600                    self.zoom *= 1.0 - step; 
601                }
602                else{
603                    let step = (fs.scroll.y).min(200.0) / 500.0;
604                    self.zoom *= 1.0 + step;
605                }
606                self.zoom = self.zoom.max(0.01).min(10.0);
607                
608                // we should shift the pan to stay in the same place
609                let pan1 = (fs.abs - fs.rect.pos) * last_zoom;
610                let pan2 = (fs.abs - fs.rect.pos) * self.zoom;
611                // we should keep it in the same place
612                
613                self.pan += pan1 - pan2;
614                self.sync_zoom_pan(cx);
615                self.redraw(cx);
616            }
617            Hit::FingerMove(fe) => {
618                match self.finger_move.as_ref().unwrap(){
619                    FingerMove::DragSubComponentOrder(cs)=>{
620                        // ok how do we do this.
621                        // lets compare our rect to the mouse
622                        // and if we are below ask the parent component view to move down
623                        if let Some(parent) = &cs.parent{
624                            let vw = parent.as_view();
625                            
626                            if let Some(mut vw) = vw.borrow_mut(){
627                                
628                                // we need to be below the 'next item' in the list
629                                let index = vw.child_index(&cs.component).unwrap();
630                                let mut reorder:Option<isize> = None;
631                                if let Some(next_child) = vw.child_at_index(index+1){
632                                    let rect = self.get_component_rect(cx, &next_child);
633                                    if let Flow::Down = vw.layout.flow{
634                                        if fe.abs.y > rect.pos.y + 0.6* rect.size.y{
635                                            reorder = Some(1);
636                                        }     
637                                    }
638                                    else{
639                                        if fe.abs.x > rect.pos.x + 0.6* rect.size.x{
640                                            reorder = Some(1);
641                                        }   
642                                    } 
643                                }
644                                if index > 0{
645                                    if let Some(prev_child) = vw.child_at_index(index-1){
646                                        let rect = self.get_component_rect(cx, &prev_child);
647                                        if let Flow::Down = vw.layout.flow{
648                                            if fe.abs.y < rect.pos.y + 0.6 *rect.size.y{
649                                                reorder = Some(-1);
650                                            }
651                                        }else{
652                                            if fe.abs.x < rect.pos.x + 0.6 *rect.size.x{
653                                                reorder = Some(-1);
654                                            }
655                                        }
656                                    }
657                                }
658                                if let Some(dir) = reorder{
659                                    let next_index = (index as isize + dir) as usize;
660                                    if !data.pending_revision{
661                                        let c1 = vw.child_at_index(index).unwrap();
662                                        /*println!("{:?}", data.to_widget.live_ptr_to_widget);
663                                        */
664                                        if let Some(comp) = data.find_component_by_widget_ref(c1){
665                                            let c2 = vw.child_at_index(next_index).unwrap();
666                                            let next_comp = data.find_component_by_widget_ref(c2).unwrap();
667                                            cx.widget_action(uid, &scope.path, DesignerViewAction::SwapComponents{
668                                                comp,
669                                                next_comp
670                                            });
671                                        }
672                                        else{
673                                            //println!("WIdget ref lost");
674                                        }
675                                    }
676                                    else{
677                                        // component map temporariliy invalid
678                                    }
679                                }
680                            }
681                            vw.redraw(cx);
682                        }
683                    }
684                    FingerMove::Pan{start_pan} =>{
685                        self.pan= *start_pan - (fe.abs - fe.abs_start) * self.zoom;
686                        self.sync_zoom_pan(cx);
687                        self.redraw(cx);
688                    }
689                    FingerMove::DragAll{rects}=>{
690                        let delta = (fe.abs - fe.abs_start)* self.zoom;
691                        let rects = rects.clone();
692                        for (id, rect) in rects{
693                            let r = Rect{
694                                pos: rect.pos + delta,
695                                size: rect.size
696                            };
697                            self.update_rect(cx, id, r, &mut data.to_widget.positions);
698                        }
699                    }
700                    FingerMove::DragEdge{edge, rect, id}=>{
701                        let delta = (fe.abs - fe.abs_start)* self.zoom;
702                        let rect = match edge{
703                             Edge::Left=>Rect{
704                                pos:dvec2(rect.pos.x + delta.x, rect.pos.y),
705                                size:dvec2(rect.size.x - delta.x, rect.size.y)
706                             },
707                             Edge::Right=>Rect{
708                                 pos: rect.pos,
709                                 size: dvec2(rect.size.x + delta.x, rect.size.y)
710                             },
711                             Edge::Top=>Rect{
712                                 pos:dvec2(rect.pos.x, rect.pos.y + delta.y),
713                                 size:dvec2(rect.size.x, rect.size.y - delta.y)
714                             },
715                             Edge::Bottom=>Rect{
716                                 pos: rect.pos,
717                                 size: dvec2(rect.size.x, rect.size.y + delta.y)
718                             },
719                             Edge::Body=>Rect{
720                                 pos: rect.pos + delta,
721                                 size: rect.size
722                             }
723                        };
724                        self.update_rect(cx, *id, rect, &mut data.to_widget.positions);
725                    }
726                    FingerMove::DragBody{ptr:_}=>{
727                        
728                    }
729                }
730            }
731            Hit::FingerUp(_) => {
732                self.finger_move = None;
733            }
734            _ => ()
735        }
736    }
737        
738    fn draw_walk(&mut self, cx: &mut Cx2d, scope:&mut Scope, walk: Walk) -> DrawStep {
739       
740        if self.color_texture.is_none(){
741            self.color_texture = Some(Texture::new_with_format(
742                cx,
743                TextureFormat::RenderBGRAu8 {
744                    size: TextureSize::Auto,
745                    initial: true,
746                },
747            ));
748        }
749        
750        if cx.will_redraw(&mut self.draw_list, walk) {
751            
752            cx.make_child_pass(&self.pass);
753            cx.begin_pass(&self.pass, None);
754            self.pass.clear_color_textures(cx);
755            self.pass.add_color_texture(
756                cx,
757                self.color_texture.as_ref().unwrap(),
758                PassClearColor::ClearWith(self.clear_color),
759            );
760                        
761            self.draw_list.begin_always(cx);
762            let size = cx.current_pass_size();
763            cx.begin_sized_turtle_no_clip(size, Layout::flow_down());
764            
765            let data = scope.data.get_mut::<DesignerData>().unwrap();
766            
767            // lets draw the component container windows and components
768            
769            if let Some(view_file) = &self.view_file{
770                // so either we have a file, or a single component.
771                match data.node_map.get(view_file){
772                    Some(OutlineNode::File{children,..})=>{
773                        for child in children{
774                            // alright so. we need to use a path entry in our
775                            // datastructure
776                            if let Some(OutlineNode::Component{ptr,name,..}) = data.node_map.get(child){
777                                if name == "App=<App>"{ // we need to skip inwards to 
778                                    if let Some(child) = data.get_node_by_path(*child, "ui:/main_window=/body="){
779                                        if let Some(OutlineNode::Component{ptr,name,..}) = data.node_map.get(&child){
780                                            // lets fetch the position of this thing
781                                            
782                                            self.draw_container(cx, child, *ptr, name, &mut data.to_widget);
783                                        }
784                                    }
785                                }
786                                else{
787                                    // lets fetch the position of this thing
788                                    self.draw_container(cx, *child, *ptr, name, &mut data.to_widget);
789                                }
790                            }
791                        }
792                    }
793                    _=>()
794                }
795            }
796            self.reapply = false;
797                        
798            cx.end_pass_sized_turtle_no_clip();
799            self.draw_list.end(cx);
800            cx.end_pass(&self.pass);
801           // self.containers.retain_visible()
802        }
803        
804        self.draw_bg.draw_vars.set_texture(0, self.color_texture.as_ref().unwrap());
805        let rect = cx.walk_turtle_with_area(&mut self.area, walk);
806        self.draw_bg.draw_abs(cx, rect);
807        // lets draw all the outlines on top
808        
809        // alright and now we need to highlight a component
810        if let Some(cs) = &self.selected_subcomponent{
811            let rect = self.get_component_rect(cx, &cs.component);
812            self.draw_outline.draw_abs(cx, rect);
813        } 
814        else if let Some(component) = self.selected_component{
815            if let Some(container) = self.containers.get(&component){
816                let mut rect = rect;
817                rect.pos += (container.rect.pos - self.pan)/self.zoom;
818                rect.size = container.rect.size;
819                rect.size /= self.zoom;
820                self.draw_outline.draw_abs(cx, rect);
821            } 
822        }
823        cx.set_pass_area_with_origin(
824            &self.pass,
825            self.area,
826            dvec2(0.0,0.0)
827        );
828        cx.set_pass_shift_scale(&self.pass, self.pan, dvec2(self.zoom,self.zoom));
829        
830        DrawStep::done()
831    }
832}
833
834impl DesignerViewRef{
835    pub fn select_component(&self, cx:&mut Cx, comp:Option<LiveId>) {
836        if let Some(mut inner) = self.borrow_mut(){
837            inner.select_component(cx, comp);
838            inner.redraw(cx);
839        }
840    }
841    
842    pub fn view_file(&self, cx:&mut Cx, file_id:LiveId){
843        if let Some(mut inner) = self.borrow_mut(){
844            if inner.view_file != Some(file_id){
845                inner.containers.clear();
846                inner.view_file = Some(file_id);
847                inner.redraw(cx);
848            }
849        }
850    }
851    
852    pub fn set_zoom_pan (&self, cx:&mut Cx, zp:&DesignerZoomPan){
853        if let Some(mut inner) = self.borrow_mut(){
854            inner.zoom = zp.zoom;
855            inner.pan.x = zp.pan_x;
856            inner.pan.y = zp.pan_y;
857            inner.redraw(cx);
858        }
859    }
860    /*
861    pub fn reload_view(&self, cx:&mut Cx) {
862        if let Some(mut inner) = self.borrow_mut(){
863            inner.containers.clear();
864            inner.redraw(cx);
865        }
866    }*/
867    
868    pub fn selected(&self, actions: &Actions) -> Option<(LiveId,KeyModifiers,u32)> {
869        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
870            if let DesignerViewAction::Selected{id, km, tap_count} = item.cast() {
871                return Some((id, km, tap_count))
872            }
873        }
874        None
875    }
876    
877    pub fn swap_components(&self, actions: &Actions) -> Option<(LiveId,LiveId)> {
878        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
879            if let DesignerViewAction::SwapComponents{comp,next_comp} = item.cast() {
880                return Some((comp, next_comp))
881            }
882        }
883        None
884    }
885}