Compare commits
11 commits
iced-switc
...
master
Author | SHA1 | Date | |
---|---|---|---|
fae83aedc5 | |||
035f8896f1 | |||
6c8cb6c5b2 | |||
d6b4cc6297 | |||
4792304d8b | |||
23cd34388b | |||
4ccb186189 | |||
1446e35c58 | |||
5f3d867ad7 | |||
aa5e7420f1 | |||
213e47bf6d |
12 changed files with 1221 additions and 435 deletions
542
Cargo.lock
generated
542
Cargo.lock
generated
|
@ -141,6 +141,15 @@ version = "0.1.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
|
||||
|
||||
[[package]]
|
||||
name = "aligned-vec"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b"
|
||||
dependencies = [
|
||||
"equator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
|
@ -267,6 +276,12 @@ dependencies = [
|
|||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||
|
||||
[[package]]
|
||||
name = "apply"
|
||||
version = "0.3.0"
|
||||
|
@ -282,6 +297,23 @@ dependencies = [
|
|||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
|
||||
|
||||
[[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.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.9"
|
||||
|
@ -614,6 +646,29 @@ version = "1.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "av1-grain"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arrayvec",
|
||||
"log",
|
||||
"nom",
|
||||
"num-rational",
|
||||
"v_frame",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "avif-serialize"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47c8fbc0f831f4519fe8b810b6a7a91410ec83031b8233f730a0480029f6a23f"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.75"
|
||||
|
@ -689,6 +744,12 @@ version = "0.7.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22"
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -704,6 +765,12 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitstream-io"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2"
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
|
@ -750,6 +817,12 @@ dependencies = [
|
|||
"piper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "built"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.19.0"
|
||||
|
@ -852,6 +925,16 @@ dependencies = [
|
|||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-expr"
|
||||
version = "0.15.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
"target-lexicon 0.12.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-expr"
|
||||
version = "0.20.2"
|
||||
|
@ -859,7 +942,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "c8d458d63f0f0f482c8da9b7c8b76c21bd885a02056cc94c6404d861ca2b8206"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
"target-lexicon",
|
||||
"target-lexicon 0.13.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1276,7 +1359,7 @@ dependencies = [
|
|||
"log",
|
||||
"rangemap",
|
||||
"rustc-hash 1.1.0",
|
||||
"rustybuzz",
|
||||
"rustybuzz 0.14.1",
|
||||
"self_cell",
|
||||
"smol_str",
|
||||
"swash",
|
||||
|
@ -1796,6 +1879,26 @@ dependencies = [
|
|||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equator"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc"
|
||||
dependencies = [
|
||||
"equator-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equator-macro"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
|
@ -1886,6 +1989,21 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exr"
|
||||
version = "1.73.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"half",
|
||||
"lebe",
|
||||
"miniz_oxide",
|
||||
"rayon-core",
|
||||
"smallvec",
|
||||
"zune-inflate",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "extended"
|
||||
version = "0.1.0"
|
||||
|
@ -1913,6 +2031,26 @@ version = "2.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "fax"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab"
|
||||
dependencies = [
|
||||
"fax_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fax_derive"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fd-lock"
|
||||
version = "4.0.4"
|
||||
|
@ -2300,7 +2438,7 @@ dependencies = [
|
|||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 7.0.5",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
|
@ -2362,7 +2500,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "8ab79e1ed126803a8fb827e3de0e2ff95191912b8db65cee467edb56fc4cc215"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 7.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2400,7 +2538,7 @@ checksum = "ec9aca94bb73989e3cfdbf8f2e0f1f6da04db4d291c431f444838925c4c63eda"
|
|||
dependencies = [
|
||||
"glib-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 7.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2511,7 +2649,7 @@ dependencies = [
|
|||
"gstreamer-base-sys",
|
||||
"gstreamer-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 7.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2541,7 +2679,7 @@ dependencies = [
|
|||
"gstreamer-base-sys",
|
||||
"gstreamer-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 7.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2568,7 +2706,7 @@ dependencies = [
|
|||
"gobject-sys",
|
||||
"gstreamer-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 7.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2598,7 +2736,7 @@ dependencies = [
|
|||
"gstreamer-sys",
|
||||
"gstreamer-video-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 7.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2610,7 +2748,7 @@ dependencies = [
|
|||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 7.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2641,7 +2779,7 @@ dependencies = [
|
|||
"gstreamer-base-sys",
|
||||
"gstreamer-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 7.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2943,7 +3081,7 @@ dependencies = [
|
|||
"iced_graphics",
|
||||
"kurbo 0.10.4",
|
||||
"log",
|
||||
"resvg",
|
||||
"resvg 0.42.0",
|
||||
"rustc-hash 2.1.1",
|
||||
"softbuffer",
|
||||
"tiny-skia",
|
||||
|
@ -2984,7 +3122,7 @@ dependencies = [
|
|||
"lyon",
|
||||
"once_cell",
|
||||
"raw-window-handle",
|
||||
"resvg",
|
||||
"resvg 0.42.0",
|
||||
"rustc-hash 2.1.1",
|
||||
"rustix 0.38.44",
|
||||
"thiserror 1.0.69",
|
||||
|
@ -3154,24 +3292,56 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.6"
|
||||
version = "0.25.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a"
|
||||
checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
"color_quant",
|
||||
"exr",
|
||||
"gif",
|
||||
"image-webp",
|
||||
"moxcms",
|
||||
"num-traits",
|
||||
"png",
|
||||
"png 0.18.0",
|
||||
"qoi",
|
||||
"ravif",
|
||||
"rayon",
|
||||
"rgb",
|
||||
"tiff",
|
||||
"zune-core",
|
||||
"zune-jpeg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image-webp"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
|
||||
dependencies = [
|
||||
"byteorder-lite",
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imagesize"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284"
|
||||
|
||||
[[package]]
|
||||
name = "imagesize"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285"
|
||||
|
||||
[[package]]
|
||||
name = "imgref"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408"
|
||||
|
||||
[[package]]
|
||||
name = "immutable-chunkmap"
|
||||
version = "2.0.6"
|
||||
|
@ -3241,6 +3411,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.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.11"
|
||||
|
@ -3275,6 +3456,15 @@ version = "1.70.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
|
@ -3432,6 +3622,12 @@ dependencies = [
|
|||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lebe"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
||||
|
||||
[[package]]
|
||||
name = "lewton"
|
||||
version = "0.10.2"
|
||||
|
@ -3518,6 +3714,16 @@ dependencies = [
|
|||
"zbus 5.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.8"
|
||||
|
@ -3621,6 +3827,15 @@ version = "0.4.27"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "loop9"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
|
||||
dependencies = [
|
||||
"imgref",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.12.5"
|
||||
|
@ -3638,11 +3853,13 @@ dependencies = [
|
|||
"gstreamer",
|
||||
"gstreamer-app",
|
||||
"iced_video_player",
|
||||
"image",
|
||||
"lexpr",
|
||||
"libcosmic",
|
||||
"miette",
|
||||
"pretty_assertions",
|
||||
"rayon",
|
||||
"resvg 0.45.1",
|
||||
"rodio",
|
||||
"ron 0.8.1",
|
||||
"serde",
|
||||
|
@ -3736,6 +3953,16 @@ dependencies = [
|
|||
"regex-automata 0.1.10",
|
||||
]
|
||||
|
||||
[[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"
|
||||
|
@ -3875,6 +4102,16 @@ dependencies = [
|
|||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moxcms"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddd32fa8935aeadb8a8a6b6b351e40225570a37c43de67690383d87ef170cd08"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"pxfm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "muldiv"
|
||||
version = "1.0.1"
|
||||
|
@ -3961,6 +4198,12 @@ dependencies = [
|
|||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||
|
||||
[[package]]
|
||||
name = "nibble_vec"
|
||||
version = "0.1.0"
|
||||
|
@ -4017,6 +4260,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 = "notify"
|
||||
version = "8.2.0"
|
||||
|
@ -4051,6 +4300,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint-dig"
|
||||
version = "0.8.4"
|
||||
|
@ -4111,6 +4370,7 @@ version = "0.4.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
@ -4804,6 +5064,19 @@ dependencies = [
|
|||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
|
||||
dependencies = [
|
||||
"bitflags 2.9.2",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "2.8.0"
|
||||
|
@ -4926,6 +5199,43 @@ name = "profiling"
|
|||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
|
||||
dependencies = [
|
||||
"profiling-procmacros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "profiling-procmacros"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pxfm"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e790881194f6f6e86945f0a42a6981977323669aeb6c40e9c7ec253133b96f8"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[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"
|
||||
|
@ -5032,6 +5342,56 @@ version = "1.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93e7e49bb0bf967717f7bd674458b3d6b0c5f48ec7e3038166026a69fc22223"
|
||||
|
||||
[[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 6.2.2",
|
||||
"thiserror 1.0.69",
|
||||
"v_frame",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ravif"
|
||||
version = "0.11.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b"
|
||||
dependencies = [
|
||||
"avif-serialize",
|
||||
"imgref",
|
||||
"loop9",
|
||||
"quick-error",
|
||||
"rav1e",
|
||||
"rayon",
|
||||
"rgb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.6.2"
|
||||
|
@ -5200,7 +5560,24 @@ dependencies = [
|
|||
"rgb",
|
||||
"svgtypes",
|
||||
"tiny-skia",
|
||||
"usvg",
|
||||
"usvg 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "resvg"
|
||||
version = "0.45.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8928798c0a55e03c9ca6c4c6846f76377427d2c1e1f7e6de3c06ae57942df43"
|
||||
dependencies = [
|
||||
"gif",
|
||||
"image-webp",
|
||||
"log",
|
||||
"pico-args",
|
||||
"rgb",
|
||||
"svgtypes",
|
||||
"tiny-skia",
|
||||
"usvg 0.45.1",
|
||||
"zune-jpeg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5376,8 +5753,26 @@ dependencies = [
|
|||
"libm",
|
||||
"smallvec",
|
||||
"ttf-parser 0.21.1",
|
||||
"unicode-bidi-mirroring",
|
||||
"unicode-ccc",
|
||||
"unicode-bidi-mirroring 0.2.0",
|
||||
"unicode-ccc 0.2.0",
|
||||
"unicode-properties",
|
||||
"unicode-script",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustybuzz"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702"
|
||||
dependencies = [
|
||||
"bitflags 2.9.2",
|
||||
"bytemuck",
|
||||
"core_maths",
|
||||
"log",
|
||||
"smallvec",
|
||||
"ttf-parser 0.25.1",
|
||||
"unicode-bidi-mirroring 0.4.0",
|
||||
"unicode-ccc 0.4.0",
|
||||
"unicode-properties",
|
||||
"unicode-script",
|
||||
]
|
||||
|
@ -5643,6 +6038,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.2"
|
||||
|
@ -6304,13 +6708,26 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "6.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349"
|
||||
dependencies = [
|
||||
"cfg-expr 0.15.8",
|
||||
"heck 0.5.0",
|
||||
"pkg-config",
|
||||
"toml",
|
||||
"version-compare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "7.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4be53aa0cba896d2dc615bd42bbc130acdcffa239e0a2d965ea5b3b2a86ffdb"
|
||||
dependencies = [
|
||||
"cfg-expr",
|
||||
"cfg-expr 0.20.2",
|
||||
"heck 0.5.0",
|
||||
"pkg-config",
|
||||
"toml",
|
||||
|
@ -6328,6 +6745,12 @@ dependencies = [
|
|||
"slotmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.13.2"
|
||||
|
@ -6431,6 +6854,20 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f"
|
||||
dependencies = [
|
||||
"fax",
|
||||
"flate2",
|
||||
"half",
|
||||
"quick-error",
|
||||
"weezl",
|
||||
"zune-jpeg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.41"
|
||||
|
@ -6475,7 +6912,7 @@ dependencies = [
|
|||
"bytemuck",
|
||||
"cfg-if",
|
||||
"log",
|
||||
"png",
|
||||
"png 0.17.16",
|
||||
"tiny-skia-path",
|
||||
]
|
||||
|
||||
|
@ -6729,12 +7166,24 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23cb788ffebc92c5948d0e997106233eeb1d8b9512f93f41651f52b6c5f5af86"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi-mirroring"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ccc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ccc"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
|
@ -6826,12 +7275,39 @@ dependencies = [
|
|||
"data-url",
|
||||
"flate2",
|
||||
"fontdb 0.18.0",
|
||||
"imagesize",
|
||||
"imagesize 0.12.0",
|
||||
"kurbo 0.11.3",
|
||||
"log",
|
||||
"pico-args",
|
||||
"roxmltree",
|
||||
"rustybuzz",
|
||||
"rustybuzz 0.14.1",
|
||||
"simplecss",
|
||||
"siphasher",
|
||||
"strict-num",
|
||||
"svgtypes",
|
||||
"tiny-skia-path",
|
||||
"unicode-bidi",
|
||||
"unicode-script",
|
||||
"unicode-vo",
|
||||
"xmlwriter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "usvg"
|
||||
version = "0.45.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80be9b06fbae3b8b303400ab20778c80bbaf338f563afe567cf3c9eea17b47ef"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"data-url",
|
||||
"flate2",
|
||||
"fontdb 0.23.0",
|
||||
"imagesize 0.13.0",
|
||||
"kurbo 0.11.3",
|
||||
"log",
|
||||
"pico-args",
|
||||
"roxmltree",
|
||||
"rustybuzz 0.20.1",
|
||||
"simplecss",
|
||||
"siphasher",
|
||||
"strict-num",
|
||||
|
@ -6861,6 +7337,17 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "v_frame"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2"
|
||||
dependencies = [
|
||||
"aligned-vec",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.1"
|
||||
|
@ -8178,6 +8665,15 @@ 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.20"
|
||||
|
|
|
@ -8,7 +8,6 @@ description = "A cli presentation system"
|
|||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.20", features = ["debug", "derive"] }
|
||||
libcosmic = { git = "https://github.com/pop-os/libcosmic", default-features = false, features = ["debug", "winit", "desktop", "winit_wgpu", "winit_tokio", "tokio", "rfd", "dbus-config", "a11y", "wgpu", "multi-window"] }
|
||||
lexpr = "0.2.7"
|
||||
miette = { version = "7.2.0", features = ["fancy"] }
|
||||
pretty_assertions = "1.4.1"
|
||||
|
@ -33,12 +32,18 @@ gstreamer-app = "0.23"
|
|||
url = "2"
|
||||
colors-transform = "0.2.11"
|
||||
rayon = "1.11.0"
|
||||
# resvg = "0.45.1"
|
||||
resvg = "0.45.1"
|
||||
image = "0.25.8"
|
||||
# femtovg = { version = "0.16.0", features = ["wgpu"] }
|
||||
# wgpu = "26.0.1"
|
||||
# mupdf = "0.5.0"
|
||||
# rfd = { version = "0.12.1", features = ["xdg-portal"], default-features = false }
|
||||
|
||||
[dependencies.libcosmic]
|
||||
git = "https://github.com/pop-os/libcosmic"
|
||||
default-features = false
|
||||
features = ["debug", "winit", "desktop", "winit_wgpu", "winit_tokio", "tokio", "rfd", "dbus-config", "a11y", "wgpu", "multi-window"]
|
||||
|
||||
[dependencies.iced_video_player]
|
||||
git = "https://github.com/jackpot51/iced_video_player.git"
|
||||
branch = "cosmic"
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use std::borrow::Cow;
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use cosmic::iced::clipboard::mime::{AllowedMimeTypes, AsMimeTypes};
|
||||
use crisp::types::{Keyword, Symbol, Value};
|
||||
use miette::Result;
|
||||
use resvg::usvg::fontdb;
|
||||
use tracing::{debug, error};
|
||||
|
||||
use crate::Slide;
|
||||
|
@ -17,13 +18,13 @@ use super::videos::Video;
|
|||
|
||||
use super::kinds::ServiceItemKind;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ServiceItem {
|
||||
pub id: i32,
|
||||
pub title: String,
|
||||
pub database_id: i32,
|
||||
pub kind: ServiceItemKind,
|
||||
pub slides: Arc<[Slide]>,
|
||||
pub slides: Vec<Slide>,
|
||||
// pub item: Box<dyn ServiceTrait>,
|
||||
}
|
||||
|
||||
|
@ -121,7 +122,7 @@ impl Default for ServiceItem {
|
|||
title: String::default(),
|
||||
database_id: 0,
|
||||
kind: ServiceItemKind::Content(Slide::default()),
|
||||
slides: Arc::new([]),
|
||||
slides: vec![],
|
||||
// item: Box::new(Image::default()),
|
||||
}
|
||||
}
|
||||
|
@ -171,7 +172,7 @@ impl From<&Value> for ServiceItem {
|
|||
kind: ServiceItemKind::Content(
|
||||
slide.clone(),
|
||||
),
|
||||
slides: Arc::new([slide]),
|
||||
slides: vec![slide],
|
||||
}
|
||||
} else if let Some(background) =
|
||||
list.get(background_pos)
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
use crisp::types::{Keyword, Symbol, Value};
|
||||
use iced_video_player::Video;
|
||||
use miette::{miette, Result};
|
||||
use resvg::usvg::fontdb;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fmt::Display,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use tracing::error;
|
||||
|
||||
|
@ -13,6 +15,40 @@ use crate::ui::text_svg::{self, TextSvg};
|
|||
|
||||
use super::songs::Song;
|
||||
|
||||
#[derive(
|
||||
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
|
||||
)]
|
||||
pub struct Slide {
|
||||
id: i32,
|
||||
background: Background,
|
||||
text: String,
|
||||
font: String,
|
||||
font_size: i32,
|
||||
text_alignment: TextAlignment,
|
||||
audio: Option<PathBuf>,
|
||||
video_loop: bool,
|
||||
video_start_time: f32,
|
||||
video_end_time: f32,
|
||||
#[serde(skip)]
|
||||
pub text_svg: Option<TextSvg>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||
)]
|
||||
pub enum BackgroundKind {
|
||||
#[default]
|
||||
Image,
|
||||
Video,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
struct Image {
|
||||
pub source: String,
|
||||
pub fit: String,
|
||||
pub children: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
|
@ -203,15 +239,6 @@ impl Display for ParseError {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||
)]
|
||||
pub enum BackgroundKind {
|
||||
#[default]
|
||||
Image,
|
||||
Video,
|
||||
}
|
||||
|
||||
impl From<String> for BackgroundKind {
|
||||
fn from(value: String) -> Self {
|
||||
if value == "image" {
|
||||
|
@ -222,24 +249,6 @@ impl From<String> for BackgroundKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
|
||||
)]
|
||||
pub struct Slide {
|
||||
id: i32,
|
||||
background: Background,
|
||||
text: String,
|
||||
font: String,
|
||||
font_size: i32,
|
||||
text_alignment: TextAlignment,
|
||||
audio: Option<PathBuf>,
|
||||
video_loop: bool,
|
||||
video_start_time: f32,
|
||||
video_end_time: f32,
|
||||
#[serde(skip)]
|
||||
pub text_svg: TextSvg,
|
||||
}
|
||||
|
||||
impl From<&Slide> for Value {
|
||||
fn from(value: &Slide) -> Self {
|
||||
Self::List(vec![Self::Symbol(Symbol("slide".into()))])
|
||||
|
@ -252,6 +261,11 @@ impl Slide {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn with_text_svg(mut self, text_svg: TextSvg) -> Self {
|
||||
self.text_svg = Some(text_svg);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_font(mut self, font: impl AsRef<str>) -> Self {
|
||||
self.font = font.as_ref().into();
|
||||
self
|
||||
|
@ -275,6 +289,10 @@ impl Slide {
|
|||
self.text.clone()
|
||||
}
|
||||
|
||||
pub fn text_alignment(&self) -> TextAlignment {
|
||||
self.text_alignment.clone()
|
||||
}
|
||||
|
||||
pub fn font_size(&self) -> i32 {
|
||||
self.font_size
|
||||
}
|
||||
|
@ -614,7 +632,6 @@ impl SlideBuilder {
|
|||
let Some(video_end_time) = self.video_end_time else {
|
||||
return Err(miette!("No video_end_time"));
|
||||
};
|
||||
if let Some(text_svg) = self.text_svg {
|
||||
Ok(Slide {
|
||||
background,
|
||||
text,
|
||||
|
@ -625,42 +642,10 @@ impl SlideBuilder {
|
|||
video_loop,
|
||||
video_start_time,
|
||||
video_end_time,
|
||||
text_svg,
|
||||
..Default::default()
|
||||
})
|
||||
} else {
|
||||
let text_svg = TextSvg::new(text.clone())
|
||||
.alignment(text_alignment)
|
||||
.fill("#fff")
|
||||
.shadow(text_svg::shadow(2, 2, 5, "#000000"))
|
||||
.stroke(text_svg::stroke(3, "#000"))
|
||||
.font(
|
||||
text_svg::Font::from(font.clone())
|
||||
.size(font_size.try_into().unwrap()),
|
||||
)
|
||||
.build();
|
||||
Ok(Slide {
|
||||
background,
|
||||
text,
|
||||
font,
|
||||
font_size,
|
||||
text_alignment,
|
||||
audio: self.audio,
|
||||
video_loop,
|
||||
video_start_time,
|
||||
video_end_time,
|
||||
text_svg,
|
||||
text_svg: self.text_svg,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
struct Image {
|
||||
pub source: String,
|
||||
pub fit: String,
|
||||
pub children: Vec<String>,
|
||||
}
|
||||
|
||||
impl Image {
|
||||
|
|
488
src/main.rs
488
src/main.rs
|
@ -28,8 +28,10 @@ use crisp::types::Value;
|
|||
use lisp::parse_lisp;
|
||||
use miette::{miette, Result};
|
||||
use rayon::prelude::*;
|
||||
use resvg::usvg::fontdb;
|
||||
use std::fs::read_to_string;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tracing::{debug, level_filters::LevelFilter};
|
||||
use tracing::{error, warn};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
@ -38,6 +40,8 @@ use ui::presenter::{self, Presenter};
|
|||
use ui::song_editor::{self, SongEditor};
|
||||
use ui::EditorMode;
|
||||
|
||||
use crate::ui::text_svg;
|
||||
|
||||
pub mod core;
|
||||
pub mod lisp;
|
||||
pub mod ui;
|
||||
|
@ -111,6 +115,7 @@ struct App {
|
|||
song_editor: SongEditor,
|
||||
searching: bool,
|
||||
library_dragged_item: Option<ServiceItem>,
|
||||
fontdb: Arc<fontdb::Database>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -137,6 +142,7 @@ enum Message {
|
|||
AddServiceItem(usize, ServiceItem),
|
||||
AddServiceItemDrop(usize),
|
||||
AppendServiceItem(ServiceItem),
|
||||
AddService(Vec<ServiceItem>),
|
||||
}
|
||||
|
||||
const HEADER_SPACE: u16 = 6;
|
||||
|
@ -159,6 +165,10 @@ impl cosmic::Application for App {
|
|||
debug!("init");
|
||||
let nav_model = nav_bar::Model::default();
|
||||
|
||||
let mut fontdb = fontdb::Database::new();
|
||||
fontdb.load_system_fonts();
|
||||
let fontdb = Arc::new(fontdb);
|
||||
|
||||
let mut windows = vec![];
|
||||
|
||||
if input.ui {
|
||||
|
@ -167,7 +177,7 @@ impl cosmic::Application for App {
|
|||
|
||||
let items = match read_to_string(input.file) {
|
||||
Ok(lisp) => {
|
||||
let mut slide_vector = vec![];
|
||||
let mut service_items = vec![];
|
||||
let lisp = crisp::reader::read(&lisp);
|
||||
match lisp {
|
||||
Value::List(vec) => {
|
||||
|
@ -178,12 +188,12 @@ impl cosmic::Application for App {
|
|||
// slide_vector.append(items);
|
||||
for value in vec {
|
||||
let mut inner_vector = parse_lisp(value);
|
||||
slide_vector.append(&mut inner_vector);
|
||||
service_items.append(&mut inner_vector);
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
slide_vector
|
||||
service_items
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Missing file or could not read: {e}");
|
||||
|
@ -191,20 +201,37 @@ impl cosmic::Application for App {
|
|||
}
|
||||
};
|
||||
|
||||
let items: Vec<ServiceItem> = items
|
||||
.into_par_iter()
|
||||
.map(|mut item| {
|
||||
item.slides = item
|
||||
.slides
|
||||
.into_par_iter()
|
||||
.map(|mut slide| {
|
||||
text_svg::text_svg_generator(
|
||||
&mut slide,
|
||||
Arc::clone(&fontdb),
|
||||
);
|
||||
slide
|
||||
})
|
||||
.collect();
|
||||
item
|
||||
})
|
||||
.collect();
|
||||
|
||||
let presenter = Presenter::with_items(items.clone());
|
||||
let song_editor = SongEditor::new();
|
||||
let song_editor = SongEditor::new(Arc::clone(&fontdb));
|
||||
|
||||
// for item in items.iter() {
|
||||
// nav_model.insert().text(item.title()).data(item.clone());
|
||||
// }
|
||||
|
||||
// nav_model.activate_position(0);
|
||||
|
||||
let mut app = App {
|
||||
presenter,
|
||||
core,
|
||||
nav_model,
|
||||
service: items,
|
||||
service: items.clone(),
|
||||
file: PathBuf::default(),
|
||||
windows,
|
||||
presentation_open: false,
|
||||
|
@ -217,6 +244,7 @@ impl cosmic::Application for App {
|
|||
searching: false,
|
||||
current_item: (0, 0),
|
||||
library_dragged_item: None,
|
||||
fontdb: Arc::clone(&fontdb),
|
||||
};
|
||||
|
||||
let mut batch = vec![];
|
||||
|
@ -230,160 +258,160 @@ impl cosmic::Application for App {
|
|||
};
|
||||
|
||||
batch.push(app.add_library());
|
||||
// batch.push(app.add_service(items));
|
||||
// batch.push(app.add_service(items, Arc::clone(&fontdb)));
|
||||
let batch = Task::batch(batch);
|
||||
(app, batch)
|
||||
}
|
||||
|
||||
/// Allows COSMIC to integrate with your application's [`nav_bar::Model`].
|
||||
fn nav_model(&self) -> Option<&nav_bar::Model> {
|
||||
Some(&self.nav_model)
|
||||
}
|
||||
// /// Allows COSMIC to integrate with your application's [`nav_bar::Model`].
|
||||
// fn nav_model(&self) -> Option<&nav_bar::Model> {
|
||||
// Some(&self.nav_model)
|
||||
// }
|
||||
|
||||
fn nav_bar(&self) -> Option<Element<cosmic::Action<Message>>> {
|
||||
if !self.core().nav_bar_active() {
|
||||
return None;
|
||||
}
|
||||
// fn nav_bar(&self) -> Option<Element<cosmic::Action<Message>>> {
|
||||
// if !self.core().nav_bar_active() {
|
||||
// return None;
|
||||
// }
|
||||
|
||||
// let nav_model = self.nav_model()?;
|
||||
// // let nav_model = self.nav_model()?;
|
||||
|
||||
// let mut nav = cosmic::widget::nav_bar(nav_model, |id| {
|
||||
// cosmic::Action::Cosmic(cosmic::app::Action::NavBar(id))
|
||||
// // let mut nav = cosmic::widget::nav_bar(nav_model, |id| {
|
||||
// // cosmic::Action::Cosmic(cosmic::app::Action::NavBar(id))
|
||||
// // })
|
||||
// // .on_dnd_drop::<ServiceItem>(|entity, data, action| {
|
||||
// // debug!(?entity);
|
||||
// // debug!(?data);
|
||||
// // debug!(?action);
|
||||
// // cosmic::Action::App(Message::DndDrop)
|
||||
// // })
|
||||
// // .on_dnd_enter(|entity, data| {
|
||||
// // debug!("entered");
|
||||
// // cosmic::Action::App(Message::DndEnter(entity, data))
|
||||
// // })
|
||||
// // .on_dnd_leave(|entity| {
|
||||
// // debug!("left");
|
||||
// // cosmic::Action::App(Message::DndLeave(entity))
|
||||
// // })
|
||||
// // .drag_id(DragId::new())
|
||||
// // .on_context(|id| {
|
||||
// // cosmic::Action::Cosmic(
|
||||
// // cosmic::app::Action::NavBarContext(id),
|
||||
// // )
|
||||
// // })
|
||||
// // .context_menu(None)
|
||||
// // .into_container()
|
||||
// // // XXX both must be shrink to avoid flex layout from ignoring it
|
||||
// // .width(Length::Shrink)
|
||||
// // .height(Length::Shrink);
|
||||
|
||||
// let list = self
|
||||
// .service
|
||||
// .iter()
|
||||
// .enumerate()
|
||||
// .map(|(index, item)| {
|
||||
// let button = button::standard(item.title.clone())
|
||||
// .leading_icon({
|
||||
// match item.kind {
|
||||
// core::kinds::ServiceItemKind::Song(_) => {
|
||||
// icon::from_name("folder-music-symbolic")
|
||||
// },
|
||||
// core::kinds::ServiceItemKind::Video(_) => {
|
||||
// icon::from_name("folder-videos-symbolic")
|
||||
// },
|
||||
// core::kinds::ServiceItemKind::Image(_) => {
|
||||
// icon::from_name("folder-pictures-symbolic")
|
||||
// },
|
||||
// core::kinds::ServiceItemKind::Presentation(_) => {
|
||||
// icon::from_name("x-office-presentation-symbolic")
|
||||
// },
|
||||
// core::kinds::ServiceItemKind::Content(_) => {
|
||||
// icon::from_name("x-office-presentation-symbolic")
|
||||
// },
|
||||
// }
|
||||
// })
|
||||
// .on_dnd_drop::<ServiceItem>(|entity, data, action| {
|
||||
// debug!(?entity);
|
||||
// debug!(?data);
|
||||
// debug!(?action);
|
||||
// cosmic::Action::App(Message::DndDrop)
|
||||
// .class(cosmic::theme::style::Button::HeaderBar)
|
||||
// .padding(5)
|
||||
// .width(Length::Fill)
|
||||
// .on_press(cosmic::Action::App(Message::ChangeServiceItem(index)));
|
||||
// let tooltip = tooltip(button,
|
||||
// text::body(item.kind.to_string()),
|
||||
// TPosition::Right);
|
||||
// dnd_destination(tooltip, vec!["application/service-item".into()])
|
||||
// .data_received_for::<ServiceItem>( move |item| {
|
||||
// if let Some(item) = item {
|
||||
// cosmic::Action::App(Message::AddServiceItem(index, item))
|
||||
// } else {
|
||||
// cosmic::Action::None
|
||||
// }
|
||||
// }).on_drop(move |x, y| {
|
||||
// debug!(x, y);
|
||||
// cosmic::Action::App(Message::AddServiceItemDrop(index))
|
||||
// }).on_finish(move |mime, data, action, x, y| {
|
||||
// debug!(mime, ?data, ?action, x, y);
|
||||
// let Ok(item) = ServiceItem::try_from((data, mime)) else {
|
||||
// return cosmic::Action::None;
|
||||
// };
|
||||
// debug!(?item);
|
||||
// cosmic::Action::App(Message::AddServiceItem(index, item))
|
||||
// })
|
||||
// .on_dnd_enter(|entity, data| {
|
||||
// debug!("entered");
|
||||
// cosmic::Action::App(Message::DndEnter(entity, data))
|
||||
// })
|
||||
// .on_dnd_leave(|entity| {
|
||||
// debug!("left");
|
||||
// cosmic::Action::App(Message::DndLeave(entity))
|
||||
// })
|
||||
// .drag_id(DragId::new())
|
||||
// .on_context(|id| {
|
||||
// cosmic::Action::Cosmic(
|
||||
// cosmic::app::Action::NavBarContext(id),
|
||||
// .into()
|
||||
// });
|
||||
|
||||
// let end_index = self.service.len();
|
||||
// let column = column![
|
||||
// text::heading("Service List").center().width(280),
|
||||
// column(list).spacing(10),
|
||||
// dnd_destination(
|
||||
// vertical_space(),
|
||||
// vec!["application/service-item".into()]
|
||||
// )
|
||||
// .data_received_for::<ServiceItem>(|item| {
|
||||
// if let Some(item) = item {
|
||||
// cosmic::Action::App(Message::AppendServiceItem(
|
||||
// item,
|
||||
// ))
|
||||
// } else {
|
||||
// cosmic::Action::None
|
||||
// }
|
||||
// })
|
||||
// .context_menu(None)
|
||||
// .into_container()
|
||||
// // XXX both must be shrink to avoid flex layout from ignoring it
|
||||
// .width(Length::Shrink)
|
||||
// .height(Length::Shrink);
|
||||
// .on_finish(
|
||||
// move |mime, data, action, x, y| {
|
||||
// debug!(mime, ?data, ?action, x, y);
|
||||
// let Ok(item) =
|
||||
// ServiceItem::try_from((data, mime))
|
||||
// else {
|
||||
// return cosmic::Action::None;
|
||||
// };
|
||||
// debug!(?item);
|
||||
// cosmic::Action::App(Message::AddServiceItem(
|
||||
// end_index, item,
|
||||
// ))
|
||||
// }
|
||||
// )
|
||||
// ]
|
||||
// .padding(10)
|
||||
// .spacing(10);
|
||||
// let padding = Padding::new(0.0).top(20);
|
||||
// let mut container = Container::new(column)
|
||||
// // .height(Length::Fill)
|
||||
// .style(nav_bar_style)
|
||||
// .padding(padding);
|
||||
|
||||
let list = self
|
||||
.service
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, item)| {
|
||||
let button = button::standard(item.title.clone())
|
||||
.leading_icon({
|
||||
match item.kind {
|
||||
core::kinds::ServiceItemKind::Song(_) => {
|
||||
icon::from_name("folder-music-symbolic")
|
||||
},
|
||||
core::kinds::ServiceItemKind::Video(_) => {
|
||||
icon::from_name("folder-videos-symbolic")
|
||||
},
|
||||
core::kinds::ServiceItemKind::Image(_) => {
|
||||
icon::from_name("folder-pictures-symbolic")
|
||||
},
|
||||
core::kinds::ServiceItemKind::Presentation(_) => {
|
||||
icon::from_name("x-office-presentation-symbolic")
|
||||
},
|
||||
core::kinds::ServiceItemKind::Content(_) => {
|
||||
icon::from_name("x-office-presentation-symbolic")
|
||||
},
|
||||
}
|
||||
})
|
||||
.class(cosmic::theme::style::Button::HeaderBar)
|
||||
.padding(5)
|
||||
.width(Length::Fill)
|
||||
.on_press(cosmic::Action::App(Message::ChangeServiceItem(index)));
|
||||
let tooltip = tooltip(button,
|
||||
text::body(item.kind.to_string()),
|
||||
TPosition::Right);
|
||||
dnd_destination(tooltip, vec!["application/service-item".into()])
|
||||
.data_received_for::<ServiceItem>( move |item| {
|
||||
if let Some(item) = item {
|
||||
cosmic::Action::App(Message::AddServiceItem(index, item))
|
||||
} else {
|
||||
cosmic::Action::None
|
||||
}
|
||||
}).on_drop(move |x, y| {
|
||||
debug!(x, y);
|
||||
cosmic::Action::App(Message::AddServiceItemDrop(index))
|
||||
}).on_finish(move |mime, data, action, x, y| {
|
||||
debug!(mime, ?data, ?action, x, y);
|
||||
let Ok(item) = ServiceItem::try_from((data, mime)) else {
|
||||
return cosmic::Action::None;
|
||||
};
|
||||
debug!(?item);
|
||||
cosmic::Action::App(Message::AddServiceItem(index, item))
|
||||
})
|
||||
.into()
|
||||
});
|
||||
|
||||
let end_index = self.service.len();
|
||||
let column = column![
|
||||
text::heading("Service List").center().width(280),
|
||||
column(list).spacing(10),
|
||||
dnd_destination(
|
||||
vertical_space(),
|
||||
vec!["application/service-item".into()]
|
||||
)
|
||||
.data_received_for::<ServiceItem>(|item| {
|
||||
if let Some(item) = item {
|
||||
cosmic::Action::App(Message::AppendServiceItem(
|
||||
item,
|
||||
))
|
||||
} else {
|
||||
cosmic::Action::None
|
||||
}
|
||||
})
|
||||
.on_finish(
|
||||
move |mime, data, action, x, y| {
|
||||
debug!(mime, ?data, ?action, x, y);
|
||||
let Ok(item) =
|
||||
ServiceItem::try_from((data, mime))
|
||||
else {
|
||||
return cosmic::Action::None;
|
||||
};
|
||||
debug!(?item);
|
||||
cosmic::Action::App(Message::AddServiceItem(
|
||||
end_index, item,
|
||||
))
|
||||
}
|
||||
)
|
||||
]
|
||||
.padding(10)
|
||||
.spacing(10);
|
||||
let padding = Padding::new(0.0).top(20);
|
||||
let mut container = Container::new(column)
|
||||
// .height(Length::Fill)
|
||||
.style(nav_bar_style)
|
||||
.padding(padding);
|
||||
|
||||
if !self.core().is_condensed() {
|
||||
container = container.max_width(280);
|
||||
}
|
||||
Some(container.into())
|
||||
}
|
||||
// if !self.core().is_condensed() {
|
||||
// container = container.max_width(280);
|
||||
// }
|
||||
// Some(container.into())
|
||||
// }
|
||||
|
||||
/// Called when a navigation item is selected.
|
||||
fn on_nav_select(
|
||||
&mut self,
|
||||
id: nav_bar::Id,
|
||||
) -> Task<Self::Message> {
|
||||
self.nav_model.activate(id);
|
||||
// debug!(?id);
|
||||
self.update_title()
|
||||
}
|
||||
// fn on_nav_select(
|
||||
// &mut self,
|
||||
// id: nav_bar::Id,
|
||||
// ) -> Task<Self::Message> {
|
||||
// self.nav_model.activate(id);
|
||||
// // debug!(?id);
|
||||
// self.update_title()
|
||||
// }
|
||||
|
||||
fn header_start(&self) -> Vec<Element<Self::Message>> {
|
||||
vec![]
|
||||
|
@ -917,6 +945,10 @@ impl cosmic::Application for App {
|
|||
self.library = Some(library);
|
||||
Task::none()
|
||||
}
|
||||
Message::AddService(service) => {
|
||||
self.service = service;
|
||||
Task::none()
|
||||
}
|
||||
Message::None => Task::none(),
|
||||
Message::DndLeave(entity) => {
|
||||
// debug!(?entity);
|
||||
|
@ -1032,14 +1064,23 @@ impl cosmic::Application for App {
|
|||
]
|
||||
.spacing(3);
|
||||
|
||||
let service_list = Container::new(self.service_list())
|
||||
.padding(5)
|
||||
.width(Length::FillPortion(2));
|
||||
|
||||
let library = if self.library_open {
|
||||
Container::new(if let Some(library) = &self.library {
|
||||
Container::new(
|
||||
Container::new(
|
||||
if let Some(library) = &self.library {
|
||||
library.view().map(Message::Library)
|
||||
} else {
|
||||
Space::new(0, 0).into()
|
||||
})
|
||||
.style(nav_bar_style)
|
||||
.center(Length::FillPortion(2))
|
||||
},
|
||||
)
|
||||
.style(nav_bar_style),
|
||||
)
|
||||
.padding(5)
|
||||
.width(Length::FillPortion(2))
|
||||
} else {
|
||||
Container::new(horizontal_space().width(0))
|
||||
};
|
||||
|
@ -1048,6 +1089,8 @@ impl cosmic::Application for App {
|
|||
self.song_editor.view().map(Message::SongEditor);
|
||||
|
||||
let row = row![
|
||||
library,
|
||||
service_list,
|
||||
Container::new(
|
||||
button::icon(icon_left)
|
||||
.icon_size(128)
|
||||
|
@ -1075,7 +1118,6 @@ impl cosmic::Application for App {
|
|||
)
|
||||
.center_y(Length::Fill)
|
||||
.align_left(Length::FillPortion(1)),
|
||||
library
|
||||
]
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
|
@ -1145,28 +1187,35 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
// fn add_service(
|
||||
// &mut self,
|
||||
// items: Vec<ServiceItem>,
|
||||
// ) -> Task<Message> {
|
||||
// Task::perform(
|
||||
// async move {
|
||||
// for item in items {
|
||||
// debug!(?item, "Item to be appended");
|
||||
// let slides = item.to_slides().unwrap_or(vec![]);
|
||||
// map.insert(item, slides);
|
||||
// }
|
||||
// let len = map.len();
|
||||
// debug!(len, "to be append: ");
|
||||
// map
|
||||
// },
|
||||
// |x| {
|
||||
// let len = x.len();
|
||||
// debug!(len, "to append: ");
|
||||
// cosmic::Action::App(Message::AppendService(x))
|
||||
// },
|
||||
// )
|
||||
// }
|
||||
fn add_service(
|
||||
&mut self,
|
||||
items: Vec<ServiceItem>,
|
||||
fontdb: Arc<fontdb::Database>,
|
||||
) -> Task<Message> {
|
||||
Task::perform(
|
||||
async move {
|
||||
let items: Vec<ServiceItem> = items
|
||||
.into_par_iter()
|
||||
.map(|mut item| {
|
||||
item.slides = item
|
||||
.slides
|
||||
.into_par_iter()
|
||||
.map(|mut slide| {
|
||||
text_svg::text_svg_generator(
|
||||
&mut slide,
|
||||
Arc::clone(&fontdb),
|
||||
);
|
||||
slide
|
||||
})
|
||||
.collect();
|
||||
item
|
||||
})
|
||||
.collect();
|
||||
items
|
||||
},
|
||||
|x| cosmic::Action::App(Message::AddService(x)),
|
||||
)
|
||||
}
|
||||
|
||||
fn process_key_press(
|
||||
&mut self,
|
||||
|
@ -1212,6 +1261,99 @@ where
|
|||
_ => Task::none(),
|
||||
}
|
||||
}
|
||||
|
||||
fn service_list(&self) -> Element<Message> {
|
||||
let list = self
|
||||
.service
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, item)| {
|
||||
let button = button::standard(item.title.clone())
|
||||
.leading_icon({
|
||||
match item.kind {
|
||||
core::kinds::ServiceItemKind::Song(_) => {
|
||||
icon::from_name("folder-music-symbolic")
|
||||
},
|
||||
core::kinds::ServiceItemKind::Video(_) => {
|
||||
icon::from_name("folder-videos-symbolic")
|
||||
},
|
||||
core::kinds::ServiceItemKind::Image(_) => {
|
||||
icon::from_name("folder-pictures-symbolic")
|
||||
},
|
||||
core::kinds::ServiceItemKind::Presentation(_) => {
|
||||
icon::from_name("x-office-presentation-symbolic")
|
||||
},
|
||||
core::kinds::ServiceItemKind::Content(_) => {
|
||||
icon::from_name("x-office-presentation-symbolic")
|
||||
},
|
||||
}
|
||||
})
|
||||
.class(cosmic::theme::style::Button::HeaderBar)
|
||||
.padding(5)
|
||||
.width(Length::Fill)
|
||||
.on_press(Message::ChangeServiceItem(index));
|
||||
let tooltip = tooltip(button,
|
||||
text::body(item.kind.to_string()),
|
||||
TPosition::Right);
|
||||
dnd_destination(tooltip, vec!["application/service-item".into()])
|
||||
.data_received_for::<ServiceItem>( move |item| {
|
||||
if let Some(item) = item {
|
||||
Message::AddServiceItem(index, item)
|
||||
} else {
|
||||
Message::None
|
||||
}
|
||||
}).on_drop(move |x, y| {
|
||||
debug!(x, y);
|
||||
Message::AddServiceItemDrop(index)
|
||||
}).on_finish(move |mime, data, action, x, y| {
|
||||
debug!(mime, ?data, ?action, x, y);
|
||||
let Ok(item) = ServiceItem::try_from((data, mime)) else {
|
||||
return Message::None;
|
||||
};
|
||||
debug!(?item);
|
||||
Message::AddServiceItem(index, item)
|
||||
})
|
||||
.into()
|
||||
});
|
||||
|
||||
let end_index = self.service.len();
|
||||
let column = column![
|
||||
text::heading("Service List")
|
||||
.center()
|
||||
.width(Length::Fill),
|
||||
iced::widget::horizontal_rule(1),
|
||||
column(list).spacing(10),
|
||||
dnd_destination(
|
||||
vertical_space(),
|
||||
vec!["application/service-item".into()]
|
||||
)
|
||||
.data_received_for::<ServiceItem>(|item| {
|
||||
item.map_or_else(
|
||||
|| Message::None,
|
||||
|item| Message::AppendServiceItem(item),
|
||||
)
|
||||
})
|
||||
.on_finish(
|
||||
move |mime, data, action, x, y| {
|
||||
debug!(mime, ?data, ?action, x, y);
|
||||
let Ok(item) =
|
||||
ServiceItem::try_from((data, mime))
|
||||
else {
|
||||
return Message::None;
|
||||
};
|
||||
debug!(?item);
|
||||
Message::AddServiceItem(end_index, item)
|
||||
}
|
||||
)
|
||||
]
|
||||
.padding(10)
|
||||
.spacing(10);
|
||||
let mut container = Container::new(column)
|
||||
// .height(Length::Fill)
|
||||
.style(nav_bar_style);
|
||||
|
||||
container.center(Length::FillPortion(2)).into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -264,12 +264,18 @@ impl<'a> Library {
|
|||
let presentation_library =
|
||||
self.library_item(&self.presentation_library);
|
||||
let column = column![
|
||||
text::heading("Library").center().width(Length::Fill),
|
||||
cosmic::iced::widget::horizontal_rule(1),
|
||||
song_library,
|
||||
image_library,
|
||||
video_library,
|
||||
presentation_library,
|
||||
];
|
||||
column.height(Length::Fill).spacing(5).into()
|
||||
]
|
||||
.height(Length::Fill)
|
||||
.padding(10)
|
||||
.spacing(10)
|
||||
.into();
|
||||
column
|
||||
}
|
||||
|
||||
pub fn library_item<T>(
|
||||
|
@ -454,14 +460,45 @@ impl<'a> Library {
|
|||
}))
|
||||
.center_y(20)
|
||||
.center_x(Length::Fill);
|
||||
let subtext = container(responsive(|size| {
|
||||
let subtext = container(responsive(move |size| {
|
||||
let color: Color = if item.background().is_some() {
|
||||
theme::active().cosmic().accent_text_color().into()
|
||||
if let Some((library, selected)) = self.selected_item
|
||||
{
|
||||
if model.kind == library
|
||||
&& selected == index as i32
|
||||
{
|
||||
theme::active().cosmic().control_0().into()
|
||||
} else {
|
||||
theme::active()
|
||||
.cosmic()
|
||||
.accent_text_color()
|
||||
.into()
|
||||
}
|
||||
} else {
|
||||
theme::active()
|
||||
.cosmic()
|
||||
.accent_text_color()
|
||||
.into()
|
||||
}
|
||||
} else {
|
||||
if let Some((library, selected)) = self.selected_item
|
||||
{
|
||||
if model.kind == library
|
||||
&& selected == index as i32
|
||||
{
|
||||
theme::active().cosmic().control_0().into()
|
||||
} else {
|
||||
theme::active()
|
||||
.cosmic()
|
||||
.destructive_text_color()
|
||||
.into()
|
||||
}
|
||||
} else {
|
||||
theme::active()
|
||||
.cosmic()
|
||||
.destructive_text_color()
|
||||
.into()
|
||||
}
|
||||
};
|
||||
text::body(elide_text(item.subtext(), size.width))
|
||||
.center()
|
||||
|
@ -491,9 +528,21 @@ impl<'a> Library {
|
|||
&& selected == index as i32
|
||||
{
|
||||
t.cosmic().accent.selected.into()
|
||||
} else {
|
||||
if let Some((library, hovered)) =
|
||||
self.hovered_item
|
||||
{
|
||||
if model.kind == library
|
||||
&& hovered == index as i32
|
||||
{
|
||||
t.cosmic().button.hover.into()
|
||||
} else {
|
||||
t.cosmic().button.base.into()
|
||||
}
|
||||
} else {
|
||||
t.cosmic().button.base.into()
|
||||
}
|
||||
}
|
||||
} else if let Some((library, hovered)) =
|
||||
self.hovered_item
|
||||
{
|
||||
|
@ -513,6 +562,7 @@ impl<'a> Library {
|
|||
.rounded(t.cosmic().corner_radii.radius_m),
|
||||
)
|
||||
})
|
||||
.padding([3, 0])
|
||||
.into()
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ use cosmic::{
|
|||
prelude::*,
|
||||
widget::{
|
||||
container, image, mouse_area, responsive, scrollable, text,
|
||||
Column, Container, Id, Row, Space,
|
||||
Column, Container, Id, Image, Row, Space,
|
||||
},
|
||||
Task,
|
||||
};
|
||||
|
@ -30,7 +30,7 @@ use url::Url;
|
|||
|
||||
use crate::{
|
||||
core::{service_items::ServiceItem, slide::Slide},
|
||||
// ui::widgets::slide_text,
|
||||
ui::text_svg,
|
||||
BackgroundKind,
|
||||
};
|
||||
|
||||
|
@ -132,7 +132,9 @@ impl Presenter {
|
|||
Some(v)
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Had an error creating the video object: {e}, likely the first slide isn't a video");
|
||||
error!(
|
||||
"Had an error creating the video object: {e}, likely the first slide isn't a video"
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -148,6 +150,7 @@ impl Presenter {
|
|||
};
|
||||
let total_slides: usize =
|
||||
items.iter().fold(0, |a, item| a + item.slides.len());
|
||||
|
||||
Self {
|
||||
current_slide: items[0].slides[0].clone(),
|
||||
current_item: 0,
|
||||
|
@ -377,7 +380,7 @@ impl Presenter {
|
|||
self.hovered_slide = slide;
|
||||
}
|
||||
Message::StartAudio => {
|
||||
return Action::Task(self.start_audio())
|
||||
return Action::Task(self.start_audio());
|
||||
}
|
||||
Message::EndAudio => {
|
||||
self.sink.1.stop();
|
||||
|
@ -640,7 +643,9 @@ impl Presenter {
|
|||
self.video = Some(v)
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Had an error creating the video object: {e}");
|
||||
error!(
|
||||
"Had an error creating the video object: {e}"
|
||||
);
|
||||
self.video = None;
|
||||
}
|
||||
}
|
||||
|
@ -702,50 +707,8 @@ pub(crate) fn slide_view(
|
|||
let slide_text = slide.text();
|
||||
|
||||
// let font = SvgFont::from(font).size(font_size.floor() as u8);
|
||||
let text_container = if delegate {
|
||||
// text widget based
|
||||
let font_size =
|
||||
scale_font(slide.font_size() as f32, width);
|
||||
let lines = slide_text.lines();
|
||||
let text: Vec<Element<Message>> = lines
|
||||
.map(|t| {
|
||||
rich_text([span(format!("{}\n", t))
|
||||
.background(
|
||||
Background::Color(Color::BLACK)
|
||||
.scale_alpha(0.4),
|
||||
)
|
||||
.border(border::rounded(10))
|
||||
.padding(10)])
|
||||
.size(font_size)
|
||||
.font(font)
|
||||
.center()
|
||||
.into()
|
||||
// let chars: Vec<Span> = t
|
||||
// .chars()
|
||||
// .map(|c| -> Span {
|
||||
// let character: String = format!("{}/n", c);
|
||||
// span(character)
|
||||
// .size(font_size)
|
||||
// .font(font)
|
||||
// .background(
|
||||
// Background::Color(Color::BLACK)
|
||||
// .scale_alpha(0.4),
|
||||
// )
|
||||
// .border(border::rounded(10))
|
||||
// .padding(10)
|
||||
})
|
||||
.collect();
|
||||
let text = Column::with_children(text).spacing(26);
|
||||
Container::new(text)
|
||||
.center(Length::Fill)
|
||||
.align_x(Horizontal::Left)
|
||||
} else {
|
||||
// SVG based
|
||||
let text = slide.text_svg.view().map(|m| Message::None);
|
||||
Container::new(text)
|
||||
.center(Length::Fill)
|
||||
.align_x(Horizontal::Left)
|
||||
// text widget based
|
||||
// let text_container = if delegate {
|
||||
// // text widget based
|
||||
// let font_size =
|
||||
// scale_font(slide.font_size() as f32, width);
|
||||
// let lines = slide_text.lines();
|
||||
|
@ -781,7 +744,63 @@ pub(crate) fn slide_view(
|
|||
// Container::new(text)
|
||||
// .center(Length::Fill)
|
||||
// .align_x(Horizontal::Left)
|
||||
};
|
||||
// } else {
|
||||
// // SVG based
|
||||
// let text: Element<Message> =
|
||||
// if let Some(text) = &slide.text_svg {
|
||||
// if let Some(handle) = &text.handle {
|
||||
// debug!("we made it boys");
|
||||
// Image::new(handle)
|
||||
// .content_fit(ContentFit::Cover)
|
||||
// .width(Length::Fill)
|
||||
// .height(Length::Fill)
|
||||
// .into()
|
||||
// } else {
|
||||
// Space::with_width(0).into()
|
||||
// }
|
||||
// } else {
|
||||
// Space::with_width(0).into()
|
||||
// };
|
||||
// Container::new(text)
|
||||
// .center(Length::Fill)
|
||||
// .align_x(Horizontal::Left)
|
||||
// // text widget based
|
||||
// // let font_size =
|
||||
// // scale_font(slide.font_size() as f32, width);
|
||||
// // let lines = slide_text.lines();
|
||||
// // let text: Vec<Element<Message>> = lines
|
||||
// // .map(|t| {
|
||||
// // rich_text([span(format!("{}\n", t))
|
||||
// // .background(
|
||||
// // Background::Color(Color::BLACK)
|
||||
// // .scale_alpha(0.4),
|
||||
// // )
|
||||
// // .border(border::rounded(10))
|
||||
// // .padding(10)])
|
||||
// // .size(font_size)
|
||||
// // .font(font)
|
||||
// // .center()
|
||||
// // .into()
|
||||
// // // let chars: Vec<Span> = t
|
||||
// // // .chars()
|
||||
// // // .map(|c| -> Span {
|
||||
// // // let character: String = format!("{}/n", c);
|
||||
// // // span(character)
|
||||
// // // .size(font_size)
|
||||
// // // .font(font)
|
||||
// // // .background(
|
||||
// // // Background::Color(Color::BLACK)
|
||||
// // // .scale_alpha(0.4),
|
||||
// // // )
|
||||
// // // .border(border::rounded(10))
|
||||
// // // .padding(10)
|
||||
// // })
|
||||
// // .collect();
|
||||
// // let text = Column::with_children(text).spacing(26);
|
||||
// // Container::new(text)
|
||||
// // .center(Length::Fill)
|
||||
// // .align_x(Horizontal::Left)
|
||||
// };
|
||||
|
||||
// let stroke_text_container = Container::new(stroke_text)
|
||||
// .center(Length::Fill)
|
||||
|
@ -789,6 +808,21 @@ pub(crate) fn slide_view(
|
|||
|
||||
// let text_stack =
|
||||
// stack!(stroke_text_container, text_container);
|
||||
|
||||
let text: Element<Message> =
|
||||
if let Some(text) = &slide.text_svg {
|
||||
if let Some(handle) = &text.handle {
|
||||
image(handle)
|
||||
.content_fit(ContentFit::Cover)
|
||||
.width(width)
|
||||
.height(size.height)
|
||||
.into()
|
||||
} else {
|
||||
Space::with_width(0).into()
|
||||
}
|
||||
} else {
|
||||
Space::with_width(0).into()
|
||||
};
|
||||
let black = Container::new(Space::new(0, 0))
|
||||
.style(|_| {
|
||||
container::background(Background::Color(Color::BLACK))
|
||||
|
@ -796,7 +830,7 @@ pub(crate) fn slide_view(
|
|||
.clip(true)
|
||||
.width(width)
|
||||
.height(size.height);
|
||||
let container = match slide.background().kind {
|
||||
let background = match slide.background().kind {
|
||||
BackgroundKind::Image => {
|
||||
let path = slide.background().path.clone();
|
||||
Container::new(
|
||||
|
@ -845,11 +879,8 @@ pub(crate) fn slide_view(
|
|||
}
|
||||
}
|
||||
};
|
||||
let stack = stack!(
|
||||
black,
|
||||
container.center(Length::Fill),
|
||||
text_container
|
||||
);
|
||||
let stack =
|
||||
stack!(black, background.center(Length::Fill), text);
|
||||
Container::new(stack).center(Length::Fill).into()
|
||||
});
|
||||
// let vid = if let Some(video) = &video {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{io, path::PathBuf};
|
||||
use std::{io, path::PathBuf, sync::Arc};
|
||||
|
||||
use cosmic::{
|
||||
dialog::file_chooser::open::Dialog,
|
||||
|
@ -31,7 +31,7 @@ use super::presenter::slide_view;
|
|||
pub struct SongEditor {
|
||||
pub song: Option<Song>,
|
||||
title: String,
|
||||
font_db: fontdb::Database,
|
||||
font_db: Arc<fontdb::Database>,
|
||||
fonts: Vec<(fontdb::ID, String)>,
|
||||
fonts_combo: combo_box::State<String>,
|
||||
font_sizes: combo_box::State<String>,
|
||||
|
@ -72,11 +72,9 @@ pub enum Message {
|
|||
}
|
||||
|
||||
impl SongEditor {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(font_db: Arc<fontdb::Database>) -> Self {
|
||||
let fonts = font_dir();
|
||||
debug!(?fonts);
|
||||
let mut font_db = fontdb::Database::new();
|
||||
font_db.load_system_fonts();
|
||||
let mut fonts: Vec<(fontdb::ID, String)> = font_db
|
||||
.faces()
|
||||
.map(|f| {
|
||||
|
@ -447,7 +445,9 @@ order",
|
|||
|
||||
impl Default for SongEditor {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
let mut fontdb = fontdb::Database::new();
|
||||
fontdb.load_system_fonts();
|
||||
Self::new(Arc::new(fontdb))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +1,29 @@
|
|||
use std::{
|
||||
fmt::Display,
|
||||
hash::{Hash, Hasher},
|
||||
io::Read,
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use colors_transform::Rgb;
|
||||
use cosmic::{
|
||||
iced::{
|
||||
font::{Style, Weight},
|
||||
Length, Size,
|
||||
ContentFit, Length, Size,
|
||||
},
|
||||
prelude::*,
|
||||
widget::{container, svg::Handle, Svg},
|
||||
widget::{container, image::Handle, Image},
|
||||
};
|
||||
use tracing::error;
|
||||
use resvg::{
|
||||
tiny_skia::{self, Pixmap},
|
||||
usvg::{fontdb, Tree},
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
|
||||
use crate::TextAlignment;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct TextSvg {
|
||||
text: String,
|
||||
font: Font,
|
||||
|
@ -24,7 +31,20 @@ pub struct TextSvg {
|
|||
stroke: Option<Stroke>,
|
||||
fill: Color,
|
||||
alignment: TextAlignment,
|
||||
handle: Option<Handle>,
|
||||
pub handle: Option<Handle>,
|
||||
fontdb: Arc<resvg::usvg::fontdb::Database>,
|
||||
}
|
||||
|
||||
impl PartialEq for TextSvg {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.text == other.text
|
||||
&& self.font == other.font
|
||||
&& self.shadow == other.shadow
|
||||
&& self.stroke == other.stroke
|
||||
&& self.fill == other.fill
|
||||
&& self.alignment == other.alignment
|
||||
&& self.handle == other.handle
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for TextSvg {
|
||||
|
@ -46,6 +66,27 @@ pub struct Font {
|
|||
size: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Hash)]
|
||||
pub struct Shadow {
|
||||
pub offset_x: i16,
|
||||
pub offset_y: i16,
|
||||
pub spread: u16,
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Hash)]
|
||||
pub struct Stroke {
|
||||
size: u16,
|
||||
color: Color,
|
||||
}
|
||||
|
||||
pub enum Message {
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Color(Rgb);
|
||||
|
||||
impl From<cosmic::font::Font> for Font {
|
||||
fn from(value: cosmic::font::Font) -> Self {
|
||||
Self {
|
||||
|
@ -113,9 +154,6 @@ impl Font {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Color(Rgb);
|
||||
|
||||
impl Hash for Color {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.to_css_hex_string().hash(state);
|
||||
|
@ -158,24 +196,6 @@ impl Display for Color {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Hash)]
|
||||
pub struct Shadow {
|
||||
pub offset_x: i16,
|
||||
pub offset_y: i16,
|
||||
pub spread: u16,
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Hash)]
|
||||
pub struct Stroke {
|
||||
size: u16,
|
||||
color: Color,
|
||||
}
|
||||
|
||||
pub enum Message {
|
||||
None,
|
||||
}
|
||||
|
||||
impl TextSvg {
|
||||
pub fn new(text: impl Into<String>) -> Self {
|
||||
Self {
|
||||
|
@ -211,12 +231,33 @@ impl TextSvg {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn fontdb(mut self, fontdb: Arc<fontdb::Database>) -> Self {
|
||||
self.fontdb = fontdb;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn alignment(mut self, alignment: TextAlignment) -> Self {
|
||||
self.alignment = alignment;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(mut self) -> Self {
|
||||
debug!("starting...");
|
||||
|
||||
let mut path = dirs::data_local_dir().unwrap();
|
||||
path.push(PathBuf::from("lumina"));
|
||||
path.push(PathBuf::from("temp"));
|
||||
let file_title =
|
||||
&self.text.lines().next().unwrap().trim_end();
|
||||
path.push(PathBuf::from(file_title));
|
||||
path.set_extension("png");
|
||||
|
||||
if path.exists() {
|
||||
debug!("cached");
|
||||
let handle = Handle::from_path(path);
|
||||
self.handle = Some(handle);
|
||||
return self;
|
||||
}
|
||||
let shadow = if let Some(shadow) = &self.shadow {
|
||||
format!("<filter id=\"shadow\"><feDropShadow dx=\"{}\" dy=\"{}\" stdDeviation=\"{}\" flood-color=\"{}\"/></filter>",
|
||||
shadow.offset_x,
|
||||
|
@ -234,13 +275,13 @@ impl TextSvg {
|
|||
} else {
|
||||
"".into()
|
||||
};
|
||||
let size = Size::new(640.0, 360.0);
|
||||
let size = Size::new(1920.0, 1080.0);
|
||||
let font_size = self.font.size as f32;
|
||||
let total_lines = self.text.lines().count();
|
||||
let half_lines = (total_lines / 2) as f32;
|
||||
let middle_position = size.height / 2.0;
|
||||
let line_spacing = 10.0;
|
||||
let text_and_line_spacing =
|
||||
self.font.size as f32 + line_spacing;
|
||||
let text_and_line_spacing = font_size + line_spacing;
|
||||
let starting_y_position =
|
||||
middle_position - (half_lines * text_and_line_spacing);
|
||||
|
||||
|
@ -264,25 +305,35 @@ impl TextSvg {
|
|||
size.height,
|
||||
shadow,
|
||||
self.font.name,
|
||||
self.font.size,
|
||||
font_size,
|
||||
self.fill, stroke, text);
|
||||
let handle = Handle::from_memory(
|
||||
Box::leak(
|
||||
<std::string::String as Clone>::clone(&final_svg)
|
||||
.into_boxed_str(),
|
||||
debug!("text string built...");
|
||||
let resvg_tree = Tree::from_data(
|
||||
&final_svg.as_bytes(),
|
||||
&resvg::usvg::Options {
|
||||
fontdb: Arc::clone(&self.fontdb),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.as_bytes(),
|
||||
);
|
||||
.expect("Woops mama");
|
||||
debug!("parsed");
|
||||
let transform = tiny_skia::Transform::default();
|
||||
let mut pixmap =
|
||||
Pixmap::new(size.width as u32, size.height as u32)
|
||||
.expect("opops");
|
||||
resvg::render(&resvg_tree, transform, &mut pixmap.as_mut());
|
||||
let _ = pixmap.save_png(&path);
|
||||
|
||||
debug!("rendered");
|
||||
let handle = Handle::from_path(path);
|
||||
self.handle = Some(handle);
|
||||
debug!("stored");
|
||||
self
|
||||
}
|
||||
|
||||
pub fn view<'a>(&self) -> Element<'a, Message> {
|
||||
container(
|
||||
Svg::new(self.handle.clone().unwrap())
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill),
|
||||
)
|
||||
Image::new(self.handle.clone().unwrap())
|
||||
.content_fit(ContentFit::Cover)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
|
@ -322,6 +373,26 @@ pub fn color(color: impl AsRef<str>) -> Color {
|
|||
Color::from_hex_str(color)
|
||||
}
|
||||
|
||||
pub fn text_svg_generator(
|
||||
slide: &mut crate::core::slide::Slide,
|
||||
fontdb: Arc<fontdb::Database>,
|
||||
) {
|
||||
if slide.text().len() > 0 {
|
||||
let text_svg = TextSvg::new(slide.text())
|
||||
.alignment(slide.text_alignment())
|
||||
.fill("#fff")
|
||||
.shadow(shadow(2, 2, 5, "#000000"))
|
||||
.stroke(stroke(3, "#000"))
|
||||
.font(
|
||||
Font::from(slide.font().clone())
|
||||
.size(slide.font_size().try_into().unwrap()),
|
||||
)
|
||||
.fontdb(Arc::clone(&fontdb))
|
||||
.build();
|
||||
slide.text_svg = Some(text_svg);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
(slide :background (image :source "~/pics/frodo.jpg" :fit fill)
|
||||
(text "This is frodo" :font-size 90))
|
||||
(text "This is frodo" :font-size 140))
|
||||
(slide (video :source "~/vids/test/camprules2024.mp4" :fit contain))
|
||||
(slide (video :source "~/vids/never give up.mkv" :fit contain))
|
||||
(slide (video :source "~/vids/The promise of Rust.mkv" :fit contain))
|
||||
(song :id 7 :author "North Point Worship"
|
||||
:font "Quicksand Bold" :font-size 60
|
||||
:font "Quicksand" :font-size 140
|
||||
:shadow "" :stroke ""
|
||||
:title "Death Was Arrested"
|
||||
:background (image :source "file:///home/chris/nc/tfc/openlp/CMG - Bright Mountains 01.jpg" :fit cover)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
(song :id 7 :author "North Point Worship"
|
||||
:font "Quicksand Bold" :font-size 60
|
||||
:font "Quicksand" :font-size 140
|
||||
:title "Death Was Arrested"
|
||||
:background (image :source "~/nc/tfc/openlp/CMG - Bright Mountains 01.jpg" :fit cover)
|
||||
:text-alignment center
|
||||
|
|
5
todo.org
5
todo.org
|
@ -17,6 +17,11 @@ Actually, what if we just made the svg at load/creation time and stored it in th
|
|||
** SVG performs badly
|
||||
Since SVG's apparently run poorly in iced, instead I'll need to see about either creating a new text element, or teaching Iced to render strokes and shadows on text.
|
||||
|
||||
** Fork Cryoglyph
|
||||
This fork will render text 3 times. Once for the text, once for the stroke, once for the shadow. This will only be used in the slides and therefore should not be much of a performance hit since we will only be render 3 copies of the given text. This should not be bad performance since it's not a large amount of text.
|
||||
|
||||
This also means in our custom widget with our custom fork, we can animate each individually perhaps.
|
||||
|
||||
* TODO [#C] Make the presenter more modular so things are easier to change.
|
||||
|
||||
* TODO Build library to see all available songs, images, videos, presentations, and slides
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue