makepad_widgets/
tab_bar.rs

1use {
2    
3    crate::{
4        makepad_draw::*,
5        scroll_bars::ScrollBars,
6        tab::{TabAction, Tab, TabClosable},
7    },
8};
9
10live_design!{
11    TabBarBase = {{TabBar}} {}
12}
13
14#[derive(Live)]
15pub struct TabBar {
16    
17    #[live] scroll_bars: ScrollBars,
18    #[live] draw_drag: DrawColor,
19
20    #[live] draw_fill: DrawColor,
21    #[walk] walk: Walk,
22    #[live] tab: Option<LivePtr>,
23    
24    #[rust] view_area: Area,
25
26    #[rust] tab_order: Vec<LiveId>,
27    
28    #[rust] is_dragged: bool,
29    #[rust] tabs: ComponentMap<LiveId, Tab>,
30    
31    #[rust] selected_tab: Option<usize>,
32    
33    #[rust] selected_tab_id: Option<LiveId>,
34    #[rust] next_selected_tab_id: Option<LiveId>,
35}
36
37
38impl LiveHook for TabBar {
39    fn after_apply(&mut self, cx: &mut Cx, from: ApplyFrom, index: usize, nodes: &[LiveNode]) {
40        if let Some(index) = nodes.child_by_name(index, live_id!(tab).as_field()) {
41            for tab in self.tabs.values_mut() {
42                tab.apply(cx, from, index, nodes);
43            }
44        }
45        self.view_area.redraw(cx);
46    }
47}
48
49impl TabBar {
50    pub fn begin(&mut self, cx: &mut Cx2d, selected_tab: Option<usize>) {
51        self.selected_tab = selected_tab;
52        //if selected_tab.is_some(){
53        //    self.selected_tab_id = None
54        // }
55        self.scroll_bars.begin(cx, self.walk, Layout::flow_right());
56        self.tab_order.clear();
57    }
58    
59    pub fn end(&mut self, cx: &mut Cx2d) {
60        if self.is_dragged {
61            self.draw_drag.draw_walk(
62                cx,
63                Walk {
64                    width: Size::Fill,
65                    height: Size::Fill,
66                    ..Walk::default()
67                },
68            );
69        }
70        self.tabs.retain_visible();
71        self.draw_fill.draw_walk(cx, Walk::size(Size::Fill, Size::Fill));
72        self.scroll_bars.end(cx);
73    }
74    
75    pub fn draw_tab(&mut self, cx: &mut Cx2d, tab_id: LiveId, name: &str, closable:TabClosable) {
76        if let Some(selected_tab) = self.selected_tab {
77            let tab_order_len = self.tab_order.len();
78            let tab = self.get_or_create_tab(cx, tab_id);
79            if tab_order_len == selected_tab {
80                tab.set_is_selected(cx, true, Animate::No);
81            }
82            else {
83                tab.set_is_selected(cx, false, Animate::No);
84            }
85            tab.draw(cx, name, closable);
86            if tab_order_len == selected_tab {
87                self.selected_tab_id = Some(tab_id);
88            }
89            self.tab_order.push(tab_id);
90        }
91        else {
92            self.tab_order.push(tab_id);
93            let tab = self.get_or_create_tab(cx, tab_id);
94            tab.draw(cx, name, closable);
95        }
96    }
97    
98    fn get_or_create_tab(&mut self, cx: &mut Cx, tab_id: LiveId) -> &mut Tab {
99        let tab = self.tab;
100        self.tabs.get_or_insert(cx, tab_id, | cx | {
101            Tab::new_from_ptr(cx, tab)
102        })
103    }
104    
105    pub fn selected_tab_id(&self) -> Option<LiveId> {
106        self.selected_tab_id
107    }
108    
109    pub fn set_selected_tab_id(&mut self, cx: &mut Cx, tab_id: Option<LiveId>, animate: Animate) {
110        if self.selected_tab_id == tab_id {
111            return;
112        }
113        if let Some(tab_id) = self.selected_tab_id {
114            let tab = &mut self.tabs[tab_id];
115            tab.set_is_selected(cx, false, animate);
116        }
117        self.selected_tab_id = tab_id;
118        if let Some(tab_id) = self.selected_tab_id {
119            let tab = self.get_or_create_tab(cx, tab_id);
120            tab.set_is_selected(cx, true, animate);
121        }
122        self.view_area.redraw(cx);
123    }
124    
125    
126    pub fn set_next_selected_tab(&mut self, cx: &mut Cx, tab_id: LiveId, animate: Animate) {
127        if let Some(index) = self.tab_order.iter().position( | id | *id == tab_id) {
128            if self.selected_tab_id != Some(tab_id) {
129                self.next_selected_tab_id = self.selected_tab_id;
130            }
131            else if index >0 {
132                self.next_selected_tab_id = Some(self.tab_order[index - 1]);
133                self.set_selected_tab_id(cx, self.next_selected_tab_id, animate);
134            }
135            else if index + 1 < self.tab_order.len() {
136                self.next_selected_tab_id = Some(self.tab_order[index + 1]);
137                self.set_selected_tab_id(cx, self.next_selected_tab_id, animate);
138            }
139            else {
140                self.set_selected_tab_id(cx, None, animate);
141            }
142            cx.new_next_frame();
143        }
144        
145    }
146    pub fn redraw(&mut self, cx: &mut Cx) {
147        self.view_area.redraw(cx)
148    }
149    
150    pub fn is_over_tab(&self, cx:&Cx, abs:DVec2)->Option<(LiveId,Rect)>{
151        for (tab_id, tab) in self.tabs.iter() {
152            let rect = tab.area().get_rect(cx);
153            if rect.contains(abs){
154                return Some((*tab_id, rect))
155            }
156        }
157        None
158    }
159    
160    pub fn is_over_tab_bar(&self, cx:&Cx, abs:DVec2)->Option<Rect>{
161        let rect = self.scroll_bars.area().get_rect(cx);
162        if rect.contains(abs){
163            return Some(rect)
164        }
165        None
166    }
167    
168    
169    pub fn handle_event(&mut self, cx: &mut Cx, event: &Event) -> Vec<TabBarAction> {
170        let mut actions = Vec::new();
171        self.handle_event_with(cx, event, &mut | _, a | actions.push(a));
172        actions
173    }
174    
175    pub fn handle_event_with(
176        &mut self,
177        cx: &mut Cx,
178        event: &Event,
179        dispatch_action: &mut dyn FnMut(&mut Cx, TabBarAction),
180    ) {
181        let view_area = self.view_area;
182        self.scroll_bars.handle_event_with(cx, event, &mut |cx,_|{
183            view_area.redraw(cx);
184        });
185        
186        if let Some(tab_id) = self.next_selected_tab_id.take() {
187            dispatch_action(cx, TabBarAction::TabWasPressed(tab_id));
188        }
189        for (tab_id, tab) in self.tabs.iter_mut() {
190            tab.handle_event_with(cx, event, &mut | cx, action | match action {
191                TabAction::WasPressed => {
192                    dispatch_action(cx, TabBarAction::TabWasPressed(*tab_id));
193                }
194                TabAction::CloseWasPressed => {
195                    dispatch_action(cx, TabBarAction::TabCloseWasPressed(*tab_id));
196                }
197                TabAction::ShouldTabStartDrag=>{
198                    dispatch_action(cx, TabBarAction::ShouldTabStartDrag(*tab_id));
199                }
200                TabAction::ShouldTabStopDrag=>{
201                }/*
202                TabAction::DragHit(hit)=>{
203                    dispatch_action(cx, TabBarAction::DragHitTab(hit, *tab_id));
204                }*/
205            });
206        }
207        /*
208        match event.drag_hits(cx, self.scroll_bars.area()) {
209            DragHit::NoHit=>(),
210            hit=>dispatch_action(cx, TabBarAction::DragHitTabBar(hit))
211        }*/
212        /*
213        match event.drag_hits(cx, self.scroll_view.area()) {
214            DragHit::Drag(f) => match f.state {
215                DragState::In => {
216                    self.is_dragged = true;
217                    self.redraw(cx);
218                    f.action.set(DragAction::Copy);
219                }
220                DragState::Out => {
221                    self.is_dragged = false;
222                    self.redraw(cx);
223                }
224                DragState::Over => match event {
225                    Event::Drag(event) => {
226                        event.action.set(DragAction::Copy);
227                    }
228                    _ => panic!(),
229                },
230            },
231            DragHit::Drop(f) => {
232                self.is_dragged = false;
233                self.redraw(cx);
234                dispatch_action(cx, TabBarAction::ReceivedDraggedItem(f.dragged_item.clone()))
235            }
236            _ => {}
237        }*/
238    }
239}
240
241
242pub enum TabBarAction {
243    TabWasPressed(LiveId),
244    ShouldTabStartDrag(LiveId),
245    TabCloseWasPressed(LiveId),
246    //DragHitTab(DragHit, LiveId),
247    //DragHitTabBar(DragHit)
248}