gpui: Add `svg` example (#17315)

Marshall Bowers created

This PR adds an example for working with SVGs.

Release Notes:

- N/A

Change summary

crates/gpui/Cargo.toml              |  4 +
crates/gpui/examples/svg/dragon.svg | 62 +++++++++++++++++++++++
crates/gpui/examples/svg/svg.rs     | 82 +++++++++++++++++++++++++++++++
3 files changed, 148 insertions(+)

Detailed changes

crates/gpui/Cargo.toml 🔗

@@ -181,6 +181,10 @@ path = "examples/input.rs"
 name = "shadow"
 path = "examples/shadow.rs"
 
+[[example]]
+name = "svg"
+path = "examples/svg/svg.rs"
+
 [[example]]
 name = "text_wrapper"
 path = "examples/text_wrapper.rs"

crates/gpui/examples/svg/dragon.svg 🔗

@@ -0,0 +1,240 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<!-- Retrieved from https://commons.wikimedia.org/wiki/Category:SVG_files#/media/File:Dragon_clip_art.svg -->
+<!-- License: CC BY-SA 3.0 -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="273.55759"
+   height="297.81952"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.2 r9819"
+   sodipodi:docname="New document 1">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.78061715"
+     inkscape:cx="112.41895"
+     inkscape:cy="87.896202"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="1024"
+     inkscape:window-height="712"
+     inkscape:window-x="-4"
+     inkscape:window-y="-4"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(12.737105,20.750754)">
+    <path
+       style="fill:#ff0000;stroke:#000000;stroke-width:1.20000005;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:2"

crates/gpui/examples/svg/svg.rs 🔗

@@ -0,0 +1,82 @@
+use std::path::PathBuf;
+
+use gpui::*;
+use std::fs;
+
+struct Assets {
+    base: PathBuf,
+}
+
+impl AssetSource for Assets {
+    fn load(&self, path: &str) -> Result<Option<std::borrow::Cow<'static, [u8]>>> {
+        fs::read(self.base.join(path))
+            .map(|data| Some(std::borrow::Cow::Owned(data)))
+            .map_err(|err| err.into())
+    }
+
+    fn list(&self, path: &str) -> Result<Vec<SharedString>> {
+        fs::read_dir(self.base.join(path))
+            .map(|entries| {
+                entries
+                    .filter_map(|entry| {
+                        entry
+                            .ok()
+                            .and_then(|entry| entry.file_name().into_string().ok())
+                            .map(SharedString::from)
+                    })
+                    .collect()
+            })
+            .map_err(|err| err.into())
+    }
+}
+
+struct SvgExample;
+
+impl Render for SvgExample {
+    fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
+        div()
+            .flex()
+            .flex_row()
+            .size_full()
+            .justify_center()
+            .items_center()
+            .gap_8()
+            .bg(rgb(0xffffff))
+            .child(
+                svg()
+                    .path("svg/dragon.svg")
+                    .size_8()
+                    .text_color(rgb(0xff0000)),
+            )
+            .child(
+                svg()
+                    .path("svg/dragon.svg")
+                    .size_8()
+                    .text_color(rgb(0x00ff00)),
+            )
+            .child(
+                svg()
+                    .path("svg/dragon.svg")
+                    .size_8()
+                    .text_color(rgb(0x0000ff)),
+            )
+    }
+}
+
+fn main() {
+    App::new()
+        .with_assets(Assets {
+            base: PathBuf::from("crates/gpui/examples"),
+        })
+        .run(|cx: &mut AppContext| {
+            let bounds = Bounds::centered(None, size(px(300.0), px(300.0)), cx);
+            cx.open_window(
+                WindowOptions {
+                    window_bounds: Some(WindowBounds::Windowed(bounds)),
+                    ..Default::default()
+                },
+                |cx| cx.new_view(|_cx| SvgExample),
+            )
+            .unwrap();
+        });
+}