diff --git a/crates/collab_ui/src/collab_panel.rs b/crates/collab_ui/src/collab_panel.rs index 16de60e735a04d5c3cecb742e7cead60320b4ae6..f35c07d5aa0a9e98a8a24fee93c895308f7a09bb 100644 --- a/crates/collab_ui/src/collab_panel.rs +++ b/crates/collab_ui/src/collab_panel.rs @@ -8,7 +8,6 @@ use client::{ proto::PeerId, Channel, ChannelEvent, ChannelId, ChannelStore, Client, Contact, User, UserStore, }; -use components::DisclosureExt; use context_menu::{ContextMenu, ContextMenuItem}; use db::kvp::KEY_VALUE_STORE; use editor::{Cancel, Editor}; @@ -17,8 +16,9 @@ use fuzzy::{match_strings, StringMatchCandidate}; use gpui::{ actions, elements::{ - Canvas, ChildView, Component, Empty, Flex, Image, Label, List, ListOffset, ListState, - MouseEventHandler, Orientation, OverlayPositionMode, Padding, ParentElement, Stack, Svg, + Canvas, ChildView, Empty, Flex, GeneralComponent, GeneralStyleableComponent, Image, Label, + List, ListOffset, ListState, MouseEventHandler, Orientation, OverlayPositionMode, Padding, + ParentElement, Stack, Svg, }, geometry::{ rect::RectF, @@ -44,7 +44,10 @@ use workspace::{ Workspace, }; -use crate::face_pile::FacePile; +use crate::{ + collab_panel::components::{DisclosureExt, DisclosureStyle}, + face_pile::FacePile, +}; use channel_modal::ChannelModal; use self::contact_finder::ContactFinder; @@ -1616,10 +1619,17 @@ impl CollabPanel { this.deploy_channel_context_menu(Some(e.position), channel_id, cx); }) .with_cursor_style(CursorStyle::PointingHand) - .component() - .styleable() - .disclosable() - .into_element() + .dynamic_component() + .stylable() + .disclosable(true, Box::new(RemoveChannel { channel_id: 0 })) + .with_style({ + fn style() -> DisclosureStyle<()> { + todo!() + } + + style() + }) + .element() .into_any() } @@ -2531,7 +2541,7 @@ fn render_icon_button(style: &IconButton, svg_path: &'static str) -> impl Elemen mod components { use gpui::{ - elements::{Empty, Flex, GeneralComponent, ParentElement, StyleableComponent}, + elements::{Empty, Flex, GeneralComponent, GeneralStyleableComponent, ParentElement}, Action, Element, }; use theme::components::{ @@ -2539,13 +2549,13 @@ mod components { }; #[derive(Clone)] - struct DisclosureStyle { + pub struct DisclosureStyle { disclosure: ToggleIconButtonStyle, spacing: f32, content: S, } - struct Disclosable { + pub struct Disclosable { disclosed: bool, action: Box, content: C, @@ -2563,7 +2573,7 @@ mod components { } } - impl StyleableComponent for Disclosable { + impl GeneralStyleableComponent for Disclosable { type Style = DisclosureStyle; type Output = Disclosable; @@ -2578,7 +2588,7 @@ mod components { } } - impl GeneralComponent for Disclosable> { + impl GeneralComponent for Disclosable> { fn render( self, v: &mut V, @@ -2605,7 +2615,7 @@ mod components { Self: Sized; } - impl DisclosureExt for C { + impl DisclosureExt for C { fn disclosable(self, disclosed: bool, action: Box) -> Disclosable { Disclosable::new(disclosed, self, action) } diff --git a/crates/gpui/examples/components.rs b/crates/gpui/examples/components.rs index ad38b5893c48a831c245ed61300d9c92d7319383..aeeab8101d1e926f287e72c9fd22a44af8d645df 100644 --- a/crates/gpui/examples/components.rs +++ b/crates/gpui/examples/components.rs @@ -72,7 +72,7 @@ impl View for TestView { TextStyle::for_color(Color::blue()), ) .with_style(ButtonStyle::fill(Color::yellow())) - .element(), + .c_element(), ) .with_child( ToggleableButton::new(self.is_doubling, move |_, v: &mut Self, cx| { @@ -84,7 +84,7 @@ impl View for TestView { inactive: ButtonStyle::fill(Color::red()), active: ButtonStyle::fill(Color::green()), }) - .element(), + .c_element(), ) .expanded() .contained() diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index f7697d6fc13b08ac09a84ed5e2051c9cec286b6d..c0484ef9395a9e25e82384b30aa5fdc88d81bf07 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -236,6 +236,13 @@ pub trait Element: 'static { { ElementAdapter::new(self.into_any()) } + + fn dynamic_component(self) -> DynamicElementAdapter + where + Self: Sized, + { + DynamicElementAdapter::new(self.into_any()) + } } pub trait RenderElement { diff --git a/crates/gpui/src/elements/component.rs b/crates/gpui/src/elements/component.rs index ee4702a6fad308feaa148884af848a4e3148ce2e..f5a4180d7f379c059a175c731311ca46360f0132 100644 --- a/crates/gpui/src/elements/component.rs +++ b/crates/gpui/src/elements/component.rs @@ -1,4 +1,4 @@ -use std::marker::PhantomData; +use std::{any::Any, marker::PhantomData}; use pathfinder_geometry::{rect::RectF, vector::Vector2F}; @@ -11,15 +11,43 @@ use super::Empty; pub trait GeneralComponent { fn render(self, v: &mut V, cx: &mut ViewContext) -> AnyElement; + fn element(self) -> ComponentAdapter where Self: Sized, { ComponentAdapter::new(self) } + + fn stylable(self) -> GeneralStylableComponentAdapter + where + Self: Sized, + { + GeneralStylableComponentAdapter::new(self) + } +} + +pub struct GeneralStylableComponentAdapter { + component: C, +} + +impl GeneralStylableComponentAdapter { + pub fn new(component: C) -> Self { + Self { component } + } +} + +impl GeneralStyleableComponent for GeneralStylableComponentAdapter { + type Style = (); + + type Output = C; + + fn with_style(self, _: Self::Style) -> Self::Output { + self.component + } } -pub trait StyleableComponent { +pub trait GeneralStyleableComponent { type Style: Clone; type Output: GeneralComponent; @@ -32,7 +60,7 @@ impl GeneralComponent for () { } } -impl StyleableComponent for () { +impl GeneralStyleableComponent for () { type Style = (); type Output = (); @@ -41,17 +69,34 @@ impl StyleableComponent for () { } } +pub trait StyleableComponent { + type Style: Clone; + type Output: Component; + + fn c_with_style(self, style: Self::Style) -> Self::Output; +} + +impl StyleableComponent for C { + type Style = C::Style; + + type Output = C::Output; + + fn c_with_style(self, style: Self::Style) -> Self::Output { + self.with_style(style) + } +} + pub trait Component { fn render(self, v: &mut V, cx: &mut ViewContext) -> AnyElement; - fn element(self) -> ComponentAdapter + fn c_element(self) -> ComponentAdapter where Self: Sized, { ComponentAdapter::new(self) } - fn styleable(self) -> StylableComponentAdapter + fn c_styleable(self) -> StylableComponentAdapter where Self: Sized, { @@ -65,7 +110,7 @@ impl Component for C { } } -// StylableComponent -> GeneralComponent +// StylableComponent -> Component pub struct StylableComponentAdapter, V: View> { component: C, phantom: std::marker::PhantomData, @@ -80,16 +125,40 @@ impl, V: View> StylableComponentAdapter { } } -impl StyleableComponent for StylableComponentAdapter { +impl, V: View> StyleableComponent for StylableComponentAdapter { type Style = (); type Output = C; - fn with_style(self, _: Self::Style) -> Self::Output { + fn c_with_style(self, _: Self::Style) -> Self::Output { self.component } } +// Element -> GeneralComponent + +pub struct DynamicElementAdapter { + element: Box, +} + +impl DynamicElementAdapter { + pub fn new(element: AnyElement) -> Self { + DynamicElementAdapter { + element: Box::new(element) as Box, + } + } +} + +impl GeneralComponent for DynamicElementAdapter { + fn render(self, _: &mut V, _: &mut ViewContext) -> AnyElement { + let element = self + .element + .downcast::>() + .expect("Don't move elements out of their view :("); + *element + } +} + // Element -> Component pub struct ElementAdapter { element: AnyElement, diff --git a/crates/search/src/search.rs b/crates/search/src/search.rs index 2dc45e397394b84671533471e7c93937d9469354..b3167efe507f6ae36fb870412793d38d39ae4e20 100644 --- a/crates/search/src/search.rs +++ b/crates/search/src/search.rs @@ -2,7 +2,7 @@ use bitflags::bitflags; pub use buffer_search::BufferSearchBar; use gpui::{ actions, - elements::{Component, StyleableComponent, TooltipStyle}, + elements::{Component, GeneralStyleableComponent, TooltipStyle}, Action, AnyElement, AppContext, Element, View, }; pub use mode::SearchMode; @@ -96,7 +96,7 @@ impl SearchOptions { .with_contents(Svg::new(self.icon())) .toggleable(active) .with_style(button_style) - .element() + .c_element() .into_any() } } diff --git a/crates/theme/src/components.rs b/crates/theme/src/components.rs index 1e395405cbb506596248d51ac5b387ca2a654e83..3679b1fa4f1c1313d4fa8340d518d9949c5d0a31 100644 --- a/crates/theme/src/components.rs +++ b/crates/theme/src/components.rs @@ -1,4 +1,4 @@ -use gpui::elements::StyleableComponent; +use gpui::elements::GeneralStyleableComponent; use crate::{Interactive, Toggleable}; @@ -6,18 +6,18 @@ use self::{action_button::ButtonStyle, svg::SvgStyle, toggle::Toggle}; pub type ToggleIconButtonStyle = Toggleable>>; -pub trait ComponentExt { +pub trait ComponentExt { fn toggleable(self, active: bool) -> Toggle; } -impl ComponentExt for C { +impl ComponentExt for C { fn toggleable(self, active: bool) -> Toggle { Toggle::new(self, active) } } pub mod toggle { - use gpui::elements::{GeneralComponent, StyleableComponent}; + use gpui::elements::{GeneralComponent, GeneralStyleableComponent}; use crate::Toggleable; @@ -27,7 +27,7 @@ pub mod toggle { component: C, } - impl Toggle { + impl Toggle { pub fn new(component: C, active: bool) -> Self { Toggle { active, @@ -37,7 +37,7 @@ pub mod toggle { } } - impl StyleableComponent for Toggle { + impl GeneralStyleableComponent for Toggle { type Style = Toggleable; type Output = Toggle; @@ -51,7 +51,7 @@ pub mod toggle { } } - impl GeneralComponent for Toggle> { + impl GeneralComponent for Toggle> { fn render( self, v: &mut V, @@ -69,7 +69,8 @@ pub mod action_button { use gpui::{ elements::{ - ContainerStyle, GeneralComponent, MouseEventHandler, StyleableComponent, TooltipStyle, + ContainerStyle, GeneralComponent, GeneralStyleableComponent, MouseEventHandler, + TooltipStyle, }, platform::{CursorStyle, MouseButton}, Action, Element, TypeTag, View, @@ -121,7 +122,10 @@ pub mod action_button { self } - pub fn with_contents(self, contents: C) -> ActionButton { + pub fn with_contents( + self, + contents: C, + ) -> ActionButton { ActionButton { action: self.action, tag: self.tag, @@ -132,7 +136,7 @@ pub mod action_button { } } - impl StyleableComponent for ActionButton { + impl GeneralStyleableComponent for ActionButton { type Style = Interactive>; type Output = ActionButton>; @@ -148,7 +152,7 @@ pub mod action_button { } } - impl GeneralComponent for ActionButton> { + impl GeneralComponent for ActionButton> { fn render(self, v: &mut V, cx: &mut gpui::ViewContext) -> gpui::AnyElement { let mut button = MouseEventHandler::new_dynamic(self.tag, 0, cx, |state, cx| { let style = self.style.style_for(state); @@ -195,7 +199,7 @@ pub mod svg { use std::borrow::Cow; use gpui::{ - elements::{GeneralComponent, StyleableComponent}, + elements::{GeneralComponent, GeneralStyleableComponent}, Element, }; use schemars::JsonSchema; @@ -261,7 +265,7 @@ pub mod svg { } } - impl StyleableComponent for Svg<()> { + impl GeneralStyleableComponent for Svg<()> { type Style = SvgStyle; type Output = Svg; @@ -294,7 +298,7 @@ pub mod label { use std::borrow::Cow; use gpui::{ - elements::{GeneralComponent, LabelStyle, StyleableComponent}, + elements::{GeneralComponent, GeneralStyleableComponent, LabelStyle}, Element, }; @@ -312,7 +316,7 @@ pub mod label { } } - impl StyleableComponent for Label<()> { + impl GeneralStyleableComponent for Label<()> { type Style = LabelStyle; type Output = Label;