chore: Fix several style lints (#17488)

It's not comprehensive enough to start linting on `style` group, but
hey, it's a start.

Release Notes:

- N/A
This commit is contained in:
Piotr Osiewicz 2024-09-06 11:58:39 +02:00 committed by GitHub
parent 93249fc82b
commit e6c1c51b37
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
361 changed files with 3530 additions and 3587 deletions

View file

@ -1,7 +1,133 @@
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)))
}
}

View file

@ -1,127 +0,0 @@
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)))
}
}

View file

@ -1,10 +1,445 @@
mod button;
pub(self) mod button_icon;
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)
}))
}),
)
}
}

View file

@ -1,438 +0,0 @@
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)
}))
}),
)
}
}

View file

@ -284,7 +284,7 @@ impl ButtonStyle {
elevation: Option<Elevation>,
cx: &mut WindowContext,
) -> ButtonLikeStyles {
let filled_background = element_bg_from_elevation(elevation, cx).fade_out(0.82);
element_bg_from_elevation(elevation, cx).fade_out(0.82);
match self {
ButtonStyle::Filled => ButtonLikeStyles {

View file

@ -1,7 +1,8 @@
use gpui::{AnyView, DefiniteLength};
use super::button_like::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle};
use crate::{prelude::*, ElevationIndex, SelectableButton};
use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, IconName, IconSize};
use crate::{IconName, IconSize};
use super::button_icon::ButtonIcon;

View file

@ -1,5 +1,116 @@
mod checkbox;
mod checkbox_with_label;
pub use checkbox::*;
pub use checkbox_with_label::*;
use gpui::{div, prelude::*, ElementId, IntoElement, Styled, WindowContext};
use crate::prelude::*;
use crate::{Color, Icon, IconName, Selection};
/// # Checkbox
///
/// Checkboxes are used for multiple choices, not for mutually exclusive choices.
/// Each checkbox works independently from other checkboxes in the list,
/// therefore checking an additional box does not affect any other selections.
#[derive(IntoElement)]
pub struct Checkbox {
id: ElementId,
checked: Selection,
disabled: bool,
on_click: Option<Box<dyn Fn(&Selection, &mut WindowContext) + 'static>>,
}
impl Checkbox {
pub fn new(id: impl Into<ElementId>, checked: Selection) -> Self {
Self {
id: id.into(),
checked,
disabled: false,
on_click: None,
}
}
pub fn disabled(mut self, disabled: bool) -> Self {
self.disabled = disabled;
self
}
pub fn on_click(mut self, handler: impl Fn(&Selection, &mut WindowContext) + 'static) -> Self {
self.on_click = Some(Box::new(handler));
self
}
}
impl RenderOnce for Checkbox {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
let group_id = format!("checkbox_group_{:?}", self.id);
let icon = match self.checked {
Selection::Selected => Some(Icon::new(IconName::Check).size(IconSize::Small).color(
if self.disabled {
Color::Disabled
} else {
Color::Selected
},
)),
Selection::Indeterminate => Some(
Icon::new(IconName::Dash)
.size(IconSize::Small)
.color(if self.disabled {
Color::Disabled
} else {
Color::Selected
}),
),
Selection::Unselected => None,
};
let selected =
self.checked == Selection::Selected || self.checked == Selection::Indeterminate;
let (bg_color, border_color) = match (self.disabled, selected) {
(true, _) => (
cx.theme().colors().ghost_element_disabled,
cx.theme().colors().border_disabled,
),
(false, true) => (
cx.theme().colors().element_selected,
cx.theme().colors().border,
),
(false, false) => (
cx.theme().colors().element_background,
cx.theme().colors().border,
),
};
h_flex()
.id(self.id)
.justify_center()
.items_center()
.size(crate::styles::custom_spacing(cx, 20.))
.group(group_id.clone())
.child(
div()
.flex()
.flex_none()
.justify_center()
.items_center()
.m(Spacing::Small.px(cx))
.size(crate::styles::custom_spacing(cx, 16.))
.rounded_sm()
.bg(bg_color)
.border_1()
.border_color(border_color)
.when(!self.disabled, |this| {
this.group_hover(group_id.clone(), |el| {
el.bg(cx.theme().colors().element_hover)
})
})
.children(icon),
)
.when_some(
self.on_click.filter(|_| !self.disabled),
|this, on_click| this.on_click(move |_, cx| on_click(&self.checked.inverse(), cx)),
)
}
}

View file

@ -212,16 +212,16 @@ impl ContextMenu {
pub fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext<Self>) {
let context = self.action_context.as_ref();
match self.selected_index.and_then(|ix| self.items.get(ix)) {
Some(
ContextMenuItem::Entry {
handler,
disabled: false,
..
}
| ContextMenuItem::CustomEntry { handler, .. },
) => (handler)(context, cx),
_ => {}
if let Some(
ContextMenuItem::Entry {
handler,
disabled: false,
..
}
| ContextMenuItem::CustomEntry { handler, .. },
) = self.selected_index.and_then(|ix| self.items.get(ix))
{
(handler)(context, cx)
}
cx.emit(DismissEvent);

View file

@ -1,7 +1,190 @@
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)
}
}

View file

@ -62,7 +62,7 @@ impl LabelCommon for HighlightedLabel {
pub fn highlight_ranges(
text: &str,
indices: &Vec<usize>,
indices: &[usize],
style: HighlightStyle,
) -> Vec<(Range<usize>, HighlightStyle)> {
let mut highlight_indices = indices.iter().copied().peekable();

View file

@ -1,184 +0,0 @@
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)
}
}

View file

@ -59,6 +59,12 @@ pub struct LabelLike {
alpha: Option<f32>,
}
impl Default for LabelLike {
fn default() -> Self {
Self::new()
}
}
impl LabelLike {
pub fn new() -> Self {
Self {

View file

@ -1,11 +1,76 @@
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)),
}
})
}
}

View file

