diff --git a/Cargo.lock b/Cargo.lock index 6a1d772..aed1c08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,6 +84,23 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +[[package]] +name = "async-trait" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async_once" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce4f10ea3abcd6617873bae9f91d1c5332b4a778bd9ce34d0cd517474c1de82" + [[package]] name = "autocfg" version = "1.1.0" @@ -147,6 +164,44 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +[[package]] +name = "cached" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5877db5d1af7fae60d06b5db9430b68056a69b3582a0be8e3691e87654aeb6" +dependencies = [ + "async-trait", + "async_once", + "cached_proc_macro", + "cached_proc_macro_types", + "futures", + "hashbrown 0.13.2", + "instant", + "lazy_static", + "once_cell", + "thiserror", + "tokio", +] + +[[package]] +name = "cached_proc_macro" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10ca87c81aaa3a949dbbe2b5e6c2c45dbc94ba4897e45ea31ff9ec5087be3dc" +dependencies = [ + "cached_proc_macro_types", + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cached_proc_macro_types" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" + [[package]] name = "cc" version = "1.0.78" @@ -394,6 +449,41 @@ dependencies = [ "syn", ] +[[package]] +name = "darling" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685" +dependencies = [ + "darling_core", + "quote", + "syn", +] + [[package]] name = "data-url" version = "0.2.0" @@ -578,6 +668,12 @@ dependencies = [ "spin", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "fontconfig-parser" version = "0.5.1" @@ -616,16 +712,65 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] -name = "futures-core" -version = "0.3.25" +name = "futures" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" + +[[package]] +name = "futures-io" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" + +[[package]] +name = "futures-task" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" + +[[package]] +name = "futures-util" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +dependencies = [ + "futures-core", + "futures-sink", + "futures-task", + "pin-project-lite", + "pin-utils", +] [[package]] name = "getrandom" @@ -708,6 +853,12 @@ dependencies = [ "ahash 0.4.7", ] +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + [[package]] name = "heck" version = "0.4.0" @@ -756,6 +907,12 @@ dependencies = [ "cxx-build", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "image" version = "0.24.5" @@ -1177,7 +1334,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c672c7ad9ec066e428c00eb917124a06f08db19e2584de982cc34b1f4c12485" dependencies = [ "dlv-list", - "hashbrown", + "hashbrown 0.9.1", ] [[package]] @@ -1362,9 +1519,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] @@ -1373,6 +1530,7 @@ dependencies = [ name = "protostar" version = "0.4.0" dependencies = [ + "cached", "clap", "color-eyre", "directories", diff --git a/Cargo.toml b/Cargo.toml index 030ab86..8943d72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.4.0" edition = "2021" [dependencies] +cached = "0.42.0" clap = { version = "4.1.3", features = ["derive"] } color-eyre = "0.6.2" directories = "4.0.1" diff --git a/examples/app_grid.rs b/examples/app_grid.rs index 658c17a..5cb8c95 100644 --- a/examples/app_grid.rs +++ b/examples/app_grid.rs @@ -11,7 +11,7 @@ use stardust_xr_fusion::{ spatial::Spatial, drawable::{Text, TextStyle, Bounds, TextFit, Alignment}, core::values::Transform, }; -const APP_LIMIT: usize = 100; +const APP_LIMIT: usize = 300; const APP_SIZE: f32 = 0.05; const GRID_PADDING: f32 = 0.01; diff --git a/src/protostar.rs b/src/protostar.rs index 7197703..4ad7c3d 100644 --- a/src/protostar.rs +++ b/src/protostar.rs @@ -18,26 +18,34 @@ use tween::{QuartInOut, Tweener}; use ustr::ustr; fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result { + return match &icon.icon_type { - IconType::Png(path) => { + IconType::Png => { + let t = Transform::from_rotation_scale(Quat::from_rotation_x(PI/2.0),[0.03,0.03,0.03]); + let model = Model::create( parent, - Transform::from_rotation(Quat::from_rotation_y(PI)), - &ResourceID::new_namespaced("protostar", "cartridge"), + t, + &ResourceID::new_namespaced("protostar", "hexagon/hexagon"), )?; model.set_material_parameter( - 0, + 1, + "color", + MaterialParameter::Color([0.0,1.0,1.0,1.0]), + )?; + model.set_material_parameter( + 2, "diffuse", - MaterialParameter::Texture(ResourceID::Direct(path.clone())), + MaterialParameter::Texture(ResourceID::Direct(icon.path.clone())), )?; Ok(model) } - IconType::Gltf(path) => Ok(Model::create( + IconType::Gltf => Ok(Model::create( parent, Transform::from_scale([0.05; 3]), - &ResourceID::new_direct(path)?, + &ResourceID::new_direct(icon.path.clone())?, )?), - _ => panic!("asd"), + _ => panic!("Invalid Icon Type"), }; } @@ -57,7 +65,7 @@ impl ProtoStar { .clone() .into_iter() .find(|i| match i.icon_type { - IconType::Gltf(_) => true, + IconType::Gltf => true, _ => false, }) .or( @@ -68,7 +76,7 @@ impl ProtoStar { match icon{ Some(i) => { - icon = match i.process(128) { + icon = match i.cached_process(128) { Ok(i) => Some(i), _ => None, }}, @@ -105,8 +113,8 @@ impl ProtoStar { .unwrap_or_else(|| { Ok(Model::create( grabbable.content_parent(), - Transform::from_scale([0.05; 3]), - &ResourceID::new_namespaced("protostar", "default_icon"), + Transform::from_rotation_scale(Quat::from_rotation_x(PI/2.0),[0.03,0.03,0.03]), + &ResourceID::new_namespaced("protostar", "hexagon/hexagon"), )?) })?; Ok(ProtoStar { diff --git a/src/xdg.rs b/src/xdg.rs index 1530faa..ce7c2ac 100644 --- a/src/xdg.rs +++ b/src/xdg.rs @@ -3,13 +3,15 @@ use resvg::render; use resvg::tiny_skia::{Pixmap, Transform}; use resvg::usvg::{FitTo, Tree}; use std::ffi::OsString; -use std::fs::create_dir_all; -use std::io::{BufRead, BufReader, ErrorKind, self}; +use std::fs::{create_dir_all}; +use std::os::unix::fs::{symlink}; +use std::io::{BufRead, BufReader, ErrorKind}; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::{env, fs}; use walkdir::WalkDir; use linicon; +use cached::proc_macro::cached; fn get_data_dirs() -> Vec { let xdg_data_dirs_str = std::env::var("XDG_DATA_DIRS") @@ -178,6 +180,11 @@ impl DesktopFile { } } + let cache_icon_path = get_image_cache_dir().join(icon_name).canonicalize(); + if cache_icon_path.is_ok() { + return vec![Icon::from_path(cache_icon_path.unwrap(), 128).unwrap()] + } + let mut icons_iter= linicon::lookup_icon(icon_name).use_fallback_themes(false).peekable(); if icons_iter.peek().is_none(){ @@ -197,29 +204,34 @@ impl DesktopFile { #[derive(Debug, PartialEq, Eq, Clone)] pub struct Icon { pub icon_type: IconType, + pub path: PathBuf, pub size: u16, } #[derive(Debug, PartialEq, Eq, Clone)] pub enum IconType { - Png(PathBuf), - Svg(PathBuf), - Gltf(PathBuf), + Png, + Svg, + Gltf, } impl Icon { pub fn from_path(path: PathBuf, size: u16) -> Option{ let icon_type = match path.extension().and_then(|ext| ext.to_str()) { - Some("png") => Some(IconType::Png(path)), - Some("svg") => Some(IconType::Svg(path)), - Some("glb") | Some("gltf") => Some(IconType::Gltf(path)), + Some("png") => Some(IconType::Png), + Some("svg") => Some(IconType::Svg), + Some("glb") | Some("gltf") => Some(IconType::Gltf), _ => {return None}, }.unwrap(); - return Some(Icon{icon_type,size}) + return Some(Icon{icon_type,path,size}) } - pub fn process(self, size: u16) -> Result { + pub fn cached_process(self, size: u16) -> Result { + let new_path = get_image_cache_dir().join(self.path.with_extension("").file_name().unwrap()); + if !new_path.exists(){ + _ = symlink(self.path.clone(), new_path); + } match self.icon_type { - IconType::Svg(path) => Ok(Icon::from_path(get_png_from_svg(&path, size)?,size).unwrap()), + IconType::Svg => Ok(Icon::from_path(get_png_from_svg(self.path, size)?,size).unwrap()), _ => Ok(self), } } @@ -245,6 +257,22 @@ fn test_get_icon_path() { assert!(icon_paths.contains(&Icon::from_path(PathBuf::from("/usr/share/icons/hicolor/32x32/apps/krita.png"),32).unwrap())); } +#[cached] +pub fn get_image_cache_dir() -> PathBuf { + let cache_dir; + if let Ok(xdg_cache_home) = std::env::var("XDG_CACHE_HOME") { + cache_dir = PathBuf::from_str(&xdg_cache_home).unwrap_or( + dirs::home_dir().unwrap().join(".cache") + ) + } else { + cache_dir = dirs::home_dir().unwrap().join(".cache"); + } + let image_cache_dir = cache_dir.join("protostar_icon_cache"); + create_dir_all(&image_cache_dir).expect("Could not create image cache directory"); + return image_cache_dir +} + + pub fn get_png_from_svg(svg_path: impl AsRef, size: u16,) -> Result { let svg_path = fs::canonicalize(svg_path)?; let svg_data = fs::read(svg_path.as_path())?; @@ -254,20 +282,7 @@ pub fn get_png_from_svg(svg_path: impl AsRef, size: u16,) -> Result