@@ -72,6 +72,15 @@ pub struct AnimationElement<E> {
animator: Box<dyn Fn(E, f32) -> E + 'static>,
}
+impl<E> AnimationElement<E> {
+ /// Returns a new [`AnimationElement<E>`] after applying the given function
+ /// to the element being animated.
+ pub fn map_element(mut self, f: impl FnOnce(E) -> E) -> AnimationElement<E> {
+ self.element = self.element.map(f);
+ self
+ }
+}
+
impl<E: IntoElement + 'static> IntoElement for AnimationElement<E> {
type Element = AnimationElement<E>;
@@ -1,8 +1,46 @@
-use gpui::{svg, Hsla, IntoElement, Rems, Transformation};
+use gpui::{svg, AnimationElement, Hsla, IntoElement, Rems, Transformation};
use strum::EnumIter;
use crate::{prelude::*, Indicator};
+#[derive(IntoElement)]
+pub enum AnyIcon {
+ Icon(Icon),
+ AnimatedIcon(AnimationElement<Icon>),
+}
+
+impl AnyIcon {
+ /// Returns a new [`AnyIcon`] after applying the given mapping function
+ /// to the contained [`Icon`].
+ pub fn map(self, f: impl FnOnce(Icon) -> Icon) -> Self {
+ match self {
+ Self::Icon(icon) => Self::Icon(f(icon)),
+ Self::AnimatedIcon(animated_icon) => Self::AnimatedIcon(animated_icon.map_element(f)),
+ }
+ }
+}
+
+impl From<Icon> for AnyIcon {
+ fn from(value: Icon) -> Self {
+ Self::Icon(value)
+ }
+}
+
+impl From<AnimationElement<Icon>> for AnyIcon {
+ fn from(value: AnimationElement<Icon>) -> Self {
+ Self::AnimatedIcon(value)
+ }
+}
+
+impl RenderOnce for AnyIcon {
+ fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
+ match self {
+ Self::Icon(icon) => icon.into_any_element(),
+ Self::AnimatedIcon(animated_icon) => animated_icon.into_any_element(),
+ }
+ }
+}
+
#[derive(Default, PartialEq, Copy, Clone)]
pub enum IconSize {
Indicator,
@@ -236,7 +274,7 @@ impl IconName {
pub struct Icon {
path: SharedString,
color: Color,
- size: IconSize,
+ size: Rems,
transformation: Transformation,
}
@@ -245,7 +283,7 @@ impl Icon {
Self {
path: icon.path().into(),
color: Color::default(),
- size: IconSize::default(),
+ size: IconSize::default().rems(),
transformation: Transformation::default(),
}
}
@@ -254,7 +292,7 @@ impl Icon {
Self {
path: path.into(),
color: Color::default(),
- size: IconSize::default(),
+ size: IconSize::default().rems(),
transformation: Transformation::default(),
}
}
@@ -265,6 +303,14 @@ impl Icon {
}
pub fn size(mut self, size: IconSize) -> Self {
+ self.size = size.rems();
+ self
+ }
+
+ /// Sets a custom size for the icon, in [`Rems`].
+ ///
+ /// Not to be exposed outside of the `ui` crate.
+ pub(crate) fn custom_size(mut self, size: Rems) -> Self {
self.size = size;
self
}
@@ -279,7 +325,7 @@ impl RenderOnce for Icon {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
svg()
.with_transformation(self.transformation)
- .size(self.size.rems())
+ .size(self.size)
.flex_none()
.path(self.path)
.text_color(self.color.color(cx))
@@ -1,17 +1,17 @@
-use gpui::Position;
+use gpui::Transformation;
-use crate::prelude::*;
+use crate::{prelude::*, AnyIcon};
#[derive(Default)]
pub enum IndicatorStyle {
#[default]
Dot,
Bar,
+ Icon(AnyIcon),
}
#[derive(IntoElement)]
pub struct Indicator {
- position: Position,
style: IndicatorStyle,
pub color: Color,
}
@@ -19,7 +19,6 @@ pub struct Indicator {
impl Indicator {
pub fn dot() -> Self {
Self {
- position: Position::Relative,
style: IndicatorStyle::Dot,
color: Color::Default,
}
@@ -27,32 +26,71 @@ impl Indicator {
pub fn bar() -> Self {
Self {
- position: Position::Relative,
style: IndicatorStyle::Dot,
color: Color::Default,
}
}
+ pub fn icon(icon: impl Into<AnyIcon>) -> Self {
+ Self {
+ style: IndicatorStyle::Icon(icon.into()),
+ color: Color::Default,
+ }
+ }
+
pub fn color(mut self, color: Color) -> Self {
self.color = color;
self
}
+}
+
+impl RenderOnce for Indicator {
+ fn render(self, cx: &mut WindowContext) -> impl IntoElement {
+ let container = div().flex_none();
+
+ match self.style {
+ IndicatorStyle::Icon(icon) => container
+ .child(icon.map(|icon| icon.custom_size(rems_from_px(8.)).color(self.color))),
+ IndicatorStyle::Dot => container
+ .w_1p5()
+ .h_1p5()
+ .rounded_full()
+ .bg(self.color.color(cx)),
+ IndicatorStyle::Bar => container
+ .w_full()
+ .h_1p5()
+ .rounded_t_md()
+ .bg(self.color.color(cx)),
+ }
+ }
+}
+
+#[derive(IntoElement)]
+pub struct IndicatorIcon {
+ icon: Icon,
+ transformation: Option<Transformation>,
+}
- pub fn absolute(mut self) -> Self {
- self.position = Position::Absolute;
+impl IndicatorIcon {
+ pub fn new(icon: Icon) -> Self {
+ Self {
+ icon,
+ transformation: None,
+ }
+ }
+
+ pub fn transformation(mut self, transformation: Transformation) -> Self {
+ self.transformation = Some(transformation);
self
}
}
-impl RenderOnce for Indicator {
- fn render(self, cx: &mut WindowContext) -> impl IntoElement {
- div()
- .flex_none()
- .map(|this| match self.style {
- IndicatorStyle::Dot => this.w_1p5().h_1p5().rounded_full(),
- IndicatorStyle::Bar => this.w_full().h_1p5().rounded_t_md(),
+impl RenderOnce for IndicatorIcon {
+ fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
+ self.icon
+ .custom_size(rems_from_px(8.))
+ .when_some(self.transformation, |this, transformation| {
+ this.transform(transformation)
})
- .when(self.position == Position::Absolute, |this| this.absolute())
- .bg(self.color.color(cx))
}
}