makepad_widget/
dock.rs

1use std::mem;
2
3use makepad_render::*;
4use crate::splitter::*;
5use crate::tabcontrol::*;
6use crate::widgetstyle::*;
7use serde::*;
8
9#[derive(Clone)]
10pub struct Dock<TItem>
11where TItem: Clone
12{
13    // pub dock_items: Option<DockItem<TItem>>,
14    pub splitters: Elements<usize, Splitter, Splitter>,
15    pub tab_controls: Elements<usize, TabControl, TabControl>,
16    
17    pub drop_size: Vec2,
18    pub drop_quad: Quad,
19    pub drop_quad_view: View,
20    //pub drop_quad_color: ColorId,
21    pub _drag_move: Option<FingerMoveEvent>,
22    pub _drag_end: Option<DockDragEnd<TItem>>,
23    pub _close_tab: Option<DockTabIdent>,
24    pub _tab_select: Option<(usize, usize)>,
25    pub _tweening_quad: Option<(usize, Rect, f32)>
26}
27
28#[derive(Clone, Debug)]
29pub struct DockTabIdent {
30    tab_control_id: usize,
31    tab_id: usize
32}
33
34#[derive(Clone)]
35pub enum DockDragEnd<TItem>
36where TItem: Clone {
37    OldTab {fe: FingerUpEvent, ident: DockTabIdent},
38    NewItems {fe: FingerUpEvent, items: Vec<DockTab<TItem>>}
39}
40
41#[derive(Clone, Serialize, Deserialize)]
42pub struct DockTab<TItem>
43where TItem: Clone
44{
45    pub closeable: bool,
46    pub title: String,
47    pub item: TItem
48}
49
50#[derive(Clone, Serialize, Deserialize)]
51pub enum DockItem<TItem>
52where TItem: Clone
53{
54    Single(TItem),
55    TabControl {
56        current: usize,
57        previous: usize,
58        tabs: Vec<DockTab<TItem>>,
59    },
60    Splitter {
61        pos: f32,
62        align: SplitterAlign,
63        axis: Axis,
64        first: Box<DockItem<TItem>>,
65        last: Box<DockItem<TItem>>
66    }
67}
68
69
70struct DockWalkStack<'a, TItem>
71where TItem: Clone
72{
73    counter: usize,
74    uid: usize,
75    item: &'a mut DockItem<TItem>
76}
77
78pub enum DockEvent {
79    None,
80    DockTabClosed,
81    DockTabCloned {tab_control_id: usize, tab_id: usize},
82    DockChanged
83}
84
85pub struct DockWalker<'a, TItem>
86where TItem: Clone
87{
88    walk_uid: usize,
89    stack: Vec<DockWalkStack<'a, TItem>>,
90    // forwards for Dock
91    splitters: &'a mut Elements<usize, Splitter, Splitter>,
92    tab_controls: &'a mut Elements<usize, TabControl, TabControl>,
93    drop_quad_view: &'a mut View,
94    _drag_move: &'a mut Option<FingerMoveEvent>,
95    _drag_end: &'a mut Option<DockDragEnd<TItem>>,
96    _close_tab: &'a mut Option<DockTabIdent>,
97    _tab_select: &'a mut Option<(usize, usize)>
98}
99
100impl<'a, TItem> DockWalker<'a, TItem>
101where TItem: Clone
102{
103    
104    pub fn walk_dock_item(&mut self) -> Option<(usize, &mut DockItem<TItem>)> {
105        // lets get the current item on the stack
106        let push_or_pop = if let Some(stack_top) = self.stack.last_mut() {
107            // return item 'count'
108            match stack_top.item {
109                DockItem::Single(..) => {
110                    if stack_top.counter == 0 {
111                        stack_top.counter += 1;
112                        return Some((self.walk_uid,unsafe {mem::transmute(&mut *stack_top.item)}));
113                    }
114                    else {
115                        None
116                    }
117                },
118                DockItem::TabControl {..} => {
119                    if stack_top.counter == 0 {
120                        let uid = self.walk_uid;
121                        self.walk_uid += 1;
122                        stack_top.counter += 1;
123                        return Some((uid, unsafe {mem::transmute(&mut *stack_top.item)}));
124                    }
125                    else {
126                        None
127                    }
128                },
129                DockItem::Splitter {first, last, ..} => {
130                    if stack_top.counter == 0 {
131                        let uid = self.walk_uid;
132                        self.walk_uid += 1;
133                        stack_top.counter += 1;
134                        return Some((uid, unsafe {mem::transmute(&mut *stack_top.item)}));
135                    }
136                    else if stack_top.counter == 1 {
137                        stack_top.counter += 1;
138                        Some(DockWalkStack {counter: 0, uid: 0, item: unsafe {mem::transmute(first.as_mut())}})
139                    }
140                    else if stack_top.counter == 2 {
141                        stack_top.counter += 1;
142                        Some(DockWalkStack {counter: 0, uid: 0, item: unsafe {mem::transmute(last.as_mut())}})
143                    }
144                    else {
145                        None
146                    }
147                }
148            }
149        }
150        else {
151            return None;
152        };
153        if let Some(item) = push_or_pop {
154            self.stack.push(item);
155            return self.walk_dock_item();
156        }
157        else if self.stack.len() > 0 {
158            self.stack.pop();
159            return self.walk_dock_item();
160        }
161        return None;
162    }
163    
164    pub fn walk_handle_dock(&mut self, cx: &mut Cx, event: &mut Event) -> Option<&mut TItem> {
165        // lets get the current item on the stack
166        let push_or_pop = if let Some(stack_top) = self.stack.last_mut() {
167            // return item 'count'
168            match stack_top.item {
169                DockItem::Single(item) => {
170                    if stack_top.counter == 0 {
171                        stack_top.counter += 1;
172                        return Some(unsafe {mem::transmute(item)});
173                    }
174                    else {
175                        None
176                    }
177                },
178                DockItem::TabControl {current, previous, tabs} => {
179                    if stack_top.counter == 0 {
180                        stack_top.counter += 1;
181                        stack_top.uid = self.walk_uid;
182                        self.walk_uid += 1;
183
184                        if *current < tabs.len() {
185                            return Some(unsafe {mem::transmute(&mut tabs[*current].item)});
186                        }
187                        None
188                    }
189                    else {
190                        let tab_control = self.tab_controls.get(stack_top.uid);
191                        let mut defocus = false;
192                        if !tab_control.is_none() {
193                            match tab_control.unwrap().handle_tab_control(cx, event) {
194                                TabControlEvent::TabSelect {tab_id} => {
195                                    if *current != tab_id{
196                                        *previous = *current;
197                                        *current = tab_id;
198                                        // someday ill fix this. Luckily entire UI redraws are millisecond span
199                                        cx.redraw_child_area(Area::All);
200                                        *self._tab_select = Some((stack_top.uid, tab_id));
201                                        defocus = true;
202                                    }
203                                },
204                                TabControlEvent::TabDragMove {fe, ..} => {
205                                    *self._drag_move = Some(fe);
206                                    *self._drag_end = None;
207                                    self.drop_quad_view.redraw_view_area(cx);
208                                },
209                                TabControlEvent::TabDragEnd {fe, tab_id} => {
210                                    *self._drag_move = None;
211                                    *self._drag_end = Some(DockDragEnd::OldTab {
212                                        fe: fe,
213                                        
214                                        ident: DockTabIdent {
215                                            tab_control_id: stack_top.uid,
216                                            
217                                            tab_id: tab_id
218                                        }
219                                    });
220                                    self.drop_quad_view.redraw_view_area(cx);
221                                },
222                                TabControlEvent::TabClose {tab_id} => {
223                                    *self._close_tab = Some(DockTabIdent {
224                                        tab_control_id: stack_top.uid,
225                                        tab_id: tab_id
226                                    });
227                                    // if tab_id < current, subtract current if >0
228                                    if tab_id < *current && *current > 0 {
229                                        *current -= 1;
230                                    }
231                                    cx.redraw_child_area(Area::All);
232                                },
233                                _ => ()
234                            }
235                        }
236                        
237                        if defocus {
238                            // defocus all other tabcontrols
239                            for (id, tab_control) in self.tab_controls.enumerate() {
240                                if *id != stack_top.uid {
241                                    tab_control.set_tab_control_focus(cx, false);
242                                }
243                            }
244                        }
245
246                        None
247                    }
248                },
249                DockItem::Splitter {first, last, pos, align, ..} => {
250                    if stack_top.counter == 0 {
251                        stack_top.counter += 1;
252                        stack_top.uid = self.walk_uid;
253                        self.walk_uid += 1;
254                        let split = self.splitters.get(stack_top.uid);
255                        if let Some(split) = split {
256                            match split.handle_splitter(cx, event) {
257                                SplitterEvent::Moving {new_pos} => {
258                                    *pos = new_pos;
259                                    cx.redraw_pass_of(split._split_area);
260                                },
261                                SplitterEvent::MovingEnd {new_align, new_pos} => {
262                                    *align = new_align;
263                                    *pos = new_pos;
264                                    cx.redraw_pass_of(split._split_area);
265                                },
266                                _ => ()
267                            };
268                        }
269                        // update state in our splitter level
270                        Some(DockWalkStack {counter: 0, uid: 0, item: unsafe {mem::transmute(first.as_mut())}})
271                    }
272                    else if stack_top.counter == 1 {
273                        stack_top.counter += 1;
274                        Some(DockWalkStack {counter: 0, uid: 0, item: unsafe {mem::transmute(last.as_mut())}})
275                    }
276                    else {
277                        None
278                    }
279                }
280            }
281        }
282        else {
283            return None;
284        };
285        if let Some(item) = push_or_pop {
286            self.stack.push(item);
287            return self.walk_handle_dock(cx, event);
288        }
289        else if self.stack.len() > 0 {
290            self.stack.pop();
291            return self.walk_handle_dock(cx, event);
292        }
293        return None;
294    }
295
296    pub fn walk_draw_dock<F>(&mut self, cx: &mut Cx, mut tab_handler:F) -> Option<&'a mut TItem> 
297    where F: FnMut(&mut Cx, &mut TabControl, &DockTab<TItem>, bool) {
298        // lets get the current item on the stack
299        let push_or_pop = if let Some(stack_top) = self.stack.last_mut() {
300            // return item 'count'
301            match stack_top.item {
302                DockItem::Single(item) => {
303                    if stack_top.counter == 0 {
304                        stack_top.counter += 1;
305                        return Some(unsafe {mem::transmute(item)});
306                    }
307                    else {
308                        None
309                    }
310                },
311                DockItem::TabControl {current, previous:_, tabs} => {
312                    if stack_top.counter == 0 {
313                        stack_top.counter += 1;
314                        stack_top.uid = self.walk_uid;
315                        self.walk_uid += 1;
316                        let tab_control = self.tab_controls.get_draw(cx, stack_top.uid, | _cx, tmpl | tmpl.clone());
317                        
318                        if let Ok(_) = tab_control.begin_tabs(cx) {
319                            for (id, tab) in tabs.iter().enumerate() {
320                                tab_handler(cx, tab_control, tab, *current == id)
321                            }
322                            tab_control.end_tabs(cx);
323                        }
324                        
325                        if let Ok(_) = tab_control.begin_tab_page(cx) {
326                            if *current < tabs.len() {
327                                return Some(unsafe {mem::transmute(&mut tabs[*current].item)});
328                            }
329                            tab_control.end_tab_page(cx);
330                        }
331                        None
332                    }
333                    else {
334                        let tab_control = self.tab_controls.get_draw(cx, stack_top.uid, | _cx, tmpl | tmpl.clone());
335                        tab_control.end_tab_page(cx);
336                        None
337                    }
338                },
339                DockItem::Splitter {align, pos, axis, first, last} => {
340                    if stack_top.counter == 0 {
341                        stack_top.counter += 1;
342                        stack_top.uid = self.walk_uid;
343                        self.walk_uid += 1;
344                        // begin a split
345                        let split = self.splitters.get_draw(cx, stack_top.uid, | _cx, tmpl | tmpl.clone());
346                        split.set_splitter_state(align.clone(), *pos, axis.clone());
347                        split.begin_splitter(cx);
348                        Some(DockWalkStack {counter: 0, uid: 0, item: unsafe {mem::transmute(first.as_mut())}})
349                    }
350                    else if stack_top.counter == 1 {
351                        stack_top.counter += 1;
352                        
353                        let split = self.splitters.get_draw(cx, stack_top.uid, | _cx, tmpl | tmpl.clone());
354                        split.mid_splitter(cx);
355                        Some(DockWalkStack {counter: 0, uid: 0, item: unsafe {mem::transmute(last.as_mut())}})
356                    }
357                    else {
358                        let split = self.splitters.get_draw(cx, stack_top.uid, | _cx, tmpl | tmpl.clone());
359                        split.end_splitter(cx);
360                        None
361                    }
362                }
363            }
364        }
365        else {
366            return None
367        };
368        if let Some(item) = push_or_pop {
369            self.stack.push(item);
370            return self.walk_draw_dock(cx, tab_handler);
371        }
372        else if self.stack.len() > 0 {
373            self.stack.pop();
374            return self.walk_draw_dock(cx, tab_handler);
375        }
376        None
377    }
378}
379
380enum DockDropKind {
381    Tab(usize),
382    TabsView,
383    Left,
384    Top,
385    Right,
386    Bottom,
387    Center
388}
389
390impl<TItem> Dock<TItem>
391where TItem: Clone
392{
393    pub fn proto(cx: &mut Cx) -> Dock<TItem> {
394        Dock {
395            // dock_items:None,
396            drop_size: Vec2 {x: 100., y: 70.},
397            //drop_quad_color: Color_drop_quad::id(),
398            drop_quad: Quad {
399                z: 10.,
400                ..Quad::proto(cx)
401            },
402            splitters: Elements::new(Splitter::proto(cx)),
403            tab_controls: Elements::new(TabControl::proto(cx)),
404            drop_quad_view: View::proto_overlay(cx),
405            _close_tab: None,
406            _drag_move: None,
407            _drag_end: None,
408            _tab_select: None,
409            _tweening_quad: None
410        }
411    }
412    
413    fn recur_remove_tab(dock_walk: &mut DockItem<TItem>, control_id: usize, tab_id: usize, counter: &mut usize, clone: bool, select_previous:bool) -> Option<DockTab<TItem>>
414    where TItem: Clone
415    {
416        match dock_walk {
417            DockItem::Single(_) => {},
418            DockItem::TabControl {tabs, current, previous} => {
419                let id = *counter;
420                *counter += 1;
421                if id == control_id {
422                    if tab_id >= tabs.len() {
423                        return None;
424                    }
425                    if clone && tabs[tab_id].closeable {
426                        return Some(tabs[tab_id].clone())
427                    }
428                    else {
429                        // this select the previous tab.
430                        if select_previous && *previous != *current && *previous < tabs.len() - 1{
431                            *current = *previous;
432                        }
433                        else 
434                        if *current >= 1 && *current == tabs.len() - 1 {
435                            *current -= 1;
436                        }
437                        return Some(tabs.remove(tab_id));
438                    }
439                }
440            },
441            DockItem::Splitter {first, last, ..} => {
442                *counter += 1;
443                let left = Self::recur_remove_tab(first, control_id, tab_id, counter, clone, select_previous);
444                if !left.is_none() {
445                    return left
446                }
447                let right = Self::recur_remove_tab(last, control_id, tab_id, counter, clone, select_previous);
448                if !right.is_none() {
449                    return right
450                }
451            }
452        }
453        None
454    }
455    
456    fn recur_collapse_empty(dock_walk: &mut DockItem<TItem>) -> bool
457    where TItem: Clone
458    {
459        match dock_walk {
460            DockItem::Single(_) => {},
461            DockItem::TabControl {tabs, ..} => {
462                return tabs.len() == 0
463            },
464            DockItem::Splitter {first, last, ..} => {
465                let rem_first = Self::recur_collapse_empty(first);
466                let rem_last = Self::recur_collapse_empty(last);
467                if rem_first && rem_last {
468                    return true;
469                }
470                if rem_first {
471                    *dock_walk = *last.clone();
472                }
473                else if rem_last {
474                    *dock_walk = *first.clone();
475                }
476            }
477        }
478        false
479    }
480    
481    fn recur_split_dock(dock_walk: &mut DockItem<TItem>, items: &Vec<DockTab<TItem>>, control_id: usize, kind: &DockDropKind, counter: &mut usize)->Option<DockTabIdent>
482    where TItem: Clone
483    {
484        match dock_walk {
485            DockItem::Single(_) => {},
486            DockItem::TabControl {tabs, previous:_, current} => {
487                let id = *counter;
488                *counter += 1;
489                if id == control_id {
490                    match kind {
491                        DockDropKind::Tab(id) => {
492                            let mut idc = *id;
493                            for item in items {
494                                tabs.insert(idc, item.clone());
495                                idc += 1;
496                            }
497                            *current = idc - 1;
498                            return Some(DockTabIdent{tab_control_id:control_id, tab_id:*current})
499                        },
500                        DockDropKind::Left => {
501                            *dock_walk = DockItem::Splitter {
502                                align: SplitterAlign::Weighted,
503                                pos: 0.5,
504                                axis: Axis::Vertical,
505                                last: Box::new(dock_walk.clone()),
506                                first: Box::new(DockItem::TabControl {current: 0, previous:0, tabs: items.clone()})
507                            };
508                            return Some(DockTabIdent{tab_control_id:control_id+1, tab_id:0})
509                        },
510                        DockDropKind::Right => {
511                            *dock_walk = DockItem::Splitter {
512                                align: SplitterAlign::Weighted,
513                                pos: 0.5,
514                                axis: Axis::Vertical,
515                                first: Box::new(dock_walk.clone()),
516                                last: Box::new(DockItem::TabControl {current: 0, previous:0, tabs: items.clone()})
517                            };
518                            return Some(DockTabIdent{tab_control_id:control_id+2, tab_id:0})
519                        },
520                        DockDropKind::Top => {
521                            *dock_walk = DockItem::Splitter {
522                                align: SplitterAlign::Weighted,
523                                pos: 0.5,
524                                axis: Axis::Horizontal,
525                                last: Box::new(dock_walk.clone()),
526                                first: Box::new(DockItem::TabControl {current: 0, previous:0, tabs: items.clone()})
527                            };
528                            return Some(DockTabIdent{tab_control_id:control_id+1, tab_id:0})
529                        },
530                        DockDropKind::Bottom => {
531                            *dock_walk = DockItem::Splitter {
532                                align: SplitterAlign::Weighted,
533                                pos: 0.5,
534                                axis: Axis::Horizontal,
535                                first: Box::new(dock_walk.clone()),
536                                last: Box::new(DockItem::TabControl {current: 0, previous:0, tabs: items.clone()})
537                            };
538                            return Some(DockTabIdent{tab_control_id:control_id+2, tab_id:0})
539                        },
540                        DockDropKind::TabsView |
541                        DockDropKind::Center => {
542                            *current = tabs.len() + items.len() - 1;
543                            for item in items {
544                                tabs.push(item.clone());
545                            }
546                            return Some(DockTabIdent{tab_control_id:control_id, tab_id:tabs.len()-1})
547                        }
548                    }
549                }
550            },
551            DockItem::Splitter {first, last, ..} => {
552                *counter += 1;
553                if let Some(ret) = Self::recur_split_dock(first, items, control_id, kind, counter){
554                    return Some(ret)
555                }
556                if let Some(ret) =  Self::recur_split_dock(last, items, control_id, kind, counter){
557                    return Some(ret)
558                }
559            }
560        }
561        None
562    }
563    
564    fn get_drop_kind(pos: Vec2, drop_size: Vec2, tvr: Rect, cdr: Rect, tab_rects: Vec<Rect>) -> (DockDropKind, Rect) {
565        // this is how the drop areas look
566        //    |            Tab                |
567        //    |-------------------------------|
568        //    |      |     Top        |       |
569        //    |      |----------------|       |
570        //    |      |                |       |
571        //    |      |                |       |
572        //    | Left |    Center      | Right |
573        //    |      |                |       |
574        //    |      |                |       |
575        //    |      |----------------|       |
576        //    |      |    Bottom      |       |
577        //    ---------------------------------
578        
579        if tvr.contains(pos.x, pos.y) {
580            for (id, tr) in tab_rects.iter().enumerate() {
581                if tr.contains(pos.x, pos.y) {
582                    return (DockDropKind::Tab(id), *tr)
583                }
584            }
585            return (DockDropKind::TabsView, tvr)
586        }
587        if pos.y < cdr.y + drop_size.y {
588            return (DockDropKind::Top, Rect {
589                x: cdr.x,
590                y: cdr.y,
591                w: cdr.w,
592                h: 0.5 * cdr.h
593            })
594        }
595        if pos.y > cdr.y + cdr.h - drop_size.y {
596            return (DockDropKind::Bottom, Rect {
597                x: cdr.x,
598                y: cdr.y + 0.5 * cdr.h,
599                w: cdr.w,
600                h: 0.5 * cdr.h
601            })
602        }
603        if pos.x < cdr.x + drop_size.x {
604            return (DockDropKind::Left, Rect {
605                x: cdr.x,
606                y: cdr.y,
607                w: 0.5 * cdr.w,
608                h: cdr.h
609            })
610        }
611        if pos.x > cdr.x + cdr.w - drop_size.x {
612            return (DockDropKind::Right, Rect {
613                x: cdr.x + 0.5 * cdr.w,
614                y: cdr.y,
615                w: 0.5 * cdr.w,
616                h: cdr.h
617            })
618        }
619        (DockDropKind::Center, cdr.clone())
620    }
621    
622    pub fn dock_drag_out(&mut self, cx: &mut Cx) {
623        self._drag_move = None;
624        self.drop_quad_view.redraw_view_area(cx);
625    }
626    
627    pub fn dock_drag_move(&mut self, cx: &mut Cx, fe: FingerMoveEvent) {
628        self._drag_move = Some(fe);
629        self.drop_quad_view.redraw_view_area(cx);
630    }
631    
632    pub fn dock_drag_cancel(&mut self, cx: &mut Cx) {
633        self._drag_move = None;
634        self.drop_quad_view.redraw_view_area(cx);
635    }
636    
637    pub fn dock_drag_end(&mut self, _cx: &mut Cx, fe: FingerUpEvent, new_items: Vec<DockTab<TItem>>) {
638        self._drag_move = None;
639        self._drag_end = Some(DockDragEnd::NewItems {
640            fe: fe,
641            items: new_items
642        });
643    }
644    
645    pub fn handle_dock(&mut self, cx: &mut Cx, _event: &mut Event, dock_items: &mut DockItem<TItem>) -> DockEvent {
646        if let Some(close_tab) = &self._close_tab {
647            Self::recur_remove_tab(dock_items, close_tab.tab_control_id, close_tab.tab_id, &mut 0, false, false);
648            Self::recur_collapse_empty(dock_items);
649            cx.redraw_child_area(Area::All);
650            self._close_tab = None;
651            return DockEvent::DockTabClosed
652        }
653        if let Some(drag_end) = self._drag_end.clone() {
654            self._drag_end = None;
655            let mut tab_clone_ident = None;
656            let fe = match &drag_end {DockDragEnd::OldTab {fe, ..} => fe, DockDragEnd::NewItems {fe, ..} => fe};
657            for (target_id, tab_control) in self.tab_controls.enumerate() {
658                
659                let cdr = tab_control.get_content_drop_rect(cx);
660                let tvr = tab_control.get_tabs_view_rect(cx);
661                if tvr.contains(fe.abs.x, fe.abs.y) || cdr.contains(fe.abs.x, fe.abs.y) { // we might got dropped elsewhere
662                    // ok now, we ask the tab_controls rect
663                    let tab_rects = tab_control.get_tab_rects(cx);
664                    let (kind, _rect) = Self::get_drop_kind(fe.abs, self.drop_size, tvr, cdr, tab_rects);
665                    
666                    // alright our drag_end is an enum
667                    // its either a previous tabs index
668                    // or its a new Item
669                    // we have a kind!
670                    let mut do_tab_clone = false;
671                    let items = match &drag_end {
672                        DockDragEnd::OldTab {ident, ..} => {
673                            if fe.modifiers.control || fe.modifiers.logo {
674                                do_tab_clone = true;
675                            }
676                            let item = Self::recur_remove_tab(dock_items, ident.tab_control_id, ident.tab_id, &mut 0, do_tab_clone, true);
677                            if let Some(item) = item {
678                                if !item.closeable {
679                                    do_tab_clone = false;
680                                }
681                                vec![item]
682                            }
683                            else {
684                                vec![]
685                            }
686                        },
687                        DockDragEnd::NewItems {items, ..} => {
688                            items.clone()
689                        }
690                    };
691                    // alright we have a kind.
692                    if items.len() > 0 {
693                        let new_ident = Self::recur_split_dock(
694                            dock_items,
695                            &items,
696                            *target_id,
697                            &kind,
698                            &mut 0
699                        );
700                        if do_tab_clone{
701                            tab_clone_ident = new_ident;
702                        }
703                    };
704                }
705            }
706            Self::recur_collapse_empty(dock_items);
707            cx.redraw_child_area(Area::All);
708            //Self::recur_debug_dock(self.dock_items.as_mut().unwrap(), &mut 0, 0);
709            if let Some(ident) = tab_clone_ident {
710                return DockEvent::DockTabCloned {tab_control_id: ident.tab_control_id, tab_id: ident.tab_id}
711            }
712            return DockEvent::DockChanged
713        };
714        // ok we need to pull out the TItem from our dockpanel
715        DockEvent::None
716    }
717    
718    pub fn draw_dock(&mut self, cx: &mut Cx) {
719        // lets draw our hover layer if need be
720        if let Some(fe) = &self._drag_move {
721            if let Err(()) = self.drop_quad_view.begin_view(cx, Layout::abs_origin_zero()) {
722                return
723            }
724            let mut found_drop_zone = false;
725            for (id, tab_control) in self.tab_controls.enumerate() {
726                
727                let cdr = tab_control.get_content_drop_rect(cx);
728                let tvr = tab_control.get_tabs_view_rect(cx);
729                if tvr.contains(fe.abs.x, fe.abs.y) || cdr.contains(fe.abs.x, fe.abs.y) {
730                    let tab_rects = tab_control.get_tab_rects(cx);
731                    let (_kind, rect) = Self::get_drop_kind(fe.abs, self.drop_size, tvr, cdr, tab_rects);
732                    
733                    if !self._tweening_quad.is_none() && self._tweening_quad.unwrap().0 != *id {
734                        // restarts the animation by removing drop_quad
735                        self._tweening_quad = None;
736                    }
737                    
738                    // yay, i can finally do these kinds of animations!
739                    let (dr, alpha) = if self._tweening_quad.is_none() {
740                        self._tweening_quad = Some((*id, rect, 0.));
741                        (rect, 0.)
742                    }
743                    else {
744                        let (id, old_rc, old_alpha) = self._tweening_quad.unwrap();
745                        let move_speed = 0.0;
746                        let alpha_speed = 0.0;
747                        let alpha = old_alpha * alpha_speed + (1. - alpha_speed);
748                        let rc = Rect {
749                            x: old_rc.x * move_speed + rect.x * (1. - move_speed),
750                            y: old_rc.y * move_speed + rect.y * (1. - move_speed),
751                            w: old_rc.w * move_speed + rect.w * (1. - move_speed),
752                            h: old_rc.h * move_speed + rect.h * (1. - move_speed)
753                        };
754                        let dist = (rc.x - rect.x)
755                            .abs()
756                            .max((rc.y - rect.y).abs())
757                            .max((rc.w - rect.w).abs())
758                            .max((rc.h - rect.h).abs())
759                            .max(100. - alpha * 100.);
760                        if dist>0.5 { // keep redrawing until we are close
761                            // cx.redraw_previous_areas();
762                            //self.drop_quad_view.redraw_view_area(cx);
763                        }
764                        self._tweening_quad = Some((id, rc, alpha));
765                        (rc, alpha)
766                    };
767                    self.drop_quad.color = Theme::color_drop_quad().get(cx);
768                    self.drop_quad.color.a = alpha * 0.8;
769                    found_drop_zone = true;
770                    self.drop_quad.draw_quad_rel(cx, dr);
771                }
772            }
773            if !found_drop_zone {
774                self._tweening_quad = None;
775            }
776            self.drop_quad_view.end_view(cx);
777        }
778    }
779    
780    pub fn walker<'a>(&'a mut self, dock_items: &'a mut DockItem<TItem>) -> DockWalker<'a,
781        TItem> {
782        let mut stack = Vec::new();
783        //if !self.dock_items.is_none(){
784        stack.push(DockWalkStack {counter: 0, uid: 0, item: dock_items});
785        //}
786        DockWalker {
787            walk_uid: 0,
788            stack: stack,
789            splitters: &mut self.splitters,
790            tab_controls: &mut self.tab_controls,
791            _drag_move: &mut self._drag_move,
792            _drag_end: &mut self._drag_end,
793            _close_tab: &mut self._close_tab,
794            _tab_select: &mut self._tab_select,
795            drop_quad_view: &mut self.drop_quad_view
796        }
797    }
798
799}
800
801/*
802fn recur_debug_dock(dock_walk:&mut DockItem<TItem>, counter:&mut usize, depth:usize)
803where TItem: Clone
804{
805let mut indent = String::new();
806for i in 0..depth{indent.push_str(" ")}
807match dock_walk{
808DockItem::Single(item)=>{},
809DockItem::TabControl{tabs,..}=>{
810let id = *counter;
811*counter += 1;
812println!("{}TabControl {}", indent, id);
813for (id,tab) in tabs.iter().enumerate(){
814println!("{} Tab{} {}", indent, id, tab.title);
815}
816},
817DockItem::Splitter{first,last,..}=>{
818let id = *counter;
819*counter += 1;
820println!("{}Splitter {}", indent, id);
821Self::recur_debug_dock(first, counter, depth + 1);
822Self::recur_debug_dock(last, counter, depth + 1);
823}
824}
825}*/