use gpui_kit::{
App, IntoElement, Radians, RenderOnce, SharedString, StyleRefinement, Styled, Svg,
Transformation, Window, base::StyledExt as _, prelude::FluentBuilder as _, svg,
};
#[derive(Clone, Debug)]
pub enum IconSource {
Path(SharedString),
Bytes(&'static [u8]),
}
#[derive(Clone, IntoElement)]
pub struct Icon {
source: IconSource,
style: StyleRefinement,
rotation: Option<Radians>,
}
impl Icon {
pub fn new(path: impl Into<SharedString>) -> Self {
Self::from_source(IconSource::Path(path.into()))
}
pub fn from_bytes(bytes: &'static [u8]) -> Self {
Self::from_source(IconSource::Bytes(bytes))
}
fn from_source(source: IconSource) -> Self {
Self {
source,
style: StyleRefinement::default(),
rotation: None,
}
}
pub fn rotate(mut self, angle: impl Into<Radians>) -> Self {
self.rotation = Some(angle.into());
self
}
pub fn source(&self) -> &IconSource {
&self.source
}
}
impl From<&'static str> for Icon {
fn from(path: &'static str) -> Self {
Self::new(path)
}
}
impl From<SharedString> for Icon {
fn from(path: SharedString) -> Self {
Self::new(path)
}
}
impl From<&'static [u8]> for Icon {
fn from(bytes: &'static [u8]) -> Self {
Self::from_bytes(bytes)
}
}
impl<const N: usize> From<&'static [u8; N]> for Icon {
fn from(bytes: &'static [u8; N]) -> Self {
Self::from_bytes(bytes)
}
}
impl From<gpui_kit::assets::IconName> for Icon {
fn from(name: gpui_kit::assets::IconName) -> Self {
Self::new(name.path())
}
}
impl Styled for Icon {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.style
}
}
impl RenderOnce for Icon {
fn render(self, window: &mut Window, _: &mut App) -> impl IntoElement {
let text_style = window.text_style();
let element: Svg = match &self.source {
IconSource::Path(path) => svg().path(path.clone()),
IconSource::Bytes(bytes) => svg().data(bytes),
};
element
.flex_shrink_0()
.size_4()
.text_color(text_style.color)
.when_some(self.rotation, |this, angle| {
this.with_transformation(Transformation::rotate(angle))
})
.refine_style(&self.style)
}
}