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 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 }});
206 }
207 }
239}
240
241
242pub enum TabBarAction {
243 TabWasPressed(LiveId),
244 ShouldTabStartDrag(LiveId),
245 TabCloseWasPressed(LiveId),
246 }