From 077a29e5ee928322007bbf884d5e76dcf83100c1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 29 Feb 2024 11:25:46 -0700 Subject: [PATCH] Implement drag selection in grid view --- Cargo.lock | 176 +++++++++++++++++------------------ src/mouse_area.rs | 135 ++++++++++++++++----------- src/tab.rs | 228 +++++++++++++++++++++++++++++----------------- 3 files changed, 315 insertions(+), 224 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9515119..96ba9b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -352,7 +352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" dependencies = [ "concurrent-queue", - "event-listener 5.1.0", + "event-listener 5.2.0", "event-listener-strategy 0.5.0", "futures-core", "pin-project-lite", @@ -468,7 +468,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -503,7 +503,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -728,7 +728,7 @@ checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -850,7 +850,7 @@ dependencies = [ "num-traits", "pure-rust-locales", "wasm-bindgen", - "windows-targets 0.52.3", + "windows-targets 0.52.4", ] [[package]] @@ -1127,7 +1127,7 @@ dependencies = [ [[package]] name = "cosmic-config" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "atomicwrites", "cosmic-config-derive", @@ -1144,7 +1144,7 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "quote", "syn 1.0.109", @@ -1206,7 +1206,7 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "almost", "cosmic-config", @@ -1250,9 +1250,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ "crossbeam-utils", ] @@ -1330,7 +1330,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad291aa74992b9b7a7e88c38acbbf6ad7e107f1d90ee8775b7bc1fc3394f485c" dependencies = [ "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -1400,7 +1400,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -1422,7 +1422,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core 0.20.8", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -1483,7 +1483,7 @@ dependencies = [ "darling 0.20.8", "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -1552,7 +1552,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -1651,7 +1651,7 @@ checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -1748,9 +1748,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ad6fd685ce13acd6d9541a30f6db6567a7a24c9ffd4ba2955d29e3f22c8b27" +checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" dependencies = [ "concurrent-queue", "parking", @@ -1773,7 +1773,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" dependencies = [ - "event-listener 5.1.0", + "event-listener 5.2.0", "pin-project-lite", ] @@ -1981,7 +1981,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -2131,7 +2131,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -2479,9 +2479,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379dada1584ad501b383485dd706b8afb7a70fcbc7f4da7d780638a5a6124a60" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -2554,7 +2554,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.51", + "syn 2.0.52", "unic-langid", ] @@ -2568,7 +2568,7 @@ dependencies = [ "i18n-config", "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -2597,7 +2597,7 @@ dependencies = [ [[package]] name = "iced" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "iced_accessibility", "iced_core", @@ -2612,7 +2612,7 @@ dependencies = [ [[package]] name = "iced_accessibility" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "accesskit", "accesskit_winit", @@ -2621,7 +2621,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "bitflags 1.3.2", "log", @@ -2638,7 +2638,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "futures", "iced_core", @@ -2651,7 +2651,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "bitflags 1.3.2", "bytemuck", @@ -2675,7 +2675,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2687,7 +2687,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "iced_core", "iced_futures", @@ -2697,7 +2697,7 @@ dependencies = [ [[package]] name = "iced_style" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "iced_core", "once_cell", @@ -2707,7 +2707,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "bytemuck", "cosmic-text", @@ -2724,7 +2724,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "bitflags 1.3.2", "bytemuck", @@ -2743,7 +2743,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "iced_renderer", "iced_runtime", @@ -2757,7 +2757,7 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "iced_graphics", "iced_runtime", @@ -2853,9 +2853,9 @@ checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" [[package]] name = "indexmap" -version = "2.2.3" +version = "2.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "967d6dd42f16dbf0eb8040cb9e477933562684d3918f7d253f2ff9087fb3e7a3" dependencies = [ "equivalent", "hashbrown", @@ -3101,7 +3101,7 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#7c3145828e780c6f6e9487f3f30486e5c44b4b2e" +source = "git+https://github.com/pop-os/libcosmic.git#e12d6253389860dc9fbb0d651e86287ad8f609ae" dependencies = [ "apply", "ashpd", @@ -3235,9 +3235,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "lru" @@ -3775,7 +3775,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -3946,7 +3946,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -3988,7 +3988,7 @@ checksum = "e8890702dbec0bad9116041ae586f84805b13eecd1d8b1df27c29998a9969d6d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -4105,7 +4105,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -4400,9 +4400,9 @@ checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" [[package]] name = "rayon" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", @@ -4594,7 +4594,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.51", + "syn 2.0.52", "walkdir", ] @@ -4768,7 +4768,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -4779,7 +4779,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -5066,9 +5066,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.51" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -5168,7 +5168,7 @@ checksum = "c8f546451eaa38373f549093fe9fd05e7d2bade739e2ddf834b9968621d60107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -5188,7 +5188,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -5397,7 +5397,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.2", + "winnow 0.6.3", ] [[package]] @@ -5419,7 +5419,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] @@ -5734,7 +5734,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", "wasm-bindgen-shared", ] @@ -5768,7 +5768,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6182,7 +6182,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ "windows-core", - "windows-targets 0.52.3", + "windows-targets 0.52.4", ] [[package]] @@ -6191,7 +6191,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.3", + "windows-targets 0.52.4", ] [[package]] @@ -6240,7 +6240,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.3", + "windows-targets 0.52.4", ] [[package]] @@ -6275,17 +6275,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.3", - "windows_aarch64_msvc 0.52.3", - "windows_i686_gnu 0.52.3", - "windows_i686_msvc 0.52.3", - "windows_x86_64_gnu 0.52.3", - "windows_x86_64_gnullvm 0.52.3", - "windows_x86_64_msvc 0.52.3", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -6302,9 +6302,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -6320,9 +6320,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -6338,9 +6338,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -6356,9 +6356,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -6374,9 +6374,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -6392,9 +6392,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -6410,9 +6410,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "winit" @@ -6504,9 +6504,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a4191c47f15cc3ec71fcb4913cb83d58def65dd3787610213c649283b5ce178" +checksum = "44e19b97e00a4d3db3cdb9b53c8c5f87151b5689b82cc86c2848cbdcccb2689b" dependencies = [ "memchr", ] @@ -6711,7 +6711,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.52", ] [[package]] diff --git a/src/mouse_area.rs b/src/mouse_area.rs index 996c504..fe2156f 100644 --- a/src/mouse_area.rs +++ b/src/mouse_area.rs @@ -17,9 +17,10 @@ use cosmic::{ #[allow(missing_debug_implementations)] pub struct MouseArea<'a, Message> { content: Element<'a, Message>, - on_drag: Option) -> Message + 'a>>, + on_drag: Option) -> Message + 'a>>, on_press: Option) -> Message + 'a>>, on_release: Option) -> Message + 'a>>, + on_resize: Option Message + 'a>>, on_right_press: Option) -> Message + 'a>>, on_right_press_no_capture: Option) -> Message + 'a>>, on_right_release: Option) -> Message + 'a>>, @@ -29,13 +30,13 @@ pub struct MouseArea<'a, Message> { on_back_release: Option) -> Message + 'a>>, on_forward_press: Option) -> Message + 'a>>, on_forward_release: Option) -> Message + 'a>>, - show_drag_box: bool, + show_drag_rect: bool, } impl<'a, Message> MouseArea<'a, Message> { /// The message to emit when a drag is initiated. #[must_use] - pub fn on_drag(mut self, message: impl Fn(Option) -> Message + 'a) -> Self { + pub fn on_drag(mut self, message: impl Fn(Option) -> Message + 'a) -> Self { self.on_drag = Some(Box::new(message)); self } @@ -54,6 +55,12 @@ impl<'a, Message> MouseArea<'a, Message> { self } + #[must_use] + pub fn on_resize(mut self, message: impl Fn(Size) -> Message + 'a) -> Self { + self.on_resize = Some(Box::new(message)); + self + } + /// The message to emit on a right button press. #[must_use] pub fn on_right_press(mut self, message: impl Fn(Option) -> Message + 'a) -> Self { @@ -121,8 +128,8 @@ impl<'a, Message> MouseArea<'a, Message> { } #[must_use] - pub fn show_drag_box(mut self, show_drag_box: bool) -> Self { - self.show_drag_box = show_drag_box; + pub fn show_drag_rect(mut self, show_drag_rect: bool) -> Self { + self.show_drag_rect = show_drag_rect; self } } @@ -130,10 +137,31 @@ impl<'a, Message> MouseArea<'a, Message> { /// Local state of the [`MouseArea`]. #[derive(Default)] struct State { + last_size: Option, // TODO: Support on_mouse_enter and on_mouse_exit drag_initiated: Option, } +impl State { + fn drag_rect(&self, cursor: mouse::Cursor) -> Option { + if let Some(drag_source) = self.drag_initiated { + if let Some(position) = cursor.position() { + if position.distance(drag_source) > 1.0 { + let min_x = drag_source.x.min(position.x); + let max_x = drag_source.x.max(position.x); + let min_y = drag_source.y.min(position.y); + let max_y = drag_source.y.max(position.y); + return Some(Rectangle::new( + Point::new(min_x, min_y), + Size::new(max_x - min_x, max_y - min_y), + )); + } + } + } + None + } +} + impl<'a, Message> MouseArea<'a, Message> { /// Creates a [`MouseArea`] with the given content. pub fn new(content: impl Into>) -> Self { @@ -142,6 +170,7 @@ impl<'a, Message> MouseArea<'a, Message> { on_drag: None, on_press: None, on_release: None, + on_resize: None, on_right_press: None, on_right_press_no_capture: None, on_right_release: None, @@ -151,7 +180,7 @@ impl<'a, Message> MouseArea<'a, Message> { on_back_release: None, on_forward_press: None, on_forward_release: None, - show_drag_box: false, + show_drag_rect: false, } } } @@ -274,35 +303,25 @@ where viewport, ); - if self.show_drag_box { + if self.show_drag_rect { let state = tree.state.downcast_ref::(); - if let Some(a) = state.drag_initiated { - if let Some(b) = cursor.position() { - let min_x = a.x.min(b.x); - let max_x = a.x.max(b.x); - let min_y = a.y.min(b.y); - let max_y = a.y.max(b.y); - let bounds = Rectangle::new( - Point::new(min_x, min_y), - Size::new(max_x - min_x, max_y - min_y), - ); - let cosmic = theme.cosmic(); - let mut bg_color = cosmic.accent_color(); - //TODO: get correct alpha - bg_color.alpha = 0.2; - renderer.fill_quad( - Quad { - bounds, - border: Border { - color: cosmic.accent_color().into(), - width: 1.0, - radius: cosmic.radius_xs().into(), - }, - ..Default::default() + if let Some(bounds) = state.drag_rect(cursor) { + let cosmic = theme.cosmic(); + let mut bg_color = cosmic.accent_color(); + //TODO: get correct alpha + bg_color.alpha = 0.2; + renderer.fill_quad( + Quad { + bounds, + border: Border { + color: cosmic.accent_color().into(), + width: 1.0, + radius: cosmic.radius_xs().into(), }, - Color::from(bg_color), - ); - } + ..Default::default() + }, + Color::from(bg_color), + ); } } } @@ -340,7 +359,17 @@ fn update( shell: &mut Shell<'_, Message>, state: &mut State, ) -> event::Status { - if state.drag_initiated.is_none() && !cursor.is_over(layout.bounds()) { + let layout_bounds = layout.bounds(); + + if let Some(message) = widget.on_resize.as_ref() { + let size = layout_bounds.size(); + if state.last_size != Some(size) { + shell.publish(message(size)); + state.last_size = Some(size); + } + } + + if state.drag_initiated.is_none() && !cursor.is_over(layout_bounds) { return event::Status::Ignored; } @@ -349,7 +378,7 @@ fn update( { state.drag_initiated = cursor.position(); if let Some(message) = widget.on_press.as_ref() { - shell.publish(message(cursor.position_in(layout.bounds()))); + shell.publish(message(cursor.position_in(layout_bounds))); return event::Status::Captured; } @@ -360,7 +389,7 @@ fn update( { state.drag_initiated = None; if let Some(message) = widget.on_release.as_ref() { - shell.publish(message(cursor.position_in(layout.bounds()))); + shell.publish(message(cursor.position_in(layout_bounds))); return event::Status::Captured; } @@ -368,7 +397,7 @@ fn update( if let Some(message) = widget.on_right_press.as_ref() { if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) = event { - shell.publish(message(cursor.position_in(layout.bounds()))); + shell.publish(message(cursor.position_in(layout_bounds))); return event::Status::Captured; } @@ -376,7 +405,7 @@ fn update( if let Some(message) = widget.on_right_press_no_capture.as_ref() { if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) = event { - shell.publish(message(cursor.position_in(layout.bounds()))); + shell.publish(message(cursor.position_in(layout_bounds))); return event::Status::Ignored; } @@ -384,7 +413,7 @@ fn update( if let Some(message) = widget.on_right_release.as_ref() { if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Right)) = event { - shell.publish(message(cursor.position_in(layout.bounds()))); + shell.publish(message(cursor.position_in(layout_bounds))); return event::Status::Captured; } @@ -392,7 +421,7 @@ fn update( if let Some(message) = widget.on_middle_press.as_ref() { if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Middle)) = event { - shell.publish(message(cursor.position_in(layout.bounds()))); + shell.publish(message(cursor.position_in(layout_bounds))); return event::Status::Captured; } @@ -400,7 +429,7 @@ fn update( if let Some(message) = widget.on_middle_release.as_ref() { if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Middle)) = event { - shell.publish(message(cursor.position_in(layout.bounds()))); + shell.publish(message(cursor.position_in(layout_bounds))); return event::Status::Captured; } @@ -408,7 +437,7 @@ fn update( if let Some(message) = widget.on_back_press.as_ref() { if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Back)) = event { - shell.publish(message(cursor.position_in(layout.bounds()))); + shell.publish(message(cursor.position_in(layout_bounds))); return event::Status::Captured; } @@ -416,7 +445,7 @@ fn update( if let Some(message) = widget.on_back_release.as_ref() { if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Back)) = event { - shell.publish(message(cursor.position_in(layout.bounds()))); + shell.publish(message(cursor.position_in(layout_bounds))); return event::Status::Captured; } @@ -424,7 +453,7 @@ fn update( if let Some(message) = widget.on_forward_press.as_ref() { if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Forward)) = event { - shell.publish(message(cursor.position_in(layout.bounds()))); + shell.publish(message(cursor.position_in(layout_bounds))); return event::Status::Captured; } @@ -432,20 +461,20 @@ fn update( if let Some(message) = widget.on_forward_release.as_ref() { if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Forward)) = event { - shell.publish(message(cursor.position_in(layout.bounds()))); + shell.publish(message(cursor.position_in(layout_bounds))); return event::Status::Captured; } } - if let Some((message, drag_source)) = widget.on_drag.as_ref().zip(state.drag_initiated) { - if let Some(position) = cursor.position() { - if position.distance(drag_source) > 1.0 { - shell.publish(message(cursor.position_in(layout.bounds()))); - - return event::Status::Captured; - } - } + if let Some((message, drag_rect)) = widget.on_drag.as_ref().zip(state.drag_rect(cursor)) { + shell.publish(message(drag_rect.intersection(&layout_bounds).map( + |mut rect| { + rect.x -= layout_bounds.x; + rect.y -= layout_bounds.y; + rect + }, + ))); } event::Status::Ignored diff --git a/src/tab.rs b/src/tab.rs index 1ba9e85..85ab5f8 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -9,6 +9,7 @@ use cosmic::{ //TODO: export in cosmic::widget widget::{horizontal_rule, scrollable::Viewport}, Alignment, + Color, ContentFit, Length, Point, @@ -20,6 +21,7 @@ use cosmic::{ use mime_guess::MimeGuess; use once_cell::sync::Lazy; use std::{ + cell::Cell, cmp::Ordering, collections::HashMap, fmt, @@ -40,6 +42,8 @@ use crate::{ }; const DOUBLE_CLICK_DURATION: Duration = Duration::from_millis(500); +const GRID_ITEM_HEIGHT: usize = 116; +const GRID_ITEM_WIDTH: usize = 96; //TODO: adjust for locales? const TIME_FORMAT: &'static str = "%a %-d %b %-Y %r"; static SPECIAL_DIRS: Lazy> = Lazy::new(|| { @@ -73,30 +77,39 @@ static SPECIAL_DIRS: Lazy> = Lazy::new(|| { } special_dirs }); -fn button_style(selected: bool) -> theme::Button { - //TODO: move to libcosmic + +fn button_appearance( + theme: &theme::Theme, + selected: bool, + accent: bool, +) -> widget::button::Appearance { + let cosmic = theme.cosmic(); + let mut appearance = widget::button::Appearance::new(); + if selected { + if accent { + appearance.background = Some(Color::from(cosmic.accent_color()).into()); + appearance.icon_color = Some(Color::from(cosmic.on_accent_color())); + appearance.text_color = Some(Color::from(cosmic.on_accent_color())); + } else { + appearance.background = Some(Color::from(cosmic.bg_component_color()).into()); + } + } + appearance.border_radius = cosmic.radius_s().into(); + appearance +} + +fn button_style(selected: bool, accent: bool) -> theme::Button { + //TODO: move to libcosmic? theme::Button::Custom { active: Box::new(move |focused, theme| { - let mut appearance = - widget::button::StyleSheet::active(theme, focused, &theme::Button::MenuItem); - if !selected { - appearance.background = None; - } - appearance - }), - disabled: Box::new(move |theme| { - let mut appearance = - widget::button::StyleSheet::disabled(theme, &theme::Button::MenuItem); - if !selected { - appearance.background = None; - } - appearance + button_appearance(theme, selected || focused, accent) }), + disabled: Box::new(move |theme| button_appearance(theme, selected, accent)), hovered: Box::new(move |focused, theme| { - widget::button::StyleSheet::hovered(theme, focused, &theme::Button::MenuItem) + button_appearance(theme, selected || focused, accent) }), pressed: Box::new(move |focused, theme| { - widget::button::StyleSheet::pressed(theme, focused, &theme::Button::MenuItem) + button_appearance(theme, selected || focused, accent) }), } } @@ -243,6 +256,7 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec { Some(mime) if mime.type_() == "image" => None, _ => Some(Err(())), }, + rect_opt: Cell::new(None), selected: false, click_time: None, }); @@ -323,6 +337,7 @@ pub fn scan_trash(sizes: IconSizes) -> Vec { icon_handle_grid, icon_handle_list, thumbnail_res_opt: Some(Err(())), + rect_opt: Cell::new(None), selected: false, click_time: None, }); @@ -369,7 +384,7 @@ pub enum Message { Config(TabConfig), ContextAction(Action), ContextMenu(Option), - Drag(Option), + Drag(Option), EditLocation(Option), GoNext, GoPrevious, @@ -380,6 +395,7 @@ pub enum Message { Location(Location), LocationUp, Open, + Resize(Size), RightClick(usize), Scroll(Viewport), Thumbnail(PathBuf, Result), @@ -422,6 +438,7 @@ pub struct Item { pub icon_handle_grid: widget::icon::Handle, pub icon_handle_list: widget::icon::Handle, pub thumbnail_res_opt: Option>, + pub rect_opt: Cell>, pub selected: bool, pub click_time: Option, } @@ -510,6 +527,7 @@ impl fmt::Debug for Item { .field("hidden", &self.hidden) .field("path", &self.path) // icon_handles + .field("rect_opt", &self.rect_opt) .field("selected", &self.selected) .field("click_time", &self.click_time) .finish() @@ -535,8 +553,8 @@ pub struct Tab { pub items_opt: Option>, pub view: View, pub dialog: Option, - pub drag_opt: Option, pub scroll_opt: Option, + pub size_opt: Option, pub edit_location: Option, pub edit_location_id: widget::Id, pub history_i: usize, @@ -555,10 +573,10 @@ impl Tab { location, context_menu: None, items_opt: None, - view: View::List, + view: View::Grid, dialog: None, - drag_opt: None, scroll_opt: None, + size_opt: None, edit_location: None, edit_location_id: widget::Id::unique(), history_i: 0, @@ -587,10 +605,12 @@ impl Tab { None => return, }; - println!("{:?}", rect); for (_i, item) in items.iter_mut().enumerate() { - item.selected = false; - //TODO + //TODO: modifiers + item.selected = match item.rect_opt.get() { + Some(item_rect) => item_rect.intersects(&rect), + None => false, + }; } } @@ -661,32 +681,11 @@ impl Tab { Message::ContextMenu(point_opt) => { self.context_menu = point_opt; } - Message::Drag(point_opt) => match point_opt { - Some(point) => { - let drag = match self.drag_opt { - Some(some) => some, - None => { - self.drag_opt = Some(point); - point - } - }; - let min_x = drag.x.min(point.x); - let max_x = drag.x.max(point.x); - let min_y = drag.y.min(point.y); - let max_y = drag.y.max(point.y); - let offset_y = self - .scroll_opt - .map(|x| x.absolute_offset().y) - .unwrap_or_default(); - let rect = Rectangle::new( - Point::new(min_x, min_y + offset_y), - Size::new(max_x - min_x, max_y - min_y), - ); + Message::Drag(rect_opt) => match rect_opt { + Some(rect) => { self.select_by_drag(rect); } - None => { - self.drag_opt = None; - } + None => {} }, Message::EditLocation(edit_location) => { if self.edit_location.is_none() && edit_location.is_some() { @@ -793,6 +792,9 @@ impl Tab { } } } + Message::Resize(size) => { + self.size_opt = Some(size); + } Message::RightClick(click_i) => { if let Some(ref mut items) = self.items_opt { if !items.get(click_i).map_or(false, |x| x.selected) { @@ -1106,62 +1108,121 @@ impl Tab { } pub fn grid_view(&self, core: &Core) -> Element { - let cosmic_theme::Spacing { space_xxs, .. } = core.system_theme().cosmic().spacing; + let cosmic_theme::Spacing { + space_xs, + space_xxs, + space_xxxs, + .. + } = core.system_theme().cosmic().spacing; - //TODO: get from config - let item_width = Length::Fixed(96.0); - let item_height = Length::Fixed(116.0); let TabConfig { show_hidden, icon_sizes, } = self.config; - let mut children: Vec> = Vec::new(); + let max_width = match self.size_opt { + Some(size) => { + // Hack to make room for scroll bar + (size.width.floor() as usize) + .checked_sub(space_xs as usize) + .unwrap_or(0) + } + None => 0, + } + .max(GRID_ITEM_WIDTH); + + let (cols, column_spacing) = { + let width_m1 = max_width.checked_sub(GRID_ITEM_WIDTH).unwrap_or(0); + let cols_m1 = width_m1 / (GRID_ITEM_WIDTH + space_xxs as usize); + let cols = cols_m1 + 1; + let spacing = width_m1 + .checked_div(cols_m1) + .unwrap_or(0) + .checked_sub(GRID_ITEM_WIDTH) + .unwrap_or(0); + (cols, spacing as u16) + }; + + let mut grid = widget::grid() + .column_spacing(column_spacing) + .row_spacing(space_xxs) + // Hack to make room for scroll bar + .padding([0, space_xxs, 0, 0].into()); if let Some(ref items) = self.items_opt { let mut count = 0; + let mut col = 0; + let mut row = 0; let mut hidden = 0; for (i, item) in items.iter().enumerate() { if !show_hidden && item.hidden { + item.rect_opt.set(None); hidden += 1; continue; } + item.rect_opt.set(Some(Rectangle::new( + Point::new( + (col * (GRID_ITEM_WIDTH + column_spacing as usize)) as f32, + (row * (GRID_ITEM_HEIGHT + space_xxs as usize)) as f32, + ), + Size::new(GRID_ITEM_WIDTH as f32, GRID_ITEM_HEIGHT as f32), + ))); - let button = widget::button( - widget::column::with_children(vec![ + //TODO: one focus group per grid item (needs custom widget) + let buttons = vec![ + widget::button( widget::icon::icon(item.icon_handle_grid.clone()) .content_fit(ContentFit::Contain) - .size(icon_sizes.grid()) - .into(), - widget::text(item.name.clone()).into(), - ]) + .size(icon_sizes.grid()), + ) + .on_press(Message::Click(Some(i))) + .padding(space_xxxs) + .style(button_style(item.selected, false)), + widget::button(widget::text(item.name.clone())) + .on_press(Message::Click(Some(i))) + .padding([0, space_xxs]) + .style(button_style(item.selected, true)), + ]; + + let mut column = widget::column::with_capacity(buttons.len()) .align_items(Alignment::Center) - .spacing(space_xxs) - .height(item_height) - .width(item_width), - ) - .padding(0) - .style(button_style(item.selected)) - .on_press(Message::Click(Some(i))); - if self.context_menu.is_some() { - children.push(button.into()); - } else { - children.push( - mouse_area::MouseArea::new(button) - .on_right_press_no_capture(move |_point_opt| Message::RightClick(i)) - .into(), - ); + .height(Length::Fixed(GRID_ITEM_HEIGHT as f32)) + .width(Length::Fixed(GRID_ITEM_WIDTH as f32)); + for button in buttons { + if self.context_menu.is_some() { + column = column.push(button) + } else { + column = column.push( + mouse_area::MouseArea::new(button).on_right_press_no_capture( + move |_point_opt| Message::RightClick(i), + ), + ); + } } + + grid = grid.push(column); + count += 1; + col += 1; + if col >= cols { + col = 0; + row += 1; + grid = grid.insert_row(); + } } if count == 0 { return self.empty_view(hidden > 0, core); } } - widget::scrollable(widget::flex_row(children)) - .on_scroll(Message::Scroll) - .width(Length::Fill) - .into() + //TODO: allow drag in empty area + widget::scrollable( + mouse_area::MouseArea::new(grid) + .on_drag(Message::Drag) + .show_drag_rect(true), + ) + .on_scroll(Message::Scroll) + .width(Length::Fill) + .into() } pub fn list_view(&self, core: &Core) -> Element { @@ -1218,9 +1279,12 @@ impl Tab { } = self.config; for (i, item) in items.iter().enumerate() { if !show_hidden && item.hidden { + item.rect_opt.set(None); hidden += 1; continue; } + //TODO: correct rectangle + item.rect_opt.set(None); if count > 0 { children.push(horizontal_rule(1).into()); @@ -1272,7 +1336,7 @@ impl Tab { .spacing(space_xxs), ) .padding(space_xxs) - .style(button_style(item.selected)) + .style(button_style(item.selected, false)) .on_press(Message::Click(Some(i))); if self.context_menu.is_some() { children.push(button.into()); @@ -1309,12 +1373,10 @@ impl Tab { }; let mut mouse_area = mouse_area::MouseArea::new(widget::container(item_view).height(Length::Fill)) - .on_drag(move |point_opt| Message::Drag(point_opt)) .on_press(move |_point_opt| Message::Click(None)) - .on_release(move |_point_opt| Message::Drag(None)) .on_back_press(move |_point_opt| Message::GoPrevious) .on_forward_press(move |_point_opt| Message::GoNext) - .show_drag_box(true); + .on_resize(Message::Resize); if self.context_menu.is_some() { mouse_area = mouse_area.on_right_press(move |_point_opt| Message::ContextMenu(None)); } else {