max / audiofiles
22 files changed,
+350 insertions,
-344 deletions
| @@ -3,22 +3,15 @@ | |||
| 3 | 3 | version = 4 | |
| 4 | 4 | ||
| 5 | 5 | [[package]] | |
| 6 | - | name = "ab_glyph" | |
| 7 | - | version = "0.2.32" | |
| 6 | + | name = "accesskit" | |
| 7 | + | version = "0.24.0" | |
| 8 | 8 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 9 | - | checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2" | |
| 9 | + | checksum = "5351dcebb14b579ccab05f288596b2ae097005be7ee50a7c3d4ca9d0d5a66f6a" | |
| 10 | 10 | dependencies = [ | |
| 11 | - | "ab_glyph_rasterizer", | |
| 12 | - | "owned_ttf_parser", | |
| 11 | + | "uuid", | |
| 13 | 12 | ] | |
| 14 | 13 | ||
| 15 | 14 | [[package]] | |
| 16 | - | name = "ab_glyph_rasterizer" | |
| 17 | - | version = "0.1.10" | |
| 18 | - | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 19 | - | checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" | |
| 20 | - | ||
| 21 | - | [[package]] | |
| 22 | 15 | name = "adler2" | |
| 23 | 16 | version = "2.0.1" | |
| 24 | 17 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| @@ -59,21 +52,21 @@ dependencies = [ | |||
| 59 | 52 | ||
| 60 | 53 | [[package]] | |
| 61 | 54 | name = "alsa" | |
| 62 | - | version = "0.9.1" | |
| 55 | + | version = "0.11.0" | |
| 63 | 56 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 64 | - | checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" | |
| 57 | + | checksum = "812947049edcd670a82cd5c73c3661d2e58468577ba8489de58e1a73c04cbd5d" | |
| 65 | 58 | dependencies = [ | |
| 66 | 59 | "alsa-sys", | |
| 67 | - | "bitflags 2.11.0", | |
| 60 | + | "bitflags 2.12.1", | |
| 68 | 61 | "cfg-if", | |
| 69 | 62 | "libc", | |
| 70 | 63 | ] | |
| 71 | 64 | ||
| 72 | 65 | [[package]] | |
| 73 | 66 | name = "alsa-sys" | |
| 74 | - | version = "0.3.1" | |
| 67 | + | version = "0.4.0" | |
| 75 | 68 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 76 | - | checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" | |
| 69 | + | checksum = "ad7569085a265dd3f607ebecce7458eaab2132a84393534c95b18dcbc3f31e04" | |
| 77 | 70 | dependencies = [ | |
| 78 | 71 | "libc", | |
| 79 | 72 | "pkg-config", | |
| @@ -81,23 +74,30 @@ dependencies = [ | |||
| 81 | 74 | ||
| 82 | 75 | [[package]] | |
| 83 | 76 | name = "android-activity" | |
| 84 | - | version = "0.6.0" | |
| 77 | + | version = "0.6.1" | |
| 85 | 78 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 86 | - | checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" | |
| 79 | + | checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" | |
| 87 | 80 | dependencies = [ | |
| 88 | 81 | "android-properties", | |
| 89 | - | "bitflags 2.11.0", | |
| 82 | + | "bitflags 2.12.1", | |
| 90 | 83 | "cc", | |
| 91 | - | "cesu8", | |
| 92 | - | "jni", | |
| 93 | - | "jni-sys", | |
| 84 | + | "jni 0.22.4", | |
| 94 | 85 | "libc", | |
| 95 | 86 | "log", | |
| 96 | - | "ndk 0.9.0", | |
| 87 | + | "ndk", | |
| 97 | 88 | "ndk-context", | |
| 98 | - | "ndk-sys 0.6.0+11769913", | |
| 89 | + | "ndk-sys", | |
| 99 | 90 | "num_enum", | |
| 100 | - | "thiserror 1.0.69", | |
| 91 | + | "thiserror 2.0.18", | |
| 92 | + | ] | |
| 93 | + | ||
| 94 | + | [[package]] | |
| 95 | + | name = "android-build" | |
| 96 | + | version = "0.1.4" | |
| 97 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 98 | + | checksum = "f9fc9904ad2ad097c3c1cfe2eacaaf0fc24710936fa9ed941cb310b7c6ed2ab7" | |
| 99 | + | dependencies = [ | |
| 100 | + | "windows-sys 0.52.0", | |
| 101 | 101 | ] | |
| 102 | 102 | ||
| 103 | 103 | [[package]] | |
| @@ -117,9 +117,9 @@ dependencies = [ | |||
| 117 | 117 | ||
| 118 | 118 | [[package]] | |
| 119 | 119 | name = "anyhow" | |
| 120 | - | version = "1.0.101" | |
| 120 | + | version = "1.0.102" | |
| 121 | 121 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 122 | - | checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" | |
| 122 | + | checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" | |
| 123 | 123 | ||
| 124 | 124 | [[package]] | |
| 125 | 125 | name = "arboard" | |
| @@ -130,7 +130,7 @@ dependencies = [ | |||
| 130 | 130 | "clipboard-win", | |
| 131 | 131 | "image", | |
| 132 | 132 | "log", | |
| 133 | - | "objc2 0.6.3", | |
| 133 | + | "objc2 0.6.4", | |
| 134 | 134 | "objc2-app-kit 0.3.2", | |
| 135 | 135 | "objc2-core-foundation", | |
| 136 | 136 | "objc2-core-graphics", | |
| @@ -166,15 +166,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| 166 | 166 | checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" | |
| 167 | 167 | ||
| 168 | 168 | [[package]] | |
| 169 | - | name = "ash" | |
| 170 | - | version = "0.38.0+1.3.281" | |
| 171 | - | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 172 | - | checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" | |
| 173 | - | dependencies = [ | |
| 174 | - | "libloading 0.8.9", | |
| 175 | - | ] | |
| 176 | - | ||
| 177 | - | [[package]] | |
| 178 | 169 | name = "ashpd" | |
| 179 | 170 | version = "0.11.1" | |
| 180 | 171 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| @@ -258,7 +249,7 @@ dependencies = [ | |||
| 258 | 249 | "futures-lite", | |
| 259 | 250 | "parking", | |
| 260 | 251 | "polling", | |
| 261 | - | "rustix 1.1.3", | |
| 252 | + | "rustix 1.1.4", | |
| 262 | 253 | "slab", | |
| 263 | 254 | "windows-sys 0.61.2", | |
| 264 | 255 | ] | |
| @@ -300,7 +291,7 @@ dependencies = [ | |||
| 300 | 291 | "cfg-if", | |
| 301 | 292 | "event-listener", | |
| 302 | 293 | "futures-lite", | |
| 303 | - | "rustix 1.1.3", | |
| 294 | + | "rustix 1.1.4", | |
| 304 | 295 | ] | |
| 305 | 296 | ||
| 306 | 297 | [[package]] | |
| @@ -311,14 +302,14 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" | |||
| 311 | 302 | dependencies = [ | |
| 312 | 303 | "proc-macro2", | |
| 313 | 304 | "quote", | |
| 314 | - | "syn 2.0.116", | |
| 305 | + | "syn 2.0.117", | |
| 315 | 306 | ] | |
| 316 | 307 | ||
| 317 | 308 | [[package]] | |
| 318 | 309 | name = "async-signal" | |
| 319 | - | version = "0.2.13" | |
| 310 | + | version = "0.2.14" | |
| 320 | 311 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 321 | - | checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" | |
| 312 | + | checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" | |
| 322 | 313 | dependencies = [ | |
| 323 | 314 | "async-io", | |
| 324 | 315 | "async-lock", | |
| @@ -326,7 +317,7 @@ dependencies = [ | |||
| 326 | 317 | "cfg-if", | |
| 327 | 318 | "futures-core", | |
| 328 | 319 | "futures-io", | |
| 329 | - | "rustix 1.1.3", | |
| 320 | + | "rustix 1.1.4", | |
| 330 | 321 | "signal-hook-registry", | |
| 331 | 322 | "slab", | |
| 332 | 323 | "windows-sys 0.61.2", | |
| @@ -346,7 +337,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" | |||
| 346 | 337 | dependencies = [ | |
| 347 | 338 | "proc-macro2", | |
| 348 | 339 | "quote", | |
| 349 | - | "syn 2.0.116", | |
| 340 | + | "syn 2.0.117", | |
| 350 | 341 | ] | |
| 351 | 342 | ||
| 352 | 343 | [[package]] | |
| @@ -401,6 +392,7 @@ dependencies = [ | |||
| 401 | 392 | "tempfile", | |
| 402 | 393 | "thiserror 2.0.18", | |
| 403 | 394 | "tokio", | |
| 395 | + | "toml", | |
| 404 | 396 | "tracing", | |
| 405 | 397 | "tracing-subscriber", | |
| 406 | 398 | "tray-icon", | |
| @@ -430,7 +422,7 @@ dependencies = [ | |||
| 430 | 422 | "egui_extras", | |
| 431 | 423 | "hound", | |
| 432 | 424 | "libc", | |
| 433 | - | "objc2 0.6.3", | |
| 425 | + | "objc2 0.6.4", | |
| 434 | 426 | "objc2-app-kit 0.3.2", | |
| 435 | 427 | "objc2-foundation 0.3.2", | |
| 436 | 428 | "parking_lot", | |
| @@ -444,8 +436,8 @@ dependencies = [ | |||
| 444 | 436 | "thiserror 2.0.18", | |
| 445 | 437 | "toml", | |
| 446 | 438 | "tracing", | |
| 447 | - | "windows 0.62.2", | |
| 448 | - | "windows-core 0.62.2", | |
| 439 | + | "windows", | |
| 440 | + | "windows-core", | |
| 449 | 441 | ] | |
| 450 | 442 | ||
| 451 | 443 | [[package]] | |
| @@ -519,9 +511,9 @@ dependencies = [ | |||
| 519 | 511 | ||
| 520 | 512 | [[package]] | |
| 521 | 513 | name = "autocfg" | |
| 522 | - | version = "1.5.0" | |
| 514 | + | version = "1.5.1" | |
| 523 | 515 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 524 | - | checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" | |
| 516 | + | checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" | |
| 525 | 517 | ||
| 526 | 518 | [[package]] | |
| 527 | 519 | name = "base64" | |
| @@ -536,37 +528,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| 536 | 528 | checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" | |
| 537 | 529 | ||
| 538 | 530 | [[package]] | |
| 539 | - | name = "bindgen" | |
| 540 | - | version = "0.72.1" | |
| 541 | - | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 542 | - | checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" | |
| 543 | - | dependencies = [ | |
| 544 | - | "bitflags 2.11.0", | |
| 545 | - | "cexpr", | |
| 546 | - | "clang-sys", | |
| 547 | - | "itertools", | |
| 548 | - | "proc-macro2", | |
| 549 | - | "quote", | |
| 550 | - | "regex", | |
| 551 | - | "rustc-hash 2.1.1", | |
| 552 | - | "shlex", | |
| 553 | - | "syn 2.0.116", | |
| 554 | - | ] | |
| 555 | - | ||
| 556 | - | [[package]] | |
| 557 | 531 | name = "bit-set" | |
| 558 | - | version = "0.8.0" | |
| 532 | + | version = "0.9.1" | |
| 559 | 533 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 560 | - | checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" | |
| 534 | + | checksum = "34ddef2995421ab6a5c779542c81ee77c115206f4ad9d5a8e05f4ff49716a3dd" | |
| 561 | 535 | dependencies = [ | |
| 562 | 536 | "bit-vec", | |
| 563 | 537 | ] | |
| 564 | 538 | ||
| 565 | 539 | [[package]] | |
| 566 | 540 | name = "bit-vec" | |
| 567 | - | version = "0.8.0" | |
| 541 | + | version = "0.9.1" | |
| 568 | 542 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 569 | - | checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" | |
| 543 | + | checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" | |
| 570 | 544 | ||
| 571 | 545 | [[package]] | |
| 572 | 546 | name = "bitflags" | |
| @@ -576,9 +550,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" | |||
| 576 | 550 | ||
| 577 | 551 | [[package]] | |
| 578 | 552 | name = "bitflags" | |
| 579 | - | version = "2.11.0" | |
| 553 | + | version = "2.12.1" | |
| 580 | 554 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 581 | - | checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" | |
| 555 | + | checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" | |
| 582 | 556 | dependencies = [ | |
| 583 | 557 | "serde_core", | |
| 584 | 558 | ] | |
| @@ -622,7 +596,7 @@ version = "0.6.2" | |||
| 622 | 596 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 623 | 597 | checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" | |
| 624 | 598 | dependencies = [ | |
| 625 | - | "objc2 0.6.3", | |
| 599 | + | "objc2 0.6.4", | |
| 626 | 600 | ] | |
| 627 | 601 | ||
| 628 | 602 | [[package]] | |
| @@ -646,9 +620,9 @@ checksum = "6332c61c205ff066246fff2cb876cdf9009557200f96e15d88d156193b16775b" | |||
| 646 | 620 | ||
| 647 | 621 | [[package]] | |
| 648 | 622 | name = "bumpalo" | |
| 649 | - | version = "3.19.1" | |
| 623 | + | version = "3.20.3" | |
| 650 | 624 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 651 | - | checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" | |
| 625 | + | checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" | |
| 652 | 626 | ||
| 653 | 627 | [[package]] | |
| 654 | 628 | name = "bytemuck" | |
| @@ -667,7 +641,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" | |||
| 667 | 641 | dependencies = [ | |
| 668 | 642 | "proc-macro2", | |
| 669 | 643 | "quote", | |
| 670 | - | "syn 2.0.116", | |
| 644 | + | "syn 2.0.117", | |
| 671 | 645 | ] | |
| 672 | 646 | ||
| 673 | 647 | [[package]] | |
| @@ -694,7 +668,7 @@ version = "0.18.5" | |||
| 694 | 668 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 695 | 669 | checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" | |
| 696 | 670 | dependencies = [ | |
| 697 | - | "bitflags 2.11.0", | |
| 671 | + | "bitflags 2.12.1", | |
| 698 | 672 | "cairo-sys-rs", | |
| 699 | 673 | "glib", | |
| 700 | 674 | "libc", | |
| @@ -719,7 +693,7 @@ version = "0.13.0" | |||
| 719 | 693 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 720 | 694 | checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" | |
| 721 | 695 | dependencies = [ | |
| 722 | - | "bitflags 2.11.0", | |
| 696 | + | "bitflags 2.12.1", | |
| 723 | 697 | "log", | |
| 724 | 698 | "polling", | |
| 725 | 699 | "rustix 0.38.44", | |
| @@ -733,9 +707,9 @@ version = "0.14.4" | |||
| 733 | 707 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 734 | 708 | checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" | |
| 735 | 709 | dependencies = [ | |
| 736 | - | "bitflags 2.11.0", | |
| 710 | + | "bitflags 2.12.1", | |
| 737 | 711 | "polling", | |
| 738 | - | "rustix 1.1.3", | |
| 712 | + | "rustix 1.1.4", | |
| 739 | 713 | "slab", | |
| 740 | 714 | "tracing", | |
| 741 | 715 | ] | |
| @@ -759,16 +733,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| 759 | 733 | checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa" | |
| 760 | 734 | dependencies = [ | |
| 761 | 735 | "calloop 0.14.4", | |
| 762 | - | "rustix 1.1.3", | |
| 736 | + | "rustix 1.1.4", | |
| 763 | 737 | "wayland-backend", | |
| 764 | 738 | "wayland-client", | |
| 765 | 739 | ] | |
| 766 | 740 | ||
| 767 | 741 | [[package]] | |
| 768 | 742 | name = "cc" | |
| 769 | - | version = "1.2.56" | |
| 743 | + | version = "1.2.63" | |
| 770 | 744 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 771 | - | checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" | |
| 745 | + | checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" | |
| 772 | 746 | dependencies = [ | |
| 773 | 747 | "find-msvc-tools", | |
| 774 | 748 | "jobserver", | |
| @@ -783,15 +757,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| 783 | 757 | checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" | |
| 784 | 758 | ||
| 785 | 759 | [[package]] | |
| 786 | - | name = "cexpr" | |
| 787 | - | version = "0.6.0" | |
| 788 | - | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 789 | - | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" | |
| 790 | - | dependencies = [ | |
| 791 | - | "nom", | |
| 792 | - | ] | |
| 793 | - | ||
| 794 | - | [[package]] | |
| 795 | 760 | name = "cfg-expr" | |
| 796 | 761 | version = "0.15.8" | |
| 797 | 762 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| @@ -872,17 +837,6 @@ dependencies = [ | |||
| 872 | 837 | ] | |
| 873 | 838 | ||
| 874 | 839 | [[package]] | |
| 875 | - | name = "clang-sys" | |
| 876 | - | version = "1.8.1" | |
| 877 | - | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 878 | - | checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" | |
| 879 | - | dependencies = [ | |
| 880 | - | "glob", | |
| 881 | - | "libc", | |
| 882 | - | "libloading 0.8.9", | |
| 883 | - | ] | |
| 884 | - | ||
| 885 | - | [[package]] | |
| 886 | 840 | name = "clipboard-win" | |
| 887 | 841 | version = "5.4.1" | |
| 888 | 842 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| @@ -893,15 +847,23 @@ dependencies = [ | |||
| 893 | 847 | ||
| 894 | 848 | [[package]] | |
| 895 | 849 | name = "codespan-reporting" | |
| 896 | - | version = "0.11.1" | |
| 850 | + | version = "0.13.1" | |
| 897 | 851 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 898 | - | checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" | |
| 852 | + | checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681" | |
| 899 | 853 | dependencies = [ | |
| 900 | - | "termcolor", | |
| 901 | 854 | "unicode-width", | |
| 902 | 855 | ] | |
| 903 | 856 | ||
| 904 | 857 | [[package]] | |
| 858 | + | name = "color" | |
| 859 | + | version = "0.3.3" | |
| 860 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 861 | + | checksum = "2ec7c5eb7a16992b1904d76c517d170ab353b0e0b3d5a0c81a8a0cd1037893cf" | |
| 862 | + | dependencies = [ | |
| 863 | + | "bytemuck", | |
| 864 | + | ] | |
| 865 | + | ||
| 866 | + | [[package]] | |
| 905 | 867 | name = "combine" | |
| 906 | 868 | version = "4.6.7" | |
| 907 | 869 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| @@ -992,32 +954,26 @@ dependencies = [ | |||
| 992 | 954 | ||
| 993 | 955 | [[package]] | |
| 994 | 956 | name = "coreaudio-rs" | |
| 995 | - | version = "0.11.3" | |
| 957 | + | version = "0.14.2" | |
| 996 | 958 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 997 | - | checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" | |
| 959 | + | checksum = "7d5d7dca3ebcf65a035582c9ad4385371a9d9ee6537474d2a278f4e1e475bb58" | |
| 998 | 960 | dependencies = [ | |
| 999 | - | "bitflags 1.3.2", | |
| 1000 | - | "core-foundation-sys", | |
| 1001 | - | "coreaudio-sys", | |
| 1002 | - | ] | |
| 1003 | - | ||
| 1004 | - | [[package]] | |
| 1005 | - | name = "coreaudio-sys" | |
| 1006 | - | version = "0.2.17" | |
| 1007 | - | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1008 | - | checksum = "ceec7a6067e62d6f931a2baf6f3a751f4a892595bcec1461a3c94ef9949864b6" | |
| 1009 | - | dependencies = [ | |
| 1010 | - | "bindgen", | |
| 961 | + | "bitflags 2.12.1", | |
| 962 | + | "libc", | |
| 963 | + | "objc2-audio-toolbox", | |
| 964 | + | "objc2-core-audio", | |
| 965 | + | "objc2-core-audio-types", | |
| 966 | + | "objc2-core-foundation", | |
| 1011 | 967 | ] | |
| 1012 | 968 | ||
| 1013 | 969 | [[package]] | |
| 1014 | 970 | name = "coremidi" | |
| 1015 | - | version = "0.8.0" | |
| 971 | + | version = "0.9.0" | |
| 1016 | 972 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1017 | - | checksum = "964eb3e10ea8b0d29c797086aab3ca730f75e06dced0cb980642fd274a5cca30" | |
| 973 | + | checksum = "f32f5d3e1b800aa7ea10e9e83c87cbc1daef1397ee86cd599458b3c3b136428a" | |
| 1018 | 974 | dependencies = [ | |
| 1019 | 975 | "block", | |
| 1020 | - | "core-foundation 0.9.4", | |
| 976 | + | "core-foundation 0.10.1", | |
| 1021 | 977 | "core-foundation-sys", | |
| 1022 | 978 | "coremidi-sys", | |
| 1023 | 979 | ] | |
| @@ -1033,25 +989,32 @@ dependencies = [ | |||
| 1033 | 989 | ||
| 1034 | 990 | [[package]] | |
| 1035 | 991 | name = "cpal" | |
| 1036 | - | version = "0.15.3" | |
| 992 | + | version = "0.17.3" | |
| 1037 | 993 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1038 | - | checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" | |
| 994 | + | checksum = "d8942da362c0f0d895d7cac616263f2f9424edc5687364dfd1d25ef7eba506d7" | |
| 1039 | 995 | dependencies = [ | |
| 1040 | 996 | "alsa", | |
| 1041 | - | "core-foundation-sys", | |
| 1042 | 997 | "coreaudio-rs", | |
| 1043 | 998 | "dasp_sample", | |
| 1044 | - | "jni", | |
| 999 | + | "jni 0.21.1", | |
| 1045 | 1000 | "js-sys", | |
| 1046 | 1001 | "libc", | |
| 1047 | 1002 | "mach2", | |
| 1048 | - | "ndk 0.8.0", | |
| 1003 | + | "ndk", | |
| 1049 | 1004 | "ndk-context", | |
| 1050 | - | "oboe", | |
| 1005 | + | "num-derive", | |
| 1006 | + | "num-traits", | |
| 1007 | + | "objc2 0.6.4", | |
| 1008 | + | "objc2-audio-toolbox", | |
| 1009 | + | "objc2-avf-audio", | |
| 1010 | + | "objc2-core-audio", | |
| 1011 | + | "objc2-core-audio-types", | |
| 1012 | + | "objc2-core-foundation", | |
| 1013 | + | "objc2-foundation 0.3.2", | |
| 1051 | 1014 | "wasm-bindgen", | |
| 1052 | 1015 | "wasm-bindgen-futures", | |
| 1053 | 1016 | "web-sys", | |
| 1054 | - | "windows 0.54.0", | |
| 1017 | + | "windows", | |
| 1055 | 1018 | ] | |
| 1056 | 1019 | ||
| 1057 | 1020 | [[package]] | |
| @@ -1175,32 +1138,32 @@ checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" | |||
| 1175 | 1138 | ||
| 1176 | 1139 | [[package]] | |
| 1177 | 1140 | name = "dispatch2" | |
| 1178 | - | version = "0.3.0" | |
| 1141 | + | version = "0.3.1" | |
| 1179 | 1142 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1180 | - | checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" | |
| 1143 | + | checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" | |
| 1181 | 1144 | dependencies = [ | |
| 1182 | - | "bitflags 2.11.0", | |
| 1145 | + | "bitflags 2.12.1", | |
| 1183 | 1146 | "block2 0.6.2", | |
| 1184 | 1147 | "libc", | |
| 1185 | - | "objc2 0.6.3", | |
| 1148 | + | "objc2 0.6.4", | |
| 1186 | 1149 | ] | |
| 1187 | 1150 | ||
| 1188 | 1151 | [[package]] | |
| 1189 | 1152 | name = "displaydoc" | |
| 1190 | - | version = "0.2.5" | |
| 1153 | + | version = "0.2.6" | |
| 1191 | 1154 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1192 | - | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" | |
| 1155 | + | checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" | |
| 1193 | 1156 | dependencies = [ |
Lines truncated
| @@ -12,14 +12,14 @@ audiofiles-core = { path = "crates/audiofiles-core" } | |||
| 12 | 12 | audiofiles-browser = { path = "crates/audiofiles-browser" } | |
| 13 | 13 | audiofiles-sync = { path = "crates/audiofiles-sync" } | |
| 14 | 14 | audiofiles-rhai = { path = "crates/audiofiles-rhai" } | |
| 15 | - | egui = { version = "0.31.1", default-features = false, features = ["default_fonts"] } | |
| 16 | - | egui_extras = { version = "0.31.1", default-features = false } | |
| 17 | - | eframe = { version = "0.31.1", default-features = false, features = ["default_fonts", "glow"] } | |
| 18 | - | cpal = "=0.15.3" | |
| 15 | + | egui = { version = "0.34", default-features = false, features = ["default_fonts"] } | |
| 16 | + | egui_extras = { version = "0.34", default-features = false } | |
| 17 | + | eframe = { version = "0.34", default-features = false, features = ["default_fonts", "glow"] } | |
| 18 | + | cpal = "0.17" | |
| 19 | 19 | rusqlite = { version = "0.31.0", features = ["bundled"] } | |
| 20 | 20 | thiserror = "2.0.18" | |
| 21 | 21 | sha2 = "0.10.9" | |
| 22 | - | symphonia = { version = "0.5.5", default-features = false, features = ["wav", "aiff", "mp3", "flac", "ogg", "vorbis", "pcm"] } | |
| 22 | + | symphonia = { version = "0.5.5", default-features = false, features = ["wav", "aiff", "mp3", "flac", "ogg", "vorbis", "pcm", "aac", "alac", "isomp4", "caf"] } | |
| 23 | 23 | parking_lot = "0.12.5" | |
| 24 | 24 | dirs = "6.0.0" | |
| 25 | 25 | stratum-dsp = "=1.0.0" | |
| @@ -34,7 +34,7 @@ hound = "3.5" | |||
| 34 | 34 | tracing = "0.1.44" | |
| 35 | 35 | tracing-subscriber = { version = "0.3.22", features = ["env-filter"] } | |
| 36 | 36 | rhai = { version = "1.21", features = ["sync"] } | |
| 37 | - | tray-icon = "0.21" | |
| 37 | + | tray-icon = "0.22" | |
| 38 | 38 | tokio = { version = "1", features = ["rt-multi-thread", "macros", "time", "sync"] } | |
| 39 | 39 | uuid = { version = "1", features = ["v4"] } | |
| 40 | 40 | base64 = "0.22" | |
| @@ -45,7 +45,7 @@ semver = "1" | |||
| 45 | 45 | open = "5" | |
| 46 | 46 | rayon = "1.10" | |
| 47 | 47 | libc = "0.2" | |
| 48 | - | midir = "0.10" | |
| 48 | + | midir = "0.11" | |
| 49 | 49 | docengine = { path = "../../MNW/shared/docengine" } | |
| 50 | 50 | tagtree = { path = "../../MNW/shared/tagtree" } | |
| 51 | 51 | theme-common = { path = "../../MNW/shared/theme-common" } |
| @@ -25,10 +25,11 @@ uuid = { workspace = true } | |||
| 25 | 25 | chrono = { workspace = true } | |
| 26 | 26 | midir = { workspace = true } | |
| 27 | 27 | rfd = { workspace = true } | |
| 28 | + | toml = { workspace = true } | |
| 28 | 29 | ||
| 29 | 30 | [dev-dependencies] | |
| 30 | 31 | tempfile = "3" | |
| 31 | 32 | ||
| 32 | 33 | [target.'cfg(target_os = "linux")'.dependencies] | |
| 33 | - | eframe = { version = "0.31.1", default-features = false, features = ["default_fonts", "glow", "x11", "wayland"] } | |
| 34 | + | eframe = { version = "0.34", default-features = false, features = ["default_fonts", "glow", "x11", "wayland"] } | |
| 34 | 35 | gtk = "0.18" |
| @@ -7,7 +7,7 @@ use super::{AudioFilesApp, AppScreen, SYNC_SERVER_URL}; | |||
| 7 | 7 | ||
| 8 | 8 | impl AudioFilesApp { | |
| 9 | 9 | /// Draw the license activation screen. | |
| 10 | - | pub(crate) fn draw_activation_screen(&mut self, ctx: &egui::Context) { | |
| 10 | + | pub(crate) fn draw_activation_screen(&mut self, ui: &mut egui::Ui) { | |
| 11 | 11 | // Poll async activation result (take from lock, then drop guard before mutating self) | |
| 12 | 12 | let activation = self.activation_result.lock().take(); | |
| 13 | 13 | if let Some(result) = activation { | |
| @@ -40,7 +40,7 @@ impl AudioFilesApp { | |||
| 40 | 40 | } | |
| 41 | 41 | } | |
| 42 | 42 | ||
| 43 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 43 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 44 | 44 | let available = ui.available_size(); | |
| 45 | 45 | ||
| 46 | 46 | ui.add_space((available.y * 0.35).max(40.0)); | |
| @@ -116,7 +116,7 @@ impl AudioFilesApp { | |||
| 116 | 116 | ||
| 117 | 117 | let can_activate = !self.activating && !self.license_key_input.trim().is_empty(); | |
| 118 | 118 | ui.horizontal(|ui| { | |
| 119 | - | let button_text = if self.activating { "Activating..." } else { "Activate" }; | |
| 119 | + | let button_text = if self.activating { "Activating\u{2026}" } else { "Activate" }; | |
| 120 | 120 | if ui.add_enabled(can_activate, egui::Button::new(button_text)).clicked() { | |
| 121 | 121 | self.start_activation(); | |
| 122 | 122 | } |
| @@ -37,11 +37,14 @@ pub fn start_output_stream(shared: Arc<SharedState>) -> Result<(Stream, u32, Str | |||
| 37 | 37 | .default_output_device() | |
| 38 | 38 | .ok_or(AudioError::NoDevice)?; | |
| 39 | 39 | ||
| 40 | - | let device_name = device.name().unwrap_or_else(|_| "default".to_string()); | |
| 40 | + | let device_name = device | |
| 41 | + | .description() | |
| 42 | + | .map(|d| d.name().to_string()) | |
| 43 | + | .unwrap_or_else(|_| "default".to_string()); | |
| 41 | 44 | let config = device.default_output_config()?; | |
| 42 | 45 | ||
| 43 | 46 | let channels = config.channels() as usize; | |
| 44 | - | let device_sample_rate = config.sample_rate().0; | |
| 47 | + | let device_sample_rate = config.sample_rate(); | |
| 45 | 48 | ||
| 46 | 49 | let stream = match config.sample_format() { | |
| 47 | 50 | cpal::SampleFormat::F32 => build_stream::<f32>( |
| @@ -142,21 +142,9 @@ fn main() -> eframe::Result<()> { | |||
| 142 | 142 | const SYNCKIT_TOML: &str = include_str!("../../../synckit.toml"); | |
| 143 | 143 | ||
| 144 | 144 | /// Extract the api_key value from the bundled synckit.toml. | |
| 145 | - | fn parse_synckit_toml_key() -> Option<&'static str> { | |
| 146 | - | for line in SYNCKIT_TOML.lines() { | |
| 147 | - | let line = line.trim(); | |
| 148 | - | if let Some(rest) = line.strip_prefix("api_key") { | |
| 149 | - | let rest = rest.trim_start(); | |
| 150 | - | if let Some(rest) = rest.strip_prefix('=') { | |
| 151 | - | let rest = rest.trim(); | |
| 152 | - | let rest = rest.trim_matches('"'); | |
| 153 | - | if !rest.is_empty() { | |
| 154 | - | return Some(rest); | |
| 155 | - | } | |
| 156 | - | } | |
| 157 | - | } | |
| 158 | - | } | |
| 159 | - | None | |
| 145 | + | fn parse_synckit_toml_key() -> Option<String> { | |
| 146 | + | let table: std::collections::HashMap<String, String> = toml::from_str(SYNCKIT_TOML).ok()?; | |
| 147 | + | table.get("api_key").filter(|s| !s.is_empty()).cloned() | |
| 160 | 148 | } | |
| 161 | 149 | ||
| 162 | 150 | /// Load a saved API key from the data directory, falling back to env vars and bundled toml. | |
| @@ -447,7 +435,9 @@ fn init_browser(data_dir: &Path, shared: Arc<SharedState>, vault_name: &str) -> | |||
| 447 | 435 | ||
| 448 | 436 | impl eframe::App for AudioFilesApp { | |
| 449 | 437 | #[allow(unused_variables)] | |
| 450 | - | fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { | |
| 438 | + | fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) { | |
| 439 | + | let ctx = ui.ctx().clone(); | |
| 440 | + | let ctx = &ctx; | |
| 451 | 441 | // Pump GTK events so libappindicator (tray) stays responsive on Linux. | |
| 452 | 442 | #[cfg(target_os = "linux")] | |
| 453 | 443 | if self.gtk_ok { | |
| @@ -469,13 +459,13 @@ impl eframe::App for AudioFilesApp { | |||
| 469 | 459 | ||
| 470 | 460 | match self.screen { | |
| 471 | 461 | AppScreen::Activation => { | |
| 472 | - | self.draw_activation_screen(ctx); | |
| 462 | + | self.draw_activation_screen(ui); | |
| 473 | 463 | } | |
| 474 | 464 | AppScreen::VaultSetup => { | |
| 475 | - | self.draw_vault_setup_screen(ctx); | |
| 465 | + | self.draw_vault_setup_screen(ui); | |
| 476 | 466 | } | |
| 477 | 467 | AppScreen::Browser => { | |
| 478 | - | self.update_browser(ctx); | |
| 468 | + | self.update_browser(ui); | |
| 479 | 469 | } | |
| 480 | 470 | } | |
| 481 | 471 | ||
| @@ -519,7 +509,9 @@ impl eframe::App for AudioFilesApp { | |||
| 519 | 509 | ||
| 520 | 510 | impl AudioFilesApp { | |
| 521 | 511 | /// All browser-mode update logic (tray, sync, drops, draw). | |
| 522 | - | fn update_browser(&mut self, ctx: &egui::Context) { | |
| 512 | + | fn update_browser(&mut self, ui: &mut egui::Ui) { | |
| 513 | + | let ctx = ui.ctx().clone(); | |
| 514 | + | let ctx = &ctx; | |
| 523 | 515 | // Poll tray menu events | |
| 524 | 516 | if let Some(ref tray) = self.tray { | |
| 525 | 517 | if let Some(action) = tray.poll() { | |
| @@ -716,7 +708,7 @@ impl AudioFilesApp { | |||
| 716 | 708 | } | |
| 717 | 709 | } | |
| 718 | 710 | } | |
| 719 | - | audiofiles_browser::editor::draw_browser(ctx, browser, self.sync_manager.as_ref()); | |
| 711 | + | audiofiles_browser::editor::draw_browser(ui, browser, self.sync_manager.as_ref()); | |
| 720 | 712 | ||
| 721 | 713 | // Drop target indicator: while files are hovering, paint a clear | |
| 722 | 714 | // border on top of the whole window plus a centered label. This is | |
| @@ -724,7 +716,7 @@ impl AudioFilesApp { | |||
| 724 | 716 | // us on Linux/Windows. Rendered as a foreground layer so it sits | |
| 725 | 717 | // above panel chrome but doesn't intercept clicks. | |
| 726 | 718 | if hovered_count > 0 { | |
| 727 | - | let screen = ctx.screen_rect(); | |
| 719 | + | let screen = ctx.content_rect(); | |
| 728 | 720 | let rect = screen.shrink(theme::space::MD); | |
| 729 | 721 | let painter = ctx.layer_painter(egui::LayerId::new( | |
| 730 | 722 | egui::Order::Foreground, | |
| @@ -754,7 +746,7 @@ impl AudioFilesApp { | |||
| 754 | 746 | ); | |
| 755 | 747 | } | |
| 756 | 748 | } else { | |
| 757 | - | self.draw_db_error_screen(ctx); | |
| 749 | + | self.draw_db_error_screen(ui); | |
| 758 | 750 | } | |
| 759 | 751 | } | |
| 760 | 752 | } | |
| @@ -763,8 +755,8 @@ impl AudioFilesApp { | |||
| 763 | 755 | /// Render the "vault failed to open" recovery surface. Replaces the prior | |
| 764 | 756 | /// dead-end label with explicit recovery actions: Retry the same path, | |
| 765 | 757 | /// Choose a different vault, or open the data folder for manual triage. | |
| 766 | - | fn draw_db_error_screen(&mut self, ctx: &egui::Context) { | |
| 767 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 758 | + | fn draw_db_error_screen(&mut self, ui: &mut egui::Ui) { | |
| 759 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 768 | 760 | ui.add_space(48.0); | |
| 769 | 761 | ui.vertical_centered(|ui| { | |
| 770 | 762 | ui.heading("audiofiles"); |
| @@ -12,7 +12,7 @@ const DEFAULT_VAULT_NAME: &str = "Library"; | |||
| 12 | 12 | ||
| 13 | 13 | impl AudioFilesApp { | |
| 14 | 14 | /// Draw the vault setup screen (first-open flow, after activation). | |
| 15 | - | pub(crate) fn draw_vault_setup_screen(&mut self, ctx: &egui::Context) { | |
| 15 | + | pub(crate) fn draw_vault_setup_screen(&mut self, ui: &mut egui::Ui) { | |
| 16 | 16 | let default_path = vault::default_vault_path(); | |
| 17 | 17 | let existing_db = default_path.join("audiofiles.db").exists(); | |
| 18 | 18 | ||
| @@ -21,7 +21,7 @@ impl AudioFilesApp { | |||
| 21 | 21 | self.vault_setup_name = DEFAULT_VAULT_NAME.to_string(); | |
| 22 | 22 | } | |
| 23 | 23 | ||
| 24 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 24 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 25 | 25 | let available = ui.available_size(); | |
| 26 | 26 | ui.add_space((available.y * 0.20).max(40.0)); | |
| 27 | 27 |
| @@ -10,10 +10,12 @@ use audiofiles_core::vfs::NodeType; | |||
| 10 | 10 | /// | |
| 11 | 11 | /// Pass `sync_manager: None` when sync is not configured (e.g. from the CLAP plugin). | |
| 12 | 12 | pub fn draw_browser( | |
| 13 | - | ctx: &egui::Context, | |
| 13 | + | ui: &mut egui::Ui, | |
| 14 | 14 | state: &mut BrowserState, | |
| 15 | 15 | sync_manager: Option<&audiofiles_sync::SyncManager>, | |
| 16 | 16 | ) { | |
| 17 | + | let ctx = ui.ctx().clone(); | |
| 18 | + | let ctx = &ctx; | |
| 17 | 19 | theme::apply_theme(ctx); | |
| 18 | 20 | ||
| 19 | 21 | match &state.import_mode { | |
| @@ -23,10 +25,10 @@ pub fn draw_browser( | |||
| 23 | 25 | ctx.request_repaint(); | |
| 24 | 26 | } | |
| 25 | 27 | handle_keyboard(ctx, state); | |
| 26 | - | draw_normal_browser(ctx, state, sync_manager); | |
| 28 | + | draw_normal_browser(ui, state, sync_manager); | |
| 27 | 29 | } | |
| 28 | 30 | ImportMode::ConfigureImport { .. } => { | |
| 29 | - | import_screens::draw_configure_import(ctx, state); | |
| 31 | + | import_screens::draw_configure_import(ui, state); | |
| 30 | 32 | } | |
| 31 | 33 | ImportMode::Importing { .. } | |
| 32 | 34 | | ImportMode::Analyzing { .. } | |
| @@ -37,56 +39,56 @@ pub fn draw_browser( | |||
| 37 | 39 | } | |
| 38 | 40 | match &state.import_mode { | |
| 39 | 41 | ImportMode::Importing { .. } => { | |
| 40 | - | import_screens::draw_import_progress(ctx, state); | |
| 42 | + | import_screens::draw_import_progress(ui, state); | |
| 41 | 43 | } | |
| 42 | 44 | ImportMode::Analyzing { .. } => { | |
| 43 | - | import_screens::draw_analysis_progress(ctx, state); | |
| 45 | + | import_screens::draw_analysis_progress(ui, state); | |
| 44 | 46 | } | |
| 45 | 47 | ImportMode::Exporting { .. } => { | |
| 46 | - | export_screens::draw_export_progress(ctx, state); | |
| 48 | + | export_screens::draw_export_progress(ui, state); | |
| 47 | 49 | } | |
| 48 | 50 | ImportMode::Cleaning { .. } => { | |
| 49 | - | import_screens::draw_cleanup_progress(ctx, state); | |
| 51 | + | import_screens::draw_cleanup_progress(ui, state); | |
| 50 | 52 | } | |
| 51 | 53 | // poll_workers may have transitioned the mode | |
| 52 | 54 | ImportMode::TagFolders { .. } => { | |
| 53 | - | import_screens::draw_tag_folders(ctx, state); | |
| 55 | + | import_screens::draw_tag_folders(ui, state); | |
| 54 | 56 | } | |
| 55 | 57 | ImportMode::ConfigureAnalysis { .. } => { | |
| 56 | - | import_screens::draw_configure_analysis(ctx, state); | |
| 58 | + | import_screens::draw_configure_analysis(ui, state); | |
| 57 | 59 | } | |
| 58 | 60 | ImportMode::ReviewSuggestions { .. } => { | |
| 59 | - | import_screens::draw_review_suggestions(ctx, state); | |
| 61 | + | import_screens::draw_review_suggestions(ui, state); | |
| 60 | 62 | } | |
| 61 | 63 | ImportMode::ExportComplete { .. } => { | |
| 62 | - | export_screens::draw_export_complete(ctx, state); | |
| 64 | + | export_screens::draw_export_complete(ui, state); | |
| 63 | 65 | } | |
| 64 | 66 | ImportMode::ReviewErrors => { | |
| 65 | - | import_screens::draw_review_errors(ctx, state); | |
| 67 | + | import_screens::draw_review_errors(ui, state); | |
| 66 | 68 | } | |
| 67 | 69 | _ => {} | |
| 68 | 70 | } | |
| 69 | 71 | } | |
| 70 | 72 | ImportMode::TagFolders { .. } => { | |
| 71 | - | import_screens::draw_tag_folders(ctx, state); | |
| 73 | + | import_screens::draw_tag_folders(ui, state); | |
| 72 | 74 | } | |
| 73 | 75 | ImportMode::ConfigureAnalysis { .. } => { | |
| 74 | - | import_screens::draw_configure_analysis(ctx, state); | |
| 76 | + | import_screens::draw_configure_analysis(ui, state); | |
| 75 | 77 | } | |
| 76 | 78 | ImportMode::ReviewSuggestions { .. } => { | |
| 77 | - | import_screens::draw_review_suggestions(ctx, state); | |
| 79 | + | import_screens::draw_review_suggestions(ui, state); | |
| 78 | 80 | } | |
| 79 | 81 | ImportMode::ConfigureExport { .. } => { | |
| 80 | - | export_screens::draw_configure_export(ctx, state); | |
| 82 | + | export_screens::draw_configure_export(ui, state); | |
| 81 | 83 | } | |
| 82 | 84 | ImportMode::ExportComplete { .. } => { | |
| 83 | - | export_screens::draw_export_complete(ctx, state); | |
| 85 | + | export_screens::draw_export_complete(ui, state); | |
| 84 | 86 | } | |
| 85 | 87 | ImportMode::ReviewErrors => { | |
| 86 | - | import_screens::draw_review_errors(ctx, state); | |
| 88 | + | import_screens::draw_review_errors(ui, state); | |
| 87 | 89 | } | |
| 88 | 90 | ImportMode::OperationCancelled { .. } => { | |
| 89 | - | import_screens::draw_operation_cancelled(ctx, state); | |
| 91 | + | import_screens::draw_operation_cancelled(ui, state); | |
| 90 | 92 | } | |
| 91 | 93 | } | |
| 92 | 94 | ||
| @@ -141,42 +143,45 @@ pub fn draw_browser( | |||
| 141 | 143 | ||
| 142 | 144 | /// Draw the main browser layout: toolbar, footer, sidebar, detail panel, and file list. | |
| 143 | 145 | fn draw_normal_browser( | |
| 144 | - | ctx: &egui::Context, | |
| 146 | + | ui: &mut egui::Ui, | |
| 145 | 147 | state: &mut BrowserState, | |
| 146 | 148 | sync_manager: Option<&audiofiles_sync::SyncManager>, | |
| 147 | 149 | ) { | |
| 150 | + | let ctx = ui.ctx().clone(); | |
| 151 | + | ||
| 148 | 152 | // Top toolbar (breadcrumb + search) | |
| 149 | - | egui::TopBottomPanel::top("toolbar") | |
| 150 | - | .exact_height(56.0) | |
| 151 | - | .show(ctx, |ui| { | |
| 153 | + | egui::Panel::top("toolbar") | |
| 154 | + | .exact_size(56.0) | |
| 155 | + | .show_inside(ui, |ui| { | |
| 152 | 156 | toolbar::draw_toolbar(ui, state, sync_manager); | |
| 153 | 157 | }); | |
| 154 | 158 | ||
| 155 | 159 | // Bottom footer | |
| 156 | - | egui::TopBottomPanel::bottom("footer").show(ctx, |ui| { | |
| 157 | - | footer::draw_footer(ui, ctx, state); | |
| 160 | + | egui::Panel::bottom("footer").show_inside(ui, |ui| { | |
| 161 | + | let ctx = ui.ctx().clone(); | |
| 162 | + | footer::draw_footer(ui, &ctx, state); | |
| 158 | 163 | }); | |
| 159 | 164 | ||
| 160 | 165 | // Floating MIDI/instrument window | |
| 161 | 166 | if state.show_midi_window { | |
| 162 | - | instrument_panel::draw_midi_window(ctx, state); | |
| 167 | + | instrument_panel::draw_midi_window(&ctx, state); | |
| 163 | 168 | } | |
| 164 | 169 | ||
| 165 | 170 | // Left sidebar (or filter panel) | |
| 166 | 171 | if state.filter_panel_open { | |
| 167 | - | egui::SidePanel::left("filter_panel") | |
| 168 | - | .default_width(200.0) | |
| 169 | - | .width_range(160.0..=300.0) | |
| 170 | - | .show(ctx, |ui| { | |
| 172 | + | egui::Panel::left("filter_panel") | |
| 173 | + | .default_size(200.0) | |
| 174 | + | .size_range(160.0..=300.0) | |
| 175 | + | .show_inside(ui, |ui| { | |
| 171 | 176 | egui::ScrollArea::vertical().show(ui, |ui| { | |
| 172 | 177 | filter_panel::draw_filter_panel(ui, state); | |
| 173 | 178 | }); | |
| 174 | 179 | }); | |
| 175 | 180 | } else if state.sidebar_visible { | |
| 176 | - | egui::SidePanel::left("sidebar") | |
| 177 | - | .default_width(180.0) | |
| 178 | - | .width_range(120.0..=280.0) | |
| 179 | - | .show(ctx, |ui| { | |
| 181 | + | egui::Panel::left("sidebar") | |
| 182 | + | .default_size(180.0) | |
| 183 | + | .size_range(120.0..=280.0) | |
| 184 | + | .show_inside(ui, |ui| { | |
| 180 | 185 | sidebar::draw_sidebar(ui, state); | |
| 181 | 186 | }); | |
| 182 | 187 | } | |
| @@ -184,22 +189,19 @@ fn draw_normal_browser( | |||
| 184 | 189 | // Right detail panel (auto-hide below 700px). | |
| 185 | 190 | // 700.0 is the minimum window width at which the detail panel is shown. | |
| 186 | 191 | // Below this, the file list alone needs the full width to remain usable. | |
| 187 | - | if state.detail_visible { | |
| 188 | - | let available = ctx.screen_rect().width(); | |
| 189 | - | if available >= 700.0 { | |
| 190 | - | egui::SidePanel::right("detail") | |
| 191 | - | .default_width(250.0) | |
| 192 | - | .width_range(200.0..=400.0) | |
| 193 | - | .show(ctx, |ui| { | |
| 194 | - | egui::ScrollArea::vertical().show(ui, |ui| { | |
| 195 | - | detail::draw_detail(ui, state); | |
| 196 | - | }); | |
| 192 | + | if state.detail_visible && ctx.content_rect().width() >= 700.0 { | |
| 193 | + | egui::Panel::right("detail") | |
| 194 | + | .default_size(250.0) | |
| 195 | + | .size_range(200.0..=400.0) | |
| 196 | + | .show_inside(ui, |ui| { | |
| 197 | + | egui::ScrollArea::vertical().show(ui, |ui| { | |
| 198 | + | detail::draw_detail(ui, state); | |
| 197 | 199 | }); | |
| 198 | - | } | |
| 200 | + | }); | |
| 199 | 201 | } | |
| 200 | 202 | ||
| 201 | 203 | // Central file list | |
| 202 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 204 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 203 | 205 | file_list::draw_file_list(ui, state, sync_manager); | |
| 204 | 206 | }); | |
| 205 | 207 | } |
| @@ -590,7 +590,7 @@ fn draw_multi_summary(ui: &mut egui::Ui, state: &mut BrowserState) { | |||
| 590 | 590 | .filter_map(|n| n.node.sample_hash.as_ref().map(|h| h.to_string())) | |
| 591 | 591 | .collect(); | |
| 592 | 592 | pending_apply = Some((tag.clone(), targets)); | |
| 593 | - | ui.close_menu(); | |
| 593 | + | ui.close(); | |
| 594 | 594 | } | |
| 595 | 595 | } | |
| 596 | 596 | let remove_label = if full { | |
| @@ -605,7 +605,7 @@ fn draw_multi_summary(ui: &mut egui::Ui, state: &mut BrowserState) { | |||
| 605 | 605 | .filter_map(|n| n.node.sample_hash.as_ref().map(|h| h.to_string())) | |
| 606 | 606 | .collect(); | |
| 607 | 607 | pending_remove = Some((tag.clone(), targets)); | |
| 608 | - | ui.close_menu(); | |
| 608 | + | ui.close(); | |
| 609 | 609 | } | |
| 610 | 610 | }); | |
| 611 | 611 | } |
| @@ -75,7 +75,7 @@ fn bytes_per_sec_for_config(config: &ExportConfig) -> u64 { | |||
| 75 | 75 | } | |
| 76 | 76 | ||
| 77 | 77 | /// Draw the export configuration screen. | |
| 78 | - | pub fn draw_configure_export(ctx: &egui::Context, state: &mut BrowserState) { | |
| 78 | + | pub fn draw_configure_export(ui: &mut egui::Ui, state: &mut BrowserState) { | |
| 79 | 79 | let (item_count, profile_count) = match &state.import_mode { | |
| 80 | 80 | ImportMode::ConfigureExport { | |
| 81 | 81 | items, | |
| @@ -85,7 +85,7 @@ pub fn draw_configure_export(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 85 | 85 | _ => return, | |
| 86 | 86 | }; | |
| 87 | 87 | ||
| 88 | - | egui::TopBottomPanel::bottom("export_footer").show(ctx, |ui| { | |
| 88 | + | egui::Panel::bottom("export_footer").show_inside(ui, |ui| { | |
| 89 | 89 | ui.add_space(theme::space::SM); | |
| 90 | 90 | ||
| 91 | 91 | // Warnings | |
| @@ -194,7 +194,7 @@ pub fn draw_configure_export(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 194 | 194 | ui.add_space(theme::space::XS); | |
| 195 | 195 | }); | |
| 196 | 196 | ||
| 197 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 197 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 198 | 198 | egui::ScrollArea::vertical().show(ui, |ui| { | |
| 199 | 199 | ui.heading("Export Samples"); | |
| 200 | 200 | ui.add_space(theme::space::SM); | |
| @@ -319,6 +319,23 @@ pub fn draw_configure_export(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 319 | 319 | if ui.radio(is_aiff, "AIFF (decode and re-encode)").clicked() && !is_aiff { | |
| 320 | 320 | config.format = ExportFormat::Aiff; | |
| 321 | 321 | } | |
| 322 | + | ||
| 323 | + | // Heads-up: WAV/AIFF re-encode writes only fmt+data / | |
| 324 | + | // COMM+SSND. Embedded BWF (bext), iXML, smpl loop points, | |
| 325 | + | // cue markers, and ID3 tags are not preserved. Choose | |
| 326 | + | // Original to keep them intact. | |
| 327 | + | if config.format != ExportFormat::Original { | |
| 328 | + | ui.add_space(theme::space::XS); | |
| 329 | + | ui.label( | |
| 330 | + | egui::RichText::new( | |
| 331 | + | "Re-encoding strips embedded metadata chunks \ | |
| 332 | + | (BWF, iXML, loop points, cue markers, ID3). \ | |
| 333 | + | Choose Original to preserve them.", | |
| 334 | + | ) | |
| 335 | + | .small() | |
| 336 | + | .color(theme::accent_yellow()), | |
| 337 | + | ); | |
| 338 | + | } | |
| 322 | 339 | } | |
| 323 | 340 | ui.add_space(theme::space::MD); | |
| 324 | 341 | ||
| @@ -516,7 +533,7 @@ pub fn draw_configure_export(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 516 | 533 | } | |
| 517 | 534 | ||
| 518 | 535 | /// Draw the export progress screen. | |
| 519 | - | pub fn draw_export_progress(ctx: &egui::Context, state: &mut BrowserState) { | |
| 536 | + | pub fn draw_export_progress(ui: &mut egui::Ui, state: &mut BrowserState) { | |
| 520 | 537 | let (completed, total, current_name) = match &state.import_mode { | |
| 521 | 538 | ImportMode::Exporting { | |
| 522 | 539 | completed, | |
| @@ -526,7 +543,7 @@ pub fn draw_export_progress(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 526 | 543 | _ => return, | |
| 527 | 544 | }; | |
| 528 | 545 | ||
| 529 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 546 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 530 | 547 | ui.heading("Exporting..."); | |
| 531 | 548 | ui.add_space(theme::space::SECTION); | |
| 532 | 549 | ||
| @@ -561,13 +578,13 @@ pub fn draw_export_progress(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 561 | 578 | } | |
| 562 | 579 | ||
| 563 | 580 | /// Draw the export complete screen with summary and error list. | |
| 564 | - | pub fn draw_export_complete(ctx: &egui::Context, state: &mut BrowserState) { | |
| 581 | + | pub fn draw_export_complete(ui: &mut egui::Ui, state: &mut BrowserState) { | |
| 565 | 582 | let (total, error_count) = match &state.import_mode { | |
| 566 | 583 | ImportMode::ExportComplete { total, errors } => (*total, errors.len()), | |
| 567 | 584 | _ => return, | |
| 568 | 585 | }; | |
| 569 | 586 | ||
| 570 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 587 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 571 | 588 | ui.heading("Export Complete"); | |
| 572 | 589 | ui.add_space(theme::space::LG); | |
| 573 | 590 |
| @@ -49,7 +49,7 @@ pub fn draw_context_menu( | |||
| 49 | 49 | state.status = | |
| 50 | 50 | "Sync not ready — open the Sync panel first".to_string(); | |
| 51 | 51 | } | |
| 52 | - | ui.close_menu(); | |
| 52 | + | ui.close(); | |
| 53 | 53 | } | |
| 54 | 54 | } | |
| 55 | 55 | } | |
| @@ -60,14 +60,14 @@ pub fn draw_context_menu( | |||
| 60 | 60 | let hash = hash.clone(); | |
| 61 | 61 | state.trigger_preview(&hash); | |
| 62 | 62 | } | |
| 63 | - | ui.close_menu(); | |
| 63 | + | ui.close(); | |
| 64 | 64 | } | |
| 65 | 65 | if ui.button("Copy Path").clicked() { | |
| 66 | 66 | if let Some(path) = state.selected_sample_path() { | |
| 67 | 67 | state.status = format!("Copied: {path}"); | |
| 68 | 68 | ui.ctx().copy_text(path); | |
| 69 | 69 | } | |
| 70 | - | ui.close_menu(); | |
| 70 | + | ui.close(); | |
| 71 | 71 | } | |
| 72 | 72 | // M-6: one-click jump to the file in the system file manager. | |
| 73 | 73 | // macOS / Windows highlight the file itself; Linux falls back to | |
| @@ -95,21 +95,21 @@ pub fn draw_context_menu( | |||
| 95 | 95 | let _ = std::process::Command::new("xdg-open").arg(&parent).spawn(); | |
| 96 | 96 | } | |
| 97 | 97 | } | |
| 98 | - | ui.close_menu(); | |
| 98 | + | ui.close(); | |
| 99 | 99 | } | |
| 100 | 100 | if ui.button("Find Similar (Shift+F)").clicked() { | |
| 101 | 101 | if let Some(hash) = &node.node.sample_hash { | |
| 102 | 102 | let hash = hash.clone(); | |
| 103 | 103 | state.find_similar(&hash); | |
| 104 | 104 | } | |
| 105 | - | ui.close_menu(); | |
| 105 | + | ui.close(); | |
| 106 | 106 | } | |
| 107 | 107 | if ui.button("Find Duplicates (Shift+D)").clicked() { | |
| 108 | 108 | if let Some(hash) = &node.node.sample_hash { | |
| 109 | 109 | let hash = hash.clone(); | |
| 110 | 110 | state.find_near_duplicates(&hash); | |
| 111 | 111 | } | |
| 112 | - | ui.close_menu(); | |
| 112 | + | ui.close(); | |
| 113 | 113 | } | |
| 114 | 114 | // Add to Collection submenu | |
| 115 | 115 | if let Some(hash) = &node.node.sample_hash { | |
| @@ -123,7 +123,7 @@ pub fn draw_context_menu( | |||
| 123 | 123 | let _ = state.backend.add_to_collection(coll.id, &hash_clone); | |
| 124 | 124 | state.refresh_collections(); | |
| 125 | 125 | state.status = format!("Added to {}", coll.name); | |
| 126 | - | ui.close_menu(); | |
| 126 | + | ui.close(); | |
| 127 | 127 | } | |
| 128 | 128 | } | |
| 129 | 129 | }); | |
| @@ -134,7 +134,7 @@ pub fn draw_context_menu( | |||
| 134 | 134 | let _ = state.backend.remove_from_collection(active_id, &hash_clone); | |
| 135 | 135 | state.refresh_collections(); | |
| 136 | 136 | state.activate_collection(active_id); | |
| 137 | - | ui.close_menu(); | |
| 137 | + | ui.close(); | |
| 138 | 138 | } | |
| 139 | 139 | } | |
| 140 | 140 | } | |
| @@ -144,7 +144,7 @@ pub fn draw_context_menu( | |||
| 144 | 144 | let hash_clone = hash.clone(); | |
| 145 | 145 | if ui.button("Edit... (E)").clicked() { | |
| 146 | 146 | state.open_edit_window(&hash_clone); | |
| 147 | - | ui.close_menu(); | |
| 147 | + | ui.close(); | |
| 148 | 148 | } | |
| 149 | 149 | } | |
| 150 | 150 | if ui.button("Play as Instrument").clicked() { | |
| @@ -156,12 +156,12 @@ pub fn draw_context_menu( | |||
| 156 | 156 | state.show_midi_window = true; | |
| 157 | 157 | state.status = format!("Instrument: {name}"); | |
| 158 | 158 | } | |
| 159 | - | ui.close_menu(); | |
| 159 | + | ui.close(); | |
| 160 | 160 | } | |
| 161 | 161 | if ui.button("Export...").clicked() { | |
| 162 | 162 | state.selection.set_single(row_idx); | |
| 163 | 163 | state.start_export_flow(Some(vec![node.node.id])); | |
| 164 | - | ui.close_menu(); | |
| 164 | + | ui.close(); | |
| 165 | 165 | } | |
| 166 | 166 | // M-7: single-row Re-analyze parity with the multi-row menu. | |
| 167 | 167 | // Reuses ReanalyzeOverwrite with a one-element vec so the | |
| @@ -188,41 +188,41 @@ pub fn draw_context_menu( | |||
| 188 | 188 | } | |
| 189 | 189 | } | |
| 190 | 190 | } | |
| 191 | - | ui.close_menu(); | |
| 191 | + | ui.close(); | |
| 192 | 192 | } | |
| 193 | 193 | } | |
| 194 | 194 | ui.separator(); | |
| 195 | 195 | if widgets::danger_button(ui, "Delete").clicked() { | |
| 196 | 196 | state.selection.set_single(row_idx); | |
| 197 | 197 | state.confirm_delete_selected(); | |
| 198 | - | ui.close_menu(); | |
| 198 | + | ui.close(); | |
| 199 | 199 | } | |
| 200 | 200 | } | |
| 201 | 201 | NodeType::Directory => { | |
| 202 | 202 | if ui.button("Open").clicked() { | |
| 203 | 203 | state.selection.set_single(row_idx); | |
| 204 | 204 | state.enter_directory(); | |
| 205 | - | ui.close_menu(); | |
| 205 | + | ui.close(); | |
| 206 | 206 | } | |
| 207 | 207 | if ui.button("New Folder").clicked() { | |
| 208 | 208 | state.show_dir_create = true; | |
| 209 | 209 | state.dir_create_input.clear(); | |
| 210 | - | ui.close_menu(); | |
| 210 | + | ui.close(); | |
| 211 | 211 | } | |
| 212 | 212 | if ui.button("Rename").clicked() { | |
| 213 | 213 | state.dir_rename_target = Some((node.node.id, node.node.name.clone())); | |
| 214 | - | ui.close_menu(); | |
| 214 | + | ui.close(); | |
| 215 | 215 | } | |
| 216 | 216 | if ui.button("Export...").clicked() { | |
| 217 | 217 | state.selection.set_single(row_idx); | |
| 218 | 218 | state.start_export_flow(Some(vec![node.node.id])); | |
| 219 | - | ui.close_menu(); | |
| 219 | + | ui.close(); | |
| 220 | 220 | } | |
| 221 | 221 | ui.separator(); | |
| 222 | 222 | if widgets::danger_button(ui, "Delete").clicked() { | |
| 223 | 223 | state.selection.set_single(row_idx); | |
| 224 | 224 | state.confirm_delete_selected(); | |
| 225 | - | ui.close_menu(); | |
| 225 | + | ui.close(); | |
| 226 | 226 | } | |
| 227 | 227 | } | |
| 228 | 228 | } | |
| @@ -236,14 +236,14 @@ pub fn draw_multi_context_menu(ui: &mut egui::Ui, state: &mut BrowserState) { | |||
| 236 | 236 | ||
| 237 | 237 | if ui.button("Invert Selection (Cmd+Shift+I)").clicked() { | |
| 238 | 238 | state.invert_selection(); | |
| 239 | - | ui.close_menu(); | |
| 239 | + | ui.close(); | |
| 240 | 240 | } | |
| 241 | 241 | ||
| 242 | 242 | ui.separator(); | |
| 243 | 243 | ||
| 244 | 244 | if ui.button("Tag... (Cmd+T)").clicked() { | |
| 245 | 245 | state.open_bulk_tag_modal(); | |
| 246 | - | ui.close_menu(); | |
| 246 | + | ui.close(); | |
| 247 | 247 | } | |
| 248 | 248 | // m-16: Cmd+M conflicts with the macOS minimize-window shortcut. Label | |
| 249 | 249 | // advertises Cmd+Shift+M; the actual key binding lives in | |
| @@ -251,16 +251,16 @@ pub fn draw_multi_context_menu(ui: &mut egui::Ui, state: &mut BrowserState) { | |||
| 251 | 251 | // there to match. | |
| 252 | 252 | if ui.button("Move to... (Cmd+Shift+M)").clicked() { | |
| 253 | 253 | state.open_bulk_move_modal(); | |
| 254 | - | ui.close_menu(); | |
| 254 | + | ui.close(); | |
| 255 | 255 | } | |
| 256 | 256 | if ui.button("Rename... (F2)").clicked() { | |
| 257 | 257 | state.open_bulk_rename_modal(); | |
| 258 | - | ui.close_menu(); | |
| 258 | + | ui.close(); | |
| 259 | 259 | } | |
| 260 | 260 | if ui.button("Export...").clicked() { | |
| 261 | 261 | let node_ids = state.selected_node_ids(); | |
| 262 | 262 | state.start_export_flow(Some(node_ids)); | |
| 263 | - | ui.close_menu(); | |
| 263 | + | ui.close(); | |
| 264 | 264 | } | |
| 265 | 265 | ||
| 266 | 266 | // Add to Collection submenu (bulk) | |
| @@ -277,7 +277,7 @@ pub fn draw_multi_context_menu(ui: &mut egui::Ui, state: &mut BrowserState) { | |||
| 277 | 277 | } | |
| 278 | 278 | state.refresh_collections(); | |
| 279 | 279 | state.status = format!("Added {} items to {}", nodes.len(), coll.name); | |
| 280 | - | ui.close_menu(); | |
| 280 | + | ui.close(); | |
| 281 | 281 | } | |
| 282 | 282 | } | |
| 283 | 283 | }); | |
| @@ -294,7 +294,7 @@ pub fn draw_multi_context_menu(ui: &mut egui::Ui, state: &mut BrowserState) { | |||
| 294 | 294 | } | |
| 295 | 295 | state.refresh_collections(); | |
| 296 | 296 | state.activate_collection(active_id); | |
| 297 | - | ui.close_menu(); | |
| 297 | + | ui.close(); | |
| 298 | 298 | } | |
| 299 | 299 | } | |
| 300 | 300 | ||
| @@ -325,7 +325,7 @@ pub fn draw_multi_context_menu(ui: &mut egui::Ui, state: &mut BrowserState) { | |||
| 325 | 325 | } else { | |
| 326 | 326 | state.start_analysis_flow(hashes); | |
| 327 | 327 | } | |
| 328 | - | ui.close_menu(); | |
| 328 | + | ui.close(); | |
| 329 | 329 | } | |
| 330 | 330 | ||
| 331 | 331 | // Copy tags from focused sample to all selected | |
| @@ -351,7 +351,7 @@ pub fn draw_multi_context_menu(ui: &mut egui::Ui, state: &mut BrowserState) { | |||
| 351 | 351 | state.status = format!("Copied {} tags to {} samples", src_tags.len(), applied); | |
| 352 | 352 | state.refresh_selected_tags(); | |
| 353 | 353 | } | |
| 354 | - | ui.close_menu(); | |
| 354 | + | ui.close(); | |
| 355 | 355 | } | |
| 356 | 356 | } | |
| 357 | 357 | } | |
| @@ -383,12 +383,12 @@ pub fn draw_multi_context_menu(ui: &mut egui::Ui, state: &mut BrowserState) { | |||
| 383 | 383 | }; | |
| 384 | 384 | ui.ctx().copy_text(paths.join("\n")); | |
| 385 | 385 | } | |
| 386 | - | ui.close_menu(); | |
| 386 | + | ui.close(); | |
| 387 | 387 | } | |
| 388 | 388 | ||
| 389 | 389 | if widgets::danger_button(ui, "Delete").clicked() { | |
| 390 | 390 | state.confirm_delete_selected(); | |
| 391 | - | ui.close_menu(); | |
| 391 | + | ui.close(); | |
| 392 | 392 | } | |
| 393 | 393 | } | |
| 394 | 394 | ||
| @@ -397,7 +397,7 @@ pub fn draw_background_context_menu(ui: &mut egui::Ui, state: &mut BrowserState) | |||
| 397 | 397 | if ui.button("New Folder").clicked() { | |
| 398 | 398 | state.show_dir_create = true; | |
| 399 | 399 | state.dir_create_input.clear(); | |
| 400 | - | ui.close_menu(); | |
| 400 | + | ui.close(); | |
| 401 | 401 | } | |
| 402 | 402 | if ui.button("Import files...").clicked() { | |
| 403 | 403 | if let Some(paths) = rfd::FileDialog::new() | |
| @@ -409,7 +409,7 @@ pub fn draw_background_context_menu(ui: &mut egui::Ui, state: &mut BrowserState) | |||
| 409 | 409 | state.import_path(&path); | |
| 410 | 410 | } | |
| 411 | 411 | } | |
| 412 | - | ui.close_menu(); | |
| 412 | + | ui.close(); | |
| 413 | 413 | } | |
| 414 | 414 | // C-2: matches the toolbar's "Import folder..." (wizard path). The quick | |
| 415 | 415 | // import shortcut is only offered from the toolbar to keep this menu | |
| @@ -418,7 +418,7 @@ pub fn draw_background_context_menu(ui: &mut egui::Ui, state: &mut BrowserState) | |||
| 418 | 418 | if let Some(path) = rfd::FileDialog::new().pick_folder() { | |
| 419 | 419 | state.show_import_options(path); | |
| 420 | 420 | } | |
| 421 | - | ui.close_menu(); | |
| 421 | + | ui.close(); | |
| 422 | 422 | } | |
| 423 | 423 | if state.selection.count() > 0 { | |
| 424 | 424 | ui.separator(); | |
| @@ -427,11 +427,11 @@ pub fn draw_background_context_menu(ui: &mut egui::Ui, state: &mut BrowserState) | |||
| 427 | 427 | state.selection.clear(); | |
| 428 | 428 | state.refresh_selected_tags(); | |
| 429 | 429 | state.refresh_selected_detail(); | |
| 430 | - | ui.close_menu(); | |
| 430 | + | ui.close(); | |
| 431 | 431 | } | |
| 432 | 432 | if ui.button("Invert Selection (Cmd+Shift+I)").clicked() { | |
| 433 | 433 | state.invert_selection(); | |
| 434 | - | ui.close_menu(); | |
| 434 | + | ui.close(); | |
| 435 | 435 | } | |
| 436 | 436 | } | |
| 437 | 437 | } |
| @@ -35,7 +35,7 @@ fn dot(ui: &mut egui::Ui) { | |||
| 35 | 35 | pub fn draw_footer(ui: &mut egui::Ui, ctx: &egui::Context, state: &mut BrowserState) { | |
| 36 | 36 | ui.add_space(theme::space::SM); | |
| 37 | 37 | ||
| 38 | - | let narrow = ctx.screen_rect().width() < 1000.0; | |
| 38 | + | let narrow = ctx.content_rect().width() < 1000.0; | |
| 39 | 39 | ||
| 40 | 40 | // Transport row | |
| 41 | 41 | ui.horizontal(|ui| { |
| @@ -7,7 +7,7 @@ use crate::state::{BrowserState, ImportMode}; | |||
| 7 | 7 | const STEPS: &[&str] = &["Configure", "Tag folders", "Analyze", "Review"]; | |
| 8 | 8 | ||
| 9 | 9 | /// Draw the import configuration screen with strategy radio buttons. | |
| 10 | - | pub fn draw_configure_import(ctx: &egui::Context, state: &mut BrowserState) { | |
| 10 | + | pub fn draw_configure_import(ui: &mut egui::Ui, state: &mut BrowserState) { | |
| 11 | 11 | let (source_display, file_count) = match &state.import_mode { | |
| 12 | 12 | ImportMode::ConfigureImport { source, audio_file_count, .. } => { | |
| 13 | 13 | (source.display().to_string(), *audio_file_count) | |
| @@ -15,7 +15,7 @@ pub fn draw_configure_import(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 15 | 15 | _ => return, | |
| 16 | 16 | }; | |
| 17 | 17 | ||
| 18 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 18 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 19 | 19 | widgets::wizard_steps(ui, STEPS, 0); | |
| 20 | 20 | ui.heading("Import Folder"); | |
| 21 | 21 | ui.add_space(theme::space::MD); | |
| @@ -256,7 +256,7 @@ pub fn draw_configure_import(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 256 | 256 | } | |
| 257 | 257 | ||
| 258 | 258 | /// Draw the analysis configuration screen. | |
| 259 | - | pub fn draw_configure_analysis(ctx: &egui::Context, state: &mut BrowserState) { | |
| 259 | + | pub fn draw_configure_analysis(ui: &mut egui::Ui, state: &mut BrowserState) { | |
| 260 | 260 | let (sample_count, mut config) = match &state.import_mode { | |
| 261 | 261 | ImportMode::ConfigureAnalysis { | |
| 262 | 262 | sample_hashes, | |
| @@ -265,7 +265,7 @@ pub fn draw_configure_analysis(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 265 | 265 | _ => return, | |
| 266 | 266 | }; | |
| 267 | 267 | ||
| 268 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 268 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 269 | 269 | widgets::wizard_steps(ui, STEPS, 2); | |
| 270 | 270 | ui.heading("Configure Analysis"); | |
| 271 | 271 | ui.add_space(theme::space::MD); |
| @@ -90,7 +90,8 @@ fn draw_rate_and_eta( | |||
| 90 | 90 | } | |
| 91 | 91 | ||
| 92 | 92 | /// Draw the folder import progress screen. | |
| 93 | - | pub fn draw_import_progress(ctx: &egui::Context, state: &mut BrowserState) { | |
| 93 | + | pub fn draw_import_progress(ui: &mut egui::Ui, state: &mut BrowserState) { | |
| 94 | + | let ctx = ui.ctx().clone(); | |
| 94 | 95 | let (total, completed, current_name, walking, walking_count, total_bytes, loose_files) = match &state.import_mode { | |
| 95 | 96 | ImportMode::Importing { | |
| 96 | 97 | total, | |
| @@ -104,7 +105,7 @@ pub fn draw_import_progress(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 104 | 105 | _ => return, | |
| 105 | 106 | }; | |
| 106 | 107 | ||
| 107 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 108 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 108 | 109 | ui.heading("Importing Folder..."); | |
| 109 | 110 | ui.add_space(theme::space::LG); | |
| 110 | 111 | ||
| @@ -203,7 +204,8 @@ pub fn draw_import_progress(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 203 | 204 | } | |
| 204 | 205 | ||
| 205 | 206 | /// Draw the cleanup (orphaned sample removal) progress screen. | |
| 206 | - | pub fn draw_cleanup_progress(ctx: &egui::Context, state: &mut BrowserState) { | |
| 207 | + | pub fn draw_cleanup_progress(ui: &mut egui::Ui, state: &mut BrowserState) { | |
| 208 | + | let ctx = ui.ctx().clone(); | |
| 207 | 209 | let (completed, total, current_name) = match &state.import_mode { | |
| 208 | 210 | ImportMode::Cleaning { | |
| 209 | 211 | completed, | |
| @@ -213,7 +215,7 @@ pub fn draw_cleanup_progress(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 213 | 215 | _ => return, | |
| 214 | 216 | }; | |
| 215 | 217 | ||
| 216 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 218 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 217 | 219 | ui.heading("Cleaning Up Samples..."); | |
| 218 | 220 | ui.add_space(theme::space::LG); | |
| 219 | 221 | ||
| @@ -246,7 +248,8 @@ pub fn draw_cleanup_progress(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 246 | 248 | } | |
| 247 | 249 | ||
| 248 | 250 | /// Draw the analysis progress screen. | |
| 249 | - | pub fn draw_analysis_progress(ctx: &egui::Context, state: &mut BrowserState) { | |
| 251 | + | pub fn draw_analysis_progress(ui: &mut egui::Ui, state: &mut BrowserState) { | |
| 252 | + | let ctx = ui.ctx().clone(); | |
| 250 | 253 | let (completed, total, current_name) = match &state.import_mode { | |
| 251 | 254 | ImportMode::Analyzing { | |
| 252 | 255 | completed, | |
| @@ -256,7 +259,7 @@ pub fn draw_analysis_progress(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 256 | 259 | _ => return, | |
| 257 | 260 | }; | |
| 258 | 261 | ||
| 259 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 262 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 260 | 263 | ui.heading("Analyzing Samples..."); | |
| 261 | 264 | ui.add_space(theme::space::LG); | |
| 262 | 265 | ||
| @@ -308,7 +311,7 @@ pub fn draw_analysis_progress(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 308 | 311 | /// Acknowledgement screen shown after the user cancels a long-running import, | |
| 309 | 312 | /// analysis, or export. Phase-5 C-3: cancelling shouldn't drop straight to | |
| 310 | 313 | /// `None` — the user needs to know what landed vs what was discarded. | |
| 311 | - | pub fn draw_operation_cancelled(ctx: &egui::Context, state: &mut BrowserState) { | |
| 314 | + | pub fn draw_operation_cancelled(ui: &mut egui::Ui, state: &mut BrowserState) { | |
| 312 | 315 | let (kind, completed, total, destination) = match &state.import_mode { | |
| 313 | 316 | ImportMode::OperationCancelled { | |
| 314 | 317 | kind, completed, total, destination, | |
| @@ -334,7 +337,7 @@ pub fn draw_operation_cancelled(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 334 | 337 | ), | |
| 335 | 338 | }; | |
| 336 | 339 | ||
| 337 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 340 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 338 | 341 | ui.heading(heading); | |
| 339 | 342 | ui.add_space(theme::space::LG); | |
| 340 | 343 | ui.label( |
| @@ -5,12 +5,12 @@ use crate::state::{BrowserState, ConfirmAction, ImportMode}; | |||
| 5 | 5 | use super::super::{theme, widgets}; | |
| 6 | 6 | ||
| 7 | 7 | /// Draw the post-import error review screen. | |
| 8 | - | pub fn draw_review_errors(ctx: &egui::Context, state: &mut BrowserState) { | |
| 8 | + | pub fn draw_review_errors(ui: &mut egui::Ui, state: &mut BrowserState) { | |
| 9 | 9 | if !matches!(state.import_mode, ImportMode::ReviewErrors) { | |
| 10 | 10 | return; | |
| 11 | 11 | } | |
| 12 | 12 | ||
| 13 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 13 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 14 | 14 | ui.heading("Import Summary"); | |
| 15 | 15 | ui.add_space(theme::space::LG); | |
| 16 | 16 |
| @@ -10,7 +10,7 @@ const STEPS: &[&str] = &["Configure", "Tag folders", "Analyze", "Review"]; | |||
| 10 | 10 | ||
| 11 | 11 | ||
| 12 | 12 | /// Draw the post-import folder tagging screen. | |
| 13 | - | pub fn draw_tag_folders(ctx: &egui::Context, state: &mut BrowserState) { | |
| 13 | + | pub fn draw_tag_folders(ui: &mut egui::Ui, state: &mut BrowserState) { | |
| 14 | 14 | let (entry_count, total_samples, all_empty) = match &state.import_mode { | |
| 15 | 15 | ImportMode::TagFolders { entries, .. } => { | |
| 16 | 16 | let total: usize = entries.iter().map(|e| e.folder.samples.len()).sum(); | |
| @@ -20,7 +20,7 @@ pub fn draw_tag_folders(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 20 | 20 | _ => return, | |
| 21 | 21 | }; | |
| 22 | 22 | ||
| 23 | - | egui::TopBottomPanel::bottom("tag_folders_footer").show(ctx, |ui| { | |
| 23 | + | egui::Panel::bottom("tag_folders_footer").show_inside(ui, |ui| { | |
| 24 | 24 | ui.add_space(theme::space::SM); | |
| 25 | 25 | ui.horizontal(|ui| { | |
| 26 | 26 | if ui.button("Skip").clicked() { | |
| @@ -40,7 +40,7 @@ pub fn draw_tag_folders(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 40 | 40 | ui.add_space(theme::space::XS); | |
| 41 | 41 | }); | |
| 42 | 42 | ||
| 43 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 43 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 44 | 44 | // m-6: the breadcrumb is decorative per C-1 — the wizard has no | |
| 45 | 45 | // cross-step navigation post-Skip, so the step-1 "Tag folders" cell | |
| 46 | 46 | // staying highlighted after Skip is cosmetic only. `wizard_steps` has | |
| @@ -134,7 +134,8 @@ pub fn draw_tag_folders(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 134 | 134 | } | |
| 135 | 135 | ||
| 136 | 136 | /// Draw the tag review screen. | |
| 137 | - | pub fn draw_review_suggestions(ctx: &egui::Context, state: &mut BrowserState) { | |
| 137 | + | pub fn draw_review_suggestions(ui: &mut egui::Ui, state: &mut BrowserState) { | |
| 138 | + | let ctx = ui.ctx().clone(); | |
| 138 | 139 | let (item_count, total_suggestions, accepted_count, _current_idx) = | |
| 139 | 140 | match &state.import_mode { | |
| 140 | 141 | ImportMode::ReviewSuggestions { items, current_idx, .. } => { | |
| @@ -149,7 +150,7 @@ pub fn draw_review_suggestions(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 149 | 150 | _ => return, | |
| 150 | 151 | }; | |
| 151 | 152 | ||
| 152 | - | egui::TopBottomPanel::top("review_header").show(ctx, |ui| { | |
| 153 | + | egui::Panel::top("review_header").show_inside(ui, |ui| { | |
| 153 | 154 | widgets::wizard_steps(ui, STEPS, 3); | |
| 154 | 155 | ui.horizontal(|ui| { | |
| 155 | 156 | ui.heading("Review Tag Suggestions"); | |
| @@ -229,7 +230,7 @@ pub fn draw_review_suggestions(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 229 | 230 | } | |
| 230 | 231 | }); | |
| 231 | 232 | ||
| 232 | - | egui::TopBottomPanel::bottom("review_footer").show(ctx, |ui| { | |
| 233 | + | egui::Panel::bottom("review_footer").show_inside(ui, |ui| { | |
| 233 | 234 | ui.add_space(theme::space::SM); | |
| 234 | 235 | ui.horizontal(|ui| { | |
| 235 | 236 | if ui.button("Cancel").clicked() { | |
| @@ -271,10 +272,10 @@ pub fn draw_review_suggestions(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 271 | 272 | } | |
| 272 | 273 | }; | |
| 273 | 274 | ||
| 274 | - | egui::SidePanel::left("review_samples") | |
| 275 | + | egui::Panel::left("review_samples") | |
| 275 | 276 | .resizable(true) | |
| 276 | - | .default_width(220.0) | |
| 277 | - | .show(ctx, |ui| { | |
| 277 | + | .default_size(220.0) | |
| 278 | + | .show_inside(ui, |ui| { | |
| 278 | 279 | // p-3: sort selector at the top of the side panel. The sort | |
| 279 | 280 | // doesn't mutate `items` — `display_order` below maps display | |
| 280 | 281 | // position → item index so `current_idx` keeps pointing at the | |
| @@ -351,7 +352,7 @@ pub fn draw_review_suggestions(ctx: &egui::Context, state: &mut BrowserState) { | |||
| 351 | 352 | }); | |
| 352 | 353 | }); | |
| 353 | 354 | ||
| 354 | - | egui::CentralPanel::default().show(ctx, |ui| { | |
| 355 | + | egui::CentralPanel::default().show_inside(ui, |ui| { | |
| 355 | 356 | if let ImportMode::ReviewSuggestions { | |
| 356 | 357 | ref mut items, | |
| 357 | 358 | current_idx, |
| @@ -539,17 +539,18 @@ fn draw_piano_keyboard(ui: &mut egui::Ui, state: &mut BrowserState) { | |||
| 539 | 539 | 2.0, | |
| 540 | 540 | theme::accent_blue().linear_multiply(0.3), | |
| 541 | 541 | ); | |
| 542 | - | egui::show_tooltip_at_pointer( | |
| 543 | - | ui.ctx(), | |
| 542 | + | egui::Tooltip::always_open( | |
| 543 | + | ui.ctx().clone(), | |
| 544 | 544 | ui.layer_id(), | |
| 545 | 545 | egui::Id::new("piano_drop_hint"), | |
| 546 | - | |ui| { | |
| 547 | - | ui.label(format!( | |
| 548 | - | "Drop to create a zone centered on {}", | |
| 549 | - | note_name(root_note), | |
| 550 | - | )); | |
| 551 | - | }, | |
| 552 | - | ); | |
| 546 | + | egui::PopupAnchor::Pointer, | |
| 547 | + | ) | |
| 548 | + | .show(|ui| { | |
| 549 | + | ui.label(format!( | |
| 550 | + | "Drop to create a zone centered on {}", | |
| 551 | + | note_name(root_note), | |
| 552 | + | )); | |
| 553 | + | }); | |
| 553 | 554 | } | |
| 554 | 555 | } | |
| 555 | 556 | } |
| @@ -68,13 +68,13 @@ fn tag_context_menu(response: egui::Response, tag: &str, state: &mut BrowserStat | |||
| 68 | 68 | .cloned() | |
| 69 | 69 | .collect(); | |
| 70 | 70 | state.tag_rename_preview = Some((count, descendants)); | |
| 71 | - | ui.close_menu(); | |
| 71 | + | ui.close(); | |
| 72 | 72 | } | |
| 73 | 73 | if widgets::danger_button(ui, "Remove from all samples…").clicked() { | |
| 74 | 74 | state.pending_confirm = Some(crate::state::ConfirmAction::RemoveTagGlobally { | |
| 75 | 75 | tag: tag.to_string(), | |
| 76 | 76 | }); | |
| 77 | - | ui.close_menu(); | |
| 77 | + | ui.close(); | |
| 78 | 78 | } | |
| 79 | 79 | }); | |
| 80 | 80 | } | |
| @@ -280,7 +280,7 @@ pub fn draw_sidebar(ui: &mut egui::Ui, state: &mut BrowserState) { | |||
| 280 | 280 | resp.context_menu(|ui| { | |
| 281 | 281 | if ui.button("Rename").clicked() { | |
| 282 | 282 | state.vfs_rename_target = Some((vfs_id, vfs_name.clone())); | |
| 283 | - | ui.close_menu(); | |
| 283 | + | ui.close(); | |
| 284 | 284 | } | |
| 285 | 285 | // Always render Delete so the user can see the capability exists; | |
| 286 | 286 | // disable when removing it would leave zero vaults. | |
| @@ -298,7 +298,7 @@ pub fn draw_sidebar(ui: &mut egui::Ui, state: &mut BrowserState) { | |||
| 298 | 298 | }; | |
| 299 | 299 | if delete_resp.clicked() { | |
| 300 | 300 | state.pending_confirm = Some(crate::state::ConfirmAction::DeleteVfs { vfs_id, vfs_name }); | |
| 301 | - | ui.close_menu(); | |
| 301 | + | ui.close(); | |
| 302 | 302 | } | |
| 303 | 303 | }); | |
| 304 | 304 | } | |
| @@ -352,11 +352,11 @@ pub fn draw_sidebar(ui: &mut egui::Ui, state: &mut BrowserState) { | |||
| 352 | 352 | resp.context_menu(|ui| { | |
| 353 | 353 | if ui.button("Rename").clicked() { | |
| 354 | 354 | state.collection_rename_target = Some((coll_id, coll_name.clone())); | |
| 355 | - | ui.close_menu(); | |
| 355 | + | ui.close(); | |
| 356 | 356 | } | |
| 357 | 357 | if widgets::danger_button(ui, "Delete").clicked() { | |
| 358 | 358 | delete_id = Some((coll_id, coll_name.clone())); | |
| 359 | - | ui.close_menu(); | |
| 359 | + | ui.close(); | |
| 360 | 360 | } | |
| 361 | 361 | }); | |
| 362 | 362 | } |
| @@ -571,12 +571,12 @@ pub fn apply_theme(ctx: &egui::Context) { | |||
| 571 | 571 | ctx.set_visuals(visuals); | |
| 572 | 572 | ||
| 573 | 573 | // Apply theme spacing | |
| 574 | - | let mut style = (*ctx.style()).clone(); | |
| 574 | + | let mut style = (*ctx.global_style()).clone(); | |
| 575 | 575 | style.spacing.item_spacing = egui::vec2(spacing_x, spacing_y); | |
| 576 | 576 | style.spacing.button_padding = egui::vec2(btn_pad_x, btn_pad_y); | |
| 577 | 577 | style.spacing.window_margin = egui::vec2(win_margin, win_margin).into(); | |
| 578 | 578 | style.spacing.indent = indent; | |
| 579 | - | ctx.set_style(style); | |
| 579 | + | ctx.set_global_style(style); | |
| 580 | 580 | } | |
| 581 | 581 | ||
| 582 | 582 | #[cfg(test)] |
| @@ -76,9 +76,13 @@ pub fn draw_toolbar( | |||
| 76 | 76 | if state.collection_filter_name_input.is_empty() { | |
| 77 | 77 | state.collection_filter_name_input = state.search_filter.describe(); | |
| 78 | 78 | } | |
| 79 | - | ui.memory_mut(|m| m.toggle_popup(save_id)); | |
| 79 | + | egui::Popup::toggle_id(ui.ctx(), save_id); | |
| 80 | 80 | } | |
| 81 | - | egui::popup_below_widget(ui, save_id, &save_btn, egui::PopupCloseBehavior::CloseOnClickOutside, |ui| { | |
| 81 | + | egui::Popup::from_response(&save_btn) | |
| 82 | + | .id(save_id) | |
| 83 | + | .open_memory(None) | |
| 84 | + | .close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside) | |
| 85 | + | .show(|ui| { | |
| 82 | 86 | ui.set_min_width(200.0); | |
| 83 | 87 | ui.label(egui::RichText::new("Save as Collection").strong()); | |
| 84 | 88 | ui.add_space(theme::space::SM); | |
| @@ -94,7 +98,7 @@ pub fn draw_toolbar( | |||
| 94 | 98 | if ui.add_enabled(!name.is_empty(), egui::Button::new("Save Collection")).clicked() { | |
| 95 | 99 | state.save_dynamic_collection(&name); | |
| 96 | 100 | state.collection_filter_name_input.clear(); | |
| 97 | - | ui.memory_mut(|m| m.close_popup()); | |
| 101 | + | egui::Popup::close_id(ui.ctx(), save_id); | |
| 98 | 102 | } | |
| 99 | 103 | }); | |
| 100 | 104 | } | |
| @@ -113,7 +117,7 @@ pub fn draw_toolbar( | |||
| 113 | 117 | // window is too narrow to host them inline. Threshold ~900px keeps the | |
| 114 | 118 | // expanded row on common desktop widths but rescues half-screen / DAW | |
| 115 | 119 | // companion layouts. Same actions, single dropdown. | |
| 116 | - | let screen_w = ui.ctx().screen_rect().width(); | |
| 120 | + | let screen_w = ui.ctx().content_rect().width(); | |
| 117 | 121 | let collapse_toggles = screen_w < 900.0; | |
| 118 | 122 | // M-13 input (shared by both layouts). | |
| 119 | 123 | let detail_too_narrow = screen_w < 700.0; | |
| @@ -202,7 +206,7 @@ fn draw_view_menu(ui: &mut egui::Ui, state: &mut BrowserState, detail_hidden: bo | |||
| 202 | 206 | .clicked() | |
| 203 | 207 | { | |
| 204 | 208 | state.sidebar_visible = !state.sidebar_visible; | |
| 205 | - | ui.close_menu(); | |
| 209 | + | ui.close(); | |
| 206 | 210 | } | |
| 207 | 211 | let detail_label = if detail_hidden { | |
| 208 | 212 | format!("{}Detail (D) \u{2014} hidden (widen window)", active_dot(state.detail_visible)) | |
| @@ -211,28 +215,28 @@ fn draw_view_menu(ui: &mut egui::Ui, state: &mut BrowserState, detail_hidden: bo | |||
| 211 | 215 | }; | |
| 212 | 216 | if ui.button(detail_label).clicked() { | |
| 213 | 217 | state.detail_visible = !state.detail_visible; | |
| 214 | - | ui.close_menu(); | |
| 218 | + | ui.close(); | |
| 215 | 219 | } | |
| 216 | 220 | if ui | |
| 217 | 221 | .button(format!("{}Editor (E)", active_dot(state.edit.show_window))) | |
| 218 | 222 | .clicked() | |
| 219 | 223 | { | |
| 220 | 224 | toggle_edit_window(state); | |
| 221 | - | ui.close_menu(); | |
| 225 | + | ui.close(); | |
| 222 | 226 | } | |
| 223 | 227 | if ui | |
| 224 | 228 | .button(format!("{}Instrument (I)", active_dot(state.show_midi_window))) | |
| 225 | 229 | .clicked() | |
| 226 | 230 | { | |
| 227 | 231 | state.show_midi_window = !state.show_midi_window; | |
| 228 | - | ui.close_menu(); | |
| 232 | + | ui.close(); | |
| 229 | 233 | } | |
| 230 | 234 | if ui | |
| 231 | 235 | .button(format!("{}Loop (L)", active_dot(state.loop_enabled))) | |
| 232 | 236 | .clicked() | |
| 233 | 237 | { | |
| 234 | 238 | state.toggle_loop(); | |
| 235 | - | ui.close_menu(); | |
| 239 | + | ui.close(); | |
| 236 | 240 | } | |
| 237 | 241 | let filters_label = if filter_count > 0 { | |
| 238 | 242 | format!( | |
| @@ -245,7 +249,7 @@ fn draw_view_menu(ui: &mut egui::Ui, state: &mut BrowserState, detail_hidden: bo | |||
| 245 | 249 | }; | |
| 246 | 250 | if ui.button(filters_label).clicked() { | |
| 247 | 251 | state.filter_panel_open = !state.filter_panel_open; | |
| 248 | - | ui.close_menu(); | |
| 252 | + | ui.close(); | |
| 249 | 253 | } | |
| 250 | 254 | }); | |
| 251 | 255 | } | |
| @@ -376,11 +380,27 @@ fn draw_breadcrumb( | |||
| 376 | 380 | // Import + Export buttons + Sync + theme selector (right-aligned) | |
| 377 | 381 | ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { | |
| 378 | 382 | let import_id = ui.make_persistent_id("import_menu"); | |
| 379 | - | let import_btn = ui.button("Import"); | |
| 383 | + | // Empty-library hint: Import is the one action that does anything when | |
| 384 | + | // the user has no samples yet. Bold the label so it stands out from the | |
| 385 | + | // (functional but currently useless) Export/Sync/Settings/Help row. | |
| 386 | + | let library_empty = state.contents.is_empty() | |
| 387 | + | && state.current_dir.is_none() | |
| 388 | + | && state.search_query.is_empty() | |
| 389 | + | && !state.search_filter.is_active(); | |
| 390 | + | let import_label = if library_empty { | |
| 391 | + | egui::RichText::new("Import").strong() | |
| 392 | + | } else { | |
| 393 | + | egui::RichText::new("Import") | |
| 394 | + | }; | |
| 395 | + | let import_btn = ui.button(import_label); | |
| 380 | 396 | if import_btn.clicked() { | |
| 381 | - | ui.memory_mut(|m| m.toggle_popup(import_id)); | |
| 397 | + | egui::Popup::toggle_id(ui.ctx(), import_id); | |
| 382 | 398 | } | |
| 383 | - | egui::popup_below_widget(ui, import_id, &import_btn, egui::PopupCloseBehavior::CloseOnClick, |ui| { | |
| 399 | + | egui::Popup::from_response(&import_btn) | |
| 400 | + | .id(import_id) | |
| 401 | + | .open_memory(None) | |
| 402 | + | .close_behavior(egui::PopupCloseBehavior::CloseOnClick) | |
| 403 | + | .show(|ui| { | |
| 384 | 404 | ui.set_min_width(180.0); | |
| 385 | 405 | // C-2: label every entry point with the action it performs. | |
| 386 | 406 | // "Import folder..." now consistently means *the wizard* (strategy |