ui: Add support for rendering Icons from external files (#23195)

This PR adds support for rendering `Icon`s from external files.
Previously this could only be used with icons embedded in the binary.

To achieve this we currently need to use the `img` element until the
`svg` element supports:

1. Loading SVGs from external files
2. Rendering polychrome SVGs

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2025-01-15 16:50:16 -05:00 committed by GitHub
parent e265e69429
commit 904b367882
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -3,8 +3,11 @@
mod decorated_icon;
mod icon_decoration;
use std::path::{Path, PathBuf};
use std::sync::Arc;
pub use decorated_icon::*;
use gpui::{svg, AnimationElement, Hsla, IntoElement, Rems, Transformation};
use gpui::{img, svg, AnimationElement, Hsla, IntoElement, Rems, Transformation};
pub use icon_decoration::*;
use serde::{Deserialize, Serialize};
use strum::{EnumIter, EnumString, IntoStaticStr};
@ -324,9 +327,34 @@ impl From<IconName> for Icon {
}
}
/// The source of an icon.
enum IconSource {
/// An SVG embedded in the Zed binary.
Svg(SharedString),
/// An image file located at the specified path.
///
/// Currently our SVG renderer is missing support for the following features:
/// 1. Loading SVGs from external files.
/// 2. Rendering polychrome SVGs.
///
/// In order to support icon themes, we render the icons as images instead.
Image(Arc<Path>),
}
impl IconSource {
fn from_path(path: impl Into<SharedString>) -> Self {
let path = path.into();
if path.starts_with("icons/file_icons") {
Self::Svg(path)
} else {
Self::Image(Arc::from(PathBuf::from(path.as_ref())))
}
}
}
#[derive(IntoElement)]
pub struct Icon {
path: SharedString,
source: IconSource,
color: Color,
size: Rems,
transformation: Transformation,
@ -335,7 +363,7 @@ pub struct Icon {
impl Icon {
pub fn new(icon: IconName) -> Self {
Self {
path: icon.path().into(),
source: IconSource::Svg(icon.path().into()),
color: Color::default(),
size: IconSize::default().rems(),
transformation: Transformation::default(),
@ -344,7 +372,7 @@ impl Icon {
pub fn from_path(path: impl Into<SharedString>) -> Self {
Self {
path: path.into(),
source: IconSource::from_path(path),
color: Color::default(),
size: IconSize::default().rems(),
transformation: Transformation::default(),
@ -377,12 +405,20 @@ impl Icon {
impl RenderOnce for Icon {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
svg()
match self.source {
IconSource::Svg(path) => svg()
.with_transformation(self.transformation)
.size(self.size)
.flex_none()
.path(self.path)
.path(path)
.text_color(self.color.color(cx))
.into_any_element(),
IconSource::Image(path) => img(path)
.size(self.size)
.flex_none()
.text_color(self.color.color(cx))
.into_any_element(),
}
}
}