| @@ -0,0 +1,177 @@ |
| | 1 | use gpui::{AnyView, ClickEvent}; |
| | 2 | use ui_macros::RegisterComponent; |
| | 3 | |
| | 4 | use crate::prelude::*; |
| | 5 | use crate::{IconButton, IconName, Tooltip}; |
| | 6 | |
| | 7 | #[derive(IntoElement, RegisterComponent)] |
| | 8 | pub 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 | |
| | 18 | impl 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 | |
| | 79 | impl 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 | |
| | 115 | impl 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 | } |