Detailed changes
@@ -576,7 +576,7 @@ new_ret_no_self = { level = "allow" }
# We have a few `next` functions that differ in lifetimes
# compared to Iterator::next. Yet, clippy complains about those.
should_implement_trait = { level = "allow" }
-
+module_inception = { level = "deny" }
# Individual rules that have violations in the codebase:
type_complexity = "allow"
@@ -0,0 +1 @@
+allow-private-module-inception = true
@@ -1,133 +1,7 @@
+mod avatar;
mod avatar_audio_status_indicator;
mod avatar_availability_indicator;
+pub use avatar::*;
pub use avatar_audio_status_indicator::*;
pub use avatar_availability_indicator::*;
-
-use crate::prelude::*;
-
-use gpui::{img, AnyElement, Hsla, ImageSource, Img, IntoElement, Styled};
-
-/// The shape of an [`Avatar`].
-#[derive(Debug, Default, PartialEq, Clone)]
-pub enum AvatarShape {
- /// The avatar is shown in a circle.
- #[default]
- Circle,
- /// The avatar is shown in a rectangle with rounded corners.
- RoundedRectangle,
-}
-
-/// An element that renders a user avatar with customizable appearance options.
-///
-/// # Examples
-///
-/// ```
-/// use ui::{Avatar, AvatarShape};
-///
-/// Avatar::new("path/to/image.png")
-/// .shape(AvatarShape::Circle)
-/// .grayscale(true)
-/// .border_color(gpui::red());
-/// ```
-#[derive(IntoElement)]
-pub struct Avatar {
- image: Img,
- size: Option<AbsoluteLength>,
- border_color: Option<Hsla>,
- indicator: Option<AnyElement>,
-}
-
-impl Avatar {
- pub fn new(src: impl Into<ImageSource>) -> Self {
- Avatar {
- image: img(src),
- size: None,
- border_color: None,
- indicator: None,
- }
- }
-
- /// Sets the shape of the avatar image.
- ///
- /// This method allows the shape of the avatar to be specified using an [`AvatarShape`].
- /// It modifies the corner radius of the image to match the specified shape.
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::{Avatar, AvatarShape};
- ///
- /// Avatar::new("path/to/image.png").shape(AvatarShape::Circle);
- /// ```
- pub fn shape(mut self, shape: AvatarShape) -> Self {
- self.image = match shape {
- AvatarShape::Circle => self.image.rounded_full(),
- AvatarShape::RoundedRectangle => self.image.rounded_md(),
- };
- self
- }
-
- /// Applies a grayscale filter to the avatar image.
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::{Avatar, AvatarShape};
- ///
- /// let avatar = Avatar::new("path/to/image.png").grayscale(true);
- /// ```
- pub fn grayscale(mut self, grayscale: bool) -> Self {
- self.image = self.image.grayscale(grayscale);
- self
- }
-
- pub fn border_color(mut self, color: impl Into<Hsla>) -> Self {
- self.border_color = Some(color.into());
- self
- }
-
- /// Size overrides the avatar size. By default they are 1rem.
- pub fn size<L: Into<AbsoluteLength>>(mut self, size: impl Into<Option<L>>) -> Self {
- self.size = size.into().map(Into::into);
- self
- }
-
- pub fn indicator<E: IntoElement>(mut self, indicator: impl Into<Option<E>>) -> Self {
- self.indicator = indicator.into().map(IntoElement::into_any_element);
- self
- }
-}
-
-impl RenderOnce for Avatar {
- fn render(mut self, cx: &mut WindowContext) -> impl IntoElement {
- if self.image.style().corner_radii.top_left.is_none() {
- self = self.shape(AvatarShape::Circle);
- }
-
- let border_width = if self.border_color.is_some() {
- px(2.)
- } else {
- px(0.)
- };
-
- let image_size = self.size.unwrap_or_else(|| rems(1.).into());
- let container_size = image_size.to_pixels(cx.rem_size()) + border_width * 2.;
-
- div()
- .size(container_size)
- .map(|mut div| {
- div.style().corner_radii = self.image.style().corner_radii.clone();
- div
- })
- .when_some(self.border_color, |this, color| {
- this.border(border_width).border_color(color)
- })
- .child(
- self.image
- .size(image_size)
- .bg(cx.theme().colors().ghost_element_background),
- )
- .children(self.indicator.map(|indicator| div().child(indicator)))
- }
-}
@@ -0,0 +1,127 @@
+use crate::prelude::*;
+
+use gpui::{img, AnyElement, Hsla, ImageSource, Img, IntoElement, Styled};
+
+/// The shape of an [`Avatar`].
+#[derive(Debug, Default, PartialEq, Clone)]
+pub enum AvatarShape {
+ /// The avatar is shown in a circle.
+ #[default]
+ Circle,
+ /// The avatar is shown in a rectangle with rounded corners.
+ RoundedRectangle,
+}
+
+/// An element that renders a user avatar with customizable appearance options.
+///
+/// # Examples
+///
+/// ```
+/// use ui::{Avatar, AvatarShape};
+///
+/// Avatar::new("path/to/image.png")
+/// .shape(AvatarShape::Circle)
+/// .grayscale(true)
+/// .border_color(gpui::red());
+/// ```
+#[derive(IntoElement)]
+pub struct Avatar {
+ image: Img,
+ size: Option<AbsoluteLength>,
+ border_color: Option<Hsla>,
+ indicator: Option<AnyElement>,
+}
+
+impl Avatar {
+ pub fn new(src: impl Into<ImageSource>) -> Self {
+ Avatar {
+ image: img(src),
+ size: None,
+ border_color: None,
+ indicator: None,
+ }
+ }
+
+ /// Sets the shape of the avatar image.
+ ///
+ /// This method allows the shape of the avatar to be specified using an [`AvatarShape`].
+ /// It modifies the corner radius of the image to match the specified shape.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::{Avatar, AvatarShape};
+ ///
+ /// Avatar::new("path/to/image.png").shape(AvatarShape::Circle);
+ /// ```
+ pub fn shape(mut self, shape: AvatarShape) -> Self {
+ self.image = match shape {
+ AvatarShape::Circle => self.image.rounded_full(),
+ AvatarShape::RoundedRectangle => self.image.rounded_md(),
+ };
+ self
+ }
+
+ /// Applies a grayscale filter to the avatar image.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::{Avatar, AvatarShape};
+ ///
+ /// let avatar = Avatar::new("path/to/image.png").grayscale(true);
+ /// ```
+ pub fn grayscale(mut self, grayscale: bool) -> Self {
+ self.image = self.image.grayscale(grayscale);
+ self
+ }
+
+ pub fn border_color(mut self, color: impl Into<Hsla>) -> Self {
+ self.border_color = Some(color.into());
+ self
+ }
+
+ /// Size overrides the avatar size. By default they are 1rem.
+ pub fn size<L: Into<AbsoluteLength>>(mut self, size: impl Into<Option<L>>) -> Self {
+ self.size = size.into().map(Into::into);
+ self
+ }
+
+ pub fn indicator<E: IntoElement>(mut self, indicator: impl Into<Option<E>>) -> Self {
+ self.indicator = indicator.into().map(IntoElement::into_any_element);
+ self
+ }
+}
+
+impl RenderOnce for Avatar {
+ fn render(mut self, cx: &mut WindowContext) -> impl IntoElement {
+ if self.image.style().corner_radii.top_left.is_none() {
+ self = self.shape(AvatarShape::Circle);
+ }
+
+ let border_width = if self.border_color.is_some() {
+ px(2.)
+ } else {
+ px(0.)
+ };
+
+ let image_size = self.size.unwrap_or_else(|| rems(1.).into());
+ let container_size = image_size.to_pixels(cx.rem_size()) + border_width * 2.;
+
+ div()
+ .size(container_size)
+ .map(|mut div| {
+ div.style().corner_radii = self.image.style().corner_radii.clone();
+ div
+ })
+ .when_some(self.border_color, |this, color| {
+ this.border(border_width).border_color(color)
+ })
+ .child(
+ self.image
+ .size(image_size)
+ .bg(cx.theme().colors().ghost_element_background),
+ )
+ .children(self.indicator.map(|indicator| div().child(indicator)))
+ }
+}
@@ -1,445 +1,10 @@
-mod button_icon;
+mod button;
+pub(self) mod button_icon;
mod button_like;
mod icon_button;
mod toggle_button;
+pub use button::*;
pub use button_like::*;
pub use icon_button::*;
pub use toggle_button::*;
-
-use gpui::{AnyView, DefiniteLength};
-
-use crate::{prelude::*, ElevationIndex, KeyBinding, Spacing};
-use crate::{IconName, IconSize, Label, LineHeightStyle};
-
-use button_icon::ButtonIcon;
-
-/// An element that creates a button with a label and an optional icon.
-///
-/// Common buttons:
-/// - Label, Icon + Label: [`Button`] (this component)
-/// - Icon only: [`IconButton`]
-/// - Custom: [`ButtonLike`]
-///
-/// To create a more complex button than what the [`Button`] or [`IconButton`] components provide, use
-/// [`ButtonLike`] directly.
-///
-/// # Examples
-///
-/// **A button with a label**, is typically used in scenarios such as a form, where the button's label
-/// indicates what action will be performed when the button is clicked.
-///
-/// ```
-/// use ui::prelude::*;
-///
-/// Button::new("button_id", "Click me!")
-/// .on_click(|event, cx| {
-/// // Handle click event
-/// });
-/// ```
-///
-/// **A toggleable button**, is typically used in scenarios such as a toolbar,
-/// where the button's state indicates whether a feature is enabled or not, or
-/// a trigger for a popover menu, where clicking the button toggles the visibility of the menu.
-///
-/// ```
-/// use ui::prelude::*;
-///
-/// Button::new("button_id", "Click me!")
-/// .icon(IconName::Check)
-/// .selected(true)
-/// .on_click(|event, cx| {
-/// // Handle click event
-/// });
-/// ```
-///
-/// To change the style of the button when it is selected use the [`selected_style`][Button::selected_style] method.
-///
-/// ```
-/// use ui::prelude::*;
-/// use ui::TintColor;
-///
-/// Button::new("button_id", "Click me!")
-/// .selected(true)
-/// .selected_style(ButtonStyle::Tinted(TintColor::Accent))
-/// .on_click(|event, cx| {
-/// // Handle click event
-/// });
-/// ```
-/// This will create a button with a blue tinted background when selected.
-///
-/// **A full-width button**, is typically used in scenarios such as the bottom of a modal or form, where it occupies the entire width of its container.
-/// The button's content, including text and icons, is centered by default.
-///
-/// ```
-/// use ui::prelude::*;
-///
-/// let button = Button::new("button_id", "Click me!")
-/// .full_width()
-/// .on_click(|event, cx| {
-/// // Handle click event
-/// });
-/// ```
-///
-#[derive(IntoElement)]
-pub struct Button {
- base: ButtonLike,
- label: SharedString,
- label_color: Option<Color>,
- label_size: Option<LabelSize>,
- selected_label: Option<SharedString>,
- selected_label_color: Option<Color>,
- icon: Option<IconName>,
- icon_position: Option<IconPosition>,
- icon_size: Option<IconSize>,
- icon_color: Option<Color>,
- selected_icon: Option<IconName>,
- selected_icon_color: Option<Color>,
- key_binding: Option<KeyBinding>,
- alpha: Option<f32>,
-}
-
-impl Button {
- /// Creates a new [`Button`] with a specified identifier and label.
- ///
- /// This is the primary constructor for a [`Button`] component. It initializes
- /// the button with the provided identifier and label text, setting all other
- /// properties to their default values, which can be customized using the
- /// builder pattern methods provided by this struct.
- pub fn new(id: impl Into<ElementId>, label: impl Into<SharedString>) -> Self {
- Self {
- base: ButtonLike::new(id),
- label: label.into(),
- label_color: None,
- label_size: None,
- selected_label: None,
- selected_label_color: None,
- icon: None,
- icon_position: None,
- icon_size: None,
- icon_color: None,
- selected_icon: None,
- selected_icon_color: None,
- key_binding: None,
- alpha: None,
- }
- }
-
- /// Sets the color of the button's label.
- pub fn color(mut self, label_color: impl Into<Option<Color>>) -> Self {
- self.label_color = label_color.into();
- self
- }
-
- /// Defines the size of the button's label.
- pub fn label_size(mut self, label_size: impl Into<Option<LabelSize>>) -> Self {
- self.label_size = label_size.into();
- self
- }
-
- /// Sets the label used when the button is in a selected state.
- pub fn selected_label<L: Into<SharedString>>(mut self, label: impl Into<Option<L>>) -> Self {
- self.selected_label = label.into().map(Into::into);
- self
- }
-
- /// Sets the label color used when the button is in a selected state.
- pub fn selected_label_color(mut self, color: impl Into<Option<Color>>) -> Self {
- self.selected_label_color = color.into();
- self
- }
-
- /// Assigns an icon to the button.
- pub fn icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
- self.icon = icon.into();
- self
- }
-
- /// Sets the position of the icon relative to the label.
- pub fn icon_position(mut self, icon_position: impl Into<Option<IconPosition>>) -> Self {
- self.icon_position = icon_position.into();
- self
- }
-
- /// Specifies the size of the button's icon.
- pub fn icon_size(mut self, icon_size: impl Into<Option<IconSize>>) -> Self {
- self.icon_size = icon_size.into();
- self
- }
-
- /// Sets the color of the button's icon.
- pub fn icon_color(mut self, icon_color: impl Into<Option<Color>>) -> Self {
- self.icon_color = icon_color.into();
- self
- }
-
- /// Chooses an icon to display when the button is in a selected state.
- pub fn selected_icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
- self.selected_icon = icon.into();
- self
- }
-
- /// Sets the icon color used when the button is in a selected state.
- pub fn selected_icon_color(mut self, color: impl Into<Option<Color>>) -> Self {
- self.selected_icon_color = color.into();
- self
- }
-
- /// Binds a key combination to the button for keyboard shortcuts.
- pub fn key_binding(mut self, key_binding: impl Into<Option<KeyBinding>>) -> Self {
- self.key_binding = key_binding.into();
- self
- }
-
- /// Sets the alpha property of the color of label.
- pub fn alpha(mut self, alpha: f32) -> Self {
- self.alpha = Some(alpha);
- self
- }
-}
-
-impl Selectable for Button {
- /// Sets the selected state of the button.
- ///
- /// This method allows the selection state of the button to be specified.
- /// It modifies the button's appearance to reflect its selected state.
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::prelude::*;
- ///
- /// Button::new("button_id", "Click me!")
- /// .selected(true)
- /// .on_click(|event, cx| {
- /// // Handle click event
- /// });
- /// ```
- ///
- /// Use [`selected_style`](Button::selected_style) to change the style of the button when it is selected.
- fn selected(mut self, selected: bool) -> Self {
- self.base = self.base.selected(selected);
- self
- }
-}
-
-impl SelectableButton for Button {
- /// Sets the style for the button when selected.
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::prelude::*;
- /// use ui::TintColor;
- ///
- /// Button::new("button_id", "Click me!")
- /// .selected(true)
- /// .selected_style(ButtonStyle::Tinted(TintColor::Accent))
- /// .on_click(|event, cx| {
- /// // Handle click event
- /// });
- /// ```
- /// This results in a button with a blue tinted background when selected.
- fn selected_style(mut self, style: ButtonStyle) -> Self {
- self.base = self.base.selected_style(style);
- self
- }
-}
-
-impl Disableable for Button {
- /// Disables the button.
- ///
- /// This method allows the button to be disabled. When a button is disabled,
- /// it doesn't react to user interactions and its appearance is updated to reflect this.
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::prelude::*;
- ///
- /// Button::new("button_id", "Click me!")
- /// .disabled(true)
- /// .on_click(|event, cx| {
- /// // Handle click event
- /// });
- /// ```
- ///
- /// This results in a button that is disabled and does not respond to click events.
- fn disabled(mut self, disabled: bool) -> Self {
- self.base = self.base.disabled(disabled);
- self
- }
-}
-
-impl Clickable for Button {
- /// Sets the click event handler for the button.
- fn on_click(
- mut self,
- handler: impl Fn(&gpui::ClickEvent, &mut WindowContext) + 'static,
- ) -> Self {
- self.base = self.base.on_click(handler);
- self
- }
-
- fn cursor_style(mut self, cursor_style: gpui::CursorStyle) -> Self {
- self.base = self.base.cursor_style(cursor_style);
- self
- }
-}
-
-impl FixedWidth for Button {
- /// Sets a fixed width for the button.
- ///
- /// This function allows a button to have a fixed width instead of automatically growing or shrinking.
- /// Sets a fixed width for the button.
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::prelude::*;
- ///
- /// Button::new("button_id", "Click me!")
- /// .width(px(100.).into())
- /// .on_click(|event, cx| {
- /// // Handle click event
- /// });
- /// ```
- ///
- /// This sets the button's width to be exactly 100 pixels.
- fn width(mut self, width: DefiniteLength) -> Self {
- self.base = self.base.width(width);
- self
- }
-
- /// Sets the button to occupy the full width of its container.
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::prelude::*;
- ///
- /// Button::new("button_id", "Click me!")
- /// .full_width()
- /// .on_click(|event, cx| {
- /// // Handle click event
- /// });
- /// ```
- ///
- /// This stretches the button to the full width of its container.
- fn full_width(mut self) -> Self {
- self.base = self.base.full_width();
- self
- }
-}
-
-impl ButtonCommon for Button {
- /// Sets the button's id.
- fn id(&self) -> &ElementId {
- self.base.id()
- }
-
- /// Sets the visual style of the button using a [`ButtonStyle`].
- fn style(mut self, style: ButtonStyle) -> Self {
- self.base = self.base.style(style);
- self
- }
-
- /// Sets the button's size using a [`ButtonSize`].
- fn size(mut self, size: ButtonSize) -> Self {
- self.base = self.base.size(size);
- self
- }
-
- /// Sets a tooltip for the button.
- ///
- /// This method allows a tooltip to be set for the button. The tooltip is a function that
- /// takes a mutable reference to a [`WindowContext`] and returns an [`AnyView`]. The tooltip
- /// is displayed when the user hovers over the button.
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::prelude::*;
- /// use ui::Tooltip;
- ///
- /// Button::new("button_id", "Click me!")
- /// .tooltip(move |cx| {
- /// Tooltip::text("This is a tooltip", cx)
- /// })
- /// .on_click(|event, cx| {
- /// // Handle click event
- /// });
- /// ```
- ///
- /// This will create a button with a tooltip that displays "This is a tooltip" when hovered over.
- fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self {
- self.base = self.base.tooltip(tooltip);
- self
- }
-
- fn layer(mut self, elevation: ElevationIndex) -> Self {
- self.base = self.base.layer(elevation);
- self
- }
-}
-
-impl RenderOnce for Button {
- #[allow(refining_impl_trait)]
- fn render(self, cx: &mut WindowContext) -> ButtonLike {
- let is_disabled = self.base.disabled;
- let is_selected = self.base.selected;
-
- let label = self
- .selected_label
- .filter(|_| is_selected)
- .unwrap_or(self.label);
-
- let label_color = if is_disabled {
- Color::Disabled
- } else if is_selected {
- self.selected_label_color.unwrap_or(Color::Selected)
- } else {
- self.label_color.unwrap_or_default()
- };
-
- self.base.child(
- h_flex()
- .gap(Spacing::Small.rems(cx))
- .when(self.icon_position == Some(IconPosition::Start), |this| {
- this.children(self.icon.map(|icon| {
- ButtonIcon::new(icon)
- .disabled(is_disabled)
- .selected(is_selected)
- .selected_icon(self.selected_icon)
- .selected_icon_color(self.selected_icon_color)
- .size(self.icon_size)
- .color(self.icon_color)
- }))
- })
- .child(
- h_flex()
- .gap(Spacing::Medium.rems(cx))
- .justify_between()
- .child(
- Label::new(label)
- .color(label_color)
- .size(self.label_size.unwrap_or_default())
- .when_some(self.alpha, |this, alpha| this.alpha(alpha))
- .line_height_style(LineHeightStyle::UiLabel),
- )
- .children(self.key_binding),
- )
- .when(self.icon_position != Some(IconPosition::Start), |this| {
- this.children(self.icon.map(|icon| {
- ButtonIcon::new(icon)
- .disabled(is_disabled)
- .selected(is_selected)
- .selected_icon(self.selected_icon)
- .selected_icon_color(self.selected_icon_color)
- .size(self.icon_size)
- .color(self.icon_color)
- }))
- }),
- )
- }
-}
@@ -0,0 +1,438 @@
+use gpui::{AnyView, DefiniteLength};
+
+use crate::{prelude::*, ElevationIndex, IconPosition, KeyBinding, Spacing};
+use crate::{
+ ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, IconName, IconSize, Label, LineHeightStyle,
+};
+
+use super::button_icon::ButtonIcon;
+
+/// An element that creates a button with a label and an optional icon.
+///
+/// Common buttons:
+/// - Label, Icon + Label: [`Button`] (this component)
+/// - Icon only: [`IconButton`]
+/// - Custom: [`ButtonLike`]
+///
+/// To create a more complex button than what the [`Button`] or [`IconButton`] components provide, use
+/// [`ButtonLike`] directly.
+///
+/// # Examples
+///
+/// **A button with a label**, is typically used in scenarios such as a form, where the button's label
+/// indicates what action will be performed when the button is clicked.
+///
+/// ```
+/// use ui::prelude::*;
+///
+/// Button::new("button_id", "Click me!")
+/// .on_click(|event, cx| {
+/// // Handle click event
+/// });
+/// ```
+///
+/// **A toggleable button**, is typically used in scenarios such as a toolbar,
+/// where the button's state indicates whether a feature is enabled or not, or
+/// a trigger for a popover menu, where clicking the button toggles the visibility of the menu.
+///
+/// ```
+/// use ui::prelude::*;
+///
+/// Button::new("button_id", "Click me!")
+/// .icon(IconName::Check)
+/// .selected(true)
+/// .on_click(|event, cx| {
+/// // Handle click event
+/// });
+/// ```
+///
+/// To change the style of the button when it is selected use the [`selected_style`][Button::selected_style] method.
+///
+/// ```
+/// use ui::prelude::*;
+/// use ui::TintColor;
+///
+/// Button::new("button_id", "Click me!")
+/// .selected(true)
+/// .selected_style(ButtonStyle::Tinted(TintColor::Accent))
+/// .on_click(|event, cx| {
+/// // Handle click event
+/// });
+/// ```
+/// This will create a button with a blue tinted background when selected.
+///
+/// **A full-width button**, is typically used in scenarios such as the bottom of a modal or form, where it occupies the entire width of its container.
+/// The button's content, including text and icons, is centered by default.
+///
+/// ```
+/// use ui::prelude::*;
+///
+/// let button = Button::new("button_id", "Click me!")
+/// .full_width()
+/// .on_click(|event, cx| {
+/// // Handle click event
+/// });
+/// ```
+///
+#[derive(IntoElement)]
+pub struct Button {
+ base: ButtonLike,
+ label: SharedString,
+ label_color: Option<Color>,
+ label_size: Option<LabelSize>,
+ selected_label: Option<SharedString>,
+ selected_label_color: Option<Color>,
+ icon: Option<IconName>,
+ icon_position: Option<IconPosition>,
+ icon_size: Option<IconSize>,
+ icon_color: Option<Color>,
+ selected_icon: Option<IconName>,
+ selected_icon_color: Option<Color>,
+ key_binding: Option<KeyBinding>,
+ alpha: Option<f32>,
+}
+
+impl Button {
+ /// Creates a new [`Button`] with a specified identifier and label.
+ ///
+ /// This is the primary constructor for a [`Button`] component. It initializes
+ /// the button with the provided identifier and label text, setting all other
+ /// properties to their default values, which can be customized using the
+ /// builder pattern methods provided by this struct.
+ pub fn new(id: impl Into<ElementId>, label: impl Into<SharedString>) -> Self {
+ Self {
+ base: ButtonLike::new(id),
+ label: label.into(),
+ label_color: None,
+ label_size: None,
+ selected_label: None,
+ selected_label_color: None,
+ icon: None,
+ icon_position: None,
+ icon_size: None,
+ icon_color: None,
+ selected_icon: None,
+ selected_icon_color: None,
+ key_binding: None,
+ alpha: None,
+ }
+ }
+
+ /// Sets the color of the button's label.
+ pub fn color(mut self, label_color: impl Into<Option<Color>>) -> Self {
+ self.label_color = label_color.into();
+ self
+ }
+
+ /// Defines the size of the button's label.
+ pub fn label_size(mut self, label_size: impl Into<Option<LabelSize>>) -> Self {
+ self.label_size = label_size.into();
+ self
+ }
+
+ /// Sets the label used when the button is in a selected state.
+ pub fn selected_label<L: Into<SharedString>>(mut self, label: impl Into<Option<L>>) -> Self {
+ self.selected_label = label.into().map(Into::into);
+ self
+ }
+
+ /// Sets the label color used when the button is in a selected state.
+ pub fn selected_label_color(mut self, color: impl Into<Option<Color>>) -> Self {
+ self.selected_label_color = color.into();
+ self
+ }
+
+ /// Assigns an icon to the button.
+ pub fn icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
+ self.icon = icon.into();
+ self
+ }
+
+ /// Sets the position of the icon relative to the label.
+ pub fn icon_position(mut self, icon_position: impl Into<Option<IconPosition>>) -> Self {
+ self.icon_position = icon_position.into();
+ self
+ }
+
+ /// Specifies the size of the button's icon.
+ pub fn icon_size(mut self, icon_size: impl Into<Option<IconSize>>) -> Self {
+ self.icon_size = icon_size.into();
+ self
+ }
+
+ /// Sets the color of the button's icon.
+ pub fn icon_color(mut self, icon_color: impl Into<Option<Color>>) -> Self {
+ self.icon_color = icon_color.into();
+ self
+ }
+
+ /// Chooses an icon to display when the button is in a selected state.
+ pub fn selected_icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
+ self.selected_icon = icon.into();
+ self
+ }
+
+ /// Sets the icon color used when the button is in a selected state.
+ pub fn selected_icon_color(mut self, color: impl Into<Option<Color>>) -> Self {
+ self.selected_icon_color = color.into();
+ self
+ }
+
+ /// Binds a key combination to the button for keyboard shortcuts.
+ pub fn key_binding(mut self, key_binding: impl Into<Option<KeyBinding>>) -> Self {
+ self.key_binding = key_binding.into();
+ self
+ }
+
+ /// Sets the alpha property of the color of label.
+ pub fn alpha(mut self, alpha: f32) -> Self {
+ self.alpha = Some(alpha);
+ self
+ }
+}
+
+impl Selectable for Button {
+ /// Sets the selected state of the button.
+ ///
+ /// This method allows the selection state of the button to be specified.
+ /// It modifies the button's appearance to reflect its selected state.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::prelude::*;
+ ///
+ /// Button::new("button_id", "Click me!")
+ /// .selected(true)
+ /// .on_click(|event, cx| {
+ /// // Handle click event
+ /// });
+ /// ```
+ ///
+ /// Use [`selected_style`](Button::selected_style) to change the style of the button when it is selected.
+ fn selected(mut self, selected: bool) -> Self {
+ self.base = self.base.selected(selected);
+ self
+ }
+}
+
+impl SelectableButton for Button {
+ /// Sets the style for the button when selected.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::prelude::*;
+ /// use ui::TintColor;
+ ///
+ /// Button::new("button_id", "Click me!")
+ /// .selected(true)
+ /// .selected_style(ButtonStyle::Tinted(TintColor::Accent))
+ /// .on_click(|event, cx| {
+ /// // Handle click event
+ /// });
+ /// ```
+ /// This results in a button with a blue tinted background when selected.
+ fn selected_style(mut self, style: ButtonStyle) -> Self {
+ self.base = self.base.selected_style(style);
+ self
+ }
+}
+
+impl Disableable for Button {
+ /// Disables the button.
+ ///
+ /// This method allows the button to be disabled. When a button is disabled,
+ /// it doesn't react to user interactions and its appearance is updated to reflect this.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::prelude::*;
+ ///
+ /// Button::new("button_id", "Click me!")
+ /// .disabled(true)
+ /// .on_click(|event, cx| {
+ /// // Handle click event
+ /// });
+ /// ```
+ ///
+ /// This results in a button that is disabled and does not respond to click events.
+ fn disabled(mut self, disabled: bool) -> Self {
+ self.base = self.base.disabled(disabled);
+ self
+ }
+}
+
+impl Clickable for Button {
+ /// Sets the click event handler for the button.
+ fn on_click(
+ mut self,
+ handler: impl Fn(&gpui::ClickEvent, &mut WindowContext) + 'static,
+ ) -> Self {
+ self.base = self.base.on_click(handler);
+ self
+ }
+
+ fn cursor_style(mut self, cursor_style: gpui::CursorStyle) -> Self {
+ self.base = self.base.cursor_style(cursor_style);
+ self
+ }
+}
+
+impl FixedWidth for Button {
+ /// Sets a fixed width for the button.
+ ///
+ /// This function allows a button to have a fixed width instead of automatically growing or shrinking.
+ /// Sets a fixed width for the button.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::prelude::*;
+ ///
+ /// Button::new("button_id", "Click me!")
+ /// .width(px(100.).into())
+ /// .on_click(|event, cx| {
+ /// // Handle click event
+ /// });
+ /// ```
+ ///
+ /// This sets the button's width to be exactly 100 pixels.
+ fn width(mut self, width: DefiniteLength) -> Self {
+ self.base = self.base.width(width);
+ self
+ }
+
+ /// Sets the button to occupy the full width of its container.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::prelude::*;
+ ///
+ /// Button::new("button_id", "Click me!")
+ /// .full_width()
+ /// .on_click(|event, cx| {
+ /// // Handle click event
+ /// });
+ /// ```
+ ///
+ /// This stretches the button to the full width of its container.
+ fn full_width(mut self) -> Self {
+ self.base = self.base.full_width();
+ self
+ }
+}
+
+impl ButtonCommon for Button {
+ /// Sets the button's id.
+ fn id(&self) -> &ElementId {
+ self.base.id()
+ }
+
+ /// Sets the visual style of the button using a [`ButtonStyle`].
+ fn style(mut self, style: ButtonStyle) -> Self {
+ self.base = self.base.style(style);
+ self
+ }
+
+ /// Sets the button's size using a [`ButtonSize`].
+ fn size(mut self, size: ButtonSize) -> Self {
+ self.base = self.base.size(size);
+ self
+ }
+
+ /// Sets a tooltip for the button.
+ ///
+ /// This method allows a tooltip to be set for the button. The tooltip is a function that
+ /// takes a mutable reference to a [`WindowContext`] and returns an [`AnyView`]. The tooltip
+ /// is displayed when the user hovers over the button.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::prelude::*;
+ /// use ui::Tooltip;
+ ///
+ /// Button::new("button_id", "Click me!")
+ /// .tooltip(move |cx| {
+ /// Tooltip::text("This is a tooltip", cx)
+ /// })
+ /// .on_click(|event, cx| {
+ /// // Handle click event
+ /// });
+ /// ```
+ ///
+ /// This will create a button with a tooltip that displays "This is a tooltip" when hovered over.
+ fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self {
+ self.base = self.base.tooltip(tooltip);
+ self
+ }
+
+ fn layer(mut self, elevation: ElevationIndex) -> Self {
+ self.base = self.base.layer(elevation);
+ self
+ }
+}
+
+impl RenderOnce for Button {
+ #[allow(refining_impl_trait)]
+ fn render(self, cx: &mut WindowContext) -> ButtonLike {
+ let is_disabled = self.base.disabled;
+ let is_selected = self.base.selected;
+
+ let label = self
+ .selected_label
+ .filter(|_| is_selected)
+ .unwrap_or(self.label);
+
+ let label_color = if is_disabled {
+ Color::Disabled
+ } else if is_selected {
+ self.selected_label_color.unwrap_or(Color::Selected)
+ } else {
+ self.label_color.unwrap_or_default()
+ };
+
+ self.base.child(
+ h_flex()
+ .gap(Spacing::Small.rems(cx))
+ .when(self.icon_position == Some(IconPosition::Start), |this| {
+ this.children(self.icon.map(|icon| {
+ ButtonIcon::new(icon)
+ .disabled(is_disabled)
+ .selected(is_selected)
+ .selected_icon(self.selected_icon)
+ .selected_icon_color(self.selected_icon_color)
+ .size(self.icon_size)
+ .color(self.icon_color)
+ }))
+ })
+ .child(
+ h_flex()
+ .gap(Spacing::Medium.rems(cx))
+ .justify_between()
+ .child(
+ Label::new(label)
+ .color(label_color)
+ .size(self.label_size.unwrap_or_default())
+ .when_some(self.alpha, |this, alpha| this.alpha(alpha))
+ .line_height_style(LineHeightStyle::UiLabel),
+ )
+ .children(self.key_binding),
+ )
+ .when(self.icon_position != Some(IconPosition::Start), |this| {
+ this.children(self.icon.map(|icon| {
+ ButtonIcon::new(icon)
+ .disabled(is_disabled)
+ .selected(is_selected)
+ .selected_icon(self.selected_icon)
+ .selected_icon_color(self.selected_icon_color)
+ .size(self.icon_size)
+ .color(self.icon_color)
+ }))
+ }),
+ )
+ }
+}
@@ -1,190 +1,7 @@
mod highlighted_label;
+mod label;
mod label_like;
pub use highlighted_label::*;
+pub use label::*;
pub use label_like::*;
-
-use gpui::{StyleRefinement, WindowContext};
-
-use crate::prelude::*;
-
-/// A struct representing a label element in the UI.
-///
-/// The `Label` struct stores the label text and common properties for a label element.
-/// It provides methods for modifying these properties.
-///
-/// # Examples
-///
-/// ```
-/// use ui::prelude::*;
-///
-/// Label::new("Hello, World!");
-/// ```
-///
-/// **A colored label**, for example labeling a dangerous action:
-///
-/// ```
-/// use ui::prelude::*;
-///
-/// let my_label = Label::new("Delete").color(Color::Error);
-/// ```
-///
-/// **A label with a strikethrough**, for example labeling something that has been deleted:
-///
-/// ```
-/// use ui::prelude::*;
-///
-/// let my_label = Label::new("Deleted").strikethrough(true);
-/// ```
-#[derive(IntoElement)]
-pub struct Label {
- base: LabelLike,
- label: SharedString,
- single_line: bool,
-}
-
-impl Label {
- /// Creates a new [`Label`] with the given text.
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::prelude::*;
- ///
- /// let my_label = Label::new("Hello, World!");
- /// ```
- pub fn new(label: impl Into<SharedString>) -> Self {
- Self {
- base: LabelLike::new(),
- label: label.into(),
- single_line: false,
- }
- }
-
- /// Make the label display in a single line mode
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::prelude::*;
- ///
- /// let my_label = Label::new("Hello, World!").single_line();
- /// ```
- pub fn single_line(mut self) -> Self {
- self.single_line = true;
- self
- }
-}
-
-// Style methods.
-impl Label {
- fn style(&mut self) -> &mut StyleRefinement {
- self.base.base.style()
- }
-
- gpui::margin_style_methods!({
- visibility: pub
- });
-}
-
-impl LabelCommon for Label {
- /// Sets the size of the label using a [`LabelSize`].
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::prelude::*;
- ///
- /// let my_label = Label::new("Hello, World!").size(LabelSize::Small);
- /// ```
- fn size(mut self, size: LabelSize) -> Self {
- self.base = self.base.size(size);
- self
- }
-
- fn weight(mut self, weight: gpui::FontWeight) -> Self {
- self.base = self.base.weight(weight);
- self
- }
-
- /// Sets the line height style of the label using a [`LineHeightStyle`].
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::prelude::*;
- ///
- /// let my_label = Label::new("Hello, World!").line_height_style(LineHeightStyle::UiLabel);
- /// ```
- fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self {
- self.base = self.base.line_height_style(line_height_style);
- self
- }
-
- /// Sets the color of the label using a [`Color`].
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::prelude::*;
- ///
- /// let my_label = Label::new("Hello, World!").color(Color::Accent);
- /// ```
- fn color(mut self, color: Color) -> Self {
- self.base = self.base.color(color);
- self
- }
-
- /// Sets the strikethrough property of the label.
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::prelude::*;
- ///
- /// let my_label = Label::new("Hello, World!").strikethrough(true);
- /// ```
- fn strikethrough(mut self, strikethrough: bool) -> Self {
- self.base = self.base.strikethrough(strikethrough);
- self
- }
-
- /// Sets the italic property of the label.
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::prelude::*;
- ///
- /// let my_label = Label::new("Hello, World!").italic(true);
- /// ```
- fn italic(mut self, italic: bool) -> Self {
- self.base = self.base.italic(italic);
- self
- }
-
- /// Sets the alpha property of the color of label.
- ///
- /// # Examples
- ///
- /// ```
- /// use ui::prelude::*;
- ///
- /// let my_label = Label::new("Hello, World!").alpha(0.5);
- /// ```
- fn alpha(mut self, alpha: f32) -> Self {
- self.base = self.base.alpha(alpha);
- self
- }
-}
-
-impl RenderOnce for Label {
- fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
- let target_label = if self.single_line {
- SharedString::from(self.label.replace('\n', ""))
- } else {
- self.label
- };
- self.base.child(target_label)
- }
-}
@@ -0,0 +1,184 @@
+use gpui::{StyleRefinement, WindowContext};
+
+use crate::{prelude::*, LabelCommon, LabelLike, LabelSize, LineHeightStyle};
+
+/// A struct representing a label element in the UI.
+///
+/// The `Label` struct stores the label text and common properties for a label element.
+/// It provides methods for modifying these properties.
+///
+/// # Examples
+///
+/// ```
+/// use ui::prelude::*;
+///
+/// Label::new("Hello, World!");
+/// ```
+///
+/// **A colored label**, for example labeling a dangerous action:
+///
+/// ```
+/// use ui::prelude::*;
+///
+/// let my_label = Label::new("Delete").color(Color::Error);
+/// ```
+///
+/// **A label with a strikethrough**, for example labeling something that has been deleted:
+///
+/// ```
+/// use ui::prelude::*;
+///
+/// let my_label = Label::new("Deleted").strikethrough(true);
+/// ```
+#[derive(IntoElement)]
+pub struct Label {
+ base: LabelLike,
+ label: SharedString,
+ single_line: bool,
+}
+
+impl Label {
+ /// Creates a new [`Label`] with the given text.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::prelude::*;
+ ///
+ /// let my_label = Label::new("Hello, World!");
+ /// ```
+ pub fn new(label: impl Into<SharedString>) -> Self {
+ Self {
+ base: LabelLike::new(),
+ label: label.into(),
+ single_line: false,
+ }
+ }
+
+ /// Make the label display in a single line mode
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::prelude::*;
+ ///
+ /// let my_label = Label::new("Hello, World!").single_line();
+ /// ```
+ pub fn single_line(mut self) -> Self {
+ self.single_line = true;
+ self
+ }
+}
+
+// Style methods.
+impl Label {
+ fn style(&mut self) -> &mut StyleRefinement {
+ self.base.base.style()
+ }
+
+ gpui::margin_style_methods!({
+ visibility: pub
+ });
+}
+
+impl LabelCommon for Label {
+ /// Sets the size of the label using a [`LabelSize`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::prelude::*;
+ ///
+ /// let my_label = Label::new("Hello, World!").size(LabelSize::Small);
+ /// ```
+ fn size(mut self, size: LabelSize) -> Self {
+ self.base = self.base.size(size);
+ self
+ }
+
+ fn weight(mut self, weight: gpui::FontWeight) -> Self {
+ self.base = self.base.weight(weight);
+ self
+ }
+
+ /// Sets the line height style of the label using a [`LineHeightStyle`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::prelude::*;
+ ///
+ /// let my_label = Label::new("Hello, World!").line_height_style(LineHeightStyle::UiLabel);
+ /// ```
+ fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self {
+ self.base = self.base.line_height_style(line_height_style);
+ self
+ }
+
+ /// Sets the color of the label using a [`Color`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::prelude::*;
+ ///
+ /// let my_label = Label::new("Hello, World!").color(Color::Accent);
+ /// ```
+ fn color(mut self, color: Color) -> Self {
+ self.base = self.base.color(color);
+ self
+ }
+
+ /// Sets the strikethrough property of the label.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::prelude::*;
+ ///
+ /// let my_label = Label::new("Hello, World!").strikethrough(true);
+ /// ```
+ fn strikethrough(mut self, strikethrough: bool) -> Self {
+ self.base = self.base.strikethrough(strikethrough);
+ self
+ }
+
+ /// Sets the italic property of the label.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::prelude::*;
+ ///
+ /// let my_label = Label::new("Hello, World!").italic(true);
+ /// ```
+ fn italic(mut self, italic: bool) -> Self {
+ self.base = self.base.italic(italic);
+ self
+ }
+
+ /// Sets the alpha property of the color of label.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ui::prelude::*;
+ ///
+ /// let my_label = Label::new("Hello, World!").alpha(0.5);
+ /// ```
+ fn alpha(mut self, alpha: f32) -> Self {
+ self.base = self.base.alpha(alpha);
+ self
+ }
+}
+
+impl RenderOnce for Label {
+ fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
+ let target_label = if self.single_line {
+ SharedString::from(self.label.replace('\n', ""))
+ } else {
+ self.label
+ };
+ self.base.child(target_label)
+ }
+}
@@ -1,76 +1,11 @@
+mod list;
mod list_header;
mod list_item;
mod list_separator;
mod list_sub_header;
+pub use list::*;
pub use list_header::*;
pub use list_item::*;
pub use list_separator::*;
pub use list_sub_header::*;
-
-use gpui::AnyElement;
-use smallvec::SmallVec;
-
-use crate::{prelude::*, v_flex, Label};
-
-pub use ListHeader;
-
-#[derive(IntoElement)]
-pub struct List {
- /// Message to display when the list is empty
- /// Defaults to "No items"
- empty_message: SharedString,
- header: Option<ListHeader>,
- toggle: Option<bool>,
- children: SmallVec<[AnyElement; 2]>,
-}
-
-impl Default for List {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl List {
- pub fn new() -> Self {
- Self {
- empty_message: "No items".into(),
- header: None,
- toggle: None,
- children: SmallVec::new(),
- }
- }
-
- pub fn empty_message(mut self, empty_message: impl Into<SharedString>) -> Self {
- self.empty_message = empty_message.into();
- self
- }
-
- pub fn header(mut self, header: impl Into<Option<ListHeader>>) -> Self {
- self.header = header.into();
- self
- }
-
- pub fn toggle(mut self, toggle: impl Into<Option<bool>>) -> Self {
- self.toggle = toggle.into();
- self
- }
-}
-
-impl ParentElement for List {
- fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
- self.children.extend(elements)
- }
-}
-
-impl RenderOnce for List {
- fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
- v_flex().w_full().py_1().children(self.header).map(|this| {
- match (self.children.is_empty(), self.toggle) {
- (false, _) => this.children(self.children),
- (true, Some(false)) => this,
- (true, _) => this.child(Label::new(self.empty_message.clone()).color(Color::Muted)),
- }
- })
- }
-}
@@ -13,12 +13,6 @@ pub struct List {
children: SmallVec<[AnyElement; 2]>,
}
-impl Default for List {
- fn default() -> Self {
- Self::new()
- }
-}
-
impl List {
pub fn new() -> Self {
Self {