1use gpui::{AnyElement, ScrollHandle};
2use smallvec::SmallVec;
3
4use crate::prelude::*;
5
6#[derive(IntoElement)]
7pub struct TabBar {
8 id: ElementId,
9 start_children: SmallVec<[AnyElement; 2]>,
10 children: SmallVec<[AnyElement; 2]>,
11 end_children: SmallVec<[AnyElement; 2]>,
12 scroll_handle: Option<ScrollHandle>,
13}
14
15impl TabBar {
16 pub fn new(id: impl Into<ElementId>) -> Self {
17 Self {
18 id: id.into(),
19 start_children: SmallVec::new(),
20 children: SmallVec::new(),
21 end_children: SmallVec::new(),
22 scroll_handle: None,
23 }
24 }
25
26 pub fn track_scroll(mut self, scroll_handle: ScrollHandle) -> Self {
27 self.scroll_handle = Some(scroll_handle);
28 self
29 }
30
31 pub fn start_children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
32 &mut self.start_children
33 }
34
35 pub fn start_child(mut self, start_child: impl IntoElement) -> Self
36 where
37 Self: Sized,
38 {
39 self.start_children_mut()
40 .push(start_child.into_element().into_any());
41 self
42 }
43
44 pub fn start_children(
45 mut self,
46 start_children: impl IntoIterator<Item = impl IntoElement>,
47 ) -> Self
48 where
49 Self: Sized,
50 {
51 self.start_children_mut().extend(
52 start_children
53 .into_iter()
54 .map(|child| child.into_any_element()),
55 );
56 self
57 }
58
59 pub fn end_children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
60 &mut self.end_children
61 }
62
63 pub fn end_child(mut self, end_child: impl IntoElement) -> Self
64 where
65 Self: Sized,
66 {
67 self.end_children_mut()
68 .push(end_child.into_element().into_any());
69 self
70 }
71
72 pub fn end_children(mut self, end_children: impl IntoIterator<Item = impl IntoElement>) -> Self
73 where
74 Self: Sized,
75 {
76 self.end_children_mut().extend(
77 end_children
78 .into_iter()
79 .map(|child| child.into_any_element()),
80 );
81 self
82 }
83}
84
85impl ParentElement for TabBar {
86 fn extend(&mut self, elements: impl Iterator<Item = AnyElement>) {
87 self.children.extend(elements)
88 }
89}
90
91impl RenderOnce for TabBar {
92 fn render(self, cx: &mut WindowContext) -> impl IntoElement {
93 div()
94 .id(self.id)
95 .group("tab_bar")
96 .flex()
97 .flex_none()
98 .w_full()
99 .h(rems_from_px(29.))
100 .bg(cx.theme().colors().tab_bar_background)
101 .when(!self.start_children.is_empty(), |this| {
102 this.child(
103 h_flex()
104 .flex_none()
105 .gap_1()
106 .px_1()
107 .border_b()
108 .border_r()
109 .border_color(cx.theme().colors().border)
110 .children(self.start_children),
111 )
112 })
113 .child(
114 div()
115 .relative()
116 .flex_1()
117 .h_full()
118 .overflow_x_hidden()
119 .child(
120 div()
121 .absolute()
122 .top_0()
123 .left_0()
124 .size_full()
125 .border_b()
126 .border_color(cx.theme().colors().border),
127 )
128 .child(
129 h_flex()
130 .id("tabs")
131 .flex_grow()
132 .overflow_x_scroll()
133 .when_some(self.scroll_handle, |cx, scroll_handle| {
134 cx.track_scroll(&scroll_handle)
135 })
136 .children(self.children),
137 ),
138 )
139 .when(!self.end_children.is_empty(), |this| {
140 this.child(
141 h_flex()
142 .flex_none()
143 .gap_1()
144 .px_1()
145 .border_b()
146 .border_l()
147 .border_color(cx.theme().colors().border)
148 .children(self.end_children),
149 )
150 })
151 }
152}