From 904b367882b2ecb1793b4b97278f35ececce7b8f Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 15 Jan 2025 16:50:16 -0500 Subject: [PATCH] ui: Add support for rendering `Icon`s 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 --- crates/ui/src/components/icon.rs | 56 ++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/crates/ui/src/components/icon.rs b/crates/ui/src/components/icon.rs index c7c05451f5..6325744925 100644 --- a/crates/ui/src/components/icon.rs +++ b/crates/ui/src/components/icon.rs @@ -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 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), +} + +impl IconSource { + fn from_path(path: impl Into) -> 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) -> 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() - .with_transformation(self.transformation) - .size(self.size) - .flex_none() - .path(self.path) - .text_color(self.color.color(cx)) + match self.source { + IconSource::Svg(path) => svg() + .with_transformation(self.transformation) + .size(self.size) + .flex_none() + .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(), + } } }