diff --git a/Cargo.lock b/Cargo.lock index 305276e..5b72c47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,36 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.4" @@ -56,12 +86,60 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "async-channel" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37875bd9915b7d67c2f117ea2c30a0989874d0b2cb694fe25403c85763c0c9e" +dependencies = [ + "concurrent-queue", + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "bindgen" +version = "0.69.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ffcebc3849946a7170a05992aac39da343a90676ab392c51a4280981d6379c2" +dependencies = [ + "bitflags 2.4.0", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.37", + "which", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.4.0" @@ -69,12 +147,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] -name = "cairo-rs" -version = "0.18.2" +name = "bumpalo" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c0466dfa8c0ee78deef390c274ad756801e0a6dbb86c5ef0924a298c5761c4d" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cairo-rs" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f33613627f0dea6a731b0605101fad59ba4f193a52c96c4687728d822605a8a1" dependencies = [ - "bitflags", + "bitflags 2.4.0", "cairo-sys-rs", "glib", "libc", @@ -93,6 +195,24 @@ dependencies = [ "system-deps", ] +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-expr" version = "0.15.5" @@ -103,6 +223,37 @@ dependencies = [ "target-lexicon", ] +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets", +] + +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading 0.7.4", +] + [[package]] name = "clap" version = "4.4.6" @@ -143,18 +294,169 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "colorchoice" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "concurrent-queue" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96b852f1345da36d551b9473fa1e2b1eb5c5195585c6c018118bc92a8d91160" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "exr" +version = "1.71.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "832a761f35ab3e6664babfbdc6cef35a4860e816ec3916dcfd0882954e98a8a8" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fdeflate" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d6dafc854908ff5da46ff3f8f473c6984119a2876a383a860246dd7841a868" +dependencies = [ + "simd-adler32", +] + [[package]] name = "field-offset" version = "0.3.6" @@ -165,6 +467,25 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin", +] + [[package]] name = "futures-channel" version = "0.3.28" @@ -287,10 +608,20 @@ dependencies = [ ] [[package]] -name = "gio" -version = "0.18.2" +name = "gif" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57052f84e8e5999b258e8adf8f5f2af0ac69033864936b8b6838321db2f759b1" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "gio" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d809baf02bdf1b5ef4ad3bf60dd9d4977149db4612b7bbb58e56aef168193b" dependencies = [ "futures-channel", "futures-core", @@ -320,11 +651,11 @@ dependencies = [ [[package]] name = "glib" -version = "0.18.2" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c316afb01ce8067c5eaab1fc4f2cd47dc21ce7b6296358605e2ffab23ccbd19" +checksum = "58cf801b6f7829fa76db37449ab67c9c98a2b1bf21076d9113225621e61a0fa6" dependencies = [ - "bitflags", + "bitflags 2.4.0", "futures-channel", "futures-core", "futures-executor", @@ -343,12 +674,12 @@ dependencies = [ [[package]] name = "glib-macros" -version = "0.18.2" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8da903822b136d42360518653fcf154455defc437d3e7a81475bf9a95ff1e47" +checksum = "72793962ceece3863c2965d7f10c8786323b17c7adea75a515809fa20ab799a5" dependencies = [ "heck", - "proc-macro-crate", + "proc-macro-crate 2.0.0", "proc-macro-error", "proc-macro2", "quote", @@ -365,6 +696,12 @@ dependencies = [ "system-deps", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "gobject-sys" version = "0.18.0" @@ -458,7 +795,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d57ec49cf9b657f69a05bca8027cff0a8dfd0c49e812be026fc7311f2163832f" dependencies = [ "anyhow", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro-error", "proc-macro2", "quote", @@ -484,6 +821,15 @@ dependencies = [ "system-deps", ] +[[package]] +name = "half" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +dependencies = [ + "crunchy", +] + [[package]] name = "hashbrown" version = "0.14.1" @@ -496,6 +842,57 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "image" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-rational", + "num-traits", + "png", + "qoi", + "tiff", +] + [[package]] name = "indexmap" version = "2.0.1" @@ -506,12 +903,114 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "iter_tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531cafdc99b3b3252bb32f5620e61d56b19415efc19900b12d1b2e7483854897" +dependencies = [ + "itertools", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" +dependencies = [ + "rayon", +] + +[[package]] +name = "js-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +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.148" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +dependencies = [ + "cfg-if", + "windows-sys", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "maybe-owned" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" + [[package]] name = "memchr" version = "2.6.3" @@ -527,19 +1026,77 @@ dependencies = [ "autocfg", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + [[package]] name = "music-reader" version = "0.1.0" dependencies = [ + "async-channel", "cairo-rs", "clap", "gio", "glib", "glib-macros", "gtk4", + "pdfium-render", "poppler-rs", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -571,6 +1128,45 @@ dependencies = [ "system-deps", ] +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + +[[package]] +name = "pdfium-render" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b09ef9c34c66ce232d7af3562dcffe8801b2d0665d2c2770d06cdc46e0d2aff" +dependencies = [ + "bindgen", + "bitflags 2.4.0", + "bytemuck", + "bytes", + "chrono", + "console_error_panic_hook", + "console_log", + "image", + "iter_tools", + "js-sys", + "libloading 0.8.1", + "log", + "maybe-owned", + "once_cell", + "utf16string", + "vecmath", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -583,12 +1179,31 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piston-float" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad78bf43dcf80e8f950c92b84f938a0fc7590b7f6866fbcbeca781609c115590" + [[package]] name = "pkg-config" version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "png" +version = "0.17.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "poppler-rs" version = "0.22.0" @@ -616,6 +1231,16 @@ dependencies = [ "system-deps", ] +[[package]] +name = "prettyplease" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +dependencies = [ + "proc-macro2", + "syn 2.0.37", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -623,7 +1248,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", ] [[package]] @@ -659,6 +1293,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + [[package]] name = "quote" version = "1.0.33" @@ -668,6 +1311,61 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -677,6 +1375,25 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "semver" version = "1.0.19" @@ -712,6 +1429,18 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "slab" version = "0.4.9" @@ -727,6 +1456,15 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "strsim" version = "0.10.0" @@ -794,6 +1532,17 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "tiff" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "toml" version = "0.7.8" @@ -803,14 +1552,14 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.15", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] @@ -828,18 +1577,47 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "utf16string" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b62a1e85e12d5d712bf47a85f426b73d303e2d00a90de5f3004df3596e9d216" +dependencies = [ + "byteorder", +] + [[package]] name = "utf8parse" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "vecmath" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ae1e0d85bca567dee1dcf87fb1ca2e792792f66f87dced8381f99cd91156a" +dependencies = [ + "piston-float", +] + [[package]] name = "version-compare" version = "0.1.1" @@ -852,6 +1630,100 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasm-bindgen" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.37", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" + +[[package]] +name = "web-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "weezl" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + [[package]] name = "winapi" version = "0.3.9" @@ -874,6 +1746,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -948,3 +1829,12 @@ checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] diff --git a/Cargo.toml b/Cargo.toml index b60617f..c76189d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,9 +5,11 @@ edition = "2021" [dependencies] poppler-rs = "0.22" -cairo-rs = "0.18.2" -glib-macros = "0.18.2" -gio = "0.18.2" -glib = "0.18.2" -gtk4 = "0.7.3" +cairo-rs = "0.18.3" +glib-macros = "0.18.3" +gio = "0.18.3" +glib = "0.18.3" clap = { version = "4.4.6", features = ["derive"] } +gtk = { version = "0.7.3", package = "gtk4", features = ["v4_8"] } +async-channel = "2.1.0" +pdfium-render = "0.8.15" diff --git a/flake.nix b/flake.nix index 778cf92..3f548ca 100644 --- a/flake.nix +++ b/flake.nix @@ -17,6 +17,7 @@ pkg-config poppler wrapGAppsHook + deepin.deepin-pdfium ]; in { defaultPackage = naersk-lib.buildPackage { diff --git a/src/cache.rs b/src/cache.rs new file mode 100644 index 0000000..c5b2008 --- /dev/null +++ b/src/cache.rs @@ -0,0 +1,159 @@ +use glib::Bytes; +use gtk::gdk::Texture; +use pdfium_render::{pdfium, prelude::*}; +use std::{ + collections::BTreeMap, + path::{Path, PathBuf}, + sync::{Arc, Mutex}, +}; + +use async_channel::{Receiver, Sender}; + +type PageNumber = usize; + +pub struct PageCache<'a> { + document: PdfDocument<'a>, + render_config: PdfRenderConfig, + max_num_stored_pages: usize, + pages: BTreeMap>, +} + +impl<'a> PageCache<'a> { + pub fn new( + document: PdfDocument<'a>, + render_config: PdfRenderConfig, + max_num_stored_pages: usize, + ) -> Self { + PageCache { + document, + render_config, + max_num_stored_pages, + pages: BTreeMap::new(), + } + } + + pub fn get_page(&self, page_number: usize) -> Option> { + self.pages.get(&page_number).map(Arc::clone) + } + + pub fn cache_pages(&mut self, page_numbers: Vec) { + for page_number in page_numbers { + if self.pages.contains_key(&page_number) { + continue; + } + + let page = self.document.pages().get(page_number as u16).unwrap(); + let image = page.render_with_config(&self.render_config).unwrap(); + + // TODO: does this clone? + let bytes = Bytes::from(image.as_bytes()); + let page = Texture::from_bytes(&bytes).unwrap(); + // let page = self.document.page(page_number as i32); + self.pages.insert(page_number, Arc::new(page)); + + if self.pages.len() > self.max_num_stored_pages && self.pages.len() > 2 { + let _result = self.remove_most_distant_page(page_number); + } + } + } + + fn remove_most_distant_page(&mut self, current_page_number: usize) -> Result<(), ()> { + let (min_cached_page_number, min_cached_page) = self.pages.pop_first().ok_or(())?; + let (max_cached_page_number, max_cached_page) = self.pages.pop_last().ok_or(())?; + + if current_page_number.abs_diff(min_cached_page_number) + > current_page_number.abs_diff(max_cached_page_number) + { + self.pages.insert(max_cached_page_number, max_cached_page); + } else { + self.pages.insert(min_cached_page_number, min_cached_page); + } + + Ok(()) + } + + fn process_command(&mut self, command: CacheCommand) -> Option { + match command { + CacheCommand::CachePages { pages } => { + self.cache_pages(pages); + None + } + CacheCommand::GetCurrentTwoPages { page_left_number } => { + let page_left = self + .get_page(page_left_number) + .expect("Requested page was not cached!!!"); + + if let Some(page_right) = self.get_page(page_left_number + 1) { + Some(CacheResponse::TwoPagesLoaded { + page_left, + page_right, + }) + } else { + Some(CacheResponse::SinglePageLoaded { page: page_left }) + } + } + } + } +} + +pub enum CacheCommand { + CachePages { pages: Vec }, + GetCurrentTwoPages { page_left_number: PageNumber }, +} + +pub enum CacheResponse { + DocumentLoaded { + num_pages: usize, + }, + SinglePageLoaded { + page: Arc, + }, + TwoPagesLoaded { + page_left: Arc, + page_right: Arc, + }, +} + +pub fn spawn_async_cache( + file: impl AsRef, +) -> (Sender, Receiver) { + let (command_sender, command_receiver) = async_channel::unbounded(); + let (response_sender, response_receiver) = async_channel::unbounded(); + + let path: PathBuf = file.as_ref().to_path_buf(); + + std::thread::spawn(move || { + // Load pdf document here since Document is not thread safe and cannot be passed from main thread + let pdfium = Pdfium::default(); + + let document = pdfium.load_pdf_from_file(&path, None).unwrap(); + let render_config = PdfRenderConfig::new() + .set_target_width(2000) + .set_maximum_height(2000) + .rotate_if_landscape(PdfPageRenderRotation::Degrees90, true); + let num_pages = document.pages().iter().count(); + + // let document = poppler::Document::from_file(&uri, None).unwrap(); + // let num_pages = document.n_pages() as usize; + response_sender.send(CacheResponse::DocumentLoaded { num_pages }); + + let mut cache = PageCache::new(document, render_config, 10); + + loop { + if let Ok(command) = command_receiver.recv_blocking() { + // if !command_receiver.is_empty() { + // // ignore command if more up to date ones are available + // continue; + // } + if let Some(response) = cache.process_command(command) { + response_sender.send_blocking(response); + } + } else { + // Sender was closed, cache not needed anymore + break; + } + } + }); + + (command_sender, response_receiver) +} diff --git a/src/main.rs b/src/main.rs index 1874f66..9502dff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,9 @@ +mod cache; mod ui; use clap::Parser; -use gtk4::prelude::*; -use gtk4::Application; +use gtk::prelude::*; +use gtk::Application; use std::cell::RefCell; use std::path::PathBuf; use std::rc::Rc; diff --git a/src/ui.rs b/src/ui.rs index 9bbb955..72e0143 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,108 +1,46 @@ use std::{cell::RefCell, collections::BTreeMap, path::Path, rc::Rc, thread, time::Duration}; +use async_channel::Sender; use cairo::{Context, Format, ImageSurface}; -use gtk4::{ - prelude::*, Application, ApplicationWindow, Box, Button, DrawingArea, FileChooserAction, - FileChooserDialog, HeaderBar, Label, Orientation, ResponseType, +use gtk::{ + gdk::Paintable, gio, glib, prelude::*, Application, ApplicationWindow, Box, Button, + DrawingArea, FileChooserAction, FileChooserDialog, HeaderBar, Label, Orientation, Picture, + ResponseType, }; use poppler::{Document, Page}; +use crate::cache::{self, CacheCommand, PageCache}; +use glib::clone; +use gtk::prelude::*; + pub struct Ui { window: ApplicationWindow, - bottom_bar: gtk4::Box, - header_bar: gtk4::HeaderBar, - page_indicator: gtk4::Label, - drawing_area: gtk4::DrawingArea, + bottom_bar: gtk::Box, + header_bar: gtk::HeaderBar, + page_indicator: gtk::Label, + drawing_area: gtk::DrawingArea, + picture: Picture, drawing_context: cairo::Context, document_canvas: Option, } -pub struct PageCache { - max_num_pages: usize, - first_page_number: usize, - pages: BTreeMap>, -} - -impl PageCache { - pub fn new(max_num_pages: usize) -> Self { - PageCache { - max_num_pages, - first_page_number: 0, - pages: BTreeMap::new(), - } - } - - pub fn get_page(&self, page_number: usize) -> Option> { - let index = page_number - self.first_page_number; - self.pages.get(&index).map(Rc::clone) - } - - pub fn cache_pages( - &mut self, - current_page_number: usize, - page_numbers: Vec, - document: &Document, - ) { - for page_number in page_numbers { - if self.pages.contains_key(&page_number) { - continue; - } - - let page = document.page(page_number as i32); - if let Some(page) = page { - self.pages.insert(page_number, Rc::new(page)); - - if self.pages.len() > self.max_num_pages && self.pages.len() > 2 { - let _result = self.remove_most_distant_page(current_page_number); - } - } - } - } - - fn remove_most_distant_page(&mut self, current_page_number: usize) -> Result<(), ()> { - let (min_cached_page_number, min_cached_page) = self.pages.pop_first().ok_or(())?; - let (max_cached_page_number, max_cached_page) = self.pages.pop_last().ok_or(())?; - - if current_page_number.abs_diff(min_cached_page_number) - > current_page_number.abs_diff(max_cached_page_number) - { - self.pages.insert(max_cached_page_number, max_cached_page); - } else { - self.pages.insert(min_cached_page_number, min_cached_page); - } - - Ok(()) - } -} - pub struct DocumentCanvas { - document: Document, current_page_number: usize, - num_pages: usize, - page_cache: PageCache, + num_pages: Option, + page_cache_sender: Sender, } impl DocumentCanvas { - pub fn new(document: poppler::Document, max_num_cached_pages: usize) -> Self { - let num_pages = document.n_pages() as usize; + pub fn new(page_cache_sender: Sender) -> Self { DocumentCanvas { - document, - num_pages, current_page_number: 0, - page_cache: PageCache::new(max_num_cached_pages), + num_pages: None, + page_cache_sender, } } - pub fn get_left_page(&self) -> Option> { - self.page_cache.get_page(self.current_page_number) - } - - pub fn get_right_page(&self) -> Option> { - self.page_cache.get_page(self.current_page_number + 1) - } - pub fn increase_page_number(&mut self) { - if self.current_page_number >= self.num_pages - 2 { + if self.current_page_number >= self.num_pages.unwrap_or(0) - 2 { return; } @@ -117,33 +55,25 @@ impl DocumentCanvas { self.current_page_number -= 1; } - pub fn cache_current_two_pages(&mut self) { - self.page_cache.cache_pages( - self.current_page_number, - vec![self.current_page_number, self.current_page_number + 1], - &self.document, - ); + pub fn cache_surrounding_pages(&self) { + self.page_cache_sender + .send_blocking(CacheCommand::CachePages { + pages: vec![ + self.current_page_number.saturating_sub(2), + self.current_page_number.saturating_sub(1), + self.current_page_number, + self.current_page_number + 1, + self.current_page_number + 2, + self.current_page_number + 3, + ], + }); } - pub fn cache_surrounding_pages(&mut self) { - self.page_cache.cache_pages( - self.current_page_number, - vec![ - self.current_page_number.saturating_sub(2), - self.current_page_number.saturating_sub(1), - self.current_page_number + 2, - self.current_page_number + 3, - ], - &self.document, - ); - } - - pub fn cache_all_pages(&mut self) { - self.page_cache.cache_pages( - self.current_page_number, - (0..self.document.n_pages() as usize).collect(), - &self.document, - ); + pub fn request_to_draw_pages(&self) { + self.page_cache_sender + .send_blocking(CacheCommand::GetCurrentTwoPages { + page_left_number: self.current_page_number, + }); } } @@ -165,14 +95,18 @@ pub fn toggle_fullscreen(ui: &Ui) { fn update_page_status(ui: &Ui) { let page_status = match &ui.document_canvas { Some(doc) => { - if doc.num_pages == 1 { - format!("{} / {}", doc.current_page_number, doc.num_pages) + if doc.num_pages.unwrap_or(0) == 1 { + format!( + "{} / {}", + doc.current_page_number, + doc.num_pages.unwrap_or(0) + ) } else { format!( "{}-{} / {}", doc.current_page_number + 1, doc.current_page_number + 2, - doc.num_pages + doc.num_pages.unwrap_or(0) ) } } @@ -246,34 +180,43 @@ impl Ui { .hexpand(true) .vexpand(true) .build(), + picture: Picture::builder() + .width_request(400) + .height_request(300) + .hexpand(true) + .vexpand(true) + .build(), drawing_context: create_drawing_context(), document_canvas: None, }; let ui = Rc::new(RefCell::new(ui)); ui.borrow().header_bar.pack_start(&open_file_button); - app_wrapper.prepend(&ui.borrow().drawing_area); + // app_wrapper.prepend(&ui.borrow().drawing_area); + app_wrapper.prepend(&ui.borrow().picture); app_wrapper.append(&ui.borrow().bottom_bar); ui.borrow().bottom_bar.append(&ui.borrow().page_indicator); - let click_left = gtk4::GestureClick::new(); + let click_left = gtk::GestureClick::new(); click_left.set_button(1); click_left.connect_pressed(glib::clone!(@weak ui => @default-panic, move |_, _, x, y| { process_left_click(&mut ui.borrow_mut(), x, y); })); - let click_right = gtk4::GestureClick::new(); + let click_right = gtk::GestureClick::new(); click_right.set_button(3); click_right.connect_pressed(glib::clone!(@weak ui => @default-panic, move |_, _, x, y| { process_right_click(&mut ui.borrow_mut(), x, y); })); - ui.borrow().drawing_area.add_controller(click_left); - ui.borrow().drawing_area.add_controller(click_right); + // ui.borrow().drawing_area.add_controller(click_left); + // ui.borrow().drawing_area.add_controller(click_right); + ui.borrow().picture.add_controller(click_left); + ui.borrow().picture.add_controller(click_right); ui.borrow().drawing_area.set_draw_func( glib::clone!(@weak ui => move |area, context, _, _| { - draw(&mut ui.borrow_mut(), area, context); + // draw(&mut ui.borrow_mut(), area, context, sender.clone()); }), ); @@ -292,147 +235,148 @@ impl Ui { } } -fn draw(ui: &mut Ui, area: &DrawingArea, context: &Context) { - if ui.document_canvas.is_none() { - return; - } - let document_canvas = ui.document_canvas.as_ref().unwrap(); - if document_canvas.num_pages > 1 { - draw_two_pages(ui, area, context); - } else { - draw_single_page(ui, area, context); - } +// fn draw(ui: &mut Ui, area: &DrawingArea, context: &Context, sender: Sender) { +// if ui.document_canvas.is_none() { +// return; +// } +// let document_canvas = ui.document_canvas.as_ref().unwrap(); +// if document_canvas.num_pages.unwrap_or(0) > 1 { +// draw_two_pages(ui, area, context); +// } else { +// draw_single_page(ui, area, context); +// } - // TODO: this makes the draw wait - // ui.document_canvas - // .as_mut() - // .unwrap() - // .cache_surrounding_pages(); -} +// // gio::spawn_blocking(move || { +// // ui.document_canvas +// // .as_mut() +// // .unwrap() +// // .cache_surrounding_pages(); +// // }); +// } -fn draw_two_pages(ui: &Ui, area: &DrawingArea, context: &Context) { - if ui.document_canvas.is_none() { - return; - } - let document_canvas = ui.document_canvas.as_ref().unwrap(); +// fn draw_two_pages(ui: &Ui, area: &DrawingArea, context: &Context) { +// if ui.document_canvas.is_none() { +// return; +// } +// let document_canvas = ui.document_canvas.as_ref().unwrap(); - let page_left = document_canvas.get_left_page(); - let page_right = document_canvas.get_right_page(); +// let page_left = document_canvas.get_left_page(); +// let page_right = document_canvas.get_right_page(); - if page_left.is_none() || page_right.is_none() { - // TODO: show error message - return; - } +// if page_left.is_none() || page_right.is_none() { +// // TODO: show error message +// return; +// } - let page_left = page_left.unwrap(); - let page_right = page_right.unwrap(); +// let page_left = page_left.unwrap(); +// let page_right = page_right.unwrap(); - // Add white background - // context.set_source_rgba(1.0, 1.0, 1.0, 1.0); - // context.fill().unwrap(); - // context.paint().unwrap(); +// // Add white background +// // context.set_source_rgba(1.0, 1.0, 1.0, 1.0); +// // context.fill().unwrap(); +// // context.paint().unwrap(); - let (w_left, h_left) = page_left.size(); - let (w_right, h_right) = page_right.size(); +// let (w_left, h_left) = page_left.size(); +// let (w_right, h_right) = page_right.size(); - let h_max = f64::max(h_left, h_right); - // Make sure both pages are rendered with the same height - let w_max = match h_left < h_right { - true => w_left * h_right / h_left + w_right, - false => w_left + w_right * h_left / h_right, - }; +// let h_max = f64::max(h_left, h_right); +// // Make sure both pages are rendered with the same height +// let w_max = match h_left < h_right { +// true => w_left * h_right / h_left + w_right, +// false => w_left + w_right * h_left / h_right, +// }; - let h_scale = area.height() as f64 / h_max; - let w_scale = area.width() as f64 / w_max; - let scale = f64::min(h_scale, w_scale); - let h_page = h_max * scale; +// let h_scale = area.height() as f64 / h_max; +// let w_scale = area.width() as f64 / w_max; +// let scale = f64::min(h_scale, w_scale); +// let h_page = h_max * scale; - let scale_left = h_page / h_left; - let scale_right = h_page / h_right; +// let scale_left = h_page / h_left; +// let scale_right = h_page / h_right; - context.set_source_rgba(1.0, 1.0, 1.0, 1.0); - context.save().unwrap(); - context.translate( - area.width() as f64 / 2.0 - w_left * scale_left, - area.height() as f64 / 2.0 - h_page / 2.0, - ); - // Poppler sometimes crops white border, draw it manually - context.rectangle(0.0, 0.0, w_left * scale_left, h_page); - context.fill().unwrap(); - context.scale(scale_left, scale_left); - page_left.render(context); +// context.set_source_rgba(1.0, 1.0, 1.0, 1.0); +// context.save().unwrap(); +// context.translate( +// area.width() as f64 / 2.0 - w_left * scale_left, +// area.height() as f64 / 2.0 - h_page / 2.0, +// ); +// // Poppler sometimes crops white border, draw it manually +// context.rectangle(0.0, 0.0, w_left * scale_left, h_page); +// context.fill().unwrap(); +// context.scale(scale_left, scale_left); +// page_left.render(context); - context.restore().unwrap(); - context.translate( - area.width() as f64 / 2.0, - area.height() as f64 / 2.0 - h_page / 2.0, - ); - // Poppler sometimes crops white border, draw it manually - context.rectangle(0.0, 0.0, w_right * scale_right, h_page); - context.fill().unwrap(); - context.scale(scale_right, scale_right); - page_right.render(context); +// context.restore().unwrap(); +// context.translate( +// area.width() as f64 / 2.0, +// area.height() as f64 / 2.0 - h_page / 2.0, +// ); +// // Poppler sometimes crops white border, draw it manually +// context.rectangle(0.0, 0.0, w_right * scale_right, h_page); +// context.fill().unwrap(); +// context.scale(scale_right, scale_right); +// page_right.render(context); - let r = ui.drawing_context.paint(); - match r { - Err(v) => println!("Error painting PDF: {v:?}"), - Ok(_v) => {} - } +// let r = ui.drawing_context.paint(); +// match r { +// Err(v) => println!("Error painting PDF: {v:?}"), +// Ok(_v) => {} +// } - ui.drawing_context.show_page().unwrap(); -} -fn draw_single_page(ui: &Ui, area: &DrawingArea, context: &Context) { - if ui.document_canvas.is_none() { - return; - } - let document_canvas = ui.document_canvas.as_ref().unwrap(); +// ui.drawing_context.show_page().unwrap(); +// } +// fn draw_single_page(ui: &Ui, area: &DrawingArea, context: &Context) { +// if ui.document_canvas.is_none() { +// return; +// } +// let document_canvas = ui.document_canvas.as_ref().unwrap(); - if document_canvas.get_left_page().is_none() { - // TODO: show error message - return; - } +// if document_canvas.get_left_page().is_none() { +// // TODO: show error message +// return; +// } - let page = document_canvas.get_left_page().unwrap(); +// let page = document_canvas.get_left_page().unwrap(); - // Draw background - // context.set_source_rgba(1.0, 1.0, 1.0, 1.0); - // context.paint().unwrap(); - // context.fill().expect("uh oh"); - // context.paint().unwrap(); +// // Draw background +// // context.set_source_rgba(1.0, 1.0, 1.0, 1.0); +// // context.paint().unwrap(); +// // context.fill().expect("uh oh"); +// // context.paint().unwrap(); - let (w, h) = page.size(); +// let (w, h) = page.size(); - let width_diff = area.width() as f64 / w; - let height_diff = area.height() as f64 / h; - if width_diff > height_diff { - context.translate( - (area.width() as f64 - w * height_diff) / 2.0, - (area.height() as f64 - h * height_diff) / 2.0, - ); - context.scale(height_diff, height_diff); - } else { - context.translate( - (area.width() as f64 - w * width_diff) / 2.0, - (area.height() as f64 - h * width_diff) / 2.0, - ); - context.scale(width_diff, width_diff); - } +// let width_diff = area.width() as f64 / w; +// let height_diff = area.height() as f64 / h; +// if width_diff > height_diff { +// context.translate( +// (area.width() as f64 - w * height_diff) / 2.0, +// (area.height() as f64 - h * height_diff) / 2.0, +// ); +// context.scale(height_diff, height_diff); +// } else { +// context.translate( +// (area.width() as f64 - w * width_diff) / 2.0, +// (area.height() as f64 - h * width_diff) / 2.0, +// ); +// context.scale(width_diff, width_diff); +// } - // Poppler sometimes crops white border, draw it manually - context.set_source_rgba(1.0, 1.0, 1.0, 1.0); - context.rectangle(0.0, 0.0, w, h); - context.fill().unwrap(); +// // Poppler sometimes crops white border, draw it manually +// context.set_source_rgba(1.0, 1.0, 1.0, 1.0); +// context.rectangle(0.0, 0.0, w, h); +// context.fill().unwrap(); - page.render(context); +// page.render(context); - let r = ui.drawing_context.paint(); - match r { - Err(v) => println!("Error painting PDF: {v:?}"), - Ok(_v) => {} - } +// let r = ui.drawing_context.paint(); +// match r { +// Err(v) => println!("Error painting PDF: {v:?}"), +// Ok(_v) => {} +// } - ui.drawing_context.show_page().unwrap(); -} +// ui.drawing_context.show_page().unwrap(); +// } fn choose_file(ui: Rc>, window: &ApplicationWindow) { let filechooser = FileChooserDialog::builder() @@ -456,13 +400,25 @@ fn choose_file(ui: Rc>, window: &ApplicationWindow) { pub fn load_document(file: impl AsRef, ui: Rc>) { println!("Loading file..."); // TODO: catch errors, maybe show error dialog - let uri = format!("file://{}", file.as_ref().to_str().unwrap()); - let mut document_canvas = - DocumentCanvas::new(poppler::Document::from_file(&uri, None).unwrap(), 1000); - // document_canvas.cache_current_two_pages(); - document_canvas.cache_all_pages(); + // let uri = format!("file://{}", file.as_ref().to_str().unwrap()); + let (sender, receiver) = cache::spawn_async_cache(file); + // gtk::spawn + glib::spawn_future_local(clone!(@weak ui => async move { + while let Ok(cache_response) = receiver.recv().await { + match cache_response{ + cache::CacheResponse::DocumentLoaded { num_pages } => todo!(), //ui.borrow_mut().document_canvas.unwrap().num_pages = Some(num_pages), + cache::CacheResponse::SinglePageLoaded { page } => { ui.borrow_mut().picture.set_paintable(Some(page.as_ref()));}, + cache::CacheResponse::TwoPagesLoaded { page_left, page_right } => todo!(), + } + } + })); + + let document_canvas = DocumentCanvas::new(sender); + document_canvas.cache_surrounding_pages(); + // document_canvas.cache_all_pages(); + + // update_page_status(&ui.borrow()); + document_canvas.request_to_draw_pages(); ui.borrow_mut().document_canvas = Some(document_canvas); - - update_page_status(&ui.borrow()); }