From 60ce75c34a999161f63377772f6dd94d3cbf85f5 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Tue, 28 Nov 2023 16:52:12 -0700 Subject: [PATCH] Togglable channels, the greatest since sliced bread --- crates/collab_ui2/src/collab_panel.rs | 31 +++++++++++++----------- crates/ui2/src/components/disclosure.rs | 25 +++++++++++++------ crates/ui2/src/components/icon_button.rs | 15 ++++++++++-- crates/ui2/src/components/list.rs | 16 +++++++++--- 4 files changed, 61 insertions(+), 26 deletions(-) diff --git a/crates/collab_ui2/src/collab_panel.rs b/crates/collab_ui2/src/collab_panel.rs index a92389e6bc1475ad6b92470dc8e4c03764d00769..2a1ce758abcc39291e09aa044fe78f93307df247 100644 --- a/crates/collab_ui2/src/collab_panel.rs +++ b/crates/collab_ui2/src/collab_panel.rs @@ -2233,20 +2233,20 @@ impl CollabPanel { // self.toggle_channel_collapsed(action.location, cx); // } - // fn toggle_channel_collapsed<'a>(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { - // match self.collapsed_channels.binary_search(&channel_id) { - // Ok(ix) => { - // self.collapsed_channels.remove(ix); - // } - // Err(ix) => { - // self.collapsed_channels.insert(ix, channel_id); - // } - // }; - // self.serialize(cx); - // self.update_entries(true, cx); - // cx.notify(); - // cx.focus_self(); - // } + fn toggle_channel_collapsed<'a>(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { + match self.collapsed_channels.binary_search(&channel_id) { + Ok(ix) => { + self.collapsed_channels.remove(ix); + } + Err(ix) => { + self.collapsed_channels.insert(ix, channel_id); + } + }; + // self.serialize(cx); todo!() + self.update_entries(true, cx); + cx.notify(); + cx.focus_self(); + } fn is_channel_collapsed(&self, channel_id: ChannelId) -> bool { self.collapsed_channels.binary_search(&channel_id).is_ok() @@ -3129,6 +3129,9 @@ impl CollabPanel { } else { Toggle::NotToggleable }) + .on_toggle( + cx.listener(move |this, _, cx| this.toggle_channel_collapsed(channel_id, cx)), + ) .on_click(cx.listener(move |this, _, cx| { if this.drag_target_channel == ChannelDragTarget::None { if is_active { diff --git a/crates/ui2/src/components/disclosure.rs b/crates/ui2/src/components/disclosure.rs index 3ec8c1953e2f8edcabbf4f8a6c2eabcd0d7174d8..e0d7b1c5192611b9b2690601aaca77d6e1f89736 100644 --- a/crates/ui2/src/components/disclosure.rs +++ b/crates/ui2/src/components/disclosure.rs @@ -1,19 +1,30 @@ -use gpui::{div, Element, ParentElement}; +use std::rc::Rc; -use crate::{Color, Icon, IconElement, IconSize, Toggle}; +use gpui::{div, Element, IntoElement, MouseDownEvent, ParentElement, WindowContext}; -pub fn disclosure_control(toggle: Toggle) -> impl Element { +use crate::{Color, Icon, IconButton, IconSize, Toggle}; + +pub fn disclosure_control( + toggle: Toggle, + on_toggle: Option>, +) -> impl Element { match (toggle.is_toggleable(), toggle.is_toggled()) { (false, _) => div(), (_, true) => div().child( - IconElement::new(Icon::ChevronDown) + IconButton::new("toggle", Icon::ChevronDown) .color(Color::Muted) - .size(IconSize::Small), + .size(IconSize::Small) + .when_some(on_toggle, move |el, on_toggle| { + el.on_click(move |e, cx| on_toggle(e, cx)) + }), ), (_, false) => div().child( - IconElement::new(Icon::ChevronRight) + IconButton::new("toggle", Icon::ChevronRight) .color(Color::Muted) - .size(IconSize::Small), + .size(IconSize::Small) + .when_some(on_toggle, move |el, on_toggle| { + el.on_click(move |e, cx| on_toggle(e, cx)) + }), ), } } diff --git a/crates/ui2/src/components/icon_button.rs b/crates/ui2/src/components/icon_button.rs index b2f3f8403d6b050b6ecaa4e0638972ad3bdbe36e..104eb00ec83dc4a0b8ca9573f870628c53041b00 100644 --- a/crates/ui2/src/components/icon_button.rs +++ b/crates/ui2/src/components/icon_button.rs @@ -1,4 +1,4 @@ -use crate::{h_stack, prelude::*, Icon, IconElement}; +use crate::{h_stack, prelude::*, Icon, IconElement, IconSize}; use gpui::{prelude::*, Action, AnyView, Div, MouseButton, MouseDownEvent, Stateful}; #[derive(IntoElement)] @@ -6,6 +6,7 @@ pub struct IconButton { id: ElementId, icon: Icon, color: Color, + size: IconSize, variant: ButtonVariant, state: InteractionState, selected: bool, @@ -50,7 +51,11 @@ impl RenderOnce for IconButton { // place we use an icon button. // .hover(|style| style.bg(bg_hover_color)) .active(|style| style.bg(bg_active_color)) - .child(IconElement::new(self.icon).color(icon_color)); + .child( + IconElement::new(self.icon) + .size(self.size) + .color(icon_color), + ); if let Some(click_handler) = self.on_mouse_down { button = button.on_mouse_down(MouseButton::Left, move |event, cx| { @@ -76,6 +81,7 @@ impl IconButton { id: id.into(), icon, color: Color::default(), + size: Default::default(), variant: ButtonVariant::default(), state: InteractionState::default(), selected: false, @@ -94,6 +100,11 @@ impl IconButton { self } + pub fn size(mut self, size: IconSize) -> Self { + self.size = size; + self + } + pub fn variant(mut self, variant: ButtonVariant) -> Self { self.variant = variant; self diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index 749de951d9a3055050e18198956eb71c75684cfe..61ed483cd86eed013c46f662dd3fab4cb61f03b1 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -63,7 +63,7 @@ impl RenderOnce for ListHeader { type Rendered = Div; fn render(self, cx: &mut WindowContext) -> Self::Rendered { - let disclosure_control = disclosure_control(self.toggle); + let disclosure_control = disclosure_control(self.toggle, None); let meta = match self.meta { Some(ListHeaderMeta::Tools(icons)) => div().child( @@ -177,6 +177,7 @@ pub struct ListItem { toggle: Toggle, inset: bool, on_click: Option>, + on_toggle: Option>, on_secondary_mouse_down: Option>, children: SmallVec<[AnyElement; 2]>, } @@ -193,6 +194,7 @@ impl ListItem { inset: false, on_click: None, on_secondary_mouse_down: None, + on_toggle: None, children: SmallVec::new(), } } @@ -230,6 +232,14 @@ impl ListItem { self } + pub fn on_toggle( + mut self, + on_toggle: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static, + ) -> Self { + self.on_toggle = Some(Rc::new(on_toggle)); + self + } + pub fn selected(mut self, selected: bool) -> Self { self.selected = selected; self @@ -283,7 +293,7 @@ impl RenderOnce for ListItem { this.bg(cx.theme().colors().ghost_element_selected) }) .when_some(self.on_click.clone(), |this, on_click| { - this.on_click(move |event, cx| { + this.cursor_pointer().on_click(move |event, cx| { // HACK: GPUI currently fires `on_click` with any mouse button, // but we only care about the left button. if event.down.button == MouseButton::Left { @@ -304,7 +314,7 @@ impl RenderOnce for ListItem { .gap_1() .items_center() .relative() - .child(disclosure_control(self.toggle)) + .child(disclosure_control(self.toggle, self.on_toggle)) .children(left_content) .children(self.children) // HACK: We need to attach the `on_click` handler to the child element in order to have the click