@ -13,6 +13,12 @@ pub struct List {
children: SmallVec<[AnyElement; 2]>,
}
impl Default for List {
fn default() -> Self {
Self::new()
}
}
impl List {
pub fn new() -> Self {
Self {

View file

@ -97,6 +97,12 @@ pub struct ModalHeader {
show_back_button: bool,
}
impl Default for ModalHeader {
fn default() -> Self {
Self::new()
}
}
impl ModalHeader {
pub fn new() -> Self {
Self {
@ -182,6 +188,12 @@ pub struct ModalRow {
children: SmallVec<[AnyElement; 2]>,
}
impl Default for ModalRow {
fn default() -> Self {
Self::new()
}
}
impl ModalRow {
pub fn new() -> Self {
Self {
@ -208,6 +220,12 @@ pub struct ModalFooter {
end_slot: Option<AnyElement>,
}
impl Default for ModalFooter {
fn default() -> Self {
Self::new()
}
}
impl ModalFooter {
pub fn new() -> Self {
Self {
@ -247,6 +265,12 @@ pub struct Section {
children: SmallVec<[AnyElement; 2]>,
}
impl Default for Section {
fn default() -> Self {
Self::new()
}
}
impl Section {
pub fn new() -> Self {
Self {
@ -381,15 +405,15 @@ impl RenderOnce for SectionHeader {
}
}
impl Into<SectionHeader> for SharedString {
fn into(self) -> SectionHeader {
SectionHeader::new(self)
impl From<SharedString> for SectionHeader {
fn from(val: SharedString) -> Self {
SectionHeader::new(val)
}
}
impl Into<SectionHeader> for &'static str {
fn into(self) -> SectionHeader {
let label: SharedString = self.into();
impl From<&'static str> for SectionHeader {
fn from(val: &'static str) -> Self {
let label: SharedString = val.into();
SectionHeader::new(label)
}
}

View file

@ -56,6 +56,12 @@ impl RenderOnce for Popover {
}
}
impl Default for Popover {
fn default() -> Self {
Self::new()
}
}
impl Popover {
pub fn new() -> Self {
Self {

View file

@ -156,7 +156,7 @@ impl<M: ManagedView> PopoverMenu<M> {
}
fn resolved_attach(&self) -> AnchorCorner {
self.attach.unwrap_or_else(|| match self.anchor {
self.attach.unwrap_or(match self.anchor {
AnchorCorner::TopLeft => AnchorCorner::BottomLeft,
AnchorCorner::TopRight => AnchorCorner::BottomRight,
AnchorCorner::BottomLeft => AnchorCorner::TopLeft,
@ -322,7 +322,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
menu.prepaint(cx);
}
let hitbox_id = request_layout.child_layout_id.map(|layout_id| {
request_layout.child_layout_id.map(|layout_id| {
let bounds = cx.layout_bounds(layout_id);
cx.with_element_state(global_id.unwrap(), |element_state, _cx| {
let mut element_state: PopoverMenuElementState<M> = element_state.unwrap();
@ -331,9 +331,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
});
cx.insert_hitbox(bounds, false).id
});
hitbox_id
})
}
fn paint(

View file

@ -8,6 +8,12 @@ pub struct SettingsContainer {
children: SmallVec<[AnyElement; 2]>,
}
impl Default for SettingsContainer {
fn default() -> Self {
Self::new()
}
}
impl SettingsContainer {
pub fn new() -> Self {
Self {

View file

@ -23,7 +23,7 @@ pub fn text_for_action_in(
pub fn text_for_key_binding(key_binding: KeyBinding, platform_style: PlatformStyle) -> String {
key_binding
.keystrokes()
.into_iter()
.iter()
.map(|keystroke| text_for_keystroke(keystroke, platform_style))
.collect::<Vec<_>>()
.join(" ")

View file

@ -18,9 +18,8 @@ pub fn window_appearance(cx: &WindowContext) -> WindowBackgroundAppearance {
/// Helps determine if you need to take extra steps to prevent
/// transparent backgrounds.
pub fn window_is_transparent(cx: &WindowContext) -> bool {
match window_appearance(cx) {
WindowBackgroundAppearance::Transparent => true,
WindowBackgroundAppearance::Blurred => true,
_ => false,
}
matches!(
window_appearance(cx),
WindowBackgroundAppearance::Transparent | WindowBackgroundAppearance::Blurred
)
}

View file

@ -9,9 +9,9 @@ pub enum Elevation {
ElementIndex(ElementIndex),
}
impl Into<Elevation> for ElevationIndex {
fn into(self) -> Elevation {
Elevation::ElevationIndex(self)
impl From<ElevationIndex> for Elevation {
fn from(val: ElevationIndex) -> Self {
Elevation::ElevationIndex(val)
}
}

View file

@ -42,16 +42,6 @@ impl FormatDistance {
Self::new(date, DateTimeType::Local(Local::now()))
}
pub fn to_string(self) -> String {
format_distance(
self.date,
self.base_date.to_naive(),
self.include_seconds,
self.add_suffix,
self.hide_prefix,
)
}
pub fn include_seconds(mut self, include_seconds: bool) -> Self {
self.include_seconds = include_seconds;
self
@ -68,6 +58,21 @@ impl FormatDistance {
}
}
impl std::fmt::Display for FormatDistance {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
format_distance(
self.date,
self.base_date.to_naive(),
self.include_seconds,
self.add_suffix,
self.hide_prefix,
)
)
}
}
/// Calculates the distance in seconds between two [`NaiveDateTime`] objects.
/// It returns a signed integer denoting the difference. If `date` is earlier than `base_date`, the returned value will be negative.
///
@ -118,12 +123,7 @@ fn distance_string(
}
.to_string()
} else if distance < 40 && include_seconds {
if hide_prefix {
"half a minute"
} else {
"half a minute"
}
.to_string()
"half a minute".to_string()
} else if distance < 60 && include_seconds {
if hide_prefix {
"a minute"