Visualize transfers

This commit is contained in:
Emilia Allison 2023-05-24 18:39:38 -04:00
parent cd1f72fd9d
commit 74fa50bc0c
Signed by: emilia
GPG Key ID: 7A3F8997BFE894E0
12 changed files with 351 additions and 154 deletions

179
Cargo.lock generated
View File

@ -29,8 +29,8 @@ version = "0.1.68"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"syn 2.0.16", "syn 2.0.16",
] ]
@ -61,6 +61,12 @@ version = "3.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@ -73,7 +79,7 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"wasm-bindgen", "wasm-bindgen",
] ]
@ -95,8 +101,8 @@ checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
dependencies = [ dependencies = [
"fnv", "fnv",
"ident_case", "ident_case",
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"strsim", "strsim",
"syn 1.0.109", "syn 1.0.109",
] ]
@ -108,7 +114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote 1.0.27",
"syn 1.0.109", "syn 1.0.109",
] ]
@ -127,6 +133,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "futures"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.28" version = "0.3.28"
@ -169,8 +181,8 @@ version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"syn 2.0.16", "syn 2.0.16",
] ]
@ -210,7 +222,7 @@ version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"js-sys", "js-sys",
"libc", "libc",
"wasi", "wasi",
@ -313,7 +325,7 @@ dependencies = [
"serde_json", "serde_json",
"thiserror", "thiserror",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures 0.4.36",
"web-sys", "web-sys",
] ]
@ -378,7 +390,7 @@ dependencies = [
"js-sys", "js-sys",
"serde", "serde",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures 0.4.36",
"web-sys", "web-sys",
] ]
@ -455,7 +467,7 @@ version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
] ]
[[package]] [[package]]
@ -501,8 +513,8 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"syn 2.0.16", "syn 2.0.16",
] ]
@ -524,7 +536,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b" checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b"
dependencies = [ dependencies = [
"futures", "futures 0.3.28",
"rustversion", "rustversion",
"thiserror", "thiserror",
] ]
@ -539,6 +551,7 @@ dependencies = [
"serde", "serde",
"uuid", "uuid",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-test",
"wasm-logger", "wasm-logger",
"web-sys", "web-sys",
"yew", "yew",
@ -557,7 +570,7 @@ version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.58",
"syn 1.0.109", "syn 1.0.109",
] ]
@ -568,8 +581,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [ dependencies = [
"proc-macro-error-attr", "proc-macro-error-attr",
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"syn 1.0.109", "syn 1.0.109",
"version_check", "version_check",
] ]
@ -580,11 +593,20 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"version_check", "version_check",
] ]
[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
dependencies = [
"unicode-xid",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.58" version = "1.0.58"
@ -600,7 +622,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488" checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488"
dependencies = [ dependencies = [
"futures", "futures 0.3.28",
"gloo", "gloo",
"num_cpus", "num_cpus",
"once_cell", "once_cell",
@ -608,7 +630,16 @@ dependencies = [
"pinned", "pinned",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
"wasm-bindgen-futures", "wasm-bindgen-futures 0.4.36",
]
[[package]]
name = "quote"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
dependencies = [
"proc-macro2 0.4.30",
] ]
[[package]] [[package]]
@ -617,7 +648,7 @@ version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.58",
] ]
[[package]] [[package]]
@ -679,6 +710,12 @@ version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.163" version = "1.0.163"
@ -705,8 +742,8 @@ version = "1.0.163"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"syn 2.0.16", "syn 2.0.16",
] ]
@ -754,8 +791,8 @@ version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"unicode-ident", "unicode-ident",
] ]
@ -765,8 +802,8 @@ version = "2.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"unicode-ident", "unicode-ident",
] ]
@ -785,8 +822,8 @@ version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"syn 2.0.16", "syn 2.0.16",
] ]
@ -818,7 +855,7 @@ version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"pin-project-lite", "pin-project-lite",
"tracing-attributes", "tracing-attributes",
"tracing-core", "tracing-core",
@ -830,8 +867,8 @@ version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"syn 2.0.16", "syn 2.0.16",
] ]
@ -850,6 +887,12 @@ version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.3.3" version = "1.3.3"
@ -869,8 +912,8 @@ version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f67b459f42af2e6e1ee213cb9da4dbd022d3320788c3fb3e1b893093f1e45da" checksum = "3f67b459f42af2e6e1ee213cb9da4dbd022d3320788c3fb3e1b893093f1e45da"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"syn 2.0.16", "syn 2.0.16",
] ]
@ -892,7 +935,7 @@ version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"wasm-bindgen-macro", "wasm-bindgen-macro",
] ]
@ -905,19 +948,32 @@ dependencies = [
"bumpalo", "bumpalo",
"log", "log",
"once_cell", "once_cell",
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"syn 2.0.16", "syn 2.0.16",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]]
name = "wasm-bindgen-futures"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83420b37346c311b9ed822af41ec2e82839bfe99867ec6c54e2da43b7538771c"
dependencies = [
"cfg-if 0.1.10",
"futures 0.1.31",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]] [[package]]
name = "wasm-bindgen-futures" name = "wasm-bindgen-futures"
version = "0.4.36" version = "0.4.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
"web-sys", "web-sys",
@ -929,7 +985,7 @@ version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258"
dependencies = [ dependencies = [
"quote", "quote 1.0.27",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
] ]
@ -939,8 +995,8 @@ version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"syn 2.0.16", "syn 2.0.16",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
@ -952,6 +1008,31 @@ version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93"
[[package]]
name = "wasm-bindgen-test"
version = "0.2.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2d9693b63a742d481c7f80587e057920e568317b2806988c59cd71618bc26c1"
dependencies = [
"console_error_panic_hook",
"futures 0.1.31",
"js-sys",
"scoped-tls",
"wasm-bindgen",
"wasm-bindgen-futures 0.3.27",
"wasm-bindgen-test-macro",
]
[[package]]
name = "wasm-bindgen-test-macro"
version = "0.2.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0789dac148a8840bbcf9efe13905463b733fa96543bfbf263790535c11af7ba5"
dependencies = [
"proc-macro2 0.4.30",
"quote 0.6.13",
]
[[package]] [[package]]
name = "wasm-logger" name = "wasm-logger"
version = "0.2.0" version = "0.2.0"
@ -1046,7 +1127,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc" checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc"
dependencies = [ dependencies = [
"console_error_panic_hook", "console_error_panic_hook",
"futures", "futures 0.3.28",
"gloo", "gloo",
"implicit-clone", "implicit-clone",
"indexmap", "indexmap",
@ -1059,7 +1140,7 @@ dependencies = [
"tokio", "tokio",
"tracing", "tracing",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures 0.4.36",
"web-sys", "web-sys",
"yew-macro", "yew-macro",
] ]
@ -1074,8 +1155,8 @@ dependencies = [
"once_cell", "once_cell",
"prettyplease", "prettyplease",
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"syn 1.0.109", "syn 1.0.109",
] ]
@ -1106,7 +1187,7 @@ checksum = "25bcd923aceaa85cb4affad8657cc36e3d6b6932740e711574182f7817492739"
dependencies = [ dependencies = [
"darling", "darling",
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2 1.0.58",
"quote", "quote 1.0.27",
"syn 1.0.109", "syn 1.0.109",
] ]

View File

@ -16,3 +16,6 @@ regex = "1"
lazy_static = "1.4" lazy_static = "1.4"
uuid = { version = "1.3", features = ["v4", "fast-rng", "macro-diagnostics", "js", "serde"] } uuid = { version = "1.3", features = ["v4", "fast-rng", "macro-diagnostics", "js", "serde"] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
[dev-dependencies]
wasm-bindgen-test = "0.2"

View File

@ -16,10 +16,25 @@ div.plate_cell_inner {
td.plate_cell:hover div.plate_cell_inner { td.plate_cell:hover div.plate_cell_inner {
background: black !important; background: black !important;
} }
td.plate_cell.in_transfer div.plate_cell_inner::after {
content: "";
width: 100%;
height: 100%;
display: block;
border-radius: 50%;
background-image: repeating-linear-gradient(
45deg,
rgba(0,0,0,0.8),
rgba(0,0,0,0.8) 2px,
transparent 2px,
transparent 4px
);
}
div.source_plate td.current_select div.plate_cell_inner { div.source_plate td.current_select div.plate_cell_inner {
background: lightblue !important; background-image: linear-gradient(lightblue, lightblue);
} }
div.dest_plate td.current_select div.plate_cell_inner { div.dest_plate td.current_select div.plate_cell_inner {
background: lightcoral !important; background: lightcoral;
} }

View File

@ -2,7 +2,7 @@
use yew::prelude::*; use yew::prelude::*;
use yewdux::prelude::*; use yewdux::prelude::*;
use super::states::{MainState, NewTransferState}; use super::states::{MainState, NewTransferState, CurrentTransfer};
use super::plates::plate_container::PlateContainer; use super::plates::plate_container::PlateContainer;
use super::tree::Tree; use super::tree::Tree;
use super::transfer_menu::TransferMenu; use super::transfer_menu::TransferMenu;
@ -14,13 +14,24 @@ use crate::data::plate_instances::PlateInstance;
pub fn MainWindow() -> Html { pub fn MainWindow() -> Html {
let (main_state, main_dispatch) = use_store::<MainState>(); let (main_state, main_dispatch) = use_store::<MainState>();
let (selection_state, selection_dispatch) = use_store::<NewTransferState>(); let (selection_state, selection_dispatch) = use_store::<NewTransferState>();
let (ct_state, ct_dispatch) = use_store::<CurrentTransfer>();
let source_plate_instance: Option<PlateInstance> = main_state.source_plates.iter() let source_plate_instance: Option<PlateInstance> = main_state.source_plates.iter()
.find(|spi| {spi.get_uuid() == selection_state.source_id}) .find(|spi| {spi.get_uuid() == selection_state.source_id})
.cloned(); .cloned();
if let Some(spi) = source_plate_instance.clone() {
ct_dispatch.reduce_mut(|state| {
state.transfer.source_plate = spi.plate;
});
}
let destination_plate_instance: Option<PlateInstance> = main_state.destination_plates.iter() let destination_plate_instance: Option<PlateInstance> = main_state.destination_plates.iter()
.find(|dpi| {dpi.get_uuid() == selection_state.destination_id}) .find(|dpi| {dpi.get_uuid() == selection_state.destination_id})
.cloned(); .cloned();
if let Some(dpi) = destination_plate_instance.clone() {
ct_dispatch.reduce_mut(|state| {
state.transfer.dest_plate = dpi.plate;
});
}
let new_plate_dialog_is_open = use_state_eq(|| false); let new_plate_dialog_is_open = use_state_eq(|| false);
let new_plate_dialog_callback = { let new_plate_dialog_callback = {

View File

@ -4,38 +4,34 @@ use yewdux::prelude::*;
use std::rc::Rc; use std::rc::Rc;
use crate::data::plate_instances::PlateInstance; use crate::data::plate_instances::PlateInstance;
use crate::data::transfer_region::{TransferRegion, Region};
use crate::components::states::{NewTransferState, CurrentTransfer};
use super::super::states::NewTransferState;
use super::super::transfer_menu::RegionDisplay; use super::super::transfer_menu::RegionDisplay;
#[derive(Properties, PartialEq)] #[derive(Properties, PartialEq)]
pub struct DestinationPlateProps { pub struct DestinationPlateProps {
pub plate: PlateInstance, pub source_plate: PlateInstance,
pub destination_plate: PlateInstance,
} }
#[function_component] #[function_component]
pub fn DestinationPlate(props: &DestinationPlateProps) -> Html { pub fn DestinationPlate(props: &DestinationPlateProps) -> Html {
let (state, dispatch) = use_store::<NewTransferState>();
let (ct_state, ct_dispatch) = use_store::<CurrentTransfer>();
let m_start_handle: UseStateHandle<Option<(u8,u8)>> = use_state_eq(|| None); let m_start_handle: UseStateHandle<Option<(u8,u8)>> = use_state_eq(|| None);
let m_end_handle: UseStateHandle<Option<(u8,u8)>> = use_state_eq(|| None); let m_end_handle: UseStateHandle<Option<(u8,u8)>> = use_state_eq(|| None);
let m_stat_handle: UseStateHandle<bool> = use_state_eq(|| false); let m_stat_handle: UseStateHandle<bool> = use_state_eq(|| false);
let m_start = m_start_handle.clone(); let m_start = m_start_handle.clone();
let m_end = m_end_handle.clone(); let m_end = m_end_handle.clone();
let menu_sync_callback = { if !(*m_stat_handle) {
let m_start_handle = m_start_handle.clone(); let pt1 = (state.destination_region.col_start, state.destination_region.row_start);
let m_end_handle = m_end_handle.clone(); let pt2 = (state.destination_region.col_end, state.destination_region.row_end);
let m_stat_handle = m_stat_handle.clone(); m_start_handle.set(Some(pt1));
m_end_handle.set(Some(pt2));
move |nts: Rc<NewTransferState>| { }
if !(*m_stat_handle) { let destination_wells = ct_state.transfer.get_destination_wells();
let pt1 = (nts.destination_region.col_start, nts.destination_region.row_start);
let pt2 = (nts.destination_region.col_end, nts.destination_region.row_end);
m_start_handle.set(Some(pt1));
m_end_handle.set(Some(pt2));
}
}
};
let dispatch = Dispatch::<NewTransferState>::subscribe(menu_sync_callback);
let mouse_callback = { let mouse_callback = {
let m_start_handle = m_start_handle.clone(); let m_start_handle = m_start_handle.clone();
@ -64,11 +60,13 @@ pub fn DestinationPlate(props: &DestinationPlateProps) -> Html {
let m_stat_handle = m_stat_handle.clone(); let m_stat_handle = m_stat_handle.clone();
Callback::from(move |_: MouseEvent| { Callback::from(move |_: MouseEvent| {
let current = dispatch.get();
m_stat_handle.set(false); m_stat_handle.set(false);
if let Some(ul) = *m_start_handle { if let Some(ul) = *m_start_handle {
if let Some(br) = *m_end_handle { if let Some(br) = *m_end_handle {
if let Ok(rd) = RegionDisplay::try_from((ul.0, ul.1, br.0, br.1)) { if let Ok(rd) = RegionDisplay::try_from((ul.0, ul.1, br.0, br.1)) {
ct_dispatch.reduce_mut(|state| {
state.transfer.dest_region = Region::from(&rd);
});
dispatch.reduce_mut(|state| { dispatch.reduce_mut(|state| {
state.destination_region = rd; state.destination_region = rd;
}); });
@ -80,12 +78,14 @@ pub fn DestinationPlate(props: &DestinationPlateProps) -> Html {
let mouseleave_callback = Callback::clone(&mouseup_callback); let mouseleave_callback = Callback::clone(&mouseup_callback);
let rows = (1..=props.plate.plate.size().1).map(|i| { let rows = (1..=props.destination_plate.plate.size().0).map(|i| {
let row = (1..=props.plate.plate.size().0).map(|j| { let row = (1..=props.destination_plate.plate.size().1).map(|j| {
html! { html! {
<DestPlateCell i={i} j={j} <DestPlateCell i={i} j={j}
selected={super::source_plate::in_rect(*m_start.clone(), *m_end.clone(), (i,j))} selected={super::source_plate::in_rect(*m_start.clone(), *m_end.clone(), (i,j))}
mouse={mouse_callback.clone()} /> mouse={mouse_callback.clone()}
in_transfer={destination_wells.contains(&(i,j))}
/>
} }
}).collect::<Html>(); }).collect::<Html>();
html! { html! {
@ -122,7 +122,7 @@ pub struct DestPlateCellProps {
pub j: u8, pub j: u8,
pub selected: bool, pub selected: bool,
pub mouse: Callback<(u8,u8, MouseEventType)>, pub mouse: Callback<(u8,u8, MouseEventType)>,
pub color: Option<String> pub in_transfer: Option<bool>,
} }
#[function_component] #[function_component]
@ -131,16 +131,16 @@ fn DestPlateCell(props: &DestPlateCellProps) -> Html {
true => Some("current_select"), true => Some("current_select"),
false => None, false => None,
}; };
let _color_string = match &props.color { let in_transfer_class = match props.in_transfer {
Some(c) => c.clone(), Some(true) => Some("in_transfer"),
None => "None".to_string(), _ => None
}; };
let mouse = Callback::clone(&props.mouse); let mouse = Callback::clone(&props.mouse);
let mouse2 = Callback::clone(&props.mouse); let mouse2 = Callback::clone(&props.mouse);
let (i,j) = (props.i.clone(), props.j.clone()); let (i,j) = (props.i.clone(), props.j.clone());
html! { html! {
<td class={classes!("plate_cell", selected_class)} <td class={classes!("plate_cell", selected_class, in_transfer_class)}
onmousedown={move |_| { onmousedown={move |_| {
mouse.emit((i,j, MouseEventType::MOUSEDOWN)) mouse.emit((i,j, MouseEventType::MOUSEDOWN))
}} }}

View File

@ -17,21 +17,21 @@ pub fn PlateContainer(props: &PlateContainerProps) -> Html {
html! { html! {
<div class="plate_container"> <div class="plate_container">
if let Some(spi) = props.source_dims.clone() { if let Some(spi) = props.source_dims.clone() {
<div>
<h2>{spi.name.clone()}</h2>
<SourcePlate plate={spi} />
</div>
} else {
<h2>{"No Source Plate Selected"}</h2>
}
if let Some(dpi) = props.destination_dims.clone() { if let Some(dpi) = props.destination_dims.clone() {
<div>
<h2>{spi.name.clone()}</h2>
<SourcePlate source_plate={spi.clone()} destination_plate={dpi.clone()} />
</div>
<div> <div>
<h2>{dpi.name.clone()}</h2> <h2>{dpi.name.clone()}</h2>
<DestinationPlate plate={dpi} /> <DestinationPlate source_plate={spi.clone()} destination_plate={dpi.clone()} />
</div> </div>
} else { } else {
<h2>{"No Destination Plate Selected"}</h2> <h2>{"No Destination Plate Selected"}</h2>
} }
} else {
<h2>{"No Source Plate Selected"}</h2>
}
</div> </div>
} }
} }

View File

@ -5,39 +5,35 @@ use yewdux::prelude::*;
use std::rc::Rc; use std::rc::Rc;
use crate::data::plate_instances::PlateInstance; use crate::data::plate_instances::PlateInstance;
use crate::data::transfer_region::TransferRegion; use crate::data::transfer_region::{TransferRegion, Region};
use crate::components::states::{NewTransferState, CurrentTransfer};
use super::super::states::NewTransferState;
use super::super::transfer_menu::RegionDisplay; use super::super::transfer_menu::RegionDisplay;
#[derive(PartialEq, Properties)] #[derive(PartialEq, Properties)]
pub struct SourcePlateProps { pub struct SourcePlateProps {
pub plate: PlateInstance, pub source_plate: PlateInstance,
pub destination_plate: PlateInstance,
} }
#[function_component] #[function_component]
pub fn SourcePlate(props: &SourcePlateProps) -> Html { pub fn SourcePlate(props: &SourcePlateProps) -> Html {
let (state, dispatch) = use_store::<NewTransferState>();
let (ct_state, ct_dispatch) = use_store::<CurrentTransfer>();
let m_start_handle: UseStateHandle<Option<(u8,u8)>> = use_state_eq(|| None); let m_start_handle: UseStateHandle<Option<(u8,u8)>> = use_state_eq(|| None);
let m_end_handle: UseStateHandle<Option<(u8,u8)>> = use_state_eq(|| None); let m_end_handle: UseStateHandle<Option<(u8,u8)>> = use_state_eq(|| None);
let m_stat_handle: UseStateHandle<bool> = use_state_eq(|| false); let m_stat_handle: UseStateHandle<bool> = use_state_eq(|| false);
let m_start = m_start_handle.clone(); let m_start = m_start_handle.clone();
let m_end = m_end_handle.clone(); let m_end = m_end_handle.clone();
let menu_sync_callback = { if !(*m_stat_handle) {
let m_start_handle = m_start_handle.clone(); let pt1 = (state.source_region.col_start, state.source_region.row_start);
let m_end_handle = m_end_handle.clone(); let pt2 = (state.source_region.col_end, state.source_region.row_end);
let m_stat_handle = m_stat_handle.clone(); m_start_handle.set(Some(pt1));
m_end_handle.set(Some(pt2));
}
move |nts: Rc<NewTransferState>| { let source_wells = ct_state.transfer.get_source_wells();
if !(*m_stat_handle) {
let pt1 = (nts.source_region.col_start, nts.source_region.row_start);
let pt2 = (nts.source_region.col_end, nts.source_region.row_end);
m_start_handle.set(Some(pt1));
m_end_handle.set(Some(pt2));
}
}
};
let dispatch = Dispatch::<NewTransferState>::subscribe(menu_sync_callback);
let mouse_callback = { let mouse_callback = {
let m_start_handle = m_start_handle.clone(); let m_start_handle = m_start_handle.clone();
@ -70,6 +66,9 @@ pub fn SourcePlate(props: &SourcePlateProps) -> Html {
if let Some(ul) = *m_start_handle { if let Some(ul) = *m_start_handle {
if let Some(br) = *m_end_handle { if let Some(br) = *m_end_handle {
if let Ok(rd) = RegionDisplay::try_from((ul.0, ul.1, br.0, br.1)) { if let Ok(rd) = RegionDisplay::try_from((ul.0, ul.1, br.0, br.1)) {
ct_dispatch.reduce_mut(|state| {
state.transfer.source_region = Region::from(&rd);
});
dispatch.reduce_mut(|state| { dispatch.reduce_mut(|state| {
state.source_region = rd; state.source_region = rd;
}); });
@ -81,12 +80,14 @@ pub fn SourcePlate(props: &SourcePlateProps) -> Html {
let mouseleave_callback = Callback::clone(&mouseup_callback); let mouseleave_callback = Callback::clone(&mouseup_callback);
let rows = (1..=props.plate.plate.size().1).map(|i| { let rows = (1..=props.source_plate.plate.size().0).map(|i| {
let row = (1..=props.plate.plate.size().0).map(|j| { let row = (1..=props.source_plate.plate.size().1).map(|j| {
html! { html! {
<SourcePlateCell i={i} j={j} <SourcePlateCell i={i} j={j}
selected={in_rect(*m_start.clone(), *m_end.clone(), (i,j))} selected={in_rect(*m_start.clone(), *m_end.clone(), (i,j))}
mouse={mouse_callback.clone()}/> mouse={mouse_callback.clone()}
in_transfer={source_wells.contains(&(i,j))}
/>
} }
}).collect::<Html>(); }).collect::<Html>();
html! { html! {
@ -117,7 +118,7 @@ pub struct SourcePlateCellProps {
j: u8, j: u8,
selected: bool, selected: bool,
mouse: Callback<(u8,u8, MouseEventType)>, mouse: Callback<(u8,u8, MouseEventType)>,
color: Option<String> in_transfer: Option<bool>,
} }
#[derive(Debug)] #[derive(Debug)]
pub enum MouseEventType { pub enum MouseEventType {
@ -131,16 +132,16 @@ fn SourcePlateCell(props: &SourcePlateCellProps) -> Html {
true => Some("current_select"), true => Some("current_select"),
false => None, false => None,
}; };
let _color_string = match &props.color { let in_transfer_class = match props.in_transfer {
Some(c) => c.clone(), Some(true) => Some("in_transfer"),
None => "None".to_string(), _ => None
}; };
let mouse = Callback::clone(&props.mouse); let mouse = Callback::clone(&props.mouse);
let mouse2 = Callback::clone(&props.mouse); let mouse2 = Callback::clone(&props.mouse);
let (i,j) = (props.i.clone(), props.j.clone()); let (i,j) = (props.i.clone(), props.j.clone());
html! { html! {
<td class={classes!("plate_cell", selected_class)} <td class={classes!("plate_cell", selected_class, in_transfer_class)}
onmousedown={move |_| { onmousedown={move |_| {
mouse.emit((i,j, MouseEventType::MOUSEDOWN)) mouse.emit((i,j, MouseEventType::MOUSEDOWN))
}} }}

View File

@ -6,6 +6,7 @@ use super::transfer_menu::RegionDisplay;
use crate::data::plate_instances::PlateInstance; use crate::data::plate_instances::PlateInstance;
use crate::data::transfer::Transfer; use crate::data::transfer::Transfer;
use crate::data::plate::*; use crate::data::plate::*;
use crate::data::transfer_region::TransferRegion;
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, Store)] #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, Store)]
#[store(storage = "session")] #[store(storage = "session")]
@ -14,8 +15,14 @@ pub struct NewTransferState {
pub destination_id: Uuid, pub destination_id: Uuid,
pub source_region: RegionDisplay, pub source_region: RegionDisplay,
pub destination_region: RegionDisplay, pub destination_region: RegionDisplay,
pub interleave_x: u8, pub interleave_x: i8,
pub interleave_y: u8, pub interleave_y: i8,
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, Store)]
#[store(storage = "session")]
pub struct CurrentTransfer {
pub transfer: TransferRegion,
} }
#[derive(Default, PartialEq, Clone, Serialize, Deserialize)] #[derive(Default, PartialEq, Clone, Serialize, Deserialize)]

View File

@ -8,22 +8,27 @@ use web_sys::{EventTarget, HtmlInputElement};
use regex::Regex; use regex::Regex;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use super::states::NewTransferState; use crate::data::transfer_region::Region;
use super::states::{NewTransferState, CurrentTransfer};
#[function_component] #[function_component]
pub fn TransferMenu() -> Html { pub fn TransferMenu() -> Html {
let (state, dispatch) = use_store::<NewTransferState>(); let (state, dispatch) = use_store::<NewTransferState>();
let (ct_state, ct_dispatch) = use_store::<CurrentTransfer>();
let on_src_region_change = { let on_src_region_change = {
let state = state.clone();
let dispatch = dispatch.clone(); let dispatch = dispatch.clone();
let ct_dispatch = ct_dispatch.clone();
Callback::from(move |e: Event| { Callback::from(move |e: Event| {
log::debug!("Input changed.");
let target: Option<EventTarget> = e.target(); let target: Option<EventTarget> = e.target();
let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok()); let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
if let Some(input) = input { if let Some(input) = input {
if let Ok(rd) = RegionDisplay::try_from(input.value()) { if let Ok(rd) = RegionDisplay::try_from(input.value()) {
ct_dispatch.reduce_mut(|state| {
state.transfer.source_region = Region::from(&rd);
});
dispatch.reduce_mut(|state| { dispatch.reduce_mut(|state| {
state.source_region = rd; state.source_region = rd;
}); });
@ -35,15 +40,17 @@ pub fn TransferMenu() -> Html {
}) })
}; };
let on_dest_region_change = { let on_dest_region_change = {
let state = state.clone();
let dispatch = dispatch.clone(); let dispatch = dispatch.clone();
let ct_dispatch = ct_dispatch.clone();
Callback::from(move |e: Event| { Callback::from(move |e: Event| {
log::debug!("Input changed.");
let target: Option<EventTarget> = e.target(); let target: Option<EventTarget> = e.target();
let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok()); let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
if let Some(input) = input { if let Some(input) = input {
if let Ok(rd) = RegionDisplay::try_from(input.value()) { if let Ok(rd) = RegionDisplay::try_from(input.value()) {
ct_dispatch.reduce_mut(|state| {
state.transfer.dest_region = Region::from(&rd);
});
dispatch.reduce_mut(|state| { dispatch.reduce_mut(|state| {
state.destination_region = rd; state.destination_region = rd;
}); });
@ -54,6 +61,51 @@ pub fn TransferMenu() -> Html {
} }
}) })
}; };
let on_dest_interleave_x_change = {
let dispatch = dispatch.clone();
let ct_state = ct_state.clone();
let ct_dispatch = ct_dispatch.clone();
Callback::from(move |e: Event| {
let target: Option<EventTarget> = e.target();
let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
if let Some(input) = input {
if let Ok(num) = input.value().parse::<i8>() {
dispatch.reduce_mut(|state| {
state.interleave_x = num;
});
if let Some((_,y)) = ct_state.transfer.interleave_dest {
ct_dispatch.reduce_mut(|state| {
state.transfer.interleave_dest = Some((num, y));
});
}
}
}
})
};
let on_dest_interleave_y_change = {
let dispatch = dispatch.clone();
let ct_state = ct_state.clone();
let ct_dispatch = ct_dispatch.clone();
Callback::from(move |e: Event| {
let target: Option<EventTarget> = e.target();
let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
if let Some(input) = input {
if let Ok(num) = input.value().parse::<i8>() {
dispatch.reduce_mut(|state| {
state.interleave_y = num;
});
if let Some((x,_)) = ct_state.transfer.interleave_dest {
ct_dispatch.reduce_mut(|state| {
state.transfer.interleave_dest = Some((x, num));
});
}
}
}
})
};
html! { html! {
<div class="transfer_menu"> <div class="transfer_menu">
@ -69,14 +121,17 @@ pub fn TransferMenu() -> Html {
onchange={on_dest_region_change} value={state.destination_region.text.clone()}/> onchange={on_dest_region_change} value={state.destination_region.text.clone()}/>
</div> </div>
<div> <div>
{"Interleave "} {"Destination Interleave "}
<label for="interleave_x">{"X:"}</label> <label for="dest_interleave_x">{"X:"}</label>
<input type="number" name="interleave_x"/> <input type="number" name="dest_interleave_x"
<label for="interleave_y">{"Y:"}</label> onchange={on_dest_interleave_x_change} value={state.interleave_x.to_string()}/>
<input type="number" name="interleave_y"/> <label for="dest_interleave_y">{"Y:"}</label>
<input type="number" name="dest_interleave_y"
onchange={on_dest_interleave_y_change} value={state.interleave_y.to_string()}/>
</div> </div>
<input type="button" name="create_transfer" value={"Create"} /> <input type="button" name="create_transfer" value={"Create"} />
</form> </form>
<button>{"Refresh"}</button>
</div> </div>
} }
} }
@ -116,6 +171,15 @@ impl TryFrom<String> for RegionDisplay {
} }
} }
impl From<&RegionDisplay> for Region {
fn from(value: &RegionDisplay) -> Self {
if value.col_start == value.col_end && value.row_start == value.row_end {
Region::Point((value.col_start, value.row_start))
} else {
Region::Rect((value.col_start, value.row_start), (value.col_end, value.row_end))
}
}
}
impl TryFrom<(u8,u8,u8,u8)> for RegionDisplay { impl TryFrom<(u8,u8,u8,u8)> for RegionDisplay {
type Error = &'static str; type Error = &'static str;

View File

@ -6,9 +6,7 @@ use web_sys::{EventTarget, HtmlElement, HtmlDialogElement};
use yew::prelude::*; use yew::prelude::*;
use yewdux::prelude::*; use yewdux::prelude::*;
use crate::data::{plate_instances::PlateInstance, transfer::Transfer}; use crate::components::states::{MainState, NewTransferState, CurrentTransfer};
use crate::data::plate::*;
use crate::components::states::{MainState, NewTransferState};
use crate::components::transfer_menu::RegionDisplay; use crate::components::transfer_menu::RegionDisplay;
#[derive(PartialEq, Properties)] #[derive(PartialEq, Properties)]

View File

@ -1,6 +1,6 @@
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
#[derive(PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Debug)] #[derive(PartialEq, Eq, Default, Clone, Copy, Serialize, Deserialize, Debug)]
pub struct Plate { pub struct Plate {
pub plate_type: PlateType, pub plate_type: PlateType,
pub plate_format: PlateFormat, pub plate_format: PlateFormat,
@ -24,6 +24,11 @@ pub enum PlateType {
Source, Source,
Destination, Destination,
} }
impl Default for PlateType {
fn default() -> Self {
Self::Source
}
}
#[derive(PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Debug)] #[derive(PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Debug)]
pub enum PlateFormat { pub enum PlateFormat {
@ -36,6 +41,11 @@ pub enum PlateFormat {
W1536, W1536,
W3456, W3456,
} }
impl Default for PlateFormat {
fn default() -> Self {
Self::W96
}
}
impl std::fmt::Display for PlateFormat { impl std::fmt::Display for PlateFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
@ -53,6 +63,7 @@ impl std::fmt::Display for PlateFormat {
impl PlateFormat { impl PlateFormat {
pub fn size(&self) -> (u8, u8) { pub fn size(&self) -> (u8, u8) {
/*
match self { match self {
PlateFormat::W6 => (3, 2), PlateFormat::W6 => (3, 2),
PlateFormat::W12 => (4, 3), PlateFormat::W12 => (4, 3),
@ -63,6 +74,17 @@ impl PlateFormat {
PlateFormat::W1536 => (48, 32), PlateFormat::W1536 => (48, 32),
PlateFormat::W3456 => (72, 48), PlateFormat::W3456 => (72, 48),
} }
*/
match self {
PlateFormat::W6 => (2, 3),
PlateFormat::W12 => (3, 4),
PlateFormat::W24 => (4, 6),
PlateFormat::W48 => (6, 8),
PlateFormat::W96 => (8, 12),
PlateFormat::W384 => (16, 24),
PlateFormat::W1536 => (32, 48),
PlateFormat::W3456 => (48, 72),
}
} }
} }

View File

@ -7,6 +7,11 @@ pub enum Region {
Rect((u8, u8), (u8, u8)), Rect((u8, u8), (u8, u8)),
Point((u8, u8)), Point((u8, u8)),
} }
impl Default for Region {
fn default() -> Self {
Region::Point((1,1))
}
}
impl TryFrom<Region> for ((u8, u8), (u8, u8)) { impl TryFrom<Region> for ((u8, u8), (u8, u8)) {
type Error = &'static str; type Error = &'static str;
fn try_from(region: Region) -> Result<Self, Self::Error> { fn try_from(region: Region) -> Result<Self, Self::Error> {
@ -19,7 +24,7 @@ impl TryFrom<Region> for ((u8, u8), (u8, u8)) {
} }
} }
#[derive(PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Debug)] #[derive(PartialEq, Eq, Default, Clone, Copy, Serialize, Deserialize, Debug)]
pub struct TransferRegion { pub struct TransferRegion {
pub source_plate: Plate, pub source_plate: Plate,
pub source_region: Region, // Even if it is just a point, we don't want corners. pub source_region: Region, // Even if it is just a point, we don't want corners.
@ -31,7 +36,8 @@ pub struct TransferRegion {
impl TransferRegion { impl TransferRegion {
pub fn get_source_wells(&self) -> Vec<(u8, u8)> { pub fn get_source_wells(&self) -> Vec<(u8, u8)> {
if let Region::Rect(c1, c2) = self.source_region { match self.source_region {
Region::Rect(c1, c2) => {
let mut wells = Vec::<(u8, u8)>::new(); let mut wells = Vec::<(u8, u8)>::new();
let (ul, br) = standardize_rectangle(&c1, &c2); let (ul, br) = standardize_rectangle(&c1, &c2);
let (interleave_i, interleave_j) = self.interleave_source.unwrap_or((1, 1)); let (interleave_i, interleave_j) = self.interleave_source.unwrap_or((1, 1));
@ -50,21 +56,25 @@ impl TransferRegion {
} }
} }
return wells; return wells;
} else { },
panic!("Source region is just a point!") Region::Point(p) => return vec![p]
} }
} }
pub fn get_destination_wells(&self) -> Vec<(u8, u8)> { pub fn get_destination_wells(&self) -> Vec<(u8, u8)> {
let map = self.calculate_map(); let map = self.calculate_map();
let source_wells = self.get_source_wells(); let source_wells = self.get_source_wells();
let mut wells = Vec::<(u8, u8)>::new(); let mut wells = Vec::<(u8, u8)>::new();
log::debug!("GDW:");
for well in source_wells { for well in source_wells {
if let Some(mut dest_wells) = map(well) { if let Some(mut dest_wells) = map(well) {
log::debug!("Map {:?} to {:?}", well, dest_wells);
wells.append(&mut dest_wells); wells.append(&mut dest_wells);
} }
} }
log::debug!("GDW END.");
return wells; return wells;
} }
@ -74,6 +84,7 @@ impl TransferRegion {
// this function will not panic. :) // this function will not panic. :)
if let Err(msg) = self.validate() { if let Err(msg) = self.validate() {
eprintln!("{}", msg); eprintln!("{}", msg);
log::debug!("{}", msg);
eprintln!("This transfer will be empty."); eprintln!("This transfer will be empty.");
return Box::new(|(_, _)| None); return Box::new(|(_, _)| None);
} }
@ -82,10 +93,10 @@ impl TransferRegion {
let il_dest = self.interleave_dest.unwrap_or((1, 1)); let il_dest = self.interleave_dest.unwrap_or((1, 1));
let il_source = self.interleave_source.unwrap_or((1, 1)); let il_source = self.interleave_source.unwrap_or((1, 1));
let source_corners: ((u8, u8), (u8, u8)) = self let source_corners: ((u8, u8), (u8, u8)) = match self.source_region {
.source_region Region::Point((x,y)) => ((x,y),(x,y)),
.try_into() Region::Rect(c1,c2) => (c1,c2)
.expect("Source region should not be a point"); };
let (source_ul, _) = standardize_rectangle(&source_corners.0, &source_corners.1); let (source_ul, _) = standardize_rectangle(&source_corners.0, &source_corners.1);
// This map is not necessarily injective or surjective, // This map is not necessarily injective or surjective,
// but we will have these properties in certain cases. // but we will have these properties in certain cases.
@ -132,24 +143,6 @@ impl TransferRegion {
s2.1.checked_sub(s1.1).unwrap() + 1, s2.1.checked_sub(s1.1).unwrap() + 1,
); );
/*
println!("{} % {} == {}", i, dims.0, i*il_dest.0.abs() as u8 % dims.0);
for a in ds1.0..=ds2.0 {
for b in ds1.1..=ds2.1 {
println!("({},{}): {} % {} == {}", a, b,
a.checked_sub(ds1.0).unwrap()+1, dims.0,
(a.checked_sub(ds1.0).unwrap()+1) % dims.0);
}
}
for a in ds1.0..=ds2.0 {
for b in ds1.1..=ds2.1 {
println!("({},{}): {} % {} == {}", a, b,
a.checked_sub(ds1.0).unwrap()+1, il_dest.0.abs() as u8,
(a.checked_sub(ds1.0).unwrap()+1) % il_dest.0.abs() as u8);
}
}
*/
Some( Some(
possible_destination_wells possible_destination_wells
.into_iter() .into_iter()
@ -187,7 +180,8 @@ impl TransferRegion {
let il_dest = self.interleave_dest.unwrap_or((1, 1)); let il_dest = self.interleave_dest.unwrap_or((1, 1));
match self.source_region { match self.source_region {
Region::Point(_) => return Err("Source region should not be a point!"), Region::Point(_) => return Ok(()), // Should make sure it's actually in the plate, leave for
// later
Region::Rect(s1, s2) => { Region::Rect(s1, s2) => {
// Check if all source wells exist: // Check if all source wells exist:
if s1.0 == 0 || s1.1 == 0 || s2.0 == 0 || s2.1 == 0 { if s1.0 == 0 || s1.1 == 0 || s2.0 == 0 || s2.1 == 0 {
@ -199,6 +193,7 @@ impl TransferRegion {
return Err("Source region is out-of-bounds! (Too tall)"); return Err("Source region is out-of-bounds! (Too tall)");
} }
if s1.1 > source_max.1 || s2.1 > source_max.1 { if s1.1 > source_max.1 || s2.1 > source_max.1 {
log::debug!("s1.1: {}, max.1: {}", s1.1, source_max.1);
return Err("Source region is out-of-bounds! (Too wide)"); return Err("Source region is out-of-bounds! (Too wide)");
} }
// Check that source lengths divide destination lengths // Check that source lengths divide destination lengths