From 19930e46db3615184616659912deeea04a3783bd Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Wed, 3 Jul 2024 19:09:59 +0800 Subject: [PATCH] Add SvgImg to render svg, and with a Chart example (#13) https://github.com/huacnlee/gpui-component/assets/5518/576da9f9-4bff-4faf-a17e-19860cf6f948 --- Cargo.lock | 516 ++++++++++++++++++++++----- assets/icons/search.svg | 5 +- crates/app/src/story_workspace.rs | 17 +- crates/story/Cargo.toml | 2 + crates/story/src/fixtures/google.svg | 8 + crates/story/src/fixtures/pie.json | 66 ++++ crates/story/src/image_story.rs | 48 +++ crates/story/src/lib.rs | 2 + crates/ui/Cargo.toml | 3 + crates/ui/src/lib.rs | 2 + crates/ui/src/svg_img.rs | 202 +++++++++++ 11 files changed, 771 insertions(+), 100 deletions(-) create mode 100644 crates/story/src/fixtures/google.svg create mode 100644 crates/story/src/fixtures/pie.json create mode 100644 crates/story/src/image_story.rs create mode 100644 crates/ui/src/svg_img.rs diff --git a/Cargo.lock b/Cargo.lock index 6a3fe630..4fedb92e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,12 +8,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "adler32" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" - [[package]] name = "aes" version = "0.8.4" @@ -48,12 +42,41 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "anyhow" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "arrayref" version = "0.3.7" @@ -397,6 +420,29 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "av1-grain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876c75a42f6364451a033496a14c44bffe41f5f4a8236f697391f11024e596d2" +dependencies = [ + "arrayvec", +] + [[package]] name = "base64" version = "0.22.1" @@ -441,6 +487,12 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + [[package]] name = "bitflags" version = "1.3.2" @@ -453,6 +505,12 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "bitstream-io" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "415f8399438eb5e4b2f73ed3152a3448b98149dda642a957ee704e1daa5cf1d8" + [[package]] name = "blade-graphics" version = "0.4.0" @@ -551,6 +609,12 @@ dependencies = [ "serde", ] +[[package]] +name = "built" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6a6c0b39c38fd754ac338b00a88066436389c0f029da5d37d1e01091d9b7c17" + [[package]] name = "bumpalo" version = "3.16.0" @@ -583,6 +647,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.6.0" @@ -679,6 +749,11 @@ name = "cc" version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +dependencies = [ + "jobserver", + "libc", + "once_cell", +] [[package]] name = "cesu8" @@ -717,6 +792,32 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "charts-rs" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e85ef0639898035bf3db8070a80c90192e3a0d134c5f585fbf31438fe76660" +dependencies = [ + "charts-rs-derive", + "fontdue", + "once_cell", + "regex", + "serde", + "serde_json", + "snafu", + "substring", +] + +[[package]] +name = "charts-rs-derive" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cfe97e9b53f56e7bb7a8e8e1ac75e8187c93311502bc32ce56d01faad075185" +dependencies = [ + "quote", + "syn 2.0.66", +] + [[package]] name = "cipher" version = "0.4.4" @@ -816,7 +917,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed.git#88000eb7e239be6c8ad33988ee52738e64185a9e" +source = "git+https://github.com/zed-industries/zed.git#5c7a8f779adbaf07b74799cf743bc3a122666f24" dependencies = [ "rustc-hash", ] @@ -1103,16 +1204,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" -[[package]] -name = "deflate" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" -dependencies = [ - "adler32", - "byteorder", -] - [[package]] name = "deranged" version = "0.3.11" @@ -1139,7 +1230,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed.git#88000eb7e239be6c8ad33988ee52738e64185a9e" +source = "git+https://github.com/zed-industries/zed.git#5c7a8f779adbaf07b74799cf743bc3a122666f24" dependencies = [ "proc-macro2", "quote", @@ -1427,6 +1518,22 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "exr" +version = "1.72.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + [[package]] name = "fake" version = "2.9.2" @@ -1489,7 +1596,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", - "miniz_oxide 0.7.3", + "miniz_oxide", ] [[package]] @@ -1578,6 +1685,16 @@ dependencies = [ "ttf-parser", ] +[[package]] +name = "fontdue" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efe23d02309319171d00d794c9ff48d4f903c0e481375b1b04b017470838af04" +dependencies = [ + "hashbrown 0.14.5", + "ttf-parser", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -1902,9 +2019,9 @@ dependencies = [ [[package]] name = "gif" -version = "0.11.4" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" dependencies = [ "color_quant", "weezl", @@ -2064,7 +2181,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed.git#88000eb7e239be6c8ad33988ee52738e64185a9e" +source = "git+https://github.com/zed-industries/zed.git#5c7a8f779adbaf07b74799cf743bc3a122666f24" dependencies = [ "anyhow", "as-raw-xcb-connection", @@ -2099,7 +2216,7 @@ dependencies = [ "gpui_macros", "http 0.1.0", "image", - "itertools", + "itertools 0.11.0", "lazy_static", "linkme", "log", @@ -2151,7 +2268,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed.git#88000eb7e239be6c8ad33988ee52738e64185a9e" +source = "git+https://github.com/zed-industries/zed.git#5c7a8f779adbaf07b74799cf743bc3a122666f24" dependencies = [ "proc-macro2", "quote", @@ -2216,6 +2333,16 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -2227,6 +2354,10 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] [[package]] name = "heck" @@ -2322,7 +2453,7 @@ dependencies = [ [[package]] name = "http" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed.git#88000eb7e239be6c8ad33988ee52738e64185a9e" +source = "git+https://github.com/zed-industries/zed.git#5c7a8f779adbaf07b74799cf743bc3a122666f24" dependencies = [ "anyhow", "futures", @@ -2494,21 +2625,35 @@ dependencies = [ [[package]] name = "image" -version = "0.23.14" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" +checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11" dependencies = [ "bytemuck", "byteorder", "color_quant", + "exr", "gif", - "jpeg-decoder", - "num-iter", - "num-rational 0.3.2", + "image-webp", "num-traits", - "png 0.16.8", - "scoped_threadpool", + "png", + "qoi", + "ravif", + "rayon", + "rgb", "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d730b085583c4d789dfd07fdcf185be59501666a90c97c40162b37e4fdad272d" +dependencies = [ + "byteorder-lite", + "thiserror", ] [[package]] @@ -2517,6 +2662,12 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" +[[package]] +name = "imgref" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126" + [[package]] name = "indexmap" version = "1.9.3" @@ -2556,6 +2707,17 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "io-lifetimes" version = "1.0.11" @@ -2622,6 +2784,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.8" @@ -2680,14 +2851,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] -name = "jpeg-decoder" -version = "0.1.22" +name = "jobserver" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ - "rayon", + "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + [[package]] name = "js-sys" version = "0.3.69" @@ -2751,12 +2928,29 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + [[package]] name = "libc" version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + [[package]] name = "libloading" version = "0.8.3" @@ -2853,6 +3047,15 @@ dependencies = [ "value-bag", ] +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + [[package]] name = "mac" version = "0.1.1" @@ -2901,6 +3104,16 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + [[package]] name = "md-5" version = "0.10.6" @@ -2914,7 +3127,7 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed.git#88000eb7e239be6c8ad33988ee52738e64185a9e" +source = "git+https://github.com/zed-industries/zed.git#5c7a8f779adbaf07b74799cf743bc3a122666f24" dependencies = [ "anyhow", "bindgen", @@ -2984,25 +3197,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" -dependencies = [ - "adler32", -] - -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg", -] - [[package]] name = "miniz_oxide" version = "0.7.3" @@ -3112,6 +3306,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + [[package]] name = "num" version = "0.4.3" @@ -3122,7 +3322,7 @@ dependencies = [ "num-complex", "num-integer", "num-iter", - "num-rational 0.4.2", + "num-rational", "num-traits", ] @@ -3169,6 +3369,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "num-integer" version = "0.1.46" @@ -3189,17 +3400,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-rational" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-rational" version = "0.4.2" @@ -3616,18 +3816,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[package]] -name = "png" -version = "0.16.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "deflate", - "miniz_oxide 0.3.7", -] - [[package]] name = "png" version = "0.17.13" @@ -3638,7 +3826,7 @@ dependencies = [ "crc32fast", "fdeflate", "flate2", - "miniz_oxide 0.7.3", + "miniz_oxide", ] [[package]] @@ -3809,6 +3997,21 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quick-xml" version = "0.31.0" @@ -3914,6 +4117,56 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.12.1", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand 0.8.5", + "rand_chacha 0.3.1", + "simd_helpers", + "system-deps", + "thiserror", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67376f469e7e7840d0040bbf4b9b3334005bb167f814621326e4c7ab8cd6e944" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + [[package]] name = "raw-window-handle" version = "0.5.2" @@ -3991,7 +4244,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed.git#88000eb7e239be6c8ad33988ee52738e64185a9e" +source = "git+https://github.com/zed-industries/zed.git#5c7a8f779adbaf07b74799cf743bc3a122666f24" dependencies = [ "derive_refineable", ] @@ -4225,12 +4478,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" -[[package]] -name = "scoped_threadpool" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" - [[package]] name = "scopeguard" version = "1.2.0" @@ -4272,7 +4519,7 @@ checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" [[package]] name = "semantic_version" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed.git#88000eb7e239be6c8ad33988ee52738e64185a9e" +source = "git+https://github.com/zed-industries/zed.git#5c7a8f779adbaf07b74799cf743bc3a122666f24" dependencies = [ "anyhow", "serde", @@ -4426,6 +4673,15 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "simplecss" version = "0.2.1" @@ -4499,6 +4755,27 @@ dependencies = [ "futures-lite 1.13.0", ] +[[package]] +name = "snafu" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418b8136fec49956eba89be7da2847ec1909df92a9ae4178b5ff0ff092c8d95e" +dependencies = [ + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a4812a669da00d17d8266a0439eddcacbc88b17f732f927e52eeb9d196f7fb5" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "socket2" version = "0.4.10" @@ -4587,8 +4864,10 @@ name = "story" version = "0.1.0" dependencies = [ "anyhow", + "charts-rs", "fake", "gpui", + "image", "serde", "ui", "workspace", @@ -4635,6 +4914,15 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "substring" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ee6433ecef213b2e72f587ef64a2f5943e7cd16fbd82dbe8bc07486c534c86" +dependencies = [ + "autocfg", +] + [[package]] name = "subtle" version = "2.5.0" @@ -4644,7 +4932,7 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed.git#88000eb7e239be6c8ad33988ee52738e64185a9e" +source = "git+https://github.com/zed-industries/zed.git#5c7a8f779adbaf07b74799cf743bc3a122666f24" dependencies = [ "arrayvec", "log", @@ -4913,12 +5201,12 @@ dependencies = [ [[package]] name = "tiff" -version = "0.6.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" dependencies = [ + "flate2", "jpeg-decoder", - "miniz_oxide 0.4.4", "weezl", ] @@ -4973,7 +5261,7 @@ dependencies = [ "bytemuck", "cfg-if", "log", - "png 0.17.13", + "png", "tiny-skia-path", ] @@ -5166,11 +5454,14 @@ version = "0.1.0" dependencies = [ "anyhow", "gpui", + "image", "log", + "resvg", "serde", "serde_json", "smallvec", "unicode-segmentation", + "usvg", "windows", "wry", ] @@ -5299,7 +5590,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "util" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed.git#88000eb7e239be6c8ad33988ee52738e64185a9e" +source = "git+https://github.com/zed-industries/zed.git#5c7a8f779adbaf07b74799cf743bc3a122666f24" dependencies = [ "anyhow", "async-fs 1.6.0", @@ -5330,6 +5621,17 @@ dependencies = [ "sha1_smol", ] +[[package]] +name = "v_frame" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + [[package]] name = "value-bag" version = "1.9.0" @@ -6395,6 +6697,30 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec866b44a2a1fd6133d363f073ca1b179f438f99e7e5bfb1e33f7181facfe448" +dependencies = [ + "zune-core", +] + [[package]] name = "zvariant" version = "4.1.1" diff --git a/assets/icons/search.svg b/assets/icons/search.svg index a59b6a0d..a6583491 100644 --- a/assets/icons/search.svg +++ b/assets/icons/search.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + \ No newline at end of file diff --git a/crates/app/src/story_workspace.rs b/crates/app/src/story_workspace.rs index 82417371..51e9655d 100644 --- a/crates/app/src/story_workspace.rs +++ b/crates/app/src/story_workspace.rs @@ -1,8 +1,8 @@ use gpui::*; use prelude::FluentBuilder as _; use story::{ - ButtonStory, CheckboxStory, DropdownStory, InputStory, ListStory, PickerStory, PopoverStory, - StoryContainer, SwitchStory, TooltipStory, + ButtonStory, CheckboxStory, DropdownStory, ImageStory, InputStory, ListStory, PickerStory, + PopoverStory, StoryContainer, SwitchStory, TooltipStory, }; use workspace::{TitleBar, Workspace}; @@ -120,6 +120,15 @@ impl StoryWorkspace { ) .detach(); + StoryContainer::open( + "Image", + "Render SVG image and Chart", + ImageStory::view(cx).into(), + workspace.clone(), + cx, + ) + .detach(); + Self { workspace } } @@ -137,10 +146,10 @@ impl StoryWorkspace { appears_transparent: true, traffic_light_position: Some(point(px(9.0), px(9.0))), }), - window_min_size: Size { + window_min_size: Some(Size { width: px(640.), height: px(480.), - }, + }), kind: WindowKind::Normal, ..Default::default() }; diff --git a/crates/story/Cargo.toml b/crates/story/Cargo.toml index dd885911..8bf11372 100644 --- a/crates/story/Cargo.toml +++ b/crates/story/Cargo.toml @@ -10,6 +10,8 @@ serde.workspace = true fake = "2.9.2" anyhow = "1" workspace.workspace = true +charts-rs = "0.3" +image = "0.25.1" [lints] workspace = true diff --git a/crates/story/src/fixtures/google.svg b/crates/story/src/fixtures/google.svg new file mode 100644 index 00000000..24c555d6 --- /dev/null +++ b/crates/story/src/fixtures/google.svg @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/crates/story/src/fixtures/pie.json b/crates/story/src/fixtures/pie.json new file mode 100644 index 00000000..5bb47833 --- /dev/null +++ b/crates/story/src/fixtures/pie.json @@ -0,0 +1,66 @@ +{ + "border_radius": 2, + "width": 400, + "height": 300, + "inner_radus": 30, + "legend_margin": { + "top": 0 + }, + "legend_show": true, + "radius": 110, + "rose_type": true, + "series_list": [ + { + "name": "rose 1", + "data": [ + 40 + ] + }, + { + "name": "rose 2", + "data": [ + 38 + ] + }, + { + "name": "rose 3", + "data": [ + 32 + ] + }, + { + "name": "rose 4", + "data": [ + 30 + ] + }, + { + "name": "rose 5", + "data": [ + 28 + ] + }, + { + "name": "rose 6", + "data": [ + 26 + ] + }, + { + "name": "rose 7", + "data": [ + 22 + ] + }, + { + "name": "rose 8", + "data": [ + 18 + ] + } + ], + "sub_title_text": "Sub Title", + "theme": "light", + "title_text": "Nightingale Chart", + "type": "pie" +} \ No newline at end of file diff --git a/crates/story/src/image_story.rs b/crates/story/src/image_story.rs new file mode 100644 index 00000000..368f7f36 --- /dev/null +++ b/crates/story/src/image_story.rs @@ -0,0 +1,48 @@ +use gpui::{px, ParentElement as _, Render, Styled, View, VisualContext as _, WindowContext}; +use ui::{h_flex, v_flex, SvgImg}; + +const GOOGLE_LOGO: &str = include_str!("./fixtures/google.svg"); +const PIE_JSON: &str = include_str!("./fixtures/pie.json"); + +pub struct ImageStory { + google_logo: SvgImg, + pie_chart: SvgImg, +} + +impl ImageStory { + pub fn new(cx: &WindowContext) -> Self { + let chart = charts_rs::PieChart::from_json(PIE_JSON).unwrap(); + + Self { + google_logo: SvgImg::new(800, 800) + .svg(GOOGLE_LOGO.as_bytes(), cx) + .unwrap(), + pie_chart: SvgImg::new(400, 300) + .svg(chart.svg().unwrap().as_bytes(), cx) + .unwrap(), + } + } + + pub fn view(cx: &mut WindowContext) -> View { + cx.new_view(|cx| Self::new(cx)) + } +} + +impl Render for ImageStory { + fn render(&mut self, _cx: &mut gpui::ViewContext) -> impl gpui::IntoElement { + v_flex() + .gap_4() + .size_full() + .items_center() + .child( + h_flex() + .size_full() + .child(self.google_logo.clone().w(px(300.)).h(px(300.)).flex_grow()) + .child(self.google_logo.clone().w(px(300.)).h(px(300.)).flex_grow()) + .child(self.google_logo.clone().w(px(300.)).h(px(300.)).flex_grow()) + .child(self.google_logo.clone().w(px(300.)).h(px(300.)).flex_grow()) + .child(self.google_logo.clone().w(px(300.)).h(px(300.)).flex_grow()), + ) + .child(self.pie_chart.clone().size_full()) + } +} diff --git a/crates/story/src/lib.rs b/crates/story/src/lib.rs index 349ce5d8..61420b7e 100644 --- a/crates/story/src/lib.rs +++ b/crates/story/src/lib.rs @@ -1,6 +1,7 @@ mod button_story; mod checkbox_story; mod dropdown_story; +mod image_story; mod input_story; mod list_story; mod picker_story; @@ -11,6 +12,7 @@ mod tooltip_story; pub use button_story::ButtonStory; pub use checkbox_story::CheckboxStory; pub use dropdown_story::DropdownStory; +pub use image_story::ImageStory; pub use input_story::InputStory; pub use list_story::ListStory; pub use picker_story::PickerStory; diff --git a/crates/ui/Cargo.toml b/crates/ui/Cargo.toml index 86741e06..c4796148 100644 --- a/crates/ui/Cargo.toml +++ b/crates/ui/Cargo.toml @@ -13,6 +13,9 @@ wry = "0" smallvec = "1.13.2" windows = "0.57.0" unicode-segmentation = "1.11.0" +image = "0.25.1" +resvg = { version = "0.41.0", default-features = false } +usvg = { version = "0.41.0", default-features = false } [lints] workspace = true diff --git a/crates/ui/src/lib.rs b/crates/ui/src/lib.rs index 8f1403fb..a7444b9e 100644 --- a/crates/ui/src/lib.rs +++ b/crates/ui/src/lib.rs @@ -6,6 +6,7 @@ mod scrollbar; mod selectable; mod stock; mod styled_ext; +mod svg_img; pub mod button; pub mod checkbox; @@ -31,6 +32,7 @@ pub use selectable::{Selectable, Selection}; pub use icon::*; pub use stock::*; +pub use svg_img::*; /// Initialize the UI module. pub fn init(cx: &mut gpui::AppContext) { diff --git a/crates/ui/src/svg_img.rs b/crates/ui/src/svg_img.rs new file mode 100644 index 00000000..fa2ed69c --- /dev/null +++ b/crates/ui/src/svg_img.rs @@ -0,0 +1,202 @@ +use std::sync::Arc; + +use anyhow::Context; +use gpui::{ + px, Bounds, Element, Hitbox, ImageData, InteractiveElement, Interactivity, IntoElement, + SharedString, StyleRefinement, Styled, WindowContext, +}; + +use image::ImageBuffer; + +#[derive(Clone, Copy, Debug)] +struct SvgSize { + width: u32, + height: u32, +} + +pub struct SvgImg { + interactivity: Interactivity, + size: SvgSize, + data: Option>, +} + +impl Clone for SvgImg { + fn clone(&self) -> Self { + Self { + interactivity: Interactivity::default(), + size: self.size.clone(), + data: self.data.clone(), + } + } +} + +/// An SVG image element. +pub fn svg_img(width: usize, height: usize) -> SvgImg { + SvgImg::new(width, height) +} + +impl SvgImg { + /// Create a new svg image element. + /// + /// The `src_width` and `src_height` are the original width and height of the svg image. + pub fn new(src_width: usize, src_height: usize) -> Self { + Self { + interactivity: Interactivity::default(), + size: SvgSize { + width: src_width as u32, + height: src_height as u32, + }, + data: None, + } + } + + /// Set the path of the svg image from the asset. + pub fn path(self, path: impl Into, cx: &WindowContext) -> anyhow::Result { + let svg = cx + .asset_source() + .load(&path.into()) + .expect("failed to load svg from asset") + .expect("failed to load svg from asset, return none"); + + self.svg(&svg, cx) + } + + /// Set the svg image from the bytes. + pub fn svg(mut self, svg: &[u8], cx: &WindowContext) -> anyhow::Result { + let data = self.to_image_data(svg, cx)?; + self.data = Some(Arc::new(data)); + Ok(self) + } + + pub fn to_image_data(&self, bytes: &[u8], cx: &WindowContext) -> anyhow::Result { + if self.size.width == 0 || self.size.height == 0 { + return Err(usvg::Error::InvalidSize.into()); + } + + let scale = cx.scale_factor() as u32; + let size = SvgSize { + width: self.size.width * scale, + height: self.size.height * scale, + }; + + let options = usvg::Options { + ..Default::default() + }; + let tree = usvg::Tree::from_data(&bytes, &options)?; + + let mut pixmap = resvg::tiny_skia::Pixmap::new(size.width, size.height) + .ok_or(usvg::Error::InvalidSize)?; + + let transform = tree.view_box().to_transform( + resvg::tiny_skia::Size::from_wh(size.width as f32, size.height as f32) + .ok_or(usvg::Error::InvalidSize)?, + ); + resvg::render(&tree, transform, &mut pixmap.as_mut()); + + let mut buffer = ImageBuffer::from_raw(pixmap.width(), pixmap.height(), pixmap.take()) + .context("invalid svg image buffer")?; + + // Convert from RGBA to BGRA. + for pixel in buffer.chunks_exact_mut(4) { + pixel.swap(0, 2); + } + + Ok(ImageData::new(buffer)) + } +} + +impl IntoElement for SvgImg { + type Element = Self; + + fn into_element(self) -> Self::Element { + self + } +} + +impl Element for SvgImg { + type RequestLayoutState = (); + type PrepaintState = Option; + + fn id(&self) -> Option { + self.interactivity.element_id.clone() + } + + fn request_layout( + &mut self, + global_id: Option<&gpui::GlobalElementId>, + cx: &mut WindowContext, + ) -> (gpui::LayoutId, Self::RequestLayoutState) { + let layout_id = self + .interactivity + .request_layout(global_id, cx, |style, cx| cx.request_layout(style, None)); + (layout_id, ()) + } + + fn prepaint( + &mut self, + global_id: Option<&gpui::GlobalElementId>, + bounds: gpui::Bounds, + _: &mut Self::RequestLayoutState, + cx: &mut WindowContext, + ) -> Self::PrepaintState { + self.interactivity + .prepaint(global_id, bounds, bounds.size, cx, |_, _, hitbox, _| hitbox) + } + + fn paint( + &mut self, + global_id: Option<&gpui::GlobalElementId>, + bounds: gpui::Bounds, + _: &mut Self::RequestLayoutState, + hitbox: &mut Self::PrepaintState, + cx: &mut WindowContext, + ) { + self.interactivity + .paint(global_id, bounds, hitbox.as_ref(), cx, |_style, cx| { + if let Some(data) = self.data.as_ref() { + // To calculate the ratio of the original image size to the container bounds size. + // Scale by shortest side (width or height) to get a fit image. + // And center the image in the container bounds. + let ratio = if bounds.size.width < bounds.size.height { + bounds.size.width.0 / self.size.width as f32 + } else { + bounds.size.height.0 / self.size.height as f32 + }; + + let ratio = ratio.min(1.0); + + let new_size = gpui::Size { + width: px(self.size.width as f32 * ratio), + height: px(self.size.height as f32 * ratio), + }; + let new_origin = gpui::Point { + x: bounds.origin.x + px(((bounds.size.width - new_size.width) / 2.).into()), + y: bounds.origin.y + + px(((bounds.size.height - new_size.height) / 2.).into()), + }; + + let img_bounds = Bounds { + size: new_size, + origin: new_origin, + }; + + match cx.paint_image(img_bounds, px(0.).into(), data.clone(), false) { + Ok(_) => {} + Err(err) => eprintln!("failed to paint svg image: {:?}", err), + } + } + }) + } +} + +impl Styled for SvgImg { + fn style(&mut self) -> &mut StyleRefinement { + &mut self.interactivity.base_style + } +} + +impl InteractiveElement for SvgImg { + fn interactivity(&mut self) -> &mut Interactivity { + &mut self.interactivity + } +}