1use gpui::{AnyView, ClickEvent};
2use ui_macros::RegisterComponent;
3
4use crate::prelude::*;
5use crate::{IconButton, IconName, Tooltip};
6
7#[derive(IntoElement, RegisterComponent)]
8pub struct ThreadSidebarToggle {
9 sidebar_selected: bool,
10 thread_selected: bool,
11 flipped: bool,
12 sidebar_tooltip: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView + 'static>>,
13 thread_tooltip: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView + 'static>>,
14 on_sidebar_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
15 on_thread_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
16}
17
18impl ThreadSidebarToggle {
19 pub fn new() -> Self {
20 Self {
21 sidebar_selected: false,
22 thread_selected: false,
23 flipped: false,
24 sidebar_tooltip: None,
25 thread_tooltip: None,
26 on_sidebar_click: None,
27 on_thread_click: None,
28 }
29 }
30
31 pub fn sidebar_selected(mut self, selected: bool) -> Self {
32 self.sidebar_selected = selected;
33 self
34 }
35
36 pub fn thread_selected(mut self, selected: bool) -> Self {
37 self.thread_selected = selected;
38 self
39 }
40
41 pub fn flipped(mut self, flipped: bool) -> Self {
42 self.flipped = flipped;
43 self
44 }
45
46 pub fn sidebar_tooltip(
47 mut self,
48 tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static,
49 ) -> Self {
50 self.sidebar_tooltip = Some(Box::new(tooltip));
51 self
52 }
53
54 pub fn thread_tooltip(
55 mut self,
56 tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static,
57 ) -> Self {
58 self.thread_tooltip = Some(Box::new(tooltip));
59 self
60 }
61
62 pub fn on_sidebar_click(
63 mut self,
64 handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
65 ) -> Self {
66 self.on_sidebar_click = Some(Box::new(handler));
67 self
68 }
69
70 pub fn on_thread_click(
71 mut self,
72 handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
73 ) -> Self {
74 self.on_thread_click = Some(Box::new(handler));
75 self
76 }
77}
78
79impl RenderOnce for ThreadSidebarToggle {
80 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
81 let sidebar_icon = match (self.sidebar_selected, self.flipped) {
82 (true, false) => IconName::ThreadsSidebarLeftOpen,
83 (false, false) => IconName::ThreadsSidebarLeftClosed,
84 (true, true) => IconName::ThreadsSidebarRightOpen,
85 (false, true) => IconName::ThreadsSidebarRightClosed,
86 };
87
88 h_flex()
89 .min_w_0()
90 .rounded_sm()
91 .gap_px()
92 .border_1()
93 .border_color(cx.theme().colors().border)
94 .when(self.flipped, |this| this.flex_row_reverse())
95 .child(
96 IconButton::new("sidebar-toggle", sidebar_icon)
97 .icon_size(IconSize::Small)
98 .toggle_state(self.sidebar_selected)
99 .when_some(self.sidebar_tooltip, |this, tooltip| this.tooltip(tooltip))
100 .when_some(self.on_sidebar_click, |this, handler| {
101 this.on_click(handler)
102 }),
103 )
104 .child(div().h_4().w_px().bg(cx.theme().colors().border))
105 .child(
106 IconButton::new("thread-toggle", IconName::Thread)
107 .icon_size(IconSize::Small)
108 .toggle_state(self.thread_selected)
109 .when_some(self.thread_tooltip, |this, tooltip| this.tooltip(tooltip))
110 .when_some(self.on_thread_click, |this, handler| this.on_click(handler)),
111 )
112 }
113}
114
115impl Component for ThreadSidebarToggle {
116 fn scope() -> ComponentScope {
117 ComponentScope::Agent
118 }
119
120 fn preview(_window: &mut Window, cx: &mut App) -> Option<AnyElement> {
121 let container = || div().p_2().bg(cx.theme().colors().status_bar_background);
122
123 let examples = vec![
124 single_example(
125 "Both Unselected",
126 container()
127 .child(ThreadSidebarToggle::new())
128 .into_any_element(),
129 ),
130 single_example(
131 "Sidebar Selected",
132 container()
133 .child(ThreadSidebarToggle::new().sidebar_selected(true))
134 .into_any_element(),
135 ),
136 single_example(
137 "Thread Selected",
138 container()
139 .child(ThreadSidebarToggle::new().thread_selected(true))
140 .into_any_element(),
141 ),
142 single_example(
143 "Both Selected",
144 container()
145 .child(
146 ThreadSidebarToggle::new()
147 .sidebar_selected(true)
148 .thread_selected(true),
149 )
150 .into_any_element(),
151 ),
152 single_example(
153 "Flipped",
154 container()
155 .child(
156 ThreadSidebarToggle::new()
157 .sidebar_selected(true)
158 .thread_selected(true)
159 .flipped(true),
160 )
161 .into_any_element(),
162 ),
163 single_example(
164 "With Tooltips",
165 container()
166 .child(
167 ThreadSidebarToggle::new()
168 .sidebar_tooltip(Tooltip::text("Toggle Sidebar"))
169 .thread_tooltip(Tooltip::text("Toggle Thread")),
170 )
171 .into_any_element(),
172 ),
173 ];
174
175 Some(example_group(examples).into_any_element())
176 }
177}