1use std::sync::Arc;
2
3use gpui::{ClickEvent, CursorStyle};
4
5use crate::{prelude::*, Color, IconButton, IconButtonShape, IconName, IconSize};
6
7#[derive(IntoElement)]
8pub struct Disclosure {
9 id: ElementId,
10 is_open: bool,
11 selected: bool,
12 on_toggle: Option<Arc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
13 cursor_style: CursorStyle,
14}
15
16impl Disclosure {
17 pub fn new(id: impl Into<ElementId>, is_open: bool) -> Self {
18 Self {
19 id: id.into(),
20 is_open,
21 selected: false,
22 on_toggle: None,
23 cursor_style: CursorStyle::PointingHand,
24 }
25 }
26
27 pub fn on_toggle(
28 mut self,
29 handler: impl Into<Option<Arc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>>,
30 ) -> Self {
31 self.on_toggle = handler.into();
32 self
33 }
34}
35
36impl Toggleable for Disclosure {
37 fn toggle_state(mut self, selected: bool) -> Self {
38 self.selected = selected;
39 self
40 }
41}
42
43impl Clickable for Disclosure {
44 fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static) -> Self {
45 self.on_toggle = Some(Arc::new(handler));
46 self
47 }
48
49 fn cursor_style(mut self, cursor_style: gpui::CursorStyle) -> Self {
50 self.cursor_style = cursor_style;
51 self
52 }
53}
54
55impl RenderOnce for Disclosure {
56 fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
57 IconButton::new(
58 self.id,
59 match self.is_open {
60 true => IconName::ChevronDown,
61 false => IconName::ChevronRight,
62 },
63 )
64 .shape(IconButtonShape::Square)
65 .icon_color(Color::Muted)
66 .icon_size(IconSize::Small)
67 .toggle_state(self.selected)
68 .when_some(self.on_toggle, move |this, on_toggle| {
69 this.on_click(move |event, window, cx| on_toggle(event, window, cx))
70 })
71 }
72}