diff --git a/Cargo.lock b/Cargo.lock index b9120561d3..bdc62be85e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,11 +17,13 @@ checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" [[package]] name = "ahash" -version = "0.3.8" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" +checksum = "796540673305a66d127804eef19ad696f1f204b8c1025aaca4958c17eab32877" dependencies = [ - "const-random", + "getrandom 0.2.2", + "once_cell", + "version_check 0.9.2", ] [[package]] @@ -115,7 +117,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0df2f85c8a2abbe3b7d7e748052fdd9b76a0458fdeb16ad4223f5eca78c7c130" dependencies = [ "addr2line", - "cfg-if", + "cfg-if 0.1.10", "libc", "object", "rustc-demangle", @@ -151,7 +153,7 @@ checksum = "f1c85344eb535a31b62f0af37be84441ba9e7f0f4111eb0530f43d15e513fe57" dependencies = [ "bitflags 1.2.1", "cexpr", - "cfg-if", + "cfg-if 0.1.10", "clang-sys", "clap", "env_logger", @@ -286,6 +288,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "chrono" version = "0.4.11" @@ -293,7 +301,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" dependencies = [ "num-integer", - "num-traits 0.2.11", + "num-traits 0.2.14", "serde", "time", ] @@ -334,26 +342,6 @@ dependencies = [ "bitflags 1.2.1", ] -[[package]] -name = "const-random" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a" -dependencies = [ - "const-random-macro", - "proc-macro-hack", -] - -[[package]] -name = "const-random-macro" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a" -dependencies = [ - "getrandom", - "proc-macro-hack", -] - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -382,7 +370,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] @@ -409,12 +397,12 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" +checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ - "crossbeam-utils", - "maybe-uninit", + "cfg-if 1.0.0", + "crossbeam-utils 0.8.1", ] [[package]] @@ -424,7 +412,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ "autocfg 1.0.0", - "cfg-if", + "cfg-if 0.1.10", + "lazy_static", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +dependencies = [ + "autocfg 1.0.0", + "cfg-if 1.0.0", "lazy_static", ] @@ -469,15 +468,14 @@ dependencies = [ [[package]] name = "cursive" -version = "0.15.0" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9f12332ab2bca26979ef00cfef9a1c2e287db03b787a83d892ad9961f81374" +checksum = "6593c3409eb794bf22090bec60dda1e19d1def284478bec7e5a92da3cf977c52" dependencies = [ "ahash", - "cfg-if", + "cfg-if 1.0.0", "crossbeam-channel", "cursive_core", - "enumset", "lazy_static", "libc", "log", @@ -487,30 +485,40 @@ dependencies = [ "term_size", "unicode-segmentation", "unicode-width", + "wasmer_enumset", ] [[package]] name = "cursive_core" -version = "0.1.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe232694c965c211d5fbd8111ae89a5939b7b169cefcac4f8b6f83dde889e10" +checksum = "025ac0bcd21ced752d27b70e6aa2285a3513d07b5a0c7f89e71121d20ca1429d" dependencies = [ "ahash", "chrono", "crossbeam-channel", "enum-map", - "enumset", "lazy_static", "libc", "log", - "num", + "num 0.3.1", "owning_ref", - "signal-hook", + "syn 1.0.31", "unicode-segmentation", "unicode-width", + "wasmer_enumset", "xi-unicode", ] +[[package]] +name = "cursive_table_view" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d94aa5dc377345e85b939d4a0c4c0beea86a0095f18386eee31f4e1ba9ae508" +dependencies = [ + "cursive_core", +] + [[package]] name = "darling" version = "0.10.2" @@ -567,7 +575,7 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "dirs-sys", ] @@ -643,28 +651,6 @@ dependencies = [ "num-traits 0.1.43", ] -[[package]] -name = "enumset" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3691ce759534316ad900d57dd8e688e2c4263f9750c0f7c1e9b9a4516d4ca241" -dependencies = [ - "enumset_derive", - "num-traits 0.2.11", -] - -[[package]] -name = "enumset_derive" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74bef436ac71820c5cf768d7af9ba33121246b09a00e09a55d94ef8095a875ac" -dependencies = [ - "darling", - "proc-macro2 1.0.18", - "quote 1.0.7", - "syn 1.0.31", -] - [[package]] name = "env_logger" version = "0.7.1" @@ -712,7 +698,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "affc17579b132fc2461adf7c575cc6e8b134ebca52c51f5411388965227dc695" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "redox_syscall", "winapi 0.3.8", @@ -724,7 +710,7 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "crc32fast", "libc", "miniz_oxide", @@ -890,9 +876,20 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.10.1+wasi-snapshot-preview1", ] [[package]] @@ -930,6 +927,7 @@ dependencies = [ "clap", "ctrlc", "cursive", + "cursive_table_view", "failure", "failure_derive", "grin_api", @@ -1038,7 +1036,7 @@ dependencies = [ "lazy_static", "log", "lru-cache", - "num", + "num 0.2.1", "num-bigint", "rand 0.6.5", "serde", @@ -1084,7 +1082,7 @@ dependencies = [ "grin_util", "log", "lru-cache", - "num", + "num 0.2.1", "rand 0.6.5", "serde", "serde_derive", @@ -1517,7 +1515,7 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "serde", ] @@ -1573,12 +1571,6 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - [[package]] name = "memchr" version = "2.3.3" @@ -1610,7 +1602,7 @@ version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "fuchsia-zircon", "fuchsia-zircon-sys", "iovec", @@ -1685,7 +1677,7 @@ version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "winapi 0.3.8", ] @@ -1698,7 +1690,7 @@ checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" dependencies = [ "bitflags 1.2.1", "cc", - "cfg-if", + "cfg-if 0.1.10", "libc", "void", ] @@ -1716,7 +1708,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" dependencies = [ "memchr", - "version_check", + "version_check 0.1.5", ] [[package]] @@ -1726,11 +1718,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" dependencies = [ "num-bigint", - "num-complex", + "num-complex 0.2.4", "num-integer", "num-iter", - "num-rational", - "num-traits 0.2.11", + "num-rational 0.2.4", + "num-traits 0.2.14", +] + +[[package]] +name = "num" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" +dependencies = [ + "num-complex 0.3.1", + "num-integer", + "num-iter", + "num-rational 0.3.2", + "num-traits 0.2.14", ] [[package]] @@ -1741,7 +1746,7 @@ checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" dependencies = [ "autocfg 1.0.0", "num-integer", - "num-traits 0.2.11", + "num-traits 0.2.14", ] [[package]] @@ -1751,28 +1756,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" dependencies = [ "autocfg 1.0.0", - "num-traits 0.2.11", + "num-traits 0.2.14", +] + +[[package]] +name = "num-complex" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" +dependencies = [ + "num-traits 0.2.14", ] [[package]] name = "num-integer" -version = "0.1.42" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ "autocfg 1.0.0", - "num-traits 0.2.11", + "num-traits 0.2.14", ] [[package]] name = "num-iter" -version = "0.1.40" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" dependencies = [ "autocfg 1.0.0", "num-integer", - "num-traits 0.2.11", + "num-traits 0.2.14", ] [[package]] @@ -1784,7 +1798,18 @@ dependencies = [ "autocfg 1.0.0", "num-bigint", "num-integer", - "num-traits 0.2.11", + "num-traits 0.2.14", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg 1.0.0", + "num-integer", + "num-traits 0.2.14", ] [[package]] @@ -1793,14 +1818,14 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" dependencies = [ - "num-traits 0.2.11", + "num-traits 0.2.14", ] [[package]] name = "num-traits" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ "autocfg 1.0.0", ] @@ -1829,9 +1854,9 @@ checksum = "4eae0151b9dacf24fcc170d9995e511669a082856a91f958a2fe380bfab3fb22" [[package]] name = "once_cell" -version = "1.4.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" +checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" [[package]] name = "openssl-probe" @@ -1845,7 +1870,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" dependencies = [ - "num-traits 0.2.11", + "num-traits 0.2.14", ] [[package]] @@ -1895,7 +1920,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "cloudabi", "libc", "redox_syscall", @@ -2095,7 +2120,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.14", "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", @@ -2143,7 +2168,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.14", ] [[package]] @@ -2238,7 +2263,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" dependencies = [ - "getrandom", + "getrandom 0.1.14", "redox_syscall", "rust-argon2", ] @@ -2305,7 +2330,7 @@ dependencies = [ "base64 0.11.0", "blake2b_simd", "constant_time_eq", - "crossbeam-utils", + "crossbeam-utils 0.7.2", ] [[package]] @@ -2510,9 +2535,9 @@ checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" [[package]] name = "signal-hook" -version = "0.1.15" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff2db2112d6c761e12522c65f7768548bd6e8cd23d2a9dae162520626629bd6" +checksum = "780f5e3fe0c66f67197236097d89de1e86216f1f6fdeaf47c442f854ab46c240" dependencies = [ "libc", "signal-hook-registry", @@ -2520,11 +2545,10 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" +checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" dependencies = [ - "arc-swap", "libc", ] @@ -2552,7 +2576,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "redox_syscall", "winapi 0.3.8", @@ -2640,7 +2664,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "rand 0.7.3", "redox_syscall", @@ -2929,6 +2953,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + [[package]] name = "void" version = "1.0.2" @@ -2962,13 +2992,19 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9" + [[package]] name = "wasm-bindgen" version = "0.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c2dc4aa152834bc334f506c1a06b866416a8b6697d5c9f75b9a689c8486def0" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "wasm-bindgen-macro", ] @@ -3016,6 +3052,28 @@ version = "0.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9ba19973a58daf4db6f352eda73dc0e289493cd29fb2632eb172085b6521acd" +[[package]] +name = "wasmer_enumset" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf088cc1f7d247fd96dff0df46fb1bbb747d8a69ae1ecd71aed55c55e354b2d8" +dependencies = [ + "num-traits 0.2.14", + "wasmer_enumset_derive", +] + +[[package]] +name = "wasmer_enumset_derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1b32d98e11194200baf6d3f85eb2d6cfe56f6d9af0dd617f90ca48f958a88" +dependencies = [ + "darling", + "proc-macro2 1.0.18", + "quote 1.0.7", + "syn 1.0.31", +] + [[package]] name = "web-sys" version = "0.3.40" @@ -3109,9 +3167,9 @@ dependencies = [ [[package]] name = "xi-unicode" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7395cdb9d0a6219fa0ea77d08c946adf9c1984c72fcd443ace30365f3daadef7" +checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" [[package]] name = "yaml-rust" diff --git a/Cargo.toml b/Cargo.toml index a211efaa60..108889d1d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ blake2-rfc = "0.2" chrono = "0.4.11" clap = { version = "2.33", features = ["yaml"] } ctrlc = { version = "3.1", features = ["termination"] } +cursive_table_view = "0.13.2" humansize = "1.1.0" serde = "1" serde_json = "1" @@ -42,7 +43,7 @@ grin_servers = { path = "./servers", version = "5.1.0-alpha.1" } grin_util = { path = "./util", version = "5.1.0-alpha.1" } [dependencies.cursive] -version = "0.15" +version = "0.16" default-features = false features = ["pancurses-backend"] diff --git a/src/bin/tui/mining.rs b/src/bin/tui/mining.rs index adf7917800..31afaea827 100644 --- a/src/bin/tui/mining.rs +++ b/src/bin/tui/mining.rs @@ -33,7 +33,7 @@ use crate::tui::constants::{ use crate::tui::types::TUIStatusListener; use crate::servers::{DiffBlock, ServerStats, WorkerStats}; -use crate::tui::table::{TableView, TableViewItem}; +use cursive_table_view::{TableView, TableViewItem}; #[derive(Copy, Clone, PartialEq, Eq, Hash)] enum StratumWorkerColumn { @@ -333,7 +333,7 @@ impl TUIStatusListener for TUIMiningView { let _ = c.call_on_name( TABLE_MINING_DIFF_STATUS, |t: &mut TableView| { - t.set_items(diff_stats); + t.set_items_stable(diff_stats); }, ); let stratum_stats = stats.stratum_stats.clone(); @@ -388,7 +388,7 @@ impl TUIStatusListener for TUIMiningView { let _ = c.call_on_name( TABLE_MINING_STATUS, |t: &mut TableView| { - t.set_items(worker_stats); + t.set_items_stable(worker_stats); }, ); } diff --git a/src/bin/tui/mod.rs b/src/bin/tui/mod.rs index 367db379c4..8a2f98575e 100644 --- a/src/bin/tui/mod.rs +++ b/src/bin/tui/mod.rs @@ -22,7 +22,6 @@ mod menu; mod mining; mod peers; mod status; -pub mod table; mod types; pub mod ui; mod version; diff --git a/src/bin/tui/peers.rs b/src/bin/tui/peers.rs index 9648622299..9848985e85 100644 --- a/src/bin/tui/peers.rs +++ b/src/bin/tui/peers.rs @@ -29,8 +29,8 @@ use cursive::views::{Dialog, LinearLayout, OnEventView, ResizedView, TextView}; use cursive::Cursive; use crate::tui::constants::{MAIN_MENU, TABLE_PEER_STATUS, VIEW_PEER_SYNC}; -use crate::tui::table::{TableView, TableViewItem}; use crate::tui::types::TUIStatusListener; +use cursive_table_view::{TableView, TableViewItem}; #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub enum PeerColumn { @@ -190,7 +190,7 @@ impl TUIStatusListener for TUIPeerView { let _ = c.call_on_name( TABLE_PEER_STATUS, |t: &mut TableView| { - t.set_items(stats.peer_stats.clone()); + t.set_items_stable(stats.peer_stats.clone()); }, ); let _ = c.call_on_name("peers_total", |t: &mut TextView| { diff --git a/src/bin/tui/table.rs b/src/bin/tui/table.rs deleted file mode 100644 index 694452069a..0000000000 --- a/src/bin/tui/table.rs +++ /dev/null @@ -1,1068 +0,0 @@ -// Copyright 2020 The Grin Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Copyright (c) 2015-2017 Ivo Wetzel -// -// Permission is hereby granted, free of charge, to any -// person obtaining a copy of this software and associated -// documentation files (the "Software"), to deal in the -// Software without restriction, including without -// limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice -// shall be included in all copies or substantial portions -// of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -//! Adapted from https://github.com/behnam/rust-cursive-table-view -//! A basic table view implementation for [cursive](https://crates.io/crates/cursive). - -#![deny( - missing_docs, - missing_copy_implementations, - trivial_casts, - trivial_numeric_casts, - unsafe_code, - unused_import_braces, - unused_qualifications -)] - -// Crate Dependencies --------------------------------------------------------- -use cursive; - -// STD Dependencies ----------------------------------------------------------- -use std::cmp::{self, Ordering}; -use std::collections::HashMap; -use std::hash::Hash; -use std::rc::Rc; - -// External Dependencies ------------------------------------------------------ -use cursive::align::HAlign; -use cursive::direction::Direction; -use cursive::event::{Callback, Event, EventResult, Key}; -use cursive::theme::ColorStyle; -use cursive::theme::PaletteColor::{Highlight, HighlightInactive, Primary}; -use cursive::vec::Vec2; -use cursive::view::{ScrollBase, View}; -use cursive::With; -use cursive::{Cursive, Printer}; - -/// A trait for displaying and sorting items inside a -/// [`TableView`](struct.TableView.html). -pub trait TableViewItem: Clone + Sized -where - H: Eq + Hash + Copy + Clone + 'static, -{ - /// Method returning a string representation of the item for the - /// specified column from type `H`. - fn to_column(&self, column: H) -> String; - - /// Method comparing two items via their specified column from type `H`. - fn cmp(&self, other: &Self, column: H) -> Ordering - where - Self: Sized; -} - -/// View to select an item among a list, supporting multiple columns for -/// sorting. -/// -/// # Examples -/// -/// ```rust -/// # extern crate cursive; -/// # extern crate cursive_table_view; -/// # use std::cmp::Ordering; -/// # use cursive_table_view::{TableView, TableViewItem}; -/// # use cursive::align::HAlign; -/// # fn main() { -/// // Provide a type for the table's columns -/// #[derive(Copy, Clone, PartialEq, Eq, Hash)] -/// enum BasicColumn { -/// Name, -/// Count, -/// Rate -/// } -/// -/// // Define the item type -/// #[derive(Clone, Debug)] -/// struct Foo { -/// name: String, -/// count: usize, -/// rate: usize -/// } -/// -/// impl TableViewItem for Foo { -/// -/// fn to_column(&self, column: BasicColumn) -> String { -/// match column { -/// BasicColumn::Name => self.name.to_string(), -/// BasicColumn::Count => format!("{}", self.count), -/// BasicColumn::Rate => format!("{}", self.rate) -/// } -/// } -/// -/// fn cmp(&self, other: &Self, column: BasicColumn) -> Ordering where Self: Sized { -/// match column { -/// BasicColumn::Name => self.name.cmp(&other.name), -/// BasicColumn::Count => self.count.cmp(&other.count), -/// BasicColumn::Rate => self.rate.cmp(&other.rate) -/// } -/// } -/// -/// } -/// -/// // Configure the actual table -/// let table = TableView::::new() -/// .column(BasicColumn::Name, "Name", |c| c.width(20)) -/// .column(BasicColumn::Count, "Count", |c| c.align(HAlign::Center)) -/// .column(BasicColumn::Rate, "Rate", |c| { -/// c.ordering(Ordering::Greater).align(HAlign::Right).width(20) -/// }) -/// .default_column(BasicColumn::Name); -/// # } -/// ``` -pub struct TableView + PartialEq, H: Eq + Hash + Copy + Clone + 'static> { - enabled: bool, - scrollbase: ScrollBase, - last_size: Vec2, - - column_select: bool, - columns: Vec>, - column_indices: HashMap, - - focus: usize, - items: Vec, - rows_to_items: Vec, - - on_sort: Option>, - // TODO Pass drawing offsets into the handlers so a popup menu - // can be created easily? - on_submit: Option>, - on_select: Option>, -} - -impl + PartialEq, H: Eq + Hash + Copy + Clone + 'static> TableView { - /// Creates a new empty `TableView` without any columns. - /// - /// A TableView should be accompanied by a enum of type `H` representing - /// the table columns. - pub fn new() -> Self { - Self { - enabled: true, - scrollbase: ScrollBase::new(), - last_size: Vec2::new(0, 0), - - column_select: false, - columns: Vec::new(), - column_indices: HashMap::new(), - - focus: 0, - items: Vec::new(), - rows_to_items: Vec::new(), - - on_sort: None, - on_submit: None, - on_select: None, - } - } - - /// Adds a column for the specified table column from type `H` along with - /// a title for its visual display. - /// - /// The provided callback can be used to further configure the - /// created [`TableColumn`](struct.TableColumn.html). - pub fn column, C: FnOnce(TableColumn) -> TableColumn>( - mut self, - column: H, - title: S, - callback: C, - ) -> Self { - self.column_indices.insert(column, self.columns.len()); - self.columns - .push(callback(TableColumn::new(column, title.into()))); - - // Make the first column the default one - if self.columns.len() == 1 { - self.default_column(column) - } else { - self - } - } - - /// Sets the initially active column of the table. - pub fn default_column(mut self, column: H) -> Self { - if self.column_indices.contains_key(&column) { - for c in &mut self.columns { - c.selected = c.column == column; - if c.selected { - c.order = c.default_order; - } else { - c.order = Ordering::Equal; - } - } - } - self - } - - /// Sorts the table using the specified table `column` and the passed - /// `order`. - pub fn sort_by(&mut self, column: H, order: Ordering) { - if self.column_indices.contains_key(&column) { - for c in &mut self.columns { - if c.column == column { - c.order = order; - } else { - c.order = Ordering::Equal; - } - } - } - - self.sort_items(column, order); - } - - /// Sorts the table using the currently active column and its - /// ordering. - pub fn sort(&mut self) { - if let Some((column, order)) = self.order() { - self.sort_items(column, order); - } - } - - /// Returns the currently active column that is used for sorting - /// along with its ordering. - /// - /// Might return `None` if there are currently no items in the table - /// and it has not been sorted yet. - pub fn order(&self) -> Option<(H, Ordering)> { - for c in &self.columns { - if c.order != Ordering::Equal { - return Some((c.column, c.order)); - } - } - None - } - - /// Disables this view. - /// - /// A disabled view cannot be selected. - pub fn disable(&mut self) { - self.enabled = false; - } - - /// Re-enables this view. - pub fn enable(&mut self) { - self.enabled = true; - } - - /// Enable or disable this view. - pub fn set_enabled(&mut self, enabled: bool) { - self.enabled = enabled; - } - - /// Returns `true` if this view is enabled. - pub fn is_enabled(&self) -> bool { - self.enabled - } - - /// Sets a callback to be used when a selected column is sorted by - /// pressing ``. - /// - /// # Example - /// - /// ```norun - /// rt(|siv: &mut Cursive, column: BasicColumn, order: Ordering| {}); - /// ``` - pub fn set_on_sort(&mut self, cb: F) - where - F: Fn(&mut Cursive, H, Ordering) + 'static, - { - self.on_sort = Some(Rc::new(move |s, h, o| cb(s, h, o))); - } - - /// Sets a callback to be used when a selected column is sorted by - /// pressing ``. - /// - /// Chainable variant. - /// - /// # Example - /// - /// ```norun - /// siv: &mut Cursive, column: BasicColumn, order: Ordering| {}); - /// ``` - pub fn on_sort(self, cb: F) -> Self - where - F: Fn(&mut Cursive, H, Ordering) + 'static, - { - self.with(|t| t.set_on_sort(cb)) - } - - /// Sets a callback to be used when `` is pressed while an item - /// is selected. - /// - /// Both the currently selected row and the index of the corresponding item - /// within the underlying storage vector will be given to the callback. - /// - /// # Example - /// - /// ```norun - /// bmit(|siv: &mut Cursive, row: usize, index: usize| {}); - /// ``` - pub fn set_on_submit(&mut self, cb: F) - where - F: Fn(&mut Cursive, usize, usize) + 'static, - { - self.on_submit = Some(Rc::new(move |s, row, index| cb(s, row, index))); - } - - /// Sets a callback to be used when `` is pressed while an item - /// is selected. - /// - /// Both the currently selected row and the index of the corresponding item - /// within the underlying storage vector will be given to the callback. - /// - /// Chainable variant. - /// - /// # Example - /// - /// ```norun - /// (|siv: &mut Cursive, row: usize, index: usize| {}); - /// ``` - pub fn on_submit(self, cb: F) -> Self - where - F: Fn(&mut Cursive, usize, usize) + 'static, - { - self.with(|t| t.set_on_submit(cb)) - } - - /// Sets a callback to be used when an item is selected. - /// - /// Both the currently selected row and the index of the corresponding item - /// within the underlying storage vector will be given to the callback. - /// - /// # Example - /// - /// ```norun - /// lect(|siv: &mut Cursive, row: usize, index: usize| {}); - /// ``` - pub fn set_on_select(&mut self, cb: F) - where - F: Fn(&mut Cursive, usize, usize) + 'static, - { - self.on_select = Some(Rc::new(move |s, row, index| cb(s, row, index))); - } - - /// Sets a callback to be used when an item is selected. - /// - /// Both the currently selected row and the index of the corresponding item - /// within the underlying storage vector will be given to the callback. - /// - /// Chainable variant. - /// - /// # Example - /// - /// ```norun - /// (|siv: &mut Cursive, row: usize, index: usize| {}); - /// ``` - pub fn on_select(self, cb: F) -> Self - where - F: Fn(&mut Cursive, usize, usize) + 'static, - { - self.with(|t| t.set_on_select(cb)) - } - - /// Removes all items from this view. - pub fn clear(&mut self) { - self.items.clear(); - self.rows_to_items.clear(); - self.focus = 0; - } - - /// Returns the number of items in this table. - pub fn len(&self) -> usize { - self.items.len() - } - - /// Returns `true` if this table has no items. - pub fn is_empty(&self) -> bool { - self.items.is_empty() - } - - /// Returns the index of the currently selected table row. - pub fn row(&self) -> Option { - if self.items.is_empty() { - None - } else { - Some(self.focus) - } - } - - /// Selects the row at the specified index. - pub fn set_selected_row(&mut self, row_index: usize) { - self.focus = row_index; - self.scrollbase.scroll_to(row_index); - } - - /// Selects the row at the specified index. - /// - /// Chainable variant. - pub fn selected_row(self, row_index: usize) -> Self { - self.with(|t| t.set_selected_row(row_index)) - } - - /// Sets the contained items of the table. - /// - /// The currently active sort order is preserved and will be applied to all - /// items. The selected item will also be preserved. - pub fn set_items(&mut self, items: Vec) { - let mut new_location = 0; - if let Some(old_item_location) = self.item() { - let old_item = self.items.get(old_item_location).unwrap(); - for (i, new_item) in items.iter().enumerate() { - if old_item == new_item { - new_location = i; - break; - } - } - } - - self.items = items; - self.rows_to_items = Vec::with_capacity(self.items.len()); - - for i in 0..self.items.len() { - self.rows_to_items.push(i); - } - - if let Some((column, order)) = self.order() { - self.sort_by(column, order); - } - - self.scrollbase - .set_heights(self.last_size.y.saturating_sub(2), self.rows_to_items.len()); - - self.set_selected_item(new_location); - } - - /// Sets the contained items of the table. - /// - /// The order of the items will be preserved even when the table is sorted. - /// - /// Chainable variant. - pub fn items(self, items: Vec) -> Self { - self.with(|t| t.set_items(items)) - } - - /// Returns a immutable reference to the item at the specified index - /// within the underlying storage vector. - pub fn borrow_item(&mut self, index: usize) -> Option<&T> { - self.items.get(index) - } - - /// Returns a mutable reference to the item at the specified index within - /// the underlying storage vector. - pub fn borrow_item_mut(&mut self, index: usize) -> Option<&mut T> { - self.items.get_mut(index) - } - - /// Returns a immutable reference to the items contained within the table. - pub fn borrow_items(&mut self) -> &[T] { - &self.items - } - - /// Returns a mutable reference to the items contained within the table. - /// - /// Can be used to modify the items in place. - pub fn borrow_items_mut(&mut self) -> &mut [T] { - &mut self.items - } - - /// Returns the index of the currently selected item within the underlying - /// storage vector. - pub fn item(&self) -> Option { - if self.items.is_empty() || self.focus >= self.rows_to_items.len() { - None - } else { - Some(self.rows_to_items[self.focus]) - } - } - - /// Selects the item at the specified index within the underlying storage - /// vector. - pub fn set_selected_item(&mut self, item_index: usize) { - // TODO optimize the performance for very large item lists - if item_index < self.items.len() { - for (row, item) in self.rows_to_items.iter().enumerate() { - if *item == item_index { - self.focus = row; - self.scrollbase.scroll_to(row); - break; - } - } - } - } - - /// Selects the item at the specified index within the underlying storage - /// vector. - /// - /// Chainable variant. - pub fn selected_item(self, item_index: usize) -> Self { - self.with(|t| t.set_selected_item(item_index)) - } - - /// Inserts a new item into the table. - /// - /// The currently active sort order is preserved and will be applied to the - /// newly inserted item. - pub fn insert_item(&mut self, item: T) { - self.items.push(item); - self.rows_to_items.push(self.items.len()); - - self.scrollbase - .set_heights(self.last_size.y.saturating_sub(2), self.rows_to_items.len()); - - if let Some((column, order)) = self.order() { - self.sort_by(column, order); - } - } - - /// Removes the item at the specified index within the underlying storage - /// vector and returns it. - pub fn remove_item(&mut self, item_index: usize) -> Option { - if item_index < self.items.len() { - // Move the selection if the currently selected item gets removed - if let Some(selected_index) = self.item() { - if selected_index == item_index { - self.focus_up(1); - } - } - - // Remove the sorted reference to the item - self.rows_to_items.retain(|i| *i != item_index); - - // Adjust remaining references - for ref_index in &mut self.rows_to_items { - if *ref_index > item_index { - *ref_index -= 1; - } - } - - // Update scroll height to prevent out of index drawing - self.scrollbase - .set_heights(self.last_size.y.saturating_sub(2), self.rows_to_items.len()); - - // Remove actual item from the underlying storage - Some(self.items.remove(item_index)) - } else { - None - } - } - - /// Removes all items from the underlying storage and returns them. - pub fn take_items(&mut self) -> Vec { - self.scrollbase - .set_heights(self.last_size.y.saturating_sub(2), 0); - self.set_selected_row(0); - self.rows_to_items.clear(); - self.items.drain(0..).collect() - } -} - -impl + PartialEq, H: Eq + Hash + Copy + Clone + 'static> TableView { - fn draw_columns, &TableColumn)>( - &self, - printer: &Printer<'_, '_>, - sep: &str, - callback: C, - ) { - let mut column_offset = 0; - let column_count = self.columns.len(); - for (index, column) in self.columns.iter().enumerate() { - let printer = &printer.offset((column_offset, 0)).focused(true); - - callback(printer, column); - - if index < column_count - 1 { - printer.print((column.width + 1, 0), sep); - } - - column_offset += column.width + 3; - } - } - - fn sort_items(&mut self, column: H, order: Ordering) { - if !self.is_empty() { - let old_item = self.item(); - - let mut rows_to_items = self.rows_to_items.clone(); - rows_to_items.sort_by(|a, b| { - if order == Ordering::Less { - self.items[*a].cmp(&self.items[*b], column) - } else { - self.items[*b].cmp(&self.items[*a], column) - } - }); - self.rows_to_items = rows_to_items; - if let Some(o) = old_item { - self.set_selected_item(o) - } - } - } - - fn draw_item(&self, printer: &Printer<'_, '_>, i: usize) { - self.draw_columns(printer, "┆ ", |printer, column| { - let value = self.items[self.rows_to_items[i]].to_column(column.column); - column.draw_row(printer, value.as_str()); - }); - } - - fn focus_up(&mut self, n: usize) { - self.focus -= cmp::min(self.focus, n); - } - - fn focus_down(&mut self, n: usize) { - self.focus = cmp::min(self.focus + n, self.items.len() - 1); - } - - fn active_column(&self) -> usize { - self.columns.iter().position(|c| c.selected).unwrap_or(0) - } - - fn column_cancel(&mut self) { - self.column_select = false; - for column in &mut self.columns { - column.selected = column.order != Ordering::Equal; - } - } - - fn column_next(&mut self) -> bool { - let column = self.active_column(); - if column < self.columns.len() - 1 { - self.columns[column].selected = false; - self.columns[column + 1].selected = true; - true - } else { - false - } - } - - fn column_prev(&mut self) -> bool { - let column = self.active_column(); - if column > 0 { - self.columns[column].selected = false; - self.columns[column - 1].selected = true; - true - } else { - false - } - } - - fn column_select(&mut self) { - let next = self.active_column(); - let column = self.columns[next].column; - let current = self - .columns - .iter() - .position(|c| c.order != Ordering::Equal) - .unwrap_or(0); - - let order = if current != next { - self.columns[next].default_order - } else if self.columns[current].order == Ordering::Less { - Ordering::Greater - } else { - Ordering::Less - }; - - self.sort_by(column, order); - } -} - -impl + PartialEq + 'static, H: Eq + Hash + Copy + Clone + 'static> View - for TableView -{ - fn draw(&self, printer: &Printer<'_, '_>) { - self.draw_columns(printer, "╷ ", |printer, column| { - let color = if column.order != Ordering::Equal || column.selected { - if self.column_select && column.selected && self.enabled && printer.focused { - Highlight - } else { - HighlightInactive - } - } else { - Primary - }; - - printer.with_color(ColorStyle::from(color), |printer| { - column.draw_header(printer); - }); - }); - - self.draw_columns( - &printer.offset((0, 1)).focused(true), - "┴─", - |printer, column| { - printer.print_hline((0, 0), column.width + 1, "─"); - }, - ); - - let printer = &printer.offset((0, 2)).focused(true); - self.scrollbase.draw(printer, |printer, i| { - let color = if i == self.focus { - if !self.column_select && self.enabled && printer.focused { - Highlight - } else { - HighlightInactive - } - } else { - Primary - }; - - printer.with_color(ColorStyle::from(color), |printer| { - self.draw_item(printer, i); - }); - }); - } - - fn layout(&mut self, size: Vec2) { - if size == self.last_size { - return; - } - - let item_count = self.items.len(); - let column_count = self.columns.len(); - - // Split up all columns into sized / unsized groups - let (mut sized, mut usized): (Vec<&mut TableColumn>, Vec<&mut TableColumn>) = self - .columns - .iter_mut() - .partition(|c| c.requested_width.is_some()); - - // Subtract one for the separators between our columns (that's column_count - 1) - let mut available_width = size.x.saturating_sub(column_count.saturating_sub(1) * 3); - - // Reduce the with in case we are displaying a scrollbar - if size.y.saturating_sub(1) < item_count { - available_width = available_width.saturating_sub(2); - } - - // Calculate widths for all requested columns - let mut remaining_width = available_width; - for column in &mut sized { - column.width = match *column.requested_width.as_ref().unwrap() { - TableColumnWidth::Percent(width) => cmp::min( - (size.x as f32 / 100.0 * width as f32).ceil() as usize, - remaining_width, - ), - TableColumnWidth::Absolute(width) => width, - }; - remaining_width = remaining_width.saturating_sub(column.width); - } - - // Spread the remaining with across the unsized columns - let remaining_columns = usized.len(); - for column in &mut usized { - column.width = (remaining_width as f32 / remaining_columns as f32).floor() as usize; - } - - self.scrollbase - .set_heights(size.y.saturating_sub(2), item_count); - self.last_size = size; - } - - fn take_focus(&mut self, _: Direction) -> bool { - self.enabled && !self.items.is_empty() - } - - fn on_event(&mut self, event: Event) -> EventResult { - if !self.enabled { - return EventResult::Ignored; - } - - let last_focus = self.focus; - match event { - Event::Key(Key::Right) => { - if self.column_select { - if !self.column_next() { - return EventResult::Ignored; - } - } else { - self.column_select = true; - } - } - Event::Key(Key::Left) => { - if self.column_select { - if !self.column_prev() { - return EventResult::Ignored; - } - } else { - self.column_select = true; - } - } - Event::Key(Key::Up) if self.focus > 0 || self.column_select => { - if self.column_select { - self.column_cancel(); - } else { - self.focus_up(1); - } - } - Event::Key(Key::Down) if self.focus + 1 < self.items.len() || self.column_select => { - if self.column_select { - self.column_cancel(); - } else { - self.focus_down(1); - } - } - Event::Key(Key::PageUp) => { - self.column_cancel(); - self.focus_up(10); - } - Event::Key(Key::PageDown) => { - self.column_cancel(); - self.focus_down(10); - } - Event::Key(Key::Home) => { - self.column_cancel(); - self.focus = 0; - } - Event::Key(Key::End) => { - self.column_cancel(); - self.focus = self.items.len() - 1; - } - Event::Key(Key::Enter) => { - if self.column_select { - self.column_select(); - - if self.on_sort.is_some() { - let c = &self.columns[self.active_column()]; - let column = c.column; - let order = c.order; - - let cb = self.on_sort.clone().unwrap(); - return EventResult::Consumed(Some(Callback::from_fn(move |s| { - cb(s, column, order) - }))); - } - } else if !self.is_empty() && self.on_submit.is_some() { - let cb = self.on_submit.clone().unwrap(); - let row = self.row().unwrap(); - let index = self.item().unwrap(); - return EventResult::Consumed(Some(Callback::from_fn(move |s| { - cb(s, row, index) - }))); - } - } - _ => return EventResult::Ignored, - } - - let focus = self.focus; - self.scrollbase.scroll_to(focus); - - if self.column_select { - EventResult::Consumed(None) - } else if !self.is_empty() && last_focus != focus { - let row = self.row().unwrap(); - let index = self.item().unwrap(); - EventResult::Consumed( - self.on_select - .clone() - .map(|cb| Callback::from_fn(move |s| cb(s, row, index))), - ) - } else { - EventResult::Ignored - } - } -} - -/// A type used for the construction of columns in a -/// [`TableView`](struct.TableView.html). -pub struct TableColumn { - column: H, - title: String, - selected: bool, - alignment: HAlign, - order: Ordering, - width: usize, - default_order: Ordering, - requested_width: Option, -} - -enum TableColumnWidth { - Percent(usize), - Absolute(usize), -} - -impl TableColumn { - /// Sets the default ordering of the column. - pub fn ordering(mut self, order: Ordering) -> Self { - self.default_order = order; - self - } - - /// Sets the horizontal text alignment of the column. - pub fn align(mut self, alignment: HAlign) -> Self { - self.alignment = alignment; - self - } - - /// Sets how many characters of width this column will try to occupy. - pub fn width(mut self, width: usize) -> Self { - self.requested_width = Some(TableColumnWidth::Absolute(width)); - self - } - - /// Sets what percentage of the width of the entire table this column will - /// try to occupy. - pub fn width_percent(mut self, width: usize) -> Self { - self.requested_width = Some(TableColumnWidth::Percent(width)); - self - } - - fn new(column: H, title: String) -> Self { - Self { - column: column, - title: title, - selected: false, - alignment: HAlign::Left, - order: Ordering::Equal, - width: 0, - default_order: Ordering::Less, - requested_width: None, - } - } - - fn draw_header(&self, printer: &Printer<'_, '_>) { - let order = match self.order { - Ordering::Less => "^", - Ordering::Greater => "v", - Ordering::Equal => " ", - }; - - let header = match self.alignment { - HAlign::Left => format!( - "{: format!( - "{:>width$} [{}]", - self.title, - order, - width = self.width.saturating_sub(4) - ), - HAlign::Center => format!( - "{:^width$} [{}]", - self.title, - order, - width = self.width.saturating_sub(4) - ), - }; - printer.print((0, 0), header.as_str()); - } - - fn draw_row(&self, printer: &Printer<'_, '_>, value: &str) { - let value = match self.alignment { - HAlign::Left => format!("{: format!("{:>width$} ", value, width = self.width), - HAlign::Center => format!("{:^width$} ", value, width = self.width), - }; - printer.print((0, 0), value.as_str()); - } -} - -#[cfg(test)] -mod test { - use crate::p2p::Capabilities; - use crate::tui::peers::PeerColumn; - use crate::tui::table::TableView; - use chrono::Utc; - use grin_core::ser::ProtocolVersion; - use grin_servers::PeerStats; - use std::cmp::Ordering; - - #[test] - pub fn test_set_items_preserves_selected_item() { - let mut table = TableView::::new(); - let ps1 = PeerStats { - addr: "123.0.0.1".to_string(), - ..TestPeerStats::default() - }; - let ps2 = PeerStats { - addr: "123.0.0.2".to_string(), - ..TestPeerStats::default() - }; - - let mut items = vec![ps1, ps2]; - table.set_items(items.clone()); - assert_eq!(table.item().unwrap(), 0); - - items.reverse(); - table.set_items(items); - assert_eq!(table.item().unwrap(), 1); - } - - #[test] - pub fn test_set_items_preserves_order() { - let mut table = TableView::::new(); - let ps1 = PeerStats { - addr: "123.0.0.1".to_string(), - received_bytes_per_sec: 10, - ..TestPeerStats::default() - }; - let ps2 = PeerStats { - addr: "123.0.0.2".to_string(), - received_bytes_per_sec: 80, - ..TestPeerStats::default() - }; - - let items = vec![ps1, ps2]; - table.set_items(items); - assert_eq!(table.rows_to_items[0], 0); - table.sort_by(PeerColumn::UsedBandwidth, Ordering::Greater); - - assert_eq!(table.rows_to_items[0], 1); - } - - struct TestPeerStats(PeerStats); - - impl TestPeerStats { - fn default() -> PeerStats { - PeerStats { - state: "Connected".to_string(), - addr: "127.0.0.1".to_string(), - version: ProtocolVersion::local(), - user_agent: "".to_string(), - total_difficulty: 0, - height: 0, - direction: "Outbound".to_string(), - last_seen: Utc::now(), - sent_bytes_per_sec: 0, - received_bytes_per_sec: 0, - capabilities: Capabilities::default(), - } - } - } -} diff --git a/src/bin/tui/ui.rs b/src/bin/tui/ui.rs index bcedb7baad..f5dc912b8a 100644 --- a/src/bin/tui/ui.rs +++ b/src/bin/tui/ui.rs @@ -29,8 +29,7 @@ use cursive::utils::markup::StyledString; use cursive::views::{ CircularFocus, Dialog, LinearLayout, Panel, SelectView, StackView, TextView, ViewRef, }; -use cursive::Cursive; -use cursive::CursiveExt; +use cursive::{CursiveRunnable, CursiveRunner}; use std::sync::mpsc; use std::{thread, time}; @@ -44,7 +43,7 @@ use grin_core::global; use grin_util::logger::LogEntry; pub struct UI { - cursive: Cursive, + cursive: CursiveRunner, ui_rx: mpsc::Receiver, ui_tx: mpsc::Sender, controller_tx: mpsc::Sender, @@ -72,7 +71,7 @@ impl UI { let (ui_tx, ui_rx) = mpsc::channel::(); let mut grin_ui = UI { - cursive: Cursive::default(), + cursive: cursive::default().into_runner(), ui_tx, ui_rx, controller_tx,