this repo has no description

copy / paste works

phaz.uk d26aecbc 41952266

verified
+1
package.json
··· 13 "license": "MIT", 14 "dependencies": { 15 "@tauri-apps/api": "^2.9.0", 16 "@tauri-apps/plugin-dialog": "~2.4.2", 17 "@tauri-apps/plugin-opener": "^2.5.2", 18 "animejs": "^4.2.2",
··· 13 "license": "MIT", 14 "dependencies": { 15 "@tauri-apps/api": "^2.9.0", 16 + "@tauri-apps/plugin-clipboard-manager": "~2", 17 "@tauri-apps/plugin-dialog": "~2.4.2", 18 "@tauri-apps/plugin-opener": "^2.5.2", 19 "animejs": "^4.2.2",
+10
pnpm-lock.yaml
··· 11 '@tauri-apps/api': 12 specifier: ^2.9.0 13 version: 2.9.0 14 '@tauri-apps/plugin-dialog': 15 specifier: ~2.4.2 16 version: 2.4.2 ··· 478 resolution: {integrity: sha512-BQ7iLUXTQcyG1PpzLWeVSmBCedYDpnA/6Cm/kRFGtqjTf/eVUlyYO5S2ee07tLum3nWwDBWTGFZeruO8yEukfA==} 479 engines: {node: '>= 10'} 480 hasBin: true 481 482 '@tauri-apps/plugin-dialog@2.4.2': 483 resolution: {integrity: sha512-lNIn5CZuw8WZOn8zHzmFmDSzg5zfohWoa3mdULP0YFh/VogVdMVWZPcWSHlydsiJhRQYaTNSYKN7RmZKE2lCYQ==} ··· 1064 '@tauri-apps/cli-win32-arm64-msvc': 2.9.3 1065 '@tauri-apps/cli-win32-ia32-msvc': 2.9.3 1066 '@tauri-apps/cli-win32-x64-msvc': 2.9.3 1067 1068 '@tauri-apps/plugin-dialog@2.4.2': 1069 dependencies:
··· 11 '@tauri-apps/api': 12 specifier: ^2.9.0 13 version: 2.9.0 14 + '@tauri-apps/plugin-clipboard-manager': 15 + specifier: ~2 16 + version: 2.3.2 17 '@tauri-apps/plugin-dialog': 18 specifier: ~2.4.2 19 version: 2.4.2 ··· 481 resolution: {integrity: sha512-BQ7iLUXTQcyG1PpzLWeVSmBCedYDpnA/6Cm/kRFGtqjTf/eVUlyYO5S2ee07tLum3nWwDBWTGFZeruO8yEukfA==} 482 engines: {node: '>= 10'} 483 hasBin: true 484 + 485 + '@tauri-apps/plugin-clipboard-manager@2.3.2': 486 + resolution: {integrity: sha512-CUlb5Hqi2oZbcZf4VUyUH53XWPPdtpw43EUpCza5HWZJwxEoDowFzNUDt1tRUXA8Uq+XPn17Ysfptip33sG4eQ==} 487 488 '@tauri-apps/plugin-dialog@2.4.2': 489 resolution: {integrity: sha512-lNIn5CZuw8WZOn8zHzmFmDSzg5zfohWoa3mdULP0YFh/VogVdMVWZPcWSHlydsiJhRQYaTNSYKN7RmZKE2lCYQ==} ··· 1070 '@tauri-apps/cli-win32-arm64-msvc': 2.9.3 1071 '@tauri-apps/cli-win32-ia32-msvc': 2.9.3 1072 '@tauri-apps/cli-win32-x64-msvc': 2.9.3 1073 + 1074 + '@tauri-apps/plugin-clipboard-manager@2.3.2': 1075 + dependencies: 1076 + '@tauri-apps/api': 2.9.0 1077 1078 '@tauri-apps/plugin-dialog@2.4.2': 1079 dependencies:
+286 -8
src-tauri/Cargo.lock
··· 14 "serde_json", 15 "tauri", 16 "tauri-build", 17 "tauri-plugin-dialog", 18 "tauri-plugin-opener", 19 "tokio", ··· 65 checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" 66 67 [[package]] 68 name = "ashpd" 69 version = "0.11.0" 70 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 136 "futures-lite", 137 "parking", 138 "polling", 139 - "rustix", 140 "slab", 141 "windows-sys 0.61.2", 142 ] ··· 167 "cfg-if", 168 "event-listener", 169 "futures-lite", 170 - "rustix", 171 ] 172 173 [[package]] ··· 193 "cfg-if", 194 "futures-core", 195 "futures-io", 196 - "rustix", 197 "signal-hook-registry", 198 "slab", 199 "windows-sys 0.61.2", ··· 498 "num-traits", 499 "serde", 500 "windows-link 0.2.1", 501 ] 502 503 [[package]] ··· 609 checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 610 611 [[package]] 612 name = "crypto-common" 613 version = "0.1.6" 614 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 922 ] 923 924 [[package]] 925 name = "event-listener" 926 version = "5.4.1" 927 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 949 checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 950 951 [[package]] 952 name = "fdeflate" 953 version = "0.3.7" 954 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 974 checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" 975 976 [[package]] 977 name = "flate2" 978 version = "1.1.5" 979 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 988 version = "1.0.7" 989 source = "registry+https://github.com/rust-lang/crates.io-index" 990 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 991 992 [[package]] 993 name = "foreign-types" ··· 1239 ] 1240 1241 [[package]] 1242 name = "getrandom" 1243 version = "0.1.16" 1244 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1421 ] 1422 1423 [[package]] 1424 name = "hashbrown" 1425 version = "0.12.3" 1426 source = "registry+https://github.com/rust-lang/crates.io-index" 1427 checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 1428 1429 [[package]] 1430 name = "hashbrown" ··· 1706 "moxcms", 1707 "num-traits", 1708 "png 0.18.0", 1709 ] 1710 1711 [[package]] ··· 1949 1950 [[package]] 1951 name = "linux-raw-sys" 1952 version = "0.11.0" 1953 source = "registry+https://github.com/rust-lang/crates.io-index" 1954 checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" ··· 2031 version = "0.3.17" 2032 source = "registry+https://github.com/rust-lang/crates.io-index" 2033 checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 2034 2035 [[package]] 2036 name = "miniz_oxide" ··· 2140 checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" 2141 2142 [[package]] 2143 name = "num-conv" 2144 version = "0.1.0" 2145 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2475 ] 2476 2477 [[package]] 2478 name = "pango" 2479 version = "0.18.3" 2480 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2541 checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 2542 2543 [[package]] 2544 name = "phf" 2545 version = "0.8.0" 2546 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2752 "concurrent-queue", 2753 "hermit-abi", 2754 "pin-project-lite", 2755 - "rustix", 2756 "windows-sys 0.61.2", 2757 ] 2758 ··· 2862 dependencies = [ 2863 "num-traits", 2864 ] 2865 2866 [[package]] 2867 name = "quick-xml" ··· 3152 3153 [[package]] 3154 name = "rustix" 3155 version = "1.1.2" 3156 source = "registry+https://github.com/rust-lang/crates.io-index" 3157 checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" ··· 3159 "bitflags 2.10.0", 3160 "errno", 3161 "libc", 3162 - "linux-raw-sys", 3163 "windows-sys 0.61.2", 3164 ] 3165 ··· 3858 ] 3859 3860 [[package]] 3861 name = "tauri-plugin-dialog" 3862 version = "2.4.2" 3863 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4028 "fastrand", 4029 "getrandom 0.3.4", 4030 "once_cell", 4031 - "rustix", 4032 "windows-sys 0.61.2", 4033 ] 4034 ··· 4084 ] 4085 4086 [[package]] 4087 name = "time" 4088 version = "0.3.44" 4089 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4360 ] 4361 4362 [[package]] 4363 name = "try-lock" 4364 version = "0.2.5" 4365 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4640 dependencies = [ 4641 "cc", 4642 "downcast-rs", 4643 - "rustix", 4644 "scoped-tls", 4645 "smallvec", 4646 "wayland-sys", ··· 4653 checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" 4654 dependencies = [ 4655 "bitflags 2.10.0", 4656 - "rustix", 4657 "wayland-backend", 4658 "wayland-scanner", 4659 ] ··· 4667 "bitflags 2.10.0", 4668 "wayland-backend", 4669 "wayland-client", 4670 "wayland-scanner", 4671 ] 4672 ··· 4781 "windows", 4782 "windows-core 0.61.2", 4783 ] 4784 4785 [[package]] 4786 name = "winapi" ··· 5242 checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" 5243 5244 [[package]] 5245 name = "writeable" 5246 version = "0.6.2" 5247 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 5312 "once_cell", 5313 "pkg-config", 5314 ] 5315 5316 [[package]] 5317 name = "yoke" ··· 5470 "proc-macro2", 5471 "quote", 5472 "syn 2.0.109", 5473 ] 5474 5475 [[package]]
··· 14 "serde_json", 15 "tauri", 16 "tauri-build", 17 + "tauri-plugin-clipboard-manager", 18 "tauri-plugin-dialog", 19 "tauri-plugin-opener", 20 "tokio", ··· 66 checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" 67 68 [[package]] 69 + name = "arboard" 70 + version = "3.6.1" 71 + source = "registry+https://github.com/rust-lang/crates.io-index" 72 + checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" 73 + dependencies = [ 74 + "clipboard-win", 75 + "image", 76 + "log", 77 + "objc2 0.6.3", 78 + "objc2-app-kit", 79 + "objc2-core-foundation", 80 + "objc2-core-graphics", 81 + "objc2-foundation 0.3.2", 82 + "parking_lot", 83 + "percent-encoding", 84 + "windows-sys 0.60.2", 85 + "wl-clipboard-rs", 86 + "x11rb", 87 + ] 88 + 89 + [[package]] 90 name = "ashpd" 91 version = "0.11.0" 92 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 158 "futures-lite", 159 "parking", 160 "polling", 161 + "rustix 1.1.2", 162 "slab", 163 "windows-sys 0.61.2", 164 ] ··· 189 "cfg-if", 190 "event-listener", 191 "futures-lite", 192 + "rustix 1.1.2", 193 ] 194 195 [[package]] ··· 215 "cfg-if", 216 "futures-core", 217 "futures-io", 218 + "rustix 1.1.2", 219 "signal-hook-registry", 220 "slab", 221 "windows-sys 0.61.2", ··· 520 "num-traits", 521 "serde", 522 "windows-link 0.2.1", 523 + ] 524 + 525 + [[package]] 526 + name = "clipboard-win" 527 + version = "5.4.1" 528 + source = "registry+https://github.com/rust-lang/crates.io-index" 529 + checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" 530 + dependencies = [ 531 + "error-code", 532 ] 533 534 [[package]] ··· 640 checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 641 642 [[package]] 643 + name = "crunchy" 644 + version = "0.2.4" 645 + source = "registry+https://github.com/rust-lang/crates.io-index" 646 + checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" 647 + 648 + [[package]] 649 name = "crypto-common" 650 version = "0.1.6" 651 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 959 ] 960 961 [[package]] 962 + name = "error-code" 963 + version = "3.3.2" 964 + source = "registry+https://github.com/rust-lang/crates.io-index" 965 + checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" 966 + 967 + [[package]] 968 name = "event-listener" 969 version = "5.4.1" 970 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 992 checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 993 994 [[package]] 995 + name = "fax" 996 + version = "0.2.6" 997 + source = "registry+https://github.com/rust-lang/crates.io-index" 998 + checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" 999 + dependencies = [ 1000 + "fax_derive", 1001 + ] 1002 + 1003 + [[package]] 1004 + name = "fax_derive" 1005 + version = "0.2.0" 1006 + source = "registry+https://github.com/rust-lang/crates.io-index" 1007 + checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" 1008 + dependencies = [ 1009 + "proc-macro2", 1010 + "quote", 1011 + "syn 2.0.109", 1012 + ] 1013 + 1014 + [[package]] 1015 name = "fdeflate" 1016 version = "0.3.7" 1017 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1037 checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" 1038 1039 [[package]] 1040 + name = "fixedbitset" 1041 + version = "0.5.7" 1042 + source = "registry+https://github.com/rust-lang/crates.io-index" 1043 + checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" 1044 + 1045 + [[package]] 1046 name = "flate2" 1047 version = "1.1.5" 1048 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1057 version = "1.0.7" 1058 source = "registry+https://github.com/rust-lang/crates.io-index" 1059 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 1060 + 1061 + [[package]] 1062 + name = "foldhash" 1063 + version = "0.1.5" 1064 + source = "registry+https://github.com/rust-lang/crates.io-index" 1065 + checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" 1066 1067 [[package]] 1068 name = "foreign-types" ··· 1314 ] 1315 1316 [[package]] 1317 + name = "gethostname" 1318 + version = "1.1.0" 1319 + source = "registry+https://github.com/rust-lang/crates.io-index" 1320 + checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" 1321 + dependencies = [ 1322 + "rustix 1.1.2", 1323 + "windows-link 0.2.1", 1324 + ] 1325 + 1326 + [[package]] 1327 name = "getrandom" 1328 version = "0.1.16" 1329 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1506 ] 1507 1508 [[package]] 1509 + name = "half" 1510 + version = "2.7.1" 1511 + source = "registry+https://github.com/rust-lang/crates.io-index" 1512 + checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" 1513 + dependencies = [ 1514 + "cfg-if", 1515 + "crunchy", 1516 + "zerocopy", 1517 + ] 1518 + 1519 + [[package]] 1520 name = "hashbrown" 1521 version = "0.12.3" 1522 source = "registry+https://github.com/rust-lang/crates.io-index" 1523 checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 1524 + 1525 + [[package]] 1526 + name = "hashbrown" 1527 + version = "0.15.5" 1528 + source = "registry+https://github.com/rust-lang/crates.io-index" 1529 + checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" 1530 + dependencies = [ 1531 + "foldhash", 1532 + ] 1533 1534 [[package]] 1535 name = "hashbrown" ··· 1811 "moxcms", 1812 "num-traits", 1813 "png 0.18.0", 1814 + "tiff", 1815 ] 1816 1817 [[package]] ··· 2055 2056 [[package]] 2057 name = "linux-raw-sys" 2058 + version = "0.4.15" 2059 + source = "registry+https://github.com/rust-lang/crates.io-index" 2060 + checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 2061 + 2062 + [[package]] 2063 + name = "linux-raw-sys" 2064 version = "0.11.0" 2065 source = "registry+https://github.com/rust-lang/crates.io-index" 2066 checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" ··· 2143 version = "0.3.17" 2144 source = "registry+https://github.com/rust-lang/crates.io-index" 2145 checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 2146 + 2147 + [[package]] 2148 + name = "minimal-lexical" 2149 + version = "0.2.1" 2150 + source = "registry+https://github.com/rust-lang/crates.io-index" 2151 + checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 2152 2153 [[package]] 2154 name = "miniz_oxide" ··· 2258 checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" 2259 2260 [[package]] 2261 + name = "nom" 2262 + version = "7.1.3" 2263 + source = "registry+https://github.com/rust-lang/crates.io-index" 2264 + checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 2265 + dependencies = [ 2266 + "memchr", 2267 + "minimal-lexical", 2268 + ] 2269 + 2270 + [[package]] 2271 name = "num-conv" 2272 version = "0.1.0" 2273 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2603 ] 2604 2605 [[package]] 2606 + name = "os_pipe" 2607 + version = "1.2.3" 2608 + source = "registry+https://github.com/rust-lang/crates.io-index" 2609 + checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" 2610 + dependencies = [ 2611 + "libc", 2612 + "windows-sys 0.61.2", 2613 + ] 2614 + 2615 + [[package]] 2616 name = "pango" 2617 version = "0.18.3" 2618 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2679 checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 2680 2681 [[package]] 2682 + name = "petgraph" 2683 + version = "0.8.3" 2684 + source = "registry+https://github.com/rust-lang/crates.io-index" 2685 + checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" 2686 + dependencies = [ 2687 + "fixedbitset", 2688 + "hashbrown 0.15.5", 2689 + "indexmap 2.12.0", 2690 + ] 2691 + 2692 + [[package]] 2693 name = "phf" 2694 version = "0.8.0" 2695 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2901 "concurrent-queue", 2902 "hermit-abi", 2903 "pin-project-lite", 2904 + "rustix 1.1.2", 2905 "windows-sys 0.61.2", 2906 ] 2907 ··· 3011 dependencies = [ 3012 "num-traits", 3013 ] 3014 + 3015 + [[package]] 3016 + name = "quick-error" 3017 + version = "2.0.1" 3018 + source = "registry+https://github.com/rust-lang/crates.io-index" 3019 + checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" 3020 3021 [[package]] 3022 name = "quick-xml" ··· 3307 3308 [[package]] 3309 name = "rustix" 3310 + version = "0.38.44" 3311 + source = "registry+https://github.com/rust-lang/crates.io-index" 3312 + checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" 3313 + dependencies = [ 3314 + "bitflags 2.10.0", 3315 + "errno", 3316 + "libc", 3317 + "linux-raw-sys 0.4.15", 3318 + "windows-sys 0.59.0", 3319 + ] 3320 + 3321 + [[package]] 3322 + name = "rustix" 3323 version = "1.1.2" 3324 source = "registry+https://github.com/rust-lang/crates.io-index" 3325 checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" ··· 3327 "bitflags 2.10.0", 3328 "errno", 3329 "libc", 3330 + "linux-raw-sys 0.11.0", 3331 "windows-sys 0.61.2", 3332 ] 3333 ··· 4026 ] 4027 4028 [[package]] 4029 + name = "tauri-plugin-clipboard-manager" 4030 + version = "2.3.2" 4031 + source = "registry+https://github.com/rust-lang/crates.io-index" 4032 + checksum = "206dc20af4ed210748ba945c2774e60fd0acd52b9a73a028402caf809e9b6ecf" 4033 + dependencies = [ 4034 + "arboard", 4035 + "log", 4036 + "serde", 4037 + "serde_json", 4038 + "tauri", 4039 + "tauri-plugin", 4040 + "thiserror 2.0.17", 4041 + ] 4042 + 4043 + [[package]] 4044 name = "tauri-plugin-dialog" 4045 version = "2.4.2" 4046 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4211 "fastrand", 4212 "getrandom 0.3.4", 4213 "once_cell", 4214 + "rustix 1.1.2", 4215 "windows-sys 0.61.2", 4216 ] 4217 ··· 4267 ] 4268 4269 [[package]] 4270 + name = "tiff" 4271 + version = "0.10.3" 4272 + source = "registry+https://github.com/rust-lang/crates.io-index" 4273 + checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" 4274 + dependencies = [ 4275 + "fax", 4276 + "flate2", 4277 + "half", 4278 + "quick-error", 4279 + "weezl", 4280 + "zune-jpeg", 4281 + ] 4282 + 4283 + [[package]] 4284 name = "time" 4285 version = "0.3.44" 4286 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4557 ] 4558 4559 [[package]] 4560 + name = "tree_magic_mini" 4561 + version = "3.2.1" 4562 + source = "registry+https://github.com/rust-lang/crates.io-index" 4563 + checksum = "52fac5f7d176f7f7f7e827299ead28ef98de642c5d93a97e0cd0816d17557f19" 4564 + dependencies = [ 4565 + "memchr", 4566 + "nom", 4567 + "petgraph", 4568 + ] 4569 + 4570 + [[package]] 4571 name = "try-lock" 4572 version = "0.2.5" 4573 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4848 dependencies = [ 4849 "cc", 4850 "downcast-rs", 4851 + "rustix 1.1.2", 4852 "scoped-tls", 4853 "smallvec", 4854 "wayland-sys", ··· 4861 checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" 4862 dependencies = [ 4863 "bitflags 2.10.0", 4864 + "rustix 1.1.2", 4865 "wayland-backend", 4866 "wayland-scanner", 4867 ] ··· 4875 "bitflags 2.10.0", 4876 "wayland-backend", 4877 "wayland-client", 4878 + "wayland-scanner", 4879 + ] 4880 + 4881 + [[package]] 4882 + name = "wayland-protocols-wlr" 4883 + version = "0.3.9" 4884 + source = "registry+https://github.com/rust-lang/crates.io-index" 4885 + checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec" 4886 + dependencies = [ 4887 + "bitflags 2.10.0", 4888 + "wayland-backend", 4889 + "wayland-client", 4890 + "wayland-protocols", 4891 "wayland-scanner", 4892 ] 4893 ··· 5002 "windows", 5003 "windows-core 0.61.2", 5004 ] 5005 + 5006 + [[package]] 5007 + name = "weezl" 5008 + version = "0.1.12" 5009 + source = "registry+https://github.com/rust-lang/crates.io-index" 5010 + checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" 5011 5012 [[package]] 5013 name = "winapi" ··· 5469 checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" 5470 5471 [[package]] 5472 + name = "wl-clipboard-rs" 5473 + version = "0.9.2" 5474 + source = "registry+https://github.com/rust-lang/crates.io-index" 5475 + checksum = "8e5ff8d0e60065f549fafd9d6cb626203ea64a798186c80d8e7df4f8af56baeb" 5476 + dependencies = [ 5477 + "libc", 5478 + "log", 5479 + "os_pipe", 5480 + "rustix 0.38.44", 5481 + "tempfile", 5482 + "thiserror 2.0.17", 5483 + "tree_magic_mini", 5484 + "wayland-backend", 5485 + "wayland-client", 5486 + "wayland-protocols", 5487 + "wayland-protocols-wlr", 5488 + ] 5489 + 5490 + [[package]] 5491 name = "writeable" 5492 version = "0.6.2" 5493 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 5558 "once_cell", 5559 "pkg-config", 5560 ] 5561 + 5562 + [[package]] 5563 + name = "x11rb" 5564 + version = "0.13.2" 5565 + source = "registry+https://github.com/rust-lang/crates.io-index" 5566 + checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" 5567 + dependencies = [ 5568 + "gethostname", 5569 + "rustix 1.1.2", 5570 + "x11rb-protocol", 5571 + ] 5572 + 5573 + [[package]] 5574 + name = "x11rb-protocol" 5575 + version = "0.13.2" 5576 + source = "registry+https://github.com/rust-lang/crates.io-index" 5577 + checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" 5578 5579 [[package]] 5580 name = "yoke" ··· 5733 "proc-macro2", 5734 "quote", 5735 "syn 2.0.109", 5736 + ] 5737 + 5738 + [[package]] 5739 + name = "zune-core" 5740 + version = "0.4.12" 5741 + source = "registry+https://github.com/rust-lang/crates.io-index" 5742 + checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" 5743 + 5744 + [[package]] 5745 + name = "zune-jpeg" 5746 + version = "0.4.21" 5747 + source = "registry+https://github.com/rust-lang/crates.io-index" 5748 + checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" 5749 + dependencies = [ 5750 + "zune-core", 5751 ] 5752 5753 [[package]]
+1
src-tauri/Cargo.toml
··· 28 flate2 = "1.1" 29 tauri-plugin-dialog = "2" 30 crossbeam-channel = "0.5" 31
··· 28 flate2 = "1.1" 29 tauri-plugin-dialog = "2" 30 crossbeam-channel = "0.5" 31 + tauri-plugin-clipboard-manager = "2" 32
+3 -1
src-tauri/capabilities/default.json
··· 9 "core:default", 10 "core:window:allow-destroy", 11 "opener:default", 12 - "dialog:default" 13 ] 14 }
··· 9 "core:default", 10 "core:window:allow-destroy", 11 "opener:default", 12 + "dialog:default", 13 + "clipboard-manager:allow-read-text", 14 + "clipboard-manager:allow-write-text" 15 ] 16 }
+2 -2
src-tauri/src/frontend_calls/close_app.rs
··· 3 use crate::utils::config::Config; 4 5 #[tauri::command] 6 - pub fn close_app( conf: State<Config> ){ 7 conf.save(); 8 std::process::exit(0); 9 - }
··· 3 use crate::utils::config::Config; 4 5 #[tauri::command] 6 + pub fn close_app(conf: State<Config>) { 7 conf.save(); 8 std::process::exit(0); 9 + }
+9 -4
src-tauri/src/frontend_calls/load_previous_tabs.rs
··· 2 3 use tauri::{State, Window}; 4 5 - use crate::{ structs::nodes::Node, utils::config::Config }; 6 7 #[tauri::command] 8 - pub fn load_previous_tabs( window: Window, conf: State<Config> ) -> HashMap<String, ( Vec<Node>, String, Option<String> )> { 9 let config = conf.store.lock().unwrap(); 10 11 - if !config.hide_editor_on_start { window.show().unwrap(); } 12 13 let tabs = config.loaded_tabs.clone(); 14 tabs 15 - }
··· 2 3 use tauri::{State, Window}; 4 5 + use crate::{structs::nodes::Node, utils::config::Config}; 6 7 #[tauri::command] 8 + pub fn load_previous_tabs( 9 + window: Window, 10 + conf: State<Config>, 11 + ) -> HashMap<String, (Vec<Node>, String, Option<String>)> { 12 let config = conf.store.lock().unwrap(); 13 14 + if !config.hide_editor_on_start { 15 + window.show().unwrap(); 16 + } 17 18 let tabs = config.loaded_tabs.clone(); 19 tabs 20 + }
+3 -3
src-tauri/src/frontend_calls/mod.rs
··· 1 pub mod get_addresses; 2 pub mod save_graph; 3 pub mod sync_tab; 4 - pub mod load_previous_tabs; 5 - pub mod close_app; 6 - pub mod settings;
··· 1 + pub mod close_app; 2 pub mod get_addresses; 3 + pub mod load_previous_tabs; 4 pub mod save_graph; 5 + pub mod settings; 6 pub mod sync_tab;
+2 -2
src-tauri/src/frontend_calls/save_graph.rs
··· 1 use std::{fs::File, io::Write, path::PathBuf}; 2 3 - use flate2::{ write::GzEncoder, Compression }; 4 use tauri::State; 5 6 use crate::utils::config::Config; 7 8 #[tauri::command] 9 - pub fn save_graph( graph: String, path: PathBuf, conf: State<Config> ) { 10 let file = File::create(&path).unwrap(); 11 let mut encoder = GzEncoder::new(file, Compression::default()); 12
··· 1 use std::{fs::File, io::Write, path::PathBuf}; 2 3 + use flate2::{write::GzEncoder, Compression}; 4 use tauri::State; 5 6 use crate::utils::config::Config; 7 8 #[tauri::command] 9 + pub fn save_graph(graph: String, path: PathBuf, conf: State<Config>) { 10 let file = File::create(&path).unwrap(); 11 let mut encoder = GzEncoder::new(file, Compression::default()); 12
+3 -3
src-tauri/src/frontend_calls/settings.rs
··· 3 use crate::utils::config::Config; 4 5 #[tauri::command] 6 - pub fn set_hide_editor_on_app_start( value: bool, conf: State<Config> ){ 7 let mut config = conf.store.lock().unwrap(); 8 config.hide_editor_on_start = value; 9 } 10 11 #[tauri::command] 12 - pub fn get_hide_editor_on_app_start( conf: State<Config> ) -> bool { 13 let config = conf.store.lock().unwrap(); 14 config.hide_editor_on_start 15 - }
··· 3 use crate::utils::config::Config; 4 5 #[tauri::command] 6 + pub fn set_hide_editor_on_app_start(value: bool, conf: State<Config>) { 7 let mut config = conf.store.lock().unwrap(); 8 config.hide_editor_on_start = value; 9 } 10 11 #[tauri::command] 12 + pub fn get_hide_editor_on_app_start(conf: State<Config>) -> bool { 13 let config = conf.store.lock().unwrap(); 14 config.hide_editor_on_start 15 + }
+15 -6
src-tauri/src/frontend_calls/sync_tab.rs
··· 2 3 use tauri::State; 4 5 - use crate::{ runtime::commands::RuntimeCommand, structs::nodes::Node, utils::config::Config }; 6 7 #[tauri::command] 8 - pub fn sync_tab( graph: Vec<Node>, id: String, name: String, location: Option<String>, cmd: State<Sender<RuntimeCommand>>, conf: State<Config> ){ 9 - cmd.send(RuntimeCommand::AddTab(graph.clone(), id.clone())).unwrap(); 10 11 let mut config = conf.store.lock().unwrap(); 12 - config.loaded_tabs.insert(id, ( graph, name, location )); // TODO: When loading a tab into config, store the save state of it too 13 } 14 15 #[tauri::command] 16 - pub fn discard_tab( id: String, cmd: State<Sender<RuntimeCommand>>, conf: State<Config> ){ 17 cmd.send(RuntimeCommand::RemoveTab(id.clone())).unwrap(); 18 19 let mut config = conf.store.lock().unwrap(); 20 config.loaded_tabs.remove(&id); 21 - }
··· 2 3 use tauri::State; 4 5 + use crate::{runtime::commands::RuntimeCommand, structs::nodes::Node, utils::config::Config}; 6 7 #[tauri::command] 8 + pub fn sync_tab( 9 + graph: Vec<Node>, 10 + id: String, 11 + name: String, 12 + location: Option<String>, 13 + cmd: State<Sender<RuntimeCommand>>, 14 + conf: State<Config>, 15 + ) { 16 + cmd 17 + .send(RuntimeCommand::AddTab(graph.clone(), id.clone())) 18 + .unwrap(); 19 20 let mut config = conf.store.lock().unwrap(); 21 + config.loaded_tabs.insert(id, (graph, name, location)); // TODO: When loading a tab into config, store the save state of it too 22 } 23 24 #[tauri::command] 25 + pub fn discard_tab(id: String, cmd: State<Sender<RuntimeCommand>>, conf: State<Config>) { 26 cmd.send(RuntimeCommand::RemoveTab(id.clone())).unwrap(); 27 28 let mut config = conf.store.lock().unwrap(); 29 config.loaded_tabs.remove(&id); 30 + }
+5 -5
src-tauri/src/lib.rs
··· 1 - use std::{ fs, sync::Mutex }; 2 3 use crossbeam_channel::bounded; 4 use frontend_calls::*; 5 6 - use crate::{ osc::OSCMessage, setup::setup, utils::config::Config }; 7 8 mod frontend_calls; 9 mod osc; 10 mod setup; 11 mod structs; 12 mod utils; 13 - mod runtime; 14 15 // TODO: Add built-in OSC endpoints 16 ··· 35 36 static ADDRESSES: Mutex<Vec<OSCMessage>> = Mutex::new(Vec::new()); 37 38 - let ( runtime_sender, runtime_receiver ) = bounded(1024); 39 40 tauri::Builder::default() 41 .plugin(tauri_plugin_dialog::init()) 42 .plugin(tauri_plugin_opener::init()) 43 .invoke_handler(tauri::generate_handler![ ··· 47 sync_tab::discard_tab, 48 load_previous_tabs::load_previous_tabs, 49 close_app::close_app, 50 - 51 settings::set_hide_editor_on_app_start, 52 settings::get_hide_editor_on_app_start, 53 ])
··· 1 + use std::{fs, sync::Mutex}; 2 3 use crossbeam_channel::bounded; 4 use frontend_calls::*; 5 6 + use crate::{osc::OSCMessage, setup::setup, utils::config::Config}; 7 8 mod frontend_calls; 9 mod osc; 10 + mod runtime; 11 mod setup; 12 mod structs; 13 mod utils; 14 15 // TODO: Add built-in OSC endpoints 16 ··· 35 36 static ADDRESSES: Mutex<Vec<OSCMessage>> = Mutex::new(Vec::new()); 37 38 + let (runtime_sender, runtime_receiver) = bounded(1024); 39 40 tauri::Builder::default() 41 + .plugin(tauri_plugin_clipboard_manager::init()) 42 .plugin(tauri_plugin_dialog::init()) 43 .plugin(tauri_plugin_opener::init()) 44 .invoke_handler(tauri::generate_handler![ ··· 48 sync_tab::discard_tab, 49 load_previous_tabs::load_previous_tabs, 50 close_app::close_app, 51 settings::set_hide_editor_on_app_start, 52 settings::get_hide_editor_on_app_start, 53 ])
+34 -20
src-tauri/src/runtime.rs
··· 1 - use anyhow::{ bail, Result }; 2 3 - use crate::{ runtime::nodes::RuntimeNodeTree, structs::parameter_types::ParameterType }; 4 5 - pub mod nodes; 6 pub mod commands; 7 8 // This is horrible. I know, I'm sorry. 9 10 - pub fn runtime_dry( entry: String, parameters: &Vec<ParameterType>, tab: &mut RuntimeNodeTree ) -> Result<()>{ 11 let node = tab.nodes.get_mut(&entry); 12 - if node.is_none(){ bail!("Cannot find node"); } 13 14 let node = node.unwrap(); 15 16 let output_map = node.outputs(); 17 let args = node.execute_dry(parameters); 18 19 - if args.is_some(){ 20 let args = args.unwrap(); 21 22 - for i in 0..args.len(){ 23 let arg = &args[i]; 24 25 - for output in &output_map[i]{ 26 - if output.2 == 5{ break; } // Ignore flow outputs 27 28 let next_node = tab.nodes.get_mut(&output.0); 29 - if next_node.is_none(){ bail!("Cannot find node {}", output.0) } 30 31 let next_node = next_node.unwrap(); 32 let can_update = next_node.update_arg(output.1 as usize, arg.clone()); 33 34 - if can_update{ 35 runtime_dry(output.0.clone(), &vec![], tab)?; 36 } 37 } ··· 41 Ok(()) 42 } 43 44 - pub fn runtime( entry: String, tab: &mut RuntimeNodeTree ) -> Result<()>{ 45 let node = tab.nodes.get_mut(&entry); 46 - if node.is_none(){ bail!("Cannot find node"); } 47 48 let node = node.unwrap(); 49 50 let next = node.execute(); 51 - if next.is_some(){ 52 let next = next.unwrap(); 53 54 let outputs = node.outputs(); 55 56 - for i in 0..next.len(){ 57 let arg = &next[i]; 58 - if i >= outputs.len() { break; } 59 60 - for output in &outputs[i]{ 61 - if let ParameterType::Flow(next) = arg{ 62 - if *next{ 63 // This is a flow output, continue 64 runtime(output.0.clone(), tab)?; 65 } ··· 69 } 70 71 Ok(()) 72 - }
··· 1 + use anyhow::{bail, Result}; 2 3 + use crate::{runtime::nodes::RuntimeNodeTree, structs::parameter_types::ParameterType}; 4 5 pub mod commands; 6 + pub mod nodes; 7 8 // This is horrible. I know, I'm sorry. 9 10 + pub fn runtime_dry( 11 + entry: String, 12 + parameters: &Vec<ParameterType>, 13 + tab: &mut RuntimeNodeTree, 14 + ) -> Result<()> { 15 let node = tab.nodes.get_mut(&entry); 16 + if node.is_none() { 17 + bail!("Cannot find node"); 18 + } 19 20 let node = node.unwrap(); 21 22 let output_map = node.outputs(); 23 let args = node.execute_dry(parameters); 24 25 + if args.is_some() { 26 let args = args.unwrap(); 27 28 + for i in 0..args.len() { 29 let arg = &args[i]; 30 31 + for output in &output_map[i] { 32 + if output.2 == 5 { 33 + break; 34 + } // Ignore flow outputs 35 36 let next_node = tab.nodes.get_mut(&output.0); 37 + if next_node.is_none() { 38 + bail!("Cannot find node {}", output.0) 39 + } 40 41 let next_node = next_node.unwrap(); 42 let can_update = next_node.update_arg(output.1 as usize, arg.clone()); 43 44 + if can_update { 45 runtime_dry(output.0.clone(), &vec![], tab)?; 46 } 47 } ··· 51 Ok(()) 52 } 53 54 + pub fn runtime(entry: String, tab: &mut RuntimeNodeTree) -> Result<()> { 55 let node = tab.nodes.get_mut(&entry); 56 + if node.is_none() { 57 + bail!("Cannot find node"); 58 + } 59 60 let node = node.unwrap(); 61 62 let next = node.execute(); 63 + if next.is_some() { 64 let next = next.unwrap(); 65 66 let outputs = node.outputs(); 67 68 + for i in 0..next.len() { 69 let arg = &next[i]; 70 + if i >= outputs.len() { 71 + break; 72 + } 73 74 + for output in &outputs[i] { 75 + if let ParameterType::Flow(next) = arg { 76 + if *next { 77 // This is a flow output, continue 78 runtime(output.0.clone(), tab)?; 79 } ··· 83 } 84 85 Ok(()) 86 + }
+4 -4
src-tauri/src/runtime/commands.rs
··· 1 - use crate::{ osc::OSCMessage, structs::nodes::Node }; 2 3 #[derive(Debug)] 4 - pub enum RuntimeCommand{ 5 OSCMessage(OSCMessage), 6 7 AddTab(Vec<Node>, String), 8 - RemoveTab(String) 9 - }
··· 1 + use crate::{osc::OSCMessage, structs::nodes::Node}; 2 3 #[derive(Debug)] 4 + pub enum RuntimeCommand { 5 OSCMessage(OSCMessage), 6 7 AddTab(Vec<Node>, String), 8 + RemoveTab(String), 9 + }
+59 -28
src-tauri/src/runtime/nodes.rs
··· 1 use std::collections::HashMap; 2 3 - use crate::{ runtime::nodes::{ conditional::{ ifequal::ConditionalIfEqual, iffalse::ConditionalIfFalse, iftrue::ConditionalIfTrue }, debug::Debug, oscactions::sendchatbox::OSCActionsSendChatbox, osctrigger::OSCTrigger, statics::{ float::StaticFloat, int::StaticInt, string::StaticString } }, structs::{ nodes::Node, parameter_types::ParameterType } }; 4 5 - mod osctrigger; 6 mod debug; 7 mod statics; 8 - mod conditional; 9 - mod oscactions; 10 11 - pub struct RuntimeNodeTree{ 12 - pub nodes: HashMap<String, Box<dyn RuntimeNode>> 13 } 14 15 - unsafe impl Send for RuntimeNodeTree{} 16 17 - impl RuntimeNodeTree{ 18 - pub fn from( tree: Vec<Node> ) -> Self{ 19 let mut runtime_nodes: HashMap<String, Box<dyn RuntimeNode>> = HashMap::new(); 20 - for node in tree{ 21 - match node.type_id.as_str(){ 22 - "osctrigger" => { runtime_nodes.insert(node.id.clone(), OSCTrigger::new(node)); } 23 24 - "staticstring" => { runtime_nodes.insert(node.id.clone(), StaticString::new(node)); } 25 - "staticint" => { runtime_nodes.insert(node.id.clone(), StaticInt::new(node)); } 26 - "staticfloat" => { runtime_nodes.insert(node.id.clone(), StaticFloat::new(node)); } 27 28 - "iftrue" => { runtime_nodes.insert(node.id.clone(), ConditionalIfTrue::new(node)); } 29 - "iffalse" => { runtime_nodes.insert(node.id.clone(), ConditionalIfFalse::new(node)); } 30 - "ifequal" => { runtime_nodes.insert(node.id.clone(), ConditionalIfEqual::new(node)); } 31 32 - "oscsendchatbox" => { runtime_nodes.insert(node.id.clone(), OSCActionsSendChatbox::new(node)); } 33 34 - "debug" => { runtime_nodes.insert(node.id.clone(), Debug::new(node)); } 35 _ => {} 36 } 37 } 38 39 - Self { nodes: runtime_nodes } 40 } 41 } 42 43 - pub trait RuntimeNode{ 44 - fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>>; // Node ID, input index, output value type 45 - fn execute_dry( &mut self, msg: &Vec<ParameterType> ) -> Option<Vec<ParameterType>>; // Only update values on the first loop through 46 - fn execute( &mut self ) -> Option<Vec<ParameterType>>; // Then call functions on the second loop 47 - fn update_arg( &mut self, index: usize, value: ParameterType ) -> bool; 48 - fn is_entrypoint( &self ) -> bool; 49 - }
··· 1 use std::collections::HashMap; 2 3 + use crate::{ 4 + runtime::nodes::{ 5 + conditional::{ 6 + ifequal::ConditionalIfEqual, iffalse::ConditionalIfFalse, iftrue::ConditionalIfTrue, 7 + }, 8 + debug::Debug, 9 + oscactions::sendchatbox::OSCActionsSendChatbox, 10 + osctrigger::OSCTrigger, 11 + statics::{float::StaticFloat, int::StaticInt, string::StaticString}, 12 + }, 13 + structs::{nodes::Node, parameter_types::ParameterType}, 14 + }; 15 16 + mod conditional; 17 mod debug; 18 + mod oscactions; 19 + mod osctrigger; 20 mod statics; 21 22 + pub struct RuntimeNodeTree { 23 + pub nodes: HashMap<String, Box<dyn RuntimeNode>>, 24 } 25 26 + unsafe impl Send for RuntimeNodeTree {} 27 28 + impl RuntimeNodeTree { 29 + pub fn from(tree: Vec<Node>) -> Self { 30 let mut runtime_nodes: HashMap<String, Box<dyn RuntimeNode>> = HashMap::new(); 31 + for node in tree { 32 + match node.type_id.as_str() { 33 + "osctrigger" => { 34 + runtime_nodes.insert(node.id.clone(), OSCTrigger::new(node)); 35 + } 36 37 + "staticstring" => { 38 + runtime_nodes.insert(node.id.clone(), StaticString::new(node)); 39 + } 40 + "staticint" => { 41 + runtime_nodes.insert(node.id.clone(), StaticInt::new(node)); 42 + } 43 + "staticfloat" => { 44 + runtime_nodes.insert(node.id.clone(), StaticFloat::new(node)); 45 + } 46 47 + "iftrue" => { 48 + runtime_nodes.insert(node.id.clone(), ConditionalIfTrue::new(node)); 49 + } 50 + "iffalse" => { 51 + runtime_nodes.insert(node.id.clone(), ConditionalIfFalse::new(node)); 52 + } 53 + "ifequal" => { 54 + runtime_nodes.insert(node.id.clone(), ConditionalIfEqual::new(node)); 55 + } 56 57 + "oscsendchatbox" => { 58 + runtime_nodes.insert(node.id.clone(), OSCActionsSendChatbox::new(node)); 59 + } 60 61 + "debug" => { 62 + runtime_nodes.insert(node.id.clone(), Debug::new(node)); 63 + } 64 _ => {} 65 } 66 } 67 68 + Self { 69 + nodes: runtime_nodes, 70 + } 71 } 72 } 73 74 + pub trait RuntimeNode { 75 + fn outputs(&self) -> Vec<Vec<(String, isize, isize)>>; // Node ID, input index, output value type 76 + fn execute_dry(&mut self, msg: &Vec<ParameterType>) -> Option<Vec<ParameterType>>; // Only update values on the first loop through 77 + fn execute(&mut self) -> Option<Vec<ParameterType>>; // Then call functions on the second loop 78 + fn update_arg(&mut self, index: usize, value: ParameterType) -> bool; 79 + fn is_entrypoint(&self) -> bool; 80 + }
+39 -21
src-tauri/src/runtime/nodes/conditional/ifequal.rs
··· 1 - use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 2 3 - pub struct ConditionalIfEqual{ 4 - outputs: Vec<Vec<( String, isize, isize )>>, 5 value1: ParameterType, 6 - value2: ParameterType 7 } 8 9 - impl ConditionalIfEqual{ 10 - pub fn new( node: Node ) -> Box<Self>{ 11 Box::new(Self { 12 - outputs: node.outputs.iter() 13 - .map(| x | { 14 - x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect() 15 - }).collect(), 16 value1: ParameterType::None, 17 value2: ParameterType::None, 18 }) 19 } 20 } 21 22 - impl RuntimeNode for ConditionalIfEqual{ 23 - fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { self.outputs.clone() } 24 - fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { Some(vec![]) } 25 26 - fn execute( &mut self ) -> Option<Vec<ParameterType>> { 27 - if self.value1 == ParameterType::None && self.value2 == ParameterType::None{ 28 None 29 - } else{ 30 let equal = self.value1 == self.value2; 31 - Some(vec![ ParameterType::Flow(equal), ParameterType::Flow(!equal) ]) 32 } 33 } 34 35 - fn update_arg( &mut self, index: usize, arg: ParameterType ) -> bool { 36 - match index{ 37 1 => { 38 self.value1 = arg; 39 } ··· 46 false 47 } 48 49 - fn is_entrypoint( &self ) -> bool { false } 50 - }
··· 1 + use crate::{ 2 + runtime::nodes::RuntimeNode, 3 + structs::{nodes::Node, parameter_types::ParameterType}, 4 + }; 5 6 + pub struct ConditionalIfEqual { 7 + outputs: Vec<Vec<(String, isize, isize)>>, 8 value1: ParameterType, 9 + value2: ParameterType, 10 } 11 12 + impl ConditionalIfEqual { 13 + pub fn new(node: Node) -> Box<Self> { 14 Box::new(Self { 15 + outputs: node 16 + .outputs 17 + .iter() 18 + .map(|x| { 19 + x.connections 20 + .iter() 21 + .map(|x| (x.node.clone(), x.index, x.value_type)) 22 + .collect() 23 + }) 24 + .collect(), 25 value1: ParameterType::None, 26 value2: ParameterType::None, 27 }) 28 } 29 } 30 31 + impl RuntimeNode for ConditionalIfEqual { 32 + fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 33 + self.outputs.clone() 34 + } 35 + fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 36 + Some(vec![]) 37 + } 38 39 + fn execute(&mut self) -> Option<Vec<ParameterType>> { 40 + if self.value1 == ParameterType::None && self.value2 == ParameterType::None { 41 None 42 + } else { 43 let equal = self.value1 == self.value2; 44 + Some(vec![ 45 + ParameterType::Flow(equal), 46 + ParameterType::Flow(!equal), 47 + ]) 48 } 49 } 50 51 + fn update_arg(&mut self, index: usize, arg: ParameterType) -> bool { 52 + match index { 53 1 => { 54 self.value1 = arg; 55 } ··· 62 false 63 } 64 65 + fn is_entrypoint(&self) -> bool { 66 + false 67 + } 68 + }
+39 -21
src-tauri/src/runtime/nodes/conditional/iffalse.rs
··· 1 - use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 2 3 - pub struct ConditionalIfFalse{ 4 - outputs: Vec<Vec<( String, isize, isize )>>, 5 - runtime_active: bool 6 } 7 8 - impl ConditionalIfFalse{ 9 - pub fn new( node: Node ) -> Box<Self>{ 10 Box::new(Self { 11 - outputs: node.outputs.iter() 12 - .map(| x | { 13 - x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect() 14 - }).collect(), 15 - runtime_active: false 16 }) 17 } 18 } 19 20 - impl RuntimeNode for ConditionalIfFalse{ 21 - fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { self.outputs.clone() } 22 - fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { Some(vec![]) } 23 24 - fn execute( &mut self ) -> Option<Vec<ParameterType>> { 25 - Some(vec![ ParameterType::Flow(!self.runtime_active), ParameterType::Flow(self.runtime_active) ]) 26 } 27 28 - fn update_arg( &mut self, _: usize, arg: ParameterType ) -> bool { 29 - if arg.as_bool().unwrap(){ 30 self.runtime_active = true; 31 true 32 - } else{ 33 self.runtime_active = false; 34 false 35 } 36 } 37 38 - fn is_entrypoint( &self ) -> bool { false } 39 - }
··· 1 + use crate::{ 2 + runtime::nodes::RuntimeNode, 3 + structs::{nodes::Node, parameter_types::ParameterType}, 4 + }; 5 6 + pub struct ConditionalIfFalse { 7 + outputs: Vec<Vec<(String, isize, isize)>>, 8 + runtime_active: bool, 9 } 10 11 + impl ConditionalIfFalse { 12 + pub fn new(node: Node) -> Box<Self> { 13 Box::new(Self { 14 + outputs: node 15 + .outputs 16 + .iter() 17 + .map(|x| { 18 + x.connections 19 + .iter() 20 + .map(|x| (x.node.clone(), x.index, x.value_type)) 21 + .collect() 22 + }) 23 + .collect(), 24 + runtime_active: false, 25 }) 26 } 27 } 28 29 + impl RuntimeNode for ConditionalIfFalse { 30 + fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 31 + self.outputs.clone() 32 + } 33 + fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 34 + Some(vec![]) 35 + } 36 37 + fn execute(&mut self) -> Option<Vec<ParameterType>> { 38 + Some(vec![ 39 + ParameterType::Flow(!self.runtime_active), 40 + ParameterType::Flow(self.runtime_active), 41 + ]) 42 } 43 44 + fn update_arg(&mut self, _: usize, arg: ParameterType) -> bool { 45 + if arg.as_bool().unwrap() { 46 self.runtime_active = true; 47 true 48 + } else { 49 self.runtime_active = false; 50 false 51 } 52 } 53 54 + fn is_entrypoint(&self) -> bool { 55 + false 56 + } 57 + }
+39 -21
src-tauri/src/runtime/nodes/conditional/iftrue.rs
··· 1 - use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 2 3 - pub struct ConditionalIfTrue{ 4 - outputs: Vec<Vec<( String, isize, isize )>>, 5 - runtime_active: bool 6 } 7 8 - impl ConditionalIfTrue{ 9 - pub fn new( node: Node ) -> Box<Self>{ 10 Box::new(Self { 11 - outputs: node.outputs.iter() 12 - .map(| x | { 13 - x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect() 14 - }).collect(), 15 - runtime_active: false 16 }) 17 } 18 } 19 20 - impl RuntimeNode for ConditionalIfTrue{ 21 - fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { self.outputs.clone() } 22 - fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { Some(vec![]) } 23 24 - fn execute( &mut self ) -> Option<Vec<ParameterType>> { 25 - Some(vec![ ParameterType::Flow(self.runtime_active), ParameterType::Flow(!self.runtime_active) ]) 26 } 27 28 - fn update_arg( &mut self, _: usize, arg: ParameterType ) -> bool { 29 - if arg.as_bool().unwrap(){ 30 self.runtime_active = true; 31 true 32 - } else{ 33 self.runtime_active = false; 34 false 35 } 36 } 37 38 - fn is_entrypoint( &self ) -> bool { false } 39 - }
··· 1 + use crate::{ 2 + runtime::nodes::RuntimeNode, 3 + structs::{nodes::Node, parameter_types::ParameterType}, 4 + }; 5 6 + pub struct ConditionalIfTrue { 7 + outputs: Vec<Vec<(String, isize, isize)>>, 8 + runtime_active: bool, 9 } 10 11 + impl ConditionalIfTrue { 12 + pub fn new(node: Node) -> Box<Self> { 13 Box::new(Self { 14 + outputs: node 15 + .outputs 16 + .iter() 17 + .map(|x| { 18 + x.connections 19 + .iter() 20 + .map(|x| (x.node.clone(), x.index, x.value_type)) 21 + .collect() 22 + }) 23 + .collect(), 24 + runtime_active: false, 25 }) 26 } 27 } 28 29 + impl RuntimeNode for ConditionalIfTrue { 30 + fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 31 + self.outputs.clone() 32 + } 33 + fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 34 + Some(vec![]) 35 + } 36 37 + fn execute(&mut self) -> Option<Vec<ParameterType>> { 38 + Some(vec![ 39 + ParameterType::Flow(self.runtime_active), 40 + ParameterType::Flow(!self.runtime_active), 41 + ]) 42 } 43 44 + fn update_arg(&mut self, _: usize, arg: ParameterType) -> bool { 45 + if arg.as_bool().unwrap() { 46 self.runtime_active = true; 47 true 48 + } else { 49 self.runtime_active = false; 50 false 51 } 52 } 53 54 + fn is_entrypoint(&self) -> bool { 55 + false 56 + } 57 + }
+2 -2
src-tauri/src/runtime/nodes/conditional/mod.rs
··· 1 - pub mod iftrue; 2 pub mod iffalse; 3 - pub mod ifequal;
··· 1 + pub mod ifequal; 2 pub mod iffalse; 3 + pub mod iftrue;
+23 -14
src-tauri/src/runtime/nodes/debug.rs
··· 1 - use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 2 3 - pub struct Debug{ 4 - to_log: Option<ParameterType> 5 } 6 7 - impl Debug{ 8 - pub fn new( _: Node ) -> Box<Self>{ 9 Box::new(Self { to_log: None }) 10 } 11 } 12 13 - impl RuntimeNode for Debug{ 14 - fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { vec![] } 15 - fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { Some(vec![]) } 16 17 - fn execute( &mut self ) -> Option<Vec<ParameterType>> { 18 dbg!(&self.to_log); 19 self.to_log = None; 20 21 None 22 } 23 24 - fn update_arg( &mut self, index: usize, value: ParameterType ) -> bool { 25 - if index == 1{ 26 self.to_log = Some(value); 27 true 28 - } else{ 29 false 30 } 31 } 32 33 - fn is_entrypoint( &self ) -> bool { false } 34 - }
··· 1 + use crate::{ 2 + runtime::nodes::RuntimeNode, 3 + structs::{nodes::Node, parameter_types::ParameterType}, 4 + }; 5 6 + pub struct Debug { 7 + to_log: Option<ParameterType>, 8 } 9 10 + impl Debug { 11 + pub fn new(_: Node) -> Box<Self> { 12 Box::new(Self { to_log: None }) 13 } 14 } 15 16 + impl RuntimeNode for Debug { 17 + fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 18 + vec![] 19 + } 20 + fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 21 + Some(vec![]) 22 + } 23 24 + fn execute(&mut self) -> Option<Vec<ParameterType>> { 25 dbg!(&self.to_log); 26 self.to_log = None; 27 28 None 29 } 30 31 + fn update_arg(&mut self, index: usize, value: ParameterType) -> bool { 32 + if index == 1 { 33 self.to_log = Some(value); 34 true 35 + } else { 36 false 37 } 38 } 39 40 + fn is_entrypoint(&self) -> bool { 41 + false 42 + } 43 + }
+1 -1
src-tauri/src/runtime/nodes/oscactions/mod.rs
··· 1 - pub mod sendchatbox;
··· 1 + pub mod sendchatbox;
+33 -19
src-tauri/src/runtime/nodes/oscactions/sendchatbox.rs
··· 1 use std::vec; 2 3 - use crate::{ osc, runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 4 5 - pub struct OSCActionsSendChatbox{ 6 - to_log: String 7 } 8 9 - impl OSCActionsSendChatbox{ 10 - pub fn new( _: Node ) -> Box<Self>{ 11 Box::new(Self { to_log: "".into() }) 12 } 13 } 14 15 - impl RuntimeNode for OSCActionsSendChatbox{ 16 - fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { vec![] } 17 - fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { Some(vec![]) } 18 19 - fn execute( &mut self ) -> Option<Vec<ParameterType>> { 20 - osc::send_message("/chatbox/input", vec![ 21 - ParameterType::String(self.to_log.clone()), 22 - ParameterType::Boolean(true), 23 - ParameterType::Boolean(false) 24 - ], "127.0.0.1:9000"); 25 26 None 27 } 28 29 - fn update_arg( &mut self, index: usize, value: ParameterType ) -> bool { 30 - if index == 1{ 31 self.to_log = value.as_string().unwrap(); 32 true 33 - } else{ 34 false 35 } 36 } 37 38 - fn is_entrypoint( &self ) -> bool { false } 39 - }
··· 1 use std::vec; 2 3 + use crate::{ 4 + osc, 5 + runtime::nodes::RuntimeNode, 6 + structs::{nodes::Node, parameter_types::ParameterType}, 7 + }; 8 9 + pub struct OSCActionsSendChatbox { 10 + to_log: String, 11 } 12 13 + impl OSCActionsSendChatbox { 14 + pub fn new(_: Node) -> Box<Self> { 15 Box::new(Self { to_log: "".into() }) 16 } 17 } 18 19 + impl RuntimeNode for OSCActionsSendChatbox { 20 + fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 21 + vec![] 22 + } 23 + fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 24 + Some(vec![]) 25 + } 26 27 + fn execute(&mut self) -> Option<Vec<ParameterType>> { 28 + osc::send_message( 29 + "/chatbox/input", 30 + vec![ 31 + ParameterType::String(self.to_log.clone()), 32 + ParameterType::Boolean(true), 33 + ParameterType::Boolean(false), 34 + ], 35 + "127.0.0.1:9000", 36 + ); 37 38 None 39 } 40 41 + fn update_arg(&mut self, index: usize, value: ParameterType) -> bool { 42 + if index == 1 { 43 self.to_log = value.as_string().unwrap(); 44 true 45 + } else { 46 false 47 } 48 } 49 50 + fn is_entrypoint(&self) -> bool { 51 + false 52 + } 53 + }
+43 -26
src-tauri/src/runtime/nodes/osctrigger.rs
··· 1 - use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 2 3 - pub struct OSCTrigger{ 4 - outputs: Vec<Vec<( String, isize, isize )>>, 5 address: Option<String>, 6 - runtime_active: bool 7 } 8 9 - impl OSCTrigger{ 10 - pub fn new( node: Node ) -> Box<Self>{ 11 let value = &node.statics[0].value; 12 13 Box::new(Self { 14 - address: if value.is_null(){ None } else { Some(value.as_str().unwrap().to_owned()) }, 15 - outputs: node.outputs.iter() 16 - .map(| x | { 17 - x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect() 18 - }).collect(), 19 - runtime_active: false 20 }) 21 } 22 } 23 24 - impl RuntimeNode for OSCTrigger{ 25 - fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { 26 self.outputs.clone() 27 } 28 29 - fn execute_dry( &mut self, msg: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { 30 - if self.address.is_none(){ 31 self.runtime_active = false; 32 - return None 33 } 34 35 - if let ParameterType::String(address) = &msg[0]{ 36 - if *address == *self.address.as_ref().unwrap(){ 37 self.runtime_active = true; 38 Some(msg.clone()) 39 // The first value is technically the address value, 40 // but this value gets ignored as the first output of 41 // the osctrigger node is a flow output which gets ignored 42 // on dry runs. 43 - } else{ 44 self.runtime_active = false; 45 None 46 } 47 - } else{ 48 self.runtime_active = false; 49 None 50 } 51 } 52 53 - fn execute( &mut self ) -> Option<Vec<ParameterType>> { 54 let execute = self.runtime_active; 55 self.runtime_active = false; 56 57 - Some(vec![ ParameterType::Flow(execute) ]) 58 } 59 60 - fn update_arg( &mut self, _: usize, _: ParameterType ) -> bool { false } 61 - fn is_entrypoint( &self ) -> bool { true } 62 - }
··· 1 + use crate::{ 2 + runtime::nodes::RuntimeNode, 3 + structs::{nodes::Node, parameter_types::ParameterType}, 4 + }; 5 6 + pub struct OSCTrigger { 7 + outputs: Vec<Vec<(String, isize, isize)>>, 8 address: Option<String>, 9 + runtime_active: bool, 10 } 11 12 + impl OSCTrigger { 13 + pub fn new(node: Node) -> Box<Self> { 14 let value = &node.statics[0].value; 15 16 Box::new(Self { 17 + address: if value.is_null() { 18 + None 19 + } else { 20 + Some(value.as_str().unwrap().to_owned()) 21 + }, 22 + outputs: node 23 + .outputs 24 + .iter() 25 + .map(|x| { 26 + x.connections 27 + .iter() 28 + .map(|x| (x.node.clone(), x.index, x.value_type)) 29 + .collect() 30 + }) 31 + .collect(), 32 + runtime_active: false, 33 }) 34 } 35 } 36 37 + impl RuntimeNode for OSCTrigger { 38 + fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 39 self.outputs.clone() 40 } 41 42 + fn execute_dry(&mut self, msg: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 43 + if self.address.is_none() { 44 self.runtime_active = false; 45 + return None; 46 } 47 48 + if let ParameterType::String(address) = &msg[0] { 49 + if *address == *self.address.as_ref().unwrap() { 50 self.runtime_active = true; 51 Some(msg.clone()) 52 // The first value is technically the address value, 53 // but this value gets ignored as the first output of 54 // the osctrigger node is a flow output which gets ignored 55 // on dry runs. 56 + } else { 57 self.runtime_active = false; 58 None 59 } 60 + } else { 61 self.runtime_active = false; 62 None 63 } 64 } 65 66 + fn execute(&mut self) -> Option<Vec<ParameterType>> { 67 let execute = self.runtime_active; 68 self.runtime_active = false; 69 70 + Some(vec![ParameterType::Flow(execute)]) 71 } 72 73 + fn update_arg(&mut self, _: usize, _: ParameterType) -> bool { 74 + false 75 + } 76 + fn is_entrypoint(&self) -> bool { 77 + true 78 + } 79 + }
+40 -21
src-tauri/src/runtime/nodes/statics/float.rs
··· 1 - use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 2 3 - pub struct StaticFloat{ 4 - outputs: Vec<Vec<( String, isize, isize )>>, 5 - value: Option<f32> 6 } 7 8 - impl StaticFloat{ 9 - pub fn new( node: Node ) -> Box<Self>{ 10 let value = &node.statics[0].value; 11 12 Box::new(Self { 13 - value: if value.is_null(){ None } else { Some(value.as_f64().unwrap() as f32) }, 14 - outputs: node.outputs.iter() 15 - .map(| x | { 16 - x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect() 17 - }).collect(), 18 }) 19 } 20 } 21 22 - impl RuntimeNode for StaticFloat{ 23 - fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { 24 self.outputs.clone() 25 } 26 27 - fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { 28 - if self.value.is_some(){ 29 - Some(vec![ ParameterType::Float(self.value.clone().unwrap()) ]) 30 - } else{ 31 None 32 } 33 } 34 35 - fn execute( &mut self ) -> Option<Vec<ParameterType>> { None } 36 37 - fn update_arg( &mut self, _: usize, _: ParameterType ) -> bool { false } 38 - fn is_entrypoint( &self ) -> bool { true } 39 - }
··· 1 + use crate::{ 2 + runtime::nodes::RuntimeNode, 3 + structs::{nodes::Node, parameter_types::ParameterType}, 4 + }; 5 6 + pub struct StaticFloat { 7 + outputs: Vec<Vec<(String, isize, isize)>>, 8 + value: Option<f32>, 9 } 10 11 + impl StaticFloat { 12 + pub fn new(node: Node) -> Box<Self> { 13 let value = &node.statics[0].value; 14 15 Box::new(Self { 16 + value: if value.is_null() { 17 + None 18 + } else { 19 + Some(value.as_f64().unwrap() as f32) 20 + }, 21 + outputs: node 22 + .outputs 23 + .iter() 24 + .map(|x| { 25 + x.connections 26 + .iter() 27 + .map(|x| (x.node.clone(), x.index, x.value_type)) 28 + .collect() 29 + }) 30 + .collect(), 31 }) 32 } 33 } 34 35 + impl RuntimeNode for StaticFloat { 36 + fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 37 self.outputs.clone() 38 } 39 40 + fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 41 + if self.value.is_some() { 42 + Some(vec![ParameterType::Float(self.value.clone().unwrap())]) 43 + } else { 44 None 45 } 46 } 47 48 + fn execute(&mut self) -> Option<Vec<ParameterType>> { 49 + None 50 + } 51 52 + fn update_arg(&mut self, _: usize, _: ParameterType) -> bool { 53 + false 54 + } 55 + fn is_entrypoint(&self) -> bool { 56 + true 57 + } 58 + }
+40 -21
src-tauri/src/runtime/nodes/statics/int.rs
··· 1 - use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 2 3 - pub struct StaticInt{ 4 - outputs: Vec<Vec<( String, isize, isize )>>, 5 - value: Option<i32> 6 } 7 8 - impl StaticInt{ 9 - pub fn new( node: Node ) -> Box<Self>{ 10 let value = &node.statics[0].value; 11 12 Box::new(Self { 13 - value: if value.is_null(){ None } else { Some(value.as_i64().unwrap() as i32) }, 14 - outputs: node.outputs.iter() 15 - .map(| x | { 16 - x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect() 17 - }).collect(), 18 }) 19 } 20 } 21 22 - impl RuntimeNode for StaticInt{ 23 - fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { 24 self.outputs.clone() 25 } 26 27 - fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { 28 - if self.value.is_some(){ 29 - Some(vec![ ParameterType::Int(self.value.clone().unwrap()) ]) 30 - } else{ 31 None 32 } 33 } 34 35 - fn execute( &mut self ) -> Option<Vec<ParameterType>> { None } 36 37 - fn update_arg( &mut self, _: usize, _: ParameterType ) -> bool { false } 38 - fn is_entrypoint( &self ) -> bool { true } 39 - }
··· 1 + use crate::{ 2 + runtime::nodes::RuntimeNode, 3 + structs::{nodes::Node, parameter_types::ParameterType}, 4 + }; 5 6 + pub struct StaticInt { 7 + outputs: Vec<Vec<(String, isize, isize)>>, 8 + value: Option<i32>, 9 } 10 11 + impl StaticInt { 12 + pub fn new(node: Node) -> Box<Self> { 13 let value = &node.statics[0].value; 14 15 Box::new(Self { 16 + value: if value.is_null() { 17 + None 18 + } else { 19 + Some(value.as_i64().unwrap() as i32) 20 + }, 21 + outputs: node 22 + .outputs 23 + .iter() 24 + .map(|x| { 25 + x.connections 26 + .iter() 27 + .map(|x| (x.node.clone(), x.index, x.value_type)) 28 + .collect() 29 + }) 30 + .collect(), 31 }) 32 } 33 } 34 35 + impl RuntimeNode for StaticInt { 36 + fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 37 self.outputs.clone() 38 } 39 40 + fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 41 + if self.value.is_some() { 42 + Some(vec![ParameterType::Int(self.value.clone().unwrap())]) 43 + } else { 44 None 45 } 46 } 47 48 + fn execute(&mut self) -> Option<Vec<ParameterType>> { 49 + None 50 + } 51 52 + fn update_arg(&mut self, _: usize, _: ParameterType) -> bool { 53 + false 54 + } 55 + fn is_entrypoint(&self) -> bool { 56 + true 57 + } 58 + }
+2 -2
src-tauri/src/runtime/nodes/statics/mod.rs
··· 1 - pub mod string; 2 pub mod int; 3 - pub mod float;
··· 1 + pub mod float; 2 pub mod int; 3 + pub mod string;
+40 -21
src-tauri/src/runtime/nodes/statics/string.rs
··· 1 - use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 2 3 - pub struct StaticString{ 4 - outputs: Vec<Vec<( String, isize, isize )>>, 5 - value: Option<String> 6 } 7 8 - impl StaticString{ 9 - pub fn new( node: Node ) -> Box<Self>{ 10 let value = &node.statics[0].value; 11 12 Box::new(Self { 13 - value: if value.is_null(){ None } else { Some(value.as_str().unwrap().to_owned()) }, 14 - outputs: node.outputs.iter() 15 - .map(| x | { 16 - x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect() 17 - }).collect(), 18 }) 19 } 20 } 21 22 - impl RuntimeNode for StaticString{ 23 - fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { 24 self.outputs.clone() 25 } 26 27 - fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { 28 - if self.value.is_some(){ 29 - Some(vec![ ParameterType::String(self.value.clone().unwrap()) ]) 30 - } else{ 31 None 32 } 33 } 34 35 - fn execute( &mut self ) -> Option<Vec<ParameterType>> { None } 36 37 - fn update_arg( &mut self, _: usize, _: ParameterType ) -> bool { false } 38 - fn is_entrypoint( &self ) -> bool { true } 39 - }
··· 1 + use crate::{ 2 + runtime::nodes::RuntimeNode, 3 + structs::{nodes::Node, parameter_types::ParameterType}, 4 + }; 5 6 + pub struct StaticString { 7 + outputs: Vec<Vec<(String, isize, isize)>>, 8 + value: Option<String>, 9 } 10 11 + impl StaticString { 12 + pub fn new(node: Node) -> Box<Self> { 13 let value = &node.statics[0].value; 14 15 Box::new(Self { 16 + value: if value.is_null() { 17 + None 18 + } else { 19 + Some(value.as_str().unwrap().to_owned()) 20 + }, 21 + outputs: node 22 + .outputs 23 + .iter() 24 + .map(|x| { 25 + x.connections 26 + .iter() 27 + .map(|x| (x.node.clone(), x.index, x.value_type)) 28 + .collect() 29 + }) 30 + .collect(), 31 }) 32 } 33 } 34 35 + impl RuntimeNode for StaticString { 36 + fn outputs(&self) -> Vec<Vec<(String, isize, isize)>> { 37 self.outputs.clone() 38 } 39 40 + fn execute_dry(&mut self, _: &Vec<ParameterType>) -> Option<Vec<ParameterType>> { 41 + if self.value.is_some() { 42 + Some(vec![ParameterType::String(self.value.clone().unwrap())]) 43 + } else { 44 None 45 } 46 } 47 48 + fn execute(&mut self) -> Option<Vec<ParameterType>> { 49 + None 50 + } 51 52 + fn update_arg(&mut self, _: usize, _: ParameterType) -> bool { 53 + false 54 + } 55 + fn is_entrypoint(&self) -> bool { 56 + true 57 + } 58 + }
+42 -33
src-tauri/src/setup.rs
··· 1 - use std::{ collections::HashMap, fs::File, io::Read, sync::Mutex }; 2 - use crossbeam_channel::{ Receiver, bounded }; 3 4 use flate2::read::GzDecoder; 5 - use serde_json::{ Map, Value }; 6 - use tauri::{ App, Emitter, Listener, Manager, WindowEvent }; 7 8 - use crate::{ osc::{ self, OSCMessage }, runtime::{ commands::RuntimeCommand, nodes::RuntimeNodeTree, runtime, runtime_dry }, structs::parameter_types::ParameterType, utils::setup_traymenu::setup_traymenu }; 9 10 pub fn setup( 11 app: &mut App, 12 addresses: &'static Mutex<Vec<OSCMessage>>, 13 - runtime_command_receiver: Receiver<RuntimeCommand> 14 ) { 15 let window = app.get_webview_window("main").unwrap(); 16 window.hide().unwrap(); 17 18 let win_handle = window.clone(); 19 - window.on_window_event(move | event | { 20 - match event{ 21 - WindowEvent::CloseRequested { api, .. } => { 22 - api.prevent_close(); 23 24 - win_handle.hide().unwrap(); 25 - win_handle.emit("hide-window", ()).unwrap(); 26 - } 27 - _ => {} 28 } 29 }); 30 31 setup_traymenu(app.handle()); ··· 49 handle.emit("load_new_tab", Value::Object(map)).unwrap(); 50 }); 51 52 - let ( sender, receiver ) = bounded(1024); 53 54 tokio::spawn(async move { 55 osc::start_server(sender, "127.0.0.1:9001"); 56 }); 57 58 - let ( runtime_sender, runtime_receiver ) = bounded(1024); 59 60 let runtime_sender_1 = runtime_sender.clone(); 61 tokio::spawn(async move { ··· 73 74 let msg = message.clone(); 75 let mut addrs = addresses.lock().unwrap(); 76 - if !addrs.contains(&msg) { addrs.push(msg); } 77 78 - runtime_sender.send(RuntimeCommand::OSCMessage(message)).unwrap(); 79 } 80 }); 81 ··· 85 loop { 86 let cmd = runtime_receiver.recv().unwrap(); 87 88 - match cmd{ 89 - RuntimeCommand::OSCMessage( msg ) => { 90 - for ( _, mut tab ) in &mut tabs{ 91 - let keys: Vec<String> = tab.nodes.keys().map(| x | { x.clone() }).collect(); 92 93 - for id in keys.clone(){ 94 let entry = tab.nodes[&id].is_entrypoint(); 95 96 - if entry{ 97 let args = vec![ 98 - vec![ ParameterType::String(msg.address.clone()) ], msg.values.clone() 99 - ].concat(); 100 101 runtime_dry(id.clone(), &args, &mut tab).unwrap(); 102 } 103 } 104 105 - for id in keys{ 106 let entry = tab.nodes[&id].is_entrypoint(); 107 108 - if entry{ 109 let _ = runtime(id.clone(), &mut tab); 110 } 111 } 112 } 113 - }, 114 115 - RuntimeCommand::AddTab( graph, id ) => { 116 tabs.insert(id, RuntimeNodeTree::from(graph)); 117 - }, 118 - RuntimeCommand::RemoveTab( id ) => { 119 tabs.remove(&id); 120 } 121 } 122 } 123 }); 124 - }
··· 1 + use crossbeam_channel::{bounded, Receiver}; 2 + use std::{collections::HashMap, fs::File, io::Read, sync::Mutex}; 3 4 use flate2::read::GzDecoder; 5 + use serde_json::{Map, Value}; 6 + use tauri::{App, Emitter, Listener, Manager, WindowEvent}; 7 8 + use crate::{ 9 + osc::{self, OSCMessage}, 10 + runtime::{commands::RuntimeCommand, nodes::RuntimeNodeTree, runtime, runtime_dry}, 11 + structs::parameter_types::ParameterType, 12 + utils::setup_traymenu::setup_traymenu, 13 + }; 14 15 pub fn setup( 16 app: &mut App, 17 addresses: &'static Mutex<Vec<OSCMessage>>, 18 + runtime_command_receiver: Receiver<RuntimeCommand>, 19 ) { 20 let window = app.get_webview_window("main").unwrap(); 21 window.hide().unwrap(); 22 23 let win_handle = window.clone(); 24 + window.on_window_event(move |event| match event { 25 + WindowEvent::CloseRequested { api, .. } => { 26 + api.prevent_close(); 27 28 + win_handle.hide().unwrap(); 29 + win_handle.emit("hide-window", ()).unwrap(); 30 } 31 + _ => {} 32 }); 33 34 setup_traymenu(app.handle()); ··· 52 handle.emit("load_new_tab", Value::Object(map)).unwrap(); 53 }); 54 55 + let (sender, receiver) = bounded(1024); 56 57 tokio::spawn(async move { 58 osc::start_server(sender, "127.0.0.1:9001"); 59 }); 60 61 + let (runtime_sender, runtime_receiver) = bounded(1024); 62 63 let runtime_sender_1 = runtime_sender.clone(); 64 tokio::spawn(async move { ··· 76 77 let msg = message.clone(); 78 let mut addrs = addresses.lock().unwrap(); 79 + if !addrs.contains(&msg) { 80 + addrs.push(msg); 81 + } 82 83 + runtime_sender 84 + .send(RuntimeCommand::OSCMessage(message)) 85 + .unwrap(); 86 } 87 }); 88 ··· 92 loop { 93 let cmd = runtime_receiver.recv().unwrap(); 94 95 + match cmd { 96 + RuntimeCommand::OSCMessage(msg) => { 97 + for (_, mut tab) in &mut tabs { 98 + let keys: Vec<String> = tab.nodes.keys().map(|x| x.clone()).collect(); 99 100 + for id in keys.clone() { 101 let entry = tab.nodes[&id].is_entrypoint(); 102 103 + if entry { 104 let args = vec![ 105 + vec![ParameterType::String(msg.address.clone())], 106 + msg.values.clone(), 107 + ] 108 + .concat(); 109 110 runtime_dry(id.clone(), &args, &mut tab).unwrap(); 111 } 112 } 113 114 + for id in keys { 115 let entry = tab.nodes[&id].is_entrypoint(); 116 117 + if entry { 118 let _ = runtime(id.clone(), &mut tab); 119 } 120 } 121 } 122 + } 123 124 + RuntimeCommand::AddTab(graph, id) => { 125 tabs.insert(id, RuntimeNodeTree::from(graph)); 126 + } 127 + RuntimeCommand::RemoveTab(id) => { 128 tabs.remove(&id); 129 } 130 } 131 } 132 }); 133 + }
+1 -1
src-tauri/src/structs/mod.rs
··· 1 pub mod parameter_types; 2 - pub mod nodes;
··· 1 + pub mod nodes; 2 pub mod parameter_types;
+11 -11
src-tauri/src/structs/nodes.rs
··· 1 - use serde::{ Deserialize, Serialize }; 2 use serde_json::Value; 3 4 #[derive(Serialize, Deserialize, Debug, Clone)] 5 - pub struct Node{ 6 pub id: String, 7 pub name: String, 8 pub outputs: Vec<NodeOutput>, 9 - pub pos: [ f32; 2 ], 10 pub statics: Vec<NodeStatic>, 11 12 #[serde(rename = "typeId")] 13 - pub type_id: String 14 } 15 16 #[derive(Serialize, Deserialize, Debug, Clone)] 17 - pub struct NodeStatic{ 18 pub name: String, 19 20 #[serde(rename = "type")] 21 pub value_type: isize, 22 - pub value: Value 23 } 24 25 #[derive(Serialize, Deserialize, Debug, Clone)] 26 - pub struct NodeOutput{ 27 pub name: String, 28 29 #[serde(rename = "type")] 30 pub value_type: isize, 31 - pub connections: Vec<NodeOutputConnections> 32 } 33 34 #[derive(Serialize, Deserialize, Debug, Clone)] 35 - pub struct NodeOutputConnections{ 36 pub name: String, 37 pub node: String, 38 pub index: isize, 39 40 #[serde(rename = "type")] 41 - pub value_type: isize 42 - }
··· 1 + use serde::{Deserialize, Serialize}; 2 use serde_json::Value; 3 4 #[derive(Serialize, Deserialize, Debug, Clone)] 5 + pub struct Node { 6 pub id: String, 7 pub name: String, 8 pub outputs: Vec<NodeOutput>, 9 + pub pos: [f32; 2], 10 pub statics: Vec<NodeStatic>, 11 12 #[serde(rename = "typeId")] 13 + pub type_id: String, 14 } 15 16 #[derive(Serialize, Deserialize, Debug, Clone)] 17 + pub struct NodeStatic { 18 pub name: String, 19 20 #[serde(rename = "type")] 21 pub value_type: isize, 22 + pub value: Value, 23 } 24 25 #[derive(Serialize, Deserialize, Debug, Clone)] 26 + pub struct NodeOutput { 27 pub name: String, 28 29 #[serde(rename = "type")] 30 pub value_type: isize, 31 + pub connections: Vec<NodeOutputConnections>, 32 } 33 34 #[derive(Serialize, Deserialize, Debug, Clone)] 35 + pub struct NodeOutputConnections { 36 pub name: String, 37 pub node: String, 38 pub index: isize, 39 40 #[serde(rename = "type")] 41 + pub value_type: isize, 42 + }
+41 -29
src-tauri/src/structs/parameter_types.rs
··· 1 - use anyhow::{ Result, bail }; 2 use serde::Serialize; 3 4 #[derive(Serialize, Clone, Debug, PartialEq)] ··· 13 String(String), 14 Flow(bool), 15 16 - None 17 } 18 19 - impl ParameterType{ 20 - pub fn as_bool( &self ) -> Result<bool>{ 21 - match self{ 22 - ParameterType::Boolean( val ) => Ok(val.clone()), 23 - ParameterType::Int( val ) => if *val == 0{ Ok(false) } else { Ok(true) }, 24 - _ => bail!("Cannot cast to bool.") 25 } 26 } 27 28 - pub fn as_int( &self ) -> Result<i32>{ 29 - match self{ 30 - ParameterType::Boolean( val ) => if *val{ Ok(1) } else { Ok(0) }, 31 - ParameterType::Int( val ) => Ok(val.clone()), 32 - ParameterType::Float( val ) => Ok(val.round().clone() as i32), 33 - ParameterType::String( val ) => Ok(val.clone().parse()?), 34 - _ => bail!("Cannot cast to int.") 35 } 36 } 37 38 - pub fn as_float( &self ) -> Result<f32>{ 39 - match self{ 40 - ParameterType::Int( val ) => Ok(val.clone() as f32), 41 - ParameterType::Float( val ) => Ok(val.clone()), 42 - ParameterType::String( val ) => Ok(val.clone().parse()?), 43 - _ => bail!("Cannot cast to float.") 44 } 45 } 46 47 - pub fn as_string( &self ) -> Result<String>{ 48 - match self{ 49 - ParameterType::Boolean( val ) => Ok(val.clone().to_string()), 50 - ParameterType::Int( val ) => Ok(val.clone().to_string()), 51 - ParameterType::Float( val ) => Ok(val.clone().to_string()), 52 - ParameterType::String( val ) => Ok(val.clone()), 53 - _ => bail!("Cannot cast to string.") 54 } 55 } 56 - }
··· 1 + use anyhow::{bail, Result}; 2 use serde::Serialize; 3 4 #[derive(Serialize, Clone, Debug, PartialEq)] ··· 13 String(String), 14 Flow(bool), 15 16 + None, 17 } 18 19 + impl ParameterType { 20 + pub fn as_bool(&self) -> Result<bool> { 21 + match self { 22 + ParameterType::Boolean(val) => Ok(val.clone()), 23 + ParameterType::Int(val) => { 24 + if *val == 0 { 25 + Ok(false) 26 + } else { 27 + Ok(true) 28 + } 29 + } 30 + _ => bail!("Cannot cast to bool."), 31 } 32 } 33 34 + pub fn as_int(&self) -> Result<i32> { 35 + match self { 36 + ParameterType::Boolean(val) => { 37 + if *val { 38 + Ok(1) 39 + } else { 40 + Ok(0) 41 + } 42 + } 43 + ParameterType::Int(val) => Ok(val.clone()), 44 + ParameterType::Float(val) => Ok(val.round().clone() as i32), 45 + ParameterType::String(val) => Ok(val.clone().parse()?), 46 + _ => bail!("Cannot cast to int."), 47 } 48 } 49 50 + pub fn as_float(&self) -> Result<f32> { 51 + match self { 52 + ParameterType::Int(val) => Ok(val.clone() as f32), 53 + ParameterType::Float(val) => Ok(val.clone()), 54 + ParameterType::String(val) => Ok(val.clone().parse()?), 55 + _ => bail!("Cannot cast to float."), 56 } 57 } 58 59 + pub fn as_string(&self) -> Result<String> { 60 + match self { 61 + ParameterType::Boolean(val) => Ok(val.clone().to_string()), 62 + ParameterType::Int(val) => Ok(val.clone().to_string()), 63 + ParameterType::Float(val) => Ok(val.clone().to_string()), 64 + ParameterType::String(val) => Ok(val.clone()), 65 + _ => bail!("Cannot cast to string."), 66 } 67 } 68 + }
+12 -6
src-tauri/src/utils/config.rs
··· 1 - use std::{ collections::HashMap, fs::File, io::{ Read, Write }, path::PathBuf, sync::Mutex }; 2 3 - use flate2::{ read::GzDecoder, write::GzEncoder, Compression }; 4 - use serde::{ Deserialize, Serialize }; 5 6 use crate::structs::nodes::Node; 7 8 #[derive(Clone, Serialize, Deserialize, Debug)] 9 - pub struct ConfigValues{ 10 #[serde(default)] 11 - pub loaded_tabs: HashMap<String, ( Vec<Node>, String, Option<String> )>, 12 13 #[serde(default)] 14 - pub hide_editor_on_start: bool 15 } 16 17 pub struct Config {
··· 1 + use std::{ 2 + collections::HashMap, 3 + fs::File, 4 + io::{Read, Write}, 5 + path::PathBuf, 6 + sync::Mutex, 7 + }; 8 9 + use flate2::{read::GzDecoder, write::GzEncoder, Compression}; 10 + use serde::{Deserialize, Serialize}; 11 12 use crate::structs::nodes::Node; 13 14 #[derive(Clone, Serialize, Deserialize, Debug)] 15 + pub struct ConfigValues { 16 #[serde(default)] 17 + pub loaded_tabs: HashMap<String, (Vec<Node>, String, Option<String>)>, 18 19 #[serde(default)] 20 + pub hide_editor_on_start: bool, 21 } 22 23 pub struct Config {
+1 -1
src-tauri/src/utils/mod.rs
··· 1 pub mod config; 2 - pub mod setup_traymenu;
··· 1 pub mod config; 2 + pub mod setup_traymenu;
+6 -2
src-tauri/src/utils/setup_traymenu.rs
··· 1 - use tauri::{ AppHandle, Emitter, Manager, menu::{ MenuBuilder, MenuItemBuilder }, tray::TrayIconBuilder }; 2 3 - pub fn setup_traymenu( handle: &AppHandle ) { 4 // Setup the tray icon and menu buttons 5 let quit = MenuItemBuilder::new("Quit") 6 .id("quit")
··· 1 + use tauri::{ 2 + menu::{MenuBuilder, MenuItemBuilder}, 3 + tray::TrayIconBuilder, 4 + AppHandle, Emitter, Manager, 5 + }; 6 7 + pub fn setup_traymenu(handle: &AppHandle) { 8 // Setup the tray icon and menu buttons 9 let quit = MenuItemBuilder::new("Quit") 10 .id("quit")
+4 -1
src/App.tsx
··· 17 18 let App = () => { 19 let [ selectedNodes, setSelectedNodes ] = createSignal<Node[]>([], { equals: false }); 20 21 let canvas!: HTMLCanvasElement; 22 let ctx: CanvasRenderingContext2D; ··· 233 } 234 235 canvas.onmousemove = ( e ) => { 236 if(e.shiftKey && isMouseDown){ 237 let nodes = NodeManager.Instance.GetNodes(); 238 let hoveredNode: Node | null = null; ··· 399 isMouseDown = false; 400 } 401 402 - keybinds.load(selectedNodes, setSelectedNodes); 403 requestAnimationFrame(update); 404 405 let unlisten_0 = await listen('hide-window', () => {
··· 17 18 let App = () => { 19 let [ selectedNodes, setSelectedNodes ] = createSignal<Node[]>([], { equals: false }); 20 + let [ mousePos, setMousePos ] = createSignal<[ number, number ]>([ 0, 0 ]); 21 22 let canvas!: HTMLCanvasElement; 23 let ctx: CanvasRenderingContext2D; ··· 234 } 235 236 canvas.onmousemove = ( e ) => { 237 + setMousePos([ e.clientX, e.clientY ]); 238 + 239 if(e.shiftKey && isMouseDown){ 240 let nodes = NodeManager.Instance.GetNodes(); 241 let hoveredNode: Node | null = null; ··· 402 isMouseDown = false; 403 } 404 405 + keybinds.load(mousePos, selectedNodes, setSelectedNodes); 406 requestAnimationFrame(update); 407 408 let unlisten_0 = await listen('hide-window', () => {
+23 -5
src/keybinds.ts
··· 1 import { Accessor, Setter } from "solid-js"; 2 import { NodeManager } from "./Mangers/NodeManager"; 3 import { Node } from "./structs/node"; 4 5 let isKeyDown: any = {}; 6 7 - export let load = ( selectedNode: Accessor<Node[]>, setSelectedNode: Setter<Node[]> ) => { 8 - // TODO: Copy / paste 9 // TODO: Add undo / redo -ing 10 11 - window.onkeydown = ( e ) => { 12 isKeyDown[e.key] = true; 13 - 14 - console.log(e.key); 15 16 switch(e.key){ 17 case 'Delete': ··· 50 51 // Save 52 NodeManager.Instance.SaveTab(currentTab, true); 53 } 54 break; 55 }
··· 1 import { Accessor, Setter } from "solid-js"; 2 import { NodeManager } from "./Mangers/NodeManager"; 3 import { Node } from "./structs/node"; 4 + import { readText, writeText } from "@tauri-apps/plugin-clipboard-manager"; 5 + import { decodeNodeList, encodeNodeList } from "./utils/clipboard"; 6 7 let isKeyDown: any = {}; 8 9 + export let load = ( mousePos: Accessor<[ number, number ]>, selectedNode: Accessor<Node[]>, setSelectedNode: Setter<Node[]> ) => { 10 // TODO: Add undo / redo -ing 11 12 + window.onkeydown = async ( e ) => { 13 isKeyDown[e.key] = true; 14 15 switch(e.key){ 16 case 'Delete': ··· 49 50 // Save 51 NodeManager.Instance.SaveTab(currentTab, true); 52 + } 53 + break; 54 + case 'c': 55 + if(e.ctrlKey){ 56 + let nodes = selectedNode(); 57 + await writeText(encodeNodeList(nodes, mousePos())); 58 + } 59 + break; 60 + case 'v': 61 + if(e.ctrlKey){ 62 + let text = await readText(); 63 + 64 + let nodes = await decodeNodeList(text, mousePos()); 65 + if(!nodes)return; 66 + 67 + for(let node of nodes) 68 + NodeManager.Instance.AddNode(node); 69 + 70 + setSelectedNode(nodes); 71 } 72 break; 73 }
+41
src/utils/clipboard.ts
···
··· 1 + import { NodeManager } from "../Mangers/NodeManager"; 2 + import { NodesByID } from "../Nodes/Nodes"; 3 + import { Node } from "../structs/node"; 4 + 5 + export let encodeNodeList = ( selectedNodes: Node[], mousePos: [ number, number ] ): string => { 6 + let arr: any[] = []; 7 + 8 + for(let node of selectedNodes){ 9 + arr.push({ 10 + type_id: node.typeId, 11 + statics: node.statics, 12 + x: node.x - mousePos[0], 13 + y: node.y - mousePos[1] 14 + }) 15 + } 16 + 17 + return 'VRCMACRO' + btoa(JSON.stringify(arr)); 18 + } 19 + 20 + export let decodeNodeList = async ( text: string, mousePos: [ number, number ] ): Promise<Node[] | null> => { 21 + if(!text.startsWith("VRCMACRO"))return null; 22 + 23 + let data = text.slice(8); 24 + let json = JSON.parse(atob(data)); 25 + 26 + let nodes: Node[] = []; 27 + for(let node of json){ 28 + let n = new Node( 29 + [ node.x + mousePos[0] + 10, node.y + mousePos[1] + 10 ], 30 + NodesByID[node.type_id], 31 + await NodeManager.Instance.GetNewNodeId() 32 + ); 33 + 34 + n.statics = node.statics; 35 + await n.onStaticsUpdate(n); 36 + 37 + nodes.push(n); 38 + } 39 + 40 + return nodes; 41 + }