image.rs

  1#![allow(missing_docs)]
  2use gpui::{svg, App, IntoElement, Rems, RenderOnce, Size, Styled, Window};
  3use serde::{Deserialize, Serialize};
  4use strum::{EnumIter, EnumString, IntoStaticStr};
  5use ui_macros::{path_str, DerivePathStr};
  6
  7use crate::Color;
  8
  9#[derive(
 10    Debug,
 11    PartialEq,
 12    Eq,
 13    Copy,
 14    Clone,
 15    EnumIter,
 16    EnumString,
 17    IntoStaticStr,
 18    Serialize,
 19    Deserialize,
 20    DerivePathStr,
 21)]
 22#[strum(serialize_all = "snake_case")]
 23#[path_str(prefix = "images", suffix = ".svg")]
 24pub enum VectorName {
 25    ZedLogo,
 26    ZedXCopilot,
 27}
 28
 29/// A vector image, such as an SVG.
 30///
 31/// A [`Vector`] is different from an [`crate::Icon`] in that it is intended
 32/// to be displayed at a specific size, or series of sizes, rather
 33/// than conforming to the standard size of an icon.
 34#[derive(IntoElement)]
 35pub struct Vector {
 36    path: &'static str,
 37    color: Color,
 38    size: Size<Rems>,
 39}
 40
 41impl Vector {
 42    /// Creates a new [`Vector`] image with the given [`VectorName`] and size.
 43    pub fn new(vector: VectorName, width: Rems, height: Rems) -> Self {
 44        Self {
 45            path: vector.path(),
 46            color: Color::default(),
 47            size: Size { width, height },
 48        }
 49    }
 50
 51    /// Creates a new [`Vector`] image where the width and height are the same.
 52    pub fn square(vector: VectorName, size: Rems) -> Self {
 53        Self::new(vector, size, size)
 54    }
 55
 56    /// Sets the vector color.
 57    pub fn color(mut self, color: Color) -> Self {
 58        self.color = color;
 59        self
 60    }
 61
 62    /// Sets the vector size.
 63    pub fn size(mut self, size: impl Into<Size<Rems>>) -> Self {
 64        let size = size.into();
 65
 66        self.size = size;
 67        self
 68    }
 69}
 70
 71impl RenderOnce for Vector {
 72    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
 73        let width = self.size.width;
 74        let height = self.size.height;
 75
 76        svg()
 77            // By default, prevent the SVG from stretching
 78            // to fill its container.
 79            .flex_none()
 80            .w(width)
 81            .h(height)
 82            .path(self.path)
 83            .text_color(self.color.color(cx))
 84    }
 85}
 86
 87#[cfg(feature = "stories")]
 88pub mod story {
 89    use gpui::Render;
 90    use story::{Story, StoryItem, StorySection};
 91    use strum::IntoEnumIterator;
 92
 93    use crate::prelude::*;
 94
 95    use super::{Vector, VectorName};
 96
 97    pub struct VectorStory;
 98
 99    impl Render for VectorStory {
100        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
101            Story::container().child(StorySection::new().children(VectorName::iter().map(
102                |vector| StoryItem::new(format!("{:?}", vector), Vector::square(vector, rems(8.))),
103            )))
104        }
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111
112    #[test]
113    fn vector_path() {
114        assert_eq!(VectorName::ZedLogo.path(), "images/zed_logo.svg");
115    }
116}