zaplib_components/
tabcontrol.rs1use zaplib::*;
2
3use crate::background::*;
4use crate::scrollview::*;
5use crate::tab::*;
6
7#[derive(Default)]
8pub struct TabControl {
9 pub tabs_view: ScrollView,
10 pub tabs: Vec<Tab>,
11 pub drag_tab_view: View,
12 pub drag_tab: Tab,
13 pub page_view: View,
14 pub tab_fill: Background,
16
17 pub _dragging_tab: Option<(PointerMoveEvent, usize)>,
18 pub _tab_id_alloc: usize,
19 pub _tab_now_selected: Option<usize>,
20 pub _tab_last_selected: Option<usize>,
21 pub _focussed: bool,
22}
23
24#[derive(Clone, PartialEq)]
25pub enum TabControlEvent {
26 None,
27 TabDragMove { pe: PointerMoveEvent, tab_id: usize },
28 TabDragEnd { pe: PointerUpEvent, tab_id: usize },
29 TabSelect { tab_id: usize },
30 TabClose { tab_id: usize },
31}
32
33const COLOR_BG_NORMAL: Vec4 = Vec4::all(0.);
34
35impl TabControl {
36 pub fn new() -> Self {
37 Self {
38 tabs_view: ScrollView::default().with_scroll_h(
39 ScrollBarConfig::default().with_bar_size(8.0).with_smoothing(0.15).with_use_vertical_pointer_scroll(true),
40 ),
41
42 page_view: View::default(),
43
44 tabs: Default::default(),
45
46 drag_tab: Tab::new().with_draw_depth(10.0),
47
48 drag_tab_view: View::default().with_is_overlay(true),
49
50 tab_fill: Background::default(),
52
53 _dragging_tab: None,
54 _tab_now_selected: None,
55 _tab_last_selected: None,
56 _focussed: false,
57 _tab_id_alloc: 0,
58 }
59 }
60
61 pub fn handle_tab_control(&mut self, cx: &mut Cx, event: &mut Event) -> TabControlEvent {
62 let mut tab_control_event = TabControlEvent::None;
63
64 self.tabs_view.handle(cx, event);
65
66 for (tab_id, tab) in self.tabs.iter_mut().enumerate() {
67 match tab.handle(cx, event) {
68 TabEvent::Select => {
69 cx.request_draw();
70 tab_control_event = TabControlEvent::TabSelect { tab_id }
72 }
73 TabEvent::DragMove(pe) => {
74 self._dragging_tab = Some((pe.clone(), tab_id));
75 cx.request_draw();
78
79 tab_control_event = TabControlEvent::TabDragMove { pe, tab_id };
80 }
81 TabEvent::DragEnd(pe) => {
82 self._dragging_tab = None;
83 cx.request_draw();
84
85 tab_control_event = TabControlEvent::TabDragEnd { pe, tab_id };
86 }
87 TabEvent::Closing => {
88 if tab.selected() {
90 let next_sel = if tab_id == self._tab_id_alloc - 1 {
92 if tab_id > 0 {
94 tab_id - 1
95 } else {
96 tab_id
97 }
98 } else {
99 tab_id + 1
100 };
101 if tab_id != next_sel {
102 tab_control_event = TabControlEvent::TabSelect { tab_id: next_sel };
103 }
104 }
105 }
106 TabEvent::Close => {
107 tab_control_event = TabControlEvent::TabClose { tab_id };
109 }
110 _ => (),
111 }
112 }
113 match tab_control_event {
114 TabControlEvent::TabSelect { tab_id } => {
115 self._focussed = true;
116 for (id, tab) in self.tabs.iter_mut().enumerate() {
117 if tab_id != id {
118 tab.set_tab_selected(cx, false);
119 tab.set_tab_focus(cx, true);
120 }
121 }
122 }
123 TabControlEvent::TabClose { .. } => {
124 self.tabs.clear();
126 }
127 _ => (),
128 };
129 tab_control_event
130 }
131
132 pub fn get_tab_rects(&mut self, cx: &mut Cx) -> Vec<Rect> {
133 let mut rects = Vec::new();
134 for tab in self.tabs.iter() {
135 rects.push(tab.get_tab_rect(cx))
136 }
137 rects
138 }
139
140 pub fn set_tab_control_focus(&mut self, cx: &mut Cx, focus: bool) {
141 self._focussed = focus;
142 for tab in self.tabs.iter_mut() {
143 tab.set_tab_focus(cx, focus);
144 }
145 }
146
147 pub fn get_tabs_view_rect(&mut self, cx: &Cx) -> Rect {
148 self.tabs_view.get_rect(cx)
149 }
150
151 pub fn get_content_drop_rect(&mut self, cx: &Cx) -> Rect {
152 self.page_view.get_rect(cx)
154 }
155
156 pub fn begin_tabs(&mut self, cx: &mut Cx) {
157 self.tabs_view.begin_view(cx, LayoutSize::new(Width::Fill, Height::Compute));
158 cx.begin_row(Width::Fill, Height::Compute);
159 self._tab_now_selected = None;
160 self._tab_id_alloc = 0;
161 }
162
163 pub fn get_draw_tab(&mut self, cx: &mut Cx, label: &str, selected: bool, closeable: bool) -> &mut Tab {
164 let new_tab = self.tabs.get(self._tab_id_alloc).is_none();
165 if new_tab {
166 self.tabs.push(Tab::default());
167 }
168 let tab = &mut self.tabs[self._tab_id_alloc];
169 if selected {
170 self._tab_now_selected = Some(self._tab_id_alloc);
171 }
172 self._tab_id_alloc += 1;
173 tab.label = label.to_string();
174 tab.is_closeable = closeable;
175 if new_tab {
176 tab.set_tab_state(cx, selected, self._focussed);
177 } else {
178 tab.set_tab_selected(cx, selected);
180 }
181 tab
182 }
183
184 pub fn draw_tab(&mut self, cx: &mut Cx, label: &str, selected: bool, closeable: bool) {
185 let tab = self.get_draw_tab(cx, label, selected, closeable);
186 tab.draw_tab(cx);
187 }
188
189 pub fn end_tabs(&mut self, cx: &mut Cx) {
190 self.tab_fill.begin_draw(cx, Width::Fill, Height::Compute, COLOR_BG_NORMAL);
191 self.tab_fill.end_draw(cx);
192
193 self.tabs.truncate(self._tab_id_alloc);
194 if let Some((pe, id)) = &self._dragging_tab {
195 cx.begin_absolute_box();
196 self.drag_tab_view.begin_view(cx, LayoutSize::FILL);
197
198 self.drag_tab.abs_origin = Some(Vec2 { x: pe.abs.x - pe.rel_start.x, y: pe.abs.y - pe.rel_start.y });
199 let origin_tab = &mut self.tabs[*id];
200 self.drag_tab.label = origin_tab.label.clone();
201 self.drag_tab.is_closeable = origin_tab.is_closeable;
202 self.drag_tab.draw_tab(cx);
203
204 self.drag_tab_view.end_view(cx);
205 cx.end_absolute_box();
206 }
207 cx.end_row();
208 self.tabs_view.end_view(cx);
209
210 if self._tab_now_selected != self._tab_last_selected {
211 if let Some(tab_id) = self._tab_now_selected {
213 if let Some(tab) = self.tabs.get(tab_id) {
214 let tab_rect = tab.get_tab_rect(cx);
215 self.tabs_view.scroll_into_view_abs(cx, tab_rect);
216 }
217 }
218 self._tab_last_selected = self._tab_now_selected;
219 }
220 }
221
222 pub fn begin_tab_page(&mut self, cx: &mut Cx) {
223 cx.draw_new_line();
224 self.page_view.begin_view(cx, LayoutSize::FILL);
225 }
226
227 pub fn end_tab_page(&mut self, cx: &mut Cx) {
228 self.page_view.end_view(cx);
229 }
232}