Compare commits

...

5 Commits
0.2.0 ... main

12 changed files with 542 additions and 496 deletions

342
Cargo.lock generated
View File

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "CoreFoundation-sys"
version = "0.1.4"
@ -21,6 +23,12 @@ dependencies = [
"mach 0.1.2",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "adler32"
version = "1.2.0"
@ -44,23 +52,21 @@ checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
[[package]]
name = "atk"
version = "0.9.0"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812b4911e210bd51b24596244523c856ca749e6223c50a7fbbba3f89ee37c426"
checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd"
dependencies = [
"atk-sys",
"bitflags",
"glib",
"glib-sys",
"gobject-sys",
"libc",
]
[[package]]
name = "atk-sys"
version = "0.10.0"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f530e4af131d94cc4fa15c5c9d0348f0ef28bac64ba660b6b2a1cf2605dedfce"
checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6"
dependencies = [
"glib-sys",
"gobject-sys",
@ -76,36 +82,28 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
version = "1.2.1"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cairo-rs"
version = "0.9.1"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5c0f2e047e8ca53d0ff249c54ae047931d7a6ebe05d00af73e0ffeb6e34bdb8"
checksum = "e8b14c80d8d1a02fa6d914b9d1afeeca9bc34257f8300d9696e1e331ae114223"
dependencies = [
"bitflags",
"cairo-sys-rs",
"glib",
"glib-sys",
"gobject-sys",
"libc",
"thiserror",
]
[[package]]
name = "cairo-sys-rs"
version = "0.10.0"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ed2639b9ad5f1d6efa76de95558e11339e7318426d84ac4890b86c03e828ca7"
checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8"
dependencies = [
"glib-sys",
"libc",
@ -118,6 +116,15 @@ version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
[[package]]
name = "cfg-expr"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e068cb2806bbc15b439846dc16c5f89f8599f2c3e4d73d4449d38f9b2f0b6c5"
dependencies = [
"smallvec",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
@ -132,28 +139,31 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crc32fast"
version = "1.2.1"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "deflate"
version = "0.8.6"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174"
checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f"
dependencies = [
"adler32",
"byteorder",
]
[[package]]
name = "either"
version = "1.6.1"
name = "field-offset"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92"
dependencies = [
"memoffset",
"rustc_version",
]
[[package]]
name = "fuchsia-cprng"
@ -161,21 +171,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "futures"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.14"
@ -183,7 +178,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
@ -209,24 +203,6 @@ version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04"
[[package]]
name = "futures-macro"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b"
dependencies = [
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23"
[[package]]
name = "futures-task"
version = "0.3.14"
@ -239,60 +215,47 @@ version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"proc-macro-hack",
"proc-macro-nested",
"slab",
]
[[package]]
name = "gdk"
version = "0.13.2"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db00839b2a68a7a10af3fa28dfb3febaba3a20c3a9ac2425a33b7df1f84a6b7d"
checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8"
dependencies = [
"bitflags",
"cairo-rs",
"cairo-sys-rs",
"gdk-pixbuf",
"gdk-sys",
"gio",
"gio-sys",
"glib",
"glib-sys",
"gobject-sys",
"libc",
"pango",
]
[[package]]
name = "gdk-pixbuf"
version = "0.9.0"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f6dae3cb99dd49b758b88f0132f8d401108e63ae8edd45f432d42cdff99998a"
checksum = "d8750501d75f318c2ec0314701bc8403901303210def80bafd13f6b6059a3f45"
dependencies = [
"bitflags",
"gdk-pixbuf-sys",
"gio",
"gio-sys",
"glib",
"glib-sys",
"gobject-sys",
"libc",
]
[[package]]
name = "gdk-pixbuf-sys"
version = "0.10.0"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bfe468a7f43e97b8d193a762b6c5cf67a7d36cacbc0b9291dbcae24bfea1e8f"
checksum = "413424d9818621fa3cfc8a3a915cdb89a7c3c507d56761b4ec83a9a98e587171"
dependencies = [
"gio-sys",
"glib-sys",
@ -303,9 +266,9 @@ dependencies = [
[[package]]
name = "gdk-sys"
version = "0.10.0"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a9653cfc500fd268015b1ac055ddbc3df7a5c9ea3f4ccef147b3957bd140d69"
checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88"
dependencies = [
"cairo-sys-rs",
"gdk-pixbuf-sys",
@ -331,20 +294,16 @@ dependencies = [
[[package]]
name = "gio"
version = "0.9.1"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fb60242bfff700772dae5d9e3a1f7aa2e4ebccf18b89662a16acb2822568561"
checksum = "96efd8a1c00d890f6b45671916e165b5e43ccec61957d443aff6d7e44f62d348"
dependencies = [
"bitflags",
"futures",
"futures-channel",
"futures-core",
"futures-io",
"futures-util",
"gio-sys",
"glib",
"glib-sys",
"gobject-sys",
"libc",
"once_cell",
"thiserror",
@ -352,9 +311,9 @@ dependencies = [
[[package]]
name = "gio-sys"
version = "0.10.1"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e24fb752f8f5d2cf6bbc2c606fd2bc989c81c5e2fe321ab974d54f8b6344eac"
checksum = "1d0fa5052773f5a56b8ae47dab09d040f5d9ce1311f4f99006e16e9a08269296"
dependencies = [
"glib-sys",
"gobject-sys",
@ -365,32 +324,32 @@ dependencies = [
[[package]]
name = "glib"
version = "0.10.3"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5"
checksum = "aa570813c504bdf7539a9400180c2dd4b789a819556fb86da7226d7d1b037b49"
dependencies = [
"bitflags",
"futures-channel",
"futures-core",
"futures-executor",
"futures-task",
"futures-util",
"glib-macros",
"glib-sys",
"gobject-sys",
"libc",
"once_cell",
"smallvec",
"thiserror",
]
[[package]]
name = "glib-macros"
version = "0.10.1"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41486a26d1366a8032b160b59065a59fb528530a46a49f627e7048fb8c064039"
checksum = "41bfd8d227dead0829ac142454e97531b93f576d0805d779c42bfd799c65c572"
dependencies = [
"anyhow",
"heck",
"itertools",
"proc-macro-crate",
"proc-macro-error",
"proc-macro2",
@ -400,9 +359,9 @@ dependencies = [
[[package]]
name = "glib-sys"
version = "0.10.1"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1"
checksum = "f4366377bd56697de8aaee24e673c575d2694d72e7756324ded2b0428829a7b8"
dependencies = [
"libc",
"system-deps",
@ -410,9 +369,9 @@ dependencies = [
[[package]]
name = "gobject-sys"
version = "0.10.0"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c"
checksum = "df6859463843c20cf3837e3a9069b6ab2051aeeadf4c899d33344f4aea83189a"
dependencies = [
"glib-sys",
"libc",
@ -421,37 +380,32 @@ dependencies = [
[[package]]
name = "gtk"
version = "0.9.2"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f022f2054072b3af07666341984562c8e626a79daa8be27b955d12d06a5ad6a"
checksum = "5f2d1326b36af927fe46ae2f89a8fec38c6f0d279ebc5ef07ffeeabb70300bfc"
dependencies = [
"atk",
"bitflags",
"cairo-rs",
"cairo-sys-rs",
"cc",
"field-offset",
"futures-channel",
"gdk",
"gdk-pixbuf",
"gdk-pixbuf-sys",
"gdk-sys",
"gio",
"gio-sys",
"glib",
"glib-sys",
"gobject-sys",
"gtk-sys",
"gtk3-macros",
"libc",
"once_cell",
"pango",
"pango-sys",
"pkg-config",
]
[[package]]
name = "gtk-sys"
version = "0.10.0"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89acda6f084863307d948ba64a4b1ef674e8527dddab147ee4cdcc194c880457"
checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84"
dependencies = [
"atk-sys",
"cairo-sys-rs",
@ -466,14 +420,25 @@ dependencies = [
]
[[package]]
name = "heck"
version = "0.3.2"
name = "gtk3-macros"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac"
checksum = "24f518afe90c23fba585b2d7697856f9e6a7bbc62f65588035e66f6afb01a2e9"
dependencies = [
"unicode-segmentation",
"anyhow",
"proc-macro-crate",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
version = "0.1.18"
@ -483,15 +448,6 @@ dependencies = [
"libc",
]
[[package]]
name = "itertools"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
dependencies = [
"either",
]
[[package]]
name = "libc"
version = "0.2.94"
@ -547,17 +503,26 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.3.4"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "miniz_oxide"
version = "0.3.7"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
dependencies = [
"adler32",
"adler",
]
[[package]]
@ -591,14 +556,12 @@ checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
[[package]]
name = "pango"
version = "0.9.1"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9937068580bebd8ced19975938573803273ccbcbd598c58d4906efd4ac87c438"
checksum = "78c7420fc01a390ec200da7395b64d705f5d82fe03e5d0708aee422c46538be7"
dependencies = [
"bitflags",
"glib",
"glib-sys",
"gobject-sys",
"libc",
"once_cell",
"pango-sys",
@ -606,9 +569,9 @@ dependencies = [
[[package]]
name = "pango-sys"
version = "0.10.0"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d2650c8b62d116c020abd0cea26a4ed96526afda89b1c4ea567131fdefc890"
checksum = "7022c2fb88cd2d9d55e1a708a8c53a3ae8678234c4a54bf623400aeb7f31fac2"
dependencies = [
"glib-sys",
"gobject-sys",
@ -616,6 +579,15 @@ dependencies = [
"system-deps",
]
[[package]]
name = "pest"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
dependencies = [
"ucd-trie",
]
[[package]]
name = "pin-project-lite"
version = "0.2.6"
@ -636,9 +608,9 @@ checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[package]]
name = "png"
version = "0.16.8"
version = "0.17.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6"
checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba"
dependencies = [
"bitflags",
"crc32fast",
@ -654,10 +626,11 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a"
dependencies = [
"thiserror",
"toml",
]
@ -685,23 +658,11 @@ dependencies = [
"version_check",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro-nested"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
[[package]]
name = "proc-macro2"
version = "1.0.26"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
@ -819,6 +780,33 @@ version = "0.6.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
[[package]]
name = "rustc_version"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
dependencies = [
"semver",
]
[[package]]
name = "semver"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
dependencies = [
"pest",
]
[[package]]
name = "serde"
version = "1.0.125"
@ -849,28 +837,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
[[package]]
name = "strum"
version = "0.18.0"
name = "smallvec"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b"
[[package]]
name = "strum_macros"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
[[package]]
name = "syn"
version = "1.0.70"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
"proc-macro2",
"quote",
@ -879,22 +855,20 @@ dependencies = [
[[package]]
name = "system-deps"
version = "1.3.2"
version = "6.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b"
checksum = "a1a45a1c4c9015217e12347f2a411b57ce2c4fc543913b14b6fe40483328e709"
dependencies = [
"cfg-expr",
"heck",
"pkg-config",
"strum",
"strum_macros",
"thiserror",
"toml",
"version-compare",
]
[[package]]
name = "tarangam"
version = "0.2.0"
version = "0.3.1"
dependencies = [
"cairo-rs",
"gdk",
@ -961,10 +935,10 @@ dependencies = [
]
[[package]]
name = "unicode-segmentation"
version = "1.7.1"
name = "ucd-trie"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "unicode-xid"
@ -974,9 +948,9 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "version-compare"
version = "0.0.10"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1"
checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73"
[[package]]
name = "version_check"

View File

@ -1,25 +1,31 @@
[package]
name = "tarangam"
version = "0.2.0"
version = "0.3.1"
authors = ["PiyushXCoder <piyush.raj.kit@gmail.com>"]
license = "GPL 3.0"
license = "GPL-3.0-only"
edition = "2018"
documentation = "A simple serial plotter. एक सरल सीरीय्ल पलौटर।"
description = "A simple serial plotter. एक सरल सीरीय्ल पलौटर।"
readme = "README.md"
repository = "https://github.com/PiyushXCoder/Tarangam"
keywords = ["plotter","serial","serialplotter","arduino","gtk"]
keywords = ["plotter", "serial", "serialplotter", "arduino", "gtk"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio = { version = "1.5.0", features = ["rt", "rt-multi-thread", "macros", "time", "sync"] }
gtk = "0.9.2"
gdk = "0.13.2"
gio = "0.9.1"
glib = "0.10.3"
png = "0.16.8"
cairo-rs = { version = "0.9.1", features = ["png"] }
tokio = { version = "1.5.0", features = [
"rt",
"rt-multi-thread",
"macros",
"time",
"sync",
] }
gtk = "0.15"
gdk = "0.15"
gio = "0.15"
glib = "0.15"
png = "0.17"
cairo-rs = { version = "0.15", features = ["png"] }
rand = "0.8.1"
libmath = "0.2.1"
serialport = "4.0.1"

View File

@ -1,6 +1,5 @@
# Tarangam
It is a simple application to see log from [serialports](https://wiki.osdev.org/Serial_Ports) and plot information on graph. You can use it with IOT boards([ardino](https://www.arduino.cc/), [esp boards](https://www.espressif.com/),...) in you DIY projects. It gives to many basic controls to control graph.
It is a straightforward application to see the logs from [serial ports](https://wiki.osdev.org/Serial_Ports) and plot information on graph. You can use it with IOT boards ([Arduino](https://www.arduino.cc/), [ESP boards](https://www.espressif.com/),...) in your DIY projects. It gives many basic controls to modify the graph.
## Interface
![1](screenshots/1.png)

BIN
chitra-small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -1,20 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000"
height="1000"
width="256"
height="256"
viewBox="0 0 1000 1000"
version="1.1"
id="svg8"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="icon.svg">
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
sodipodi:docname="chitra.svg"
inkscape:export-filename="/home/piyush/Projects/tarangam/chitra-small.png"
inkscape:export-xdpi="24"
inkscape:export-ydpi="24"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2">
<linearGradient
@ -47,19 +50,20 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="605.76766"
inkscape:cy="248.85918"
inkscape:cx="607.14286"
inkscape:cy="250"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
inkscape:window-width="1214"
inkscape:window-height="757"
inkscape:window-x="295"
inkscape:window-y="198"
inkscape:window-maximized="0"
inkscape:window-width="1920"
inkscape:window-height="1002"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
units="px"
showguides="false">
showguides="false"
inkscape:pagecheckerboard="1">
<inkscape:grid
type="xygrid"
id="grid869" />

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -20,41 +20,42 @@
use gtk::prelude::*;
use gtk::DrawingArea;
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
/// A single line
#[derive(Debug)]
pub struct Line {
pub points: Vec<(f64,f64)>,
pub color: (f64, f64, f64)
pub(crate) struct Line {
pub(crate) points: Vec<(f64, f64)>,
pub(crate) color: (f64, f64, f64),
}
impl Line {
pub fn new(r: f64, g: f64, b: f64, points: Vec<(f64,f64)>) -> Self {
pub(crate) fn new(r: f64, g: f64, b: f64, points: Vec<(f64, f64)>) -> Self {
Line {
points,
color: (r,g,b)
color: (r, g, b),
}
}
}
/// Tools to draw Graph
pub struct Graph {
pub area: DrawingArea,
pub scale_x_start: f64, // start of x on pankti
pub scale_x_size: f64, // size of pankti to show
pub scale_y_start: f64, // start of y on stambh
pub scale_y_size: f64, // size of stambh to show
pub draw_patch: bool, // enable to draw circle spot on line
pub draw_box: bool, // enable to show boxes linke graph paper
pub draw_baarik_box: bool, // enable to show baarik(similar meaning to smaller) linke graph paper
pub auto_adjust_y: bool, // enable to automatically adjust y axis
pub lines: HashMap<String, Line>,
pub pankti_sankya: f64 // use used while adding to point in lines to see last count of graphable input
pub(crate) struct Graph {
pub(crate) area: DrawingArea,
pub(crate) scale_x_start: f64, // start of x on pankti
pub(crate) scale_x_size: f64, // size of pankti to show
pub(crate) scale_y_start: f64, // start of y on stambh
pub(crate) scale_y_size: f64, // size of stambh to show
pub(crate) draw_patch: bool, // enable to draw circle spot on line
pub(crate) draw_box: bool, // enable to show boxes linke graph paper
pub(crate) draw_baarik_box: bool, // enable to show baarik(similar meaning to smaller) linke graph paper
pub(crate) auto_adjust_y: bool, // enable to automatically adjust y axis
pub(crate) lines: HashMap<String, Line>,
pub(crate) pankti_sankya: f64, // use used while adding to point in lines to see last count of graphable input
}
impl Graph {
pub fn new(area: DrawingArea,
pub(crate) fn new(
area: DrawingArea,
scale_x_start: f64,
scale_x_size: f64,
scale_y_start: f64,
@ -64,8 +65,8 @@ impl Graph {
draw_baarik_box: bool,
auto_adjust_y: bool,
lines: HashMap<String, Line>,
pankti_sankya: f64) -> Rc<RefCell<Self>> {
pankti_sankya: f64,
) -> Rc<RefCell<Self>> {
let graph = Rc::new(RefCell::new(Graph {
area,
scale_x_start,
@ -77,11 +78,11 @@ impl Graph {
draw_baarik_box,
auto_adjust_y,
lines,
pankti_sankya
pankti_sankya,
}));
let graph_tmp = Rc::clone(&graph);
graph.borrow().area.connect_draw(move |area,ctx| {
graph.borrow().area.connect_draw(move |area, ctx| {
Graph::draw(area, ctx, &graph_tmp);
Inhibit(false)
});
@ -90,57 +91,62 @@ impl Graph {
}
/// used to draw box and baarik box
fn draw_boxes(ctx: &cairo::Context, area_width: f64, area_height: f64, src_x: f64, cell_size: f64, color: f64) {
fn draw_boxes(
ctx: &cairo::Context,
area_width: f64,
area_height: f64,
src_x: f64,
cell_size: f64,
color: f64,
) {
ctx.set_source_rgb(color, color, color);
ctx.set_line_width(1.0);
// lines parallel to stambh
for i in 1..math::round::ceil(area_width/cell_size, 0) as i32 {
for i in 1..math::round::ceil(area_width / cell_size, 0) as i32 {
let xi = i as f64 * cell_size + src_x;
ctx.move_to(xi, 0.0);
ctx.line_to(xi, area_height);
}
// lines parallel to pankti
for i in 1..math::round::ceil(area_height/cell_size, 0) as i32 {
for i in 1..math::round::ceil(area_height / cell_size, 0) as i32 {
let yi = area_height - i as f64 * cell_size;
ctx.move_to(src_x, yi);
ctx.line_to(area_width + src_x, yi);
}
ctx.stroke();
ctx.stroke().unwrap();
}
/// transform point to show on graph
fn transform_on_graph(
p_start: f64,
s_start: f64,
p: f64,
s: f64,
aa_dumm_pankti: f64,
aa_dumm_stambh: f64,
s_start: f64,
p: f64,
s: f64,
aa_dumm_pankti: f64,
aa_dumm_stambh: f64,
scale_x_size: f64,
scale_y_size: f64,
height: f64,
stambh_scale_width: f64) -> (f64, f64){
stambh_scale_width: f64,
) -> (f64, f64) {
(
((p - p_start) * aa_dumm_pankti)/scale_x_size + stambh_scale_width,
height - ((s - s_start) * aa_dumm_stambh) / scale_y_size
((p - p_start) * aa_dumm_pankti) / scale_x_size + stambh_scale_width,
height - ((s - s_start) * aa_dumm_stambh) / scale_y_size,
)
}
/// callback of drawing area to draw graph
fn draw(area: &gtk::DrawingArea,
ctx: &cairo::Context,
graph: &Rc<RefCell<Graph>>) {
fn draw(area: &gtk::DrawingArea, ctx: &cairo::Context, graph: &Rc<RefCell<Graph>>) {
let graph = graph.borrow();
ctx.set_source_rgb(0.1, 0.5, 0.5);
ctx.paint();
ctx.paint().unwrap();
let pankti_scale_height = 50.0;
let stambh_scale_width = 60.0;
let width = area.get_allocated_width() as f64 - stambh_scale_width;
let height = area.get_allocated_height() as f64 - pankti_scale_height;
let width = area.allocated_width() as f64 - stambh_scale_width;
let height = area.allocated_height() as f64 - pankti_scale_height;
let manjusa_maap = 50.0;
let rekha_sankhya_pankti = math::round::floor(width / manjusa_maap, 0);
@ -164,13 +170,13 @@ impl Graph {
ctx.set_line_width(2.0);
ctx.set_line_cap(cairo::LineCap::Round);
let draw_patch = graph.draw_patch;
for (_,line) in graph.lines.iter() {
for (i, (p,s)) in line.points.iter().enumerate() {
for (_, line) in graph.lines.iter() {
for (i, (p, s)) in line.points.iter().enumerate() {
// check if point is last poin on line
let (p_dumm, s_dumm) = if i < line.points.len() - 1 {
line.points[i + 1]
let (p_dumm, s_dumm) = if i < line.points.len() - 1 {
line.points[i + 1]
} else {
line.points[i]
line.points[i]
};
let bindu_t = Graph::transform_on_graph(
@ -202,14 +208,19 @@ impl Graph {
ctx.set_source_rgb(line.color.0, line.color.1, line.color.2);
ctx.move_to(bindu_dumm_t.0, bindu_dumm_t.1);
ctx.line_to(bindu_t.0, bindu_t.1);
ctx.stroke();
ctx.stroke().unwrap();
// draw circle over point
if draw_patch {
ctx.set_source_rgb(0.0, 0.0, 1.0);
ctx.arc(bindu_dumm_t.0, bindu_dumm_t.1,
5.0, 0.0, std::f64::consts::PI * 2.0);
ctx.stroke();
ctx.arc(
bindu_dumm_t.0,
bindu_dumm_t.1,
5.0,
0.0,
std::f64::consts::PI * 2.0,
);
ctx.stroke().unwrap();
}
}
}
@ -218,33 +229,41 @@ impl Graph {
ctx.set_source_rgb(0.1, 0.4, 0.4);
ctx.rectangle(0.0, 0.0, stambh_scale_width, height + pankti_scale_height);
ctx.rectangle(stambh_scale_width, height, width, pankti_scale_height);
ctx.fill();
ctx.fill().unwrap();
ctx.set_source_rgb(1.0, 1.0, 1.0);
// write numbers on pankti scale
for i in 0..(rekha_sankhya_pankti as i32 + 1) {
let text = math::round::floor(i as f64 * anupat_pankti + graph.scale_x_start, 4).to_string();
let f = ctx.text_extents(&text);
ctx.move_to(i as f64 * manjusa_maap - f.width + stambh_scale_width + f.height / 0.866, height + f.width * 0.5 + f.height);
ctx.save();
let text =
math::round::floor(i as f64 * anupat_pankti + graph.scale_x_start, 4).to_string();
let f = ctx.text_extents(&text).expect("Text dimension");
ctx.move_to(
i as f64 * manjusa_maap - f.width + stambh_scale_width + f.height / 0.866,
height + f.width * 0.5 + f.height,
);
ctx.save().unwrap();
ctx.rotate(std::f64::consts::PI / -6.0);
ctx.show_text(&text);
ctx.restore();
ctx.show_text(&text).unwrap();
ctx.restore().unwrap();
}
// write numbers on stambh scale
for i in (0..aa_dumm_stambh as i32 + 1).rev() {
let text = math::round::floor(i as f64 * anupat_stambh + graph.scale_y_start, 4).to_string();
let f = ctx.text_extents(&text);
ctx.move_to(stambh_scale_width - f.width, height - i as f64 * manjusa_maap + f.width * 0.5);
ctx.save();
let text =
math::round::floor(i as f64 * anupat_stambh + graph.scale_y_start, 4).to_string();
let f = ctx.text_extents(&text).expect("Text dimension");
ctx.move_to(
stambh_scale_width - f.width,
height - i as f64 * manjusa_maap + f.width * 0.5,
);
ctx.save().unwrap();
ctx.rotate(std::f64::consts::PI / -6.0);
ctx.show_text(&text);
ctx.restore();
ctx.show_text(&text).unwrap();
ctx.restore().unwrap();
}
}
/// Adjust stambh and pankti as needed , trim lines and redraws
pub fn redraw(&mut self) {
pub(crate) fn redraw(&mut self) {
let (mx_x, mi_x, mx_y, mi_y) = self.get_extremes();
// stambh
@ -253,13 +272,13 @@ impl Graph {
self.scale_y_start = mi_y - spread * 0.1;
self.scale_y_size = spread * 1.2;
}
// pankti
let spread = (mx_x - mi_x).abs();
if spread < self.scale_x_size {
self.scale_x_start = mi_x;
if spread < self.scale_x_size {
self.scale_x_start = mi_x;
} else {
self.scale_x_start = mx_x - self.scale_x_size;
self.scale_x_start = mx_x - self.scale_x_size;
}
self.trim_lines(); // trim
@ -267,16 +286,16 @@ impl Graph {
}
/// find minimun and maximum value from all lines
pub fn get_extremes(&self) -> (f64, f64, f64, f64){
// trick to avoid no lines
pub(crate) fn get_extremes(&self) -> (f64, f64, f64, f64) {
// trick to avoid no lines
if self.lines.len() == 0 {
return (0.0,0.0,0.0,0.0);
return (0.0, 0.0, 0.0, 0.0);
}
let mut mx_x:Option<f64> = None;
let mut mi_x:Option<f64> = None;
let mut mx_y:Option<f64> = None;
let mut mi_y:Option<f64> = None;
let mut mx_x: Option<f64> = None;
let mut mi_x: Option<f64> = None;
let mut mx_y: Option<f64> = None;
let mut mi_y: Option<f64> = None;
for (_, line) in self.lines.iter() {
if line.points.len() == 0 {
@ -307,7 +326,7 @@ impl Graph {
mi_y = Some(line.points[0].1);
}
for (x,y) in line.points.iter().skip(1) {
for (x, y) in line.points.iter().skip(1) {
mx_x = Some(f64::max(mx_x.unwrap(), *x));
mi_x = Some(f64::min(mi_x.unwrap(), *x));
mx_y = Some(f64::max(mx_y.unwrap(), *y));
@ -320,17 +339,16 @@ impl Graph {
// tims line form left side of line. Why left?? to avoid wasting time in ponits in range
// it skips i point out of screen to keep a non terminating line experience
pub fn trim_lines(&mut self) {
pub(crate) fn trim_lines(&mut self) {
for (_, line) in self.lines.iter_mut() {
let mut i = 0;
while i < line.points.len() {
match line.points.get(i + 2) {
Some(_) => {
if line.points[i+1].0 < self.scale_x_start {
if line.points[i + 1].0 < self.scale_x_start {
line.points.remove(i);
}
},
}
None => {
if line.points[line.points.len() - 1].0 < self.scale_x_start {
line.points.clear();

View File

@ -17,69 +17,95 @@
//! Feel free to see through codes. Application is not written to be used as a library for other app. :)
pub mod graph;
pub mod util;
pub mod port_util;
pub(crate) mod graph;
pub(crate) mod port_util;
pub(crate) mod util;
use gtk::prelude::*;
use glib::clone;
use gtk::prelude::*;
use rand::Rng;
use std::collections::HashMap;
use std::sync::Arc;
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::io::BufReader;
use std::rc::Rc;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use graph::Graph;
use util::Config;
use port_util as putil;
use util::Properties;
// Building and configuring GUI
pub fn build_ui(app: &gtk::Application, config: &Arc<Config>) {
let builder = gtk::Builder::from_file(&config.ui_file);
// Building and propsuring GUI
pub fn build_ui(app: &gtk::Application) {
let props = Arc::new(Properties::default());
let ui_file = include_str!("ui.glade");
let builder = gtk::Builder::from_string(ui_file);
let win = builder.get_object::<gtk::ApplicationWindow>("win").expect("Resource file missing!");
let win = builder
.object::<gtk::ApplicationWindow>("win")
.expect("Resource file missing!");
win.set_application(Some(app));
// Status Bar
let bar = builder.get_object::<gtk::Statusbar>("status_bar").expect("Resource file missing!");
let bar = builder
.object::<gtk::Statusbar>("status_bar")
.expect("Resource file missing!");
// Logging Area
let log_area = builder.get_object::<gtk::TextView>("log_area").expect("Resource file missing!");
let log_area = builder
.object::<gtk::TextView>("log_area")
.expect("Resource file missing!");
// About Window
let about_window = builder.get_object::<gtk::AboutDialog>("about_window").expect("Resource file missing!");
let about_window = builder
.object::<gtk::AboutDialog>("about_window")
.expect("Resource file missing!");
// Save Window
let save_window = builder.get_object::<gtk::FileChooserDialog>("save_window").expect("Resource file missing!");
let save_window = builder
.object::<gtk::FileChooserDialog>("save_window")
.expect("Resource file missing!");
save_window.set_transient_for(Some(&win));
save_window.set_action(gtk::FileChooserAction::Save);
save_window.add_button("_Save", gtk::ResponseType::Apply);
save_window.add_button("_Cancel", gtk::ResponseType::Cancel);
let graph = Graph::new(
builder.get_object::<gtk::DrawingArea>("draw_area").expect("Resource file missing!"),
0.0, 100.0,
0.0, 100.0,
builder
.object::<gtk::DrawingArea>("draw_area")
.expect("Resource file missing!"),
0.0,
100.0,
0.0,
100.0,
false,
true,
false,
true,
HashMap::new(),
0.0
0.0,
);
win.show_all();
// required by signals
let stambh_1 = builder.get_object::<gtk::Entry>("stambh_1").expect("Resource file missing!");
let stambh_2 = builder.get_object::<gtk::Entry>("stambh_2").expect("Resource file missing!");
let draw_baarik_box = builder.get_object::<gtk::CheckButton>("draw_baarik_box").expect("Resource file missing!");
let port = builder.get_object::<gtk::ComboBoxText>("port").expect("Resource file missing!");
let send_entry = builder.get_object::<gtk::Entry>("send_entry").expect("Resource file missing!");
let stambh_1 = builder
.object::<gtk::Entry>("stambh_1")
.expect("Resource file missing!");
let stambh_2 = builder
.object::<gtk::Entry>("stambh_2")
.expect("Resource file missing!");
let draw_baarik_box = builder
.object::<gtk::CheckButton>("draw_baarik_box")
.expect("Resource file missing!");
let port = builder
.object::<gtk::ComboBoxText>("port")
.expect("Resource file missing!");
let send_entry = builder
.object::<gtk::Entry>("send_entry")
.expect("Resource file missing!");
// Signals
builder.connect_signals(|_, handler_name| {
match handler_name {
@ -103,16 +129,16 @@ pub fn build_ui(app: &gtk::Application, config: &Arc<Config>) {
None
})),
"pankti_value_changed" => Box::new(clone!(@weak graph => @default-return None, move |a| {
let btn = a[0].get::<gtk::SpinButton>().unwrap().unwrap();
let btn = a[0].get::<gtk::SpinButton>().unwrap();
let mut tmp_graph = graph.borrow_mut();
tmp_graph.scale_x_size = btn.get_value();
tmp_graph.scale_x_size = btn.value();
tmp_graph.redraw();
None
})),
"stambh_1_changed" => Box::new(clone!(@weak graph => @default-return None, move |a| {
let entry = a[0].get::<gtk::Entry>().unwrap().unwrap();
let entry = a[0].get::<gtk::Entry>().unwrap();
let mut tmp_graph = graph.borrow_mut();
let val = entry.get_text().parse::<f64>().unwrap_or(0.0);
let val = entry.text().parse::<f64>().unwrap_or(0.0);
let purana_y_start = tmp_graph.scale_y_start;
let y_size = tmp_graph.scale_y_size;
tmp_graph.scale_y_start = val;
@ -121,44 +147,44 @@ pub fn build_ui(app: &gtk::Application, config: &Arc<Config>) {
None
})),
"stambh_2_changed" => Box::new(clone!(@weak graph => @default-return None, move |a| {
let entry = a[0].get::<gtk::Entry>().unwrap().unwrap();
let entry = a[0].get::<gtk::Entry>().unwrap();
let mut tmp_graph = graph.borrow_mut();
let val = entry.get_text().parse::<f64>().unwrap_or(0.0);
let val = entry.text().parse::<f64>().unwrap_or(0.0);
let y_start = tmp_graph.scale_y_start;
tmp_graph.scale_y_size = (val - y_start).abs();
tmp_graph.redraw();
None
})),
"nimna_stambh_toggled" => Box::new(clone!(@weak graph, @weak stambh_1, @weak stambh_2 => @default-return None, move |a| {
let btn = a[0].get::<gtk::CheckButton>().unwrap().unwrap();
graph.borrow_mut().auto_adjust_y = !btn.get_active();
stambh_1.set_sensitive(btn.get_active());
stambh_2.set_sensitive(btn.get_active());
if btn.get_active() {
let btn = a[0].get::<gtk::CheckButton>().unwrap();
graph.borrow_mut().auto_adjust_y = !btn.is_active();
stambh_1.set_sensitive(btn.is_active());
stambh_2.set_sensitive(btn.is_active());
if btn.is_active() {
stambh_1.emit_activate();
stambh_2.emit_activate();
}
None
})),
"draw_patches_toggled" => Box::new(clone!(@weak graph => @default-return None, move |a| {
let btn = a[0].get::<gtk::CheckButton>().unwrap().unwrap();
let btn = a[0].get::<gtk::CheckButton>().unwrap();
let mut tmp_graph = graph.borrow_mut();
tmp_graph.draw_patch = btn.get_active();
tmp_graph.draw_patch = btn.is_active();
tmp_graph.redraw();
None
})),
"draw_box_toggled" => Box::new(clone!(@weak graph, @weak draw_baarik_box => @default-return None, move |a| {
let btn = a[0].get::<gtk::CheckButton>().unwrap().unwrap();
let btn = a[0].get::<gtk::CheckButton>().unwrap();
let mut tmp_graph = graph.borrow_mut();
draw_baarik_box.set_sensitive(btn.get_active());
tmp_graph.draw_box = btn.get_active();
draw_baarik_box.set_sensitive(btn.is_active());
tmp_graph.draw_box = btn.is_active();
tmp_graph.redraw();
None
})),
"draw_baarik_box_toggled" => Box::new(clone!(@weak graph => @default-return None, move |a| {
let btn = a[0].get::<gtk::CheckButton>().unwrap().unwrap();
let btn = a[0].get::<gtk::CheckButton>().unwrap();
let mut tmp_graph = graph.borrow_mut();
tmp_graph.draw_baarik_box = btn.get_active();
tmp_graph.draw_baarik_box = btn.is_active();
tmp_graph.redraw();
None
})),
@ -169,24 +195,24 @@ pub fn build_ui(app: &gtk::Application, config: &Arc<Config>) {
tmp_graph.redraw();
None
})),
"bondrate_changed" => Box::new(clone!(@weak config => @default-return None, move |a| {
let btn = a[0].get::<gtk::ComboBoxText>().unwrap().unwrap();
config.bondrate.store(btn.get_active_text().unwrap().parse::<u32>().unwrap_or(9600u32), Ordering::SeqCst);
"bondrate_changed" => Box::new(clone!(@weak props => @default-return None, move |a| {
let btn = a[0].get::<gtk::ComboBoxText>().unwrap();
props.bondrate.store(btn.active_text().unwrap().parse::<u32>().unwrap_or(9600u32), Ordering::SeqCst);
None
})),
"port_changed" => Box::new(clone!(@weak config, @weak bar => @default-return None, move |a| {
let btn = a[0].get::<gtk::ComboBoxText>().unwrap().unwrap();
if let Some(val) = btn.get_active_text() {
match config.port.lock() {
"port_changed" => Box::new(clone!(@weak props, @weak bar => @default-return None, move |a| {
let btn = a[0].get::<gtk::ComboBoxText>().unwrap();
if let Some(val) = btn.active_text() {
match props.port.lock() {
Ok(mut a) => { *a = val.to_string() },
Err(_) => { bar.push(1, "Can't set Port"); }
}
}
None
})),
"refresh_port_clicked" => Box::new(clone!(@weak port, @weak bar, @weak config => @default-return None, move |_| {
"refresh_port_clicked" => Box::new(clone!(@weak port, @weak bar, @weak props => @default-return None, move |_| {
port.remove_all();
match config.status.lock() {
match props.status.lock() {
Ok(mut a) => { *a = util::Status::AVRODTIH },
Err(_) => { bar.push(1, "Can't Avrodhit"); return None; }
}
@ -203,53 +229,50 @@ pub fn build_ui(app: &gtk::Application, config: &Arc<Config>) {
}
None
})),
"jagrit_btn_clicked" => Box::new(clone!(@weak config, @weak graph, @weak bar => @default-return None, move |_| {
"jagrit_btn_clicked" => Box::new(clone!(@weak props, @weak graph, @weak bar => @default-return None, move |_| {
let mut tmp_graph = graph.borrow_mut();
tmp_graph.pankti_sankya = 0.0;
tmp_graph.lines.clear();
tmp_graph.redraw();
bar.push(1, "Jagrit");
match config.status.lock() {
match props.status.lock() {
Ok(mut a) => { *a = util::Status::PARIVARTIT },
Err(_) => { bar.push(1, "Can't Jagrit"); }
}
None
})),
"avrodith_btn_clicked" => Box::new(clone!(@weak config, @weak bar => @default-return None, move |_| {
"avrodith_btn_clicked" => Box::new(clone!(@weak props, @weak bar => @default-return None, move |_| {
bar.push(1, "Avrodhit");
match config.status.lock() {
match props.status.lock() {
Ok(mut a) => { *a = util::Status::AVRODTIH },
Err(_) => { bar.push(1, "Can't Avrodhit"); }
}
None
})),
"clear_log_clicked" => Box::new(clone!(@weak log_area => @default-return None, move |_| {
log_area.get_buffer().expect("Couldn't get window").set_text("");
log_area.buffer().expect("Couldn't get window").set_text("");
None
})),
"send_entry_key_press_event" => Box::new(clone!(@weak config, @weak bar => @default-return None, move |a| {
let ev = a[1].get::<gdk::Event>().unwrap().unwrap();
if let Some(val) = ev.get_keyval() {
if let Some(val) = gdk::keys::keyval_name(val) {
if val == "Return" {
let ent = a[0].get::<gtk::Entry>().unwrap().unwrap();
putil::send_text(&config, &ent, &bar);
}
}
"send_entry_key_press_event" => Box::new(clone!(@weak props, @weak bar => @default-return None, move |a| {
let ev = a[1].get::<gdk::Event>().unwrap();
let ev: Result<gdk::EventKey,_> = gdk::FromEvent::from(ev);
if ev.unwrap().keyval() == gdk::keys::constants::Return {
let ent = a[0].get::<gtk::Entry>().unwrap();
putil::send_text(&props, &ent, &bar);
}
Some(false.to_value())
})),
"send_btn_clicked" => Box::new(clone!(@weak config, @weak bar, @weak send_entry => @default-return None, move |_| {
putil::send_text(&config, &send_entry, &bar);
"send_btn_clicked" => Box::new(clone!(@weak props, @weak bar, @weak send_entry => @default-return None, move |_| {
putil::send_text(&props, &send_entry, &bar);
None
})),
"about_window_delete" => Box::new(|a| {
let win = a[0].get::<gtk::AboutDialog>().unwrap().unwrap();
let win = a[0].get::<gtk::AboutDialog>().unwrap();
win.hide();
Some(true.to_value())
}),
"save_window_delete" => Box::new(|a| {
let win = a[0].get::<gtk::FileChooserDialog>().unwrap().unwrap();
let win = a[0].get::<gtk::FileChooserDialog>().unwrap();
win.hide();
Some(true.to_value())
}),
@ -266,57 +289,62 @@ pub fn build_ui(app: &gtk::Application, config: &Arc<Config>) {
});
let tmp_log_area = log_area.clone();
let tmp_bar = bar.clone();
save_window.connect_response(move |win, res| {
match res {
gtk::ResponseType::Cancel => win.hide(),
gtk::ResponseType::Apply => {
if let Some(path) = win.get_filename() {
if let Some(buf) = tmp_log_area.get_buffer() {
let text = buf.get_text(&buf.get_start_iter(), &buf.get_end_iter(), false).unwrap().to_string();
let tmp_bar = bar.clone();
save_window.connect_response(move |win, res| match res {
gtk::ResponseType::Cancel => win.hide(),
gtk::ResponseType::Apply => {
if let Some(path) = win.filename() {
if let Some(buf) = tmp_log_area.buffer() {
let text = buf
.text(&buf.start_iter(), &buf.end_iter(), false)
.unwrap()
.to_string();
match std::fs::write(path, text) {
Ok(_) => {
win.hide();
},
Err(_) => {
tmp_bar.push(1, "Failed to save!");
}
match std::fs::write(path, text) {
Ok(_) => {
win.hide();
}
Err(_) => {
tmp_bar.push(1, "Failed to save!");
}
}
}
},
_ => ()
}
}
_ => (),
});
/*
Thread to manage Serial Port
The program runs a thread to read and parse the output from serial port and
send it through mpsc (rx, tx) to a recever. Where it is added to Graph
send it through mpsc (rx, tx) to a recever. Where it is added to Graph
or Log is added to text area or any status is displayed in bar
*/
let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
let tmp_config = Arc::clone(&config);
let tmp_props = Arc::clone(&props);
tokio::task::spawn(async move {
let mut bufread: Option<BufReader<Box<dyn serialport::SerialPort>>> = None;
let mut bufread: Option<BufReader<Box<dyn serialport::SerialPort>>> = None;
let mut buf = String::new();
loop {
putil::serial_thread_work(&tmp_config, &mut bufread, &sender, &mut buf).await;
putil::serial_thread_work(&tmp_props, &mut bufread, &sender, &mut buf).await;
}
});
// Reciver for MessageSerialThread from the "Thread to manage Serial Port" and works accordingly
let full_log = builder.get_object::<gtk::CheckButton>("full_log").expect("Resource file missing!");
let graph_data = builder.get_object::<gtk::TextView>("graph_data").expect("Resource file missing!");
let full_log = builder
.object::<gtk::CheckButton>("full_log")
.expect("Resource file missing!");
let graph_data = builder
.object::<gtk::TextView>("graph_data")
.expect("Resource file missing!");
let tmp_graph = Rc::clone(&graph);
receiver.attach(None, move |msg| {
match msg {
util::MessageSerialThread::Msg(text, msg_type) => {
receiver_for_msg(text, &msg_type, &full_log, &log_area);
},
}
util::MessageSerialThread::Points(points) => {
receiver_for_points(points, &tmp_graph, &graph_data);
}
@ -329,8 +357,13 @@ pub fn build_ui(app: &gtk::Application, config: &Arc<Config>) {
}
// Receives MessageSerialThread from Serial Port managing thread adds message to text area
fn receiver_for_msg(text: String, msg_type: &util::MessageSerialThreadMsgType, full_log: &gtk::CheckButton, log_area: &gtk::TextView) {
if !full_log.get_active(){
fn receiver_for_msg(
text: String,
msg_type: &util::MessageSerialThreadMsgType,
full_log: &gtk::CheckButton,
log_area: &gtk::TextView,
) {
if !full_log.is_active() {
if let util::MessageSerialThreadMsgType::Point = msg_type {
return;
}
@ -338,43 +371,49 @@ fn receiver_for_msg(text: String, msg_type: &util::MessageSerialThreadMsgType, f
if text.len() <= 0 {
return;
}
let buf = log_area.get_buffer()
.expect("Couldn't get log_area");
buf.insert(&mut buf.get_end_iter(), &format!("{}\n",text));
log_area.scroll_to_iter(&mut buf.get_end_iter(), 0.4, true, 0.0, 0.0);
let buf = log_area.buffer().expect("Couldn't get log_area");
buf.insert(&mut buf.end_iter(), &format!("{}\n", text));
log_area.scroll_to_iter(&mut buf.end_iter(), 0.4, true, 0.0, 0.0);
log_area.queue_draw();
}
// Receives MessageSerialThread from Serial Port managing thread and add points to draw on graph
fn receiver_for_points(points: Vec<(String, f64)>, graph: &Rc<RefCell<Graph>>, graph_data: &gtk::TextView) {
fn receiver_for_points(
points: Vec<(String, f64)>,
graph: &Rc<RefCell<Graph>>,
graph_data: &gtk::TextView,
) {
for (line, point) in points {
let mut gp = graph.borrow_mut();
let sankhya = gp.pankti_sankya;
match gp.lines.get_mut(&line) {
Some(val) => {
val.points.push((sankhya, point));
} None => {
}
None => {
let v = vec![(sankhya, point)];
let mut rng = rand::thread_rng();
gp.lines.insert(line, graph::Line::new(rng.gen_range(0.0..1.0), 0.0, rng.gen_range(0.0..1.0), v));
let buf = graph_data.get_buffer().expect("Couldn't get graph_data");
gp.lines.insert(
line,
graph::Line::new(rng.gen_range(0.0..1.0), 0.0, rng.gen_range(0.0..1.0), v),
);
let buf = graph_data.buffer().expect("Couldn't get graph_data");
buf.set_text("");
gp.lines.iter().for_each(|(key, line)| {
buf.insert(&mut buf.get_end_iter(), "##");
buf.insert(&mut buf.end_iter(), "##");
let tag = gtk::TextTag::new(None);
let rgba = gdk::RGBA {
red: line.color.0,
green: line.color.1,
blue: line.color.2,
alpha: 1.0
};
tag.set_property_background_rgba(Some(&rgba));
tag.set_property_foreground_rgba(Some(&rgba));
buf.get_tag_table().unwrap().add(&tag);
buf.apply_tag(&tag, &buf.get_iter_at_offset(buf.get_end_iter().get_offset() - 2), &buf.get_end_iter());
buf.insert(&mut buf.get_end_iter(), &format!(" {}, ", key));
let rgba = gdk::RGBA::new(line.color.0, line.color.1, line.color.2, 1.0);
tag.set_background_rgba(Some(&rgba));
tag.set_foreground_rgba(Some(&rgba));
buf.tag_table().unwrap().add(&tag);
buf.apply_tag(
&tag,
&buf.iter_at_offset(buf.end_iter().offset() - 2),
&buf.end_iter(),
);
buf.insert(&mut buf.end_iter(), &format!(" {}, ", key));
});
graph_data.queue_draw();
}

View File

@ -12,26 +12,16 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#![windows_subsystem = "windows"]
use gio::prelude::*;
use std::env::args;
use std::sync::Arc;
use tarangam::util::Config;
use gio::{prelude::*, ApplicationFlags};
#[tokio::main]
async fn main() {
let conf = Arc::new(Config::default());
let app = gtk::Application::new(Some("sng.tarangm"), ApplicationFlags::default());
let app = gtk::Application::new(Some("sng.tarangm"), Default::default())
.expect("Failed to initiate gtk");
let tmp_conf = Arc::clone(&conf);
app.connect_activate(move |app| {
tarangam::build_ui(app, &tmp_conf);
tarangam::build_ui(app);
});
app.run(&args().collect::<Vec<_>>());
app.run();
}

View File

@ -19,23 +19,25 @@
use gtk::prelude::*;
use std::sync::Arc;
use std::io::prelude::*;
use std::io::BufReader;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use crate::{util::Config, util};
use crate::{util, util::Properties};
// Controls the thread and read from serial port
pub async fn serial_thread_work(
config: &Arc<Config>,
bufread: &mut Option<BufReader<Box<dyn serialport::SerialPort>>>,
sender: &glib::Sender<util::MessageSerialThread>,
buf: &mut String) {
pub(crate) async fn serial_thread_work(
config: &Arc<Properties>,
bufread: &mut Option<BufReader<Box<dyn serialport::SerialPort>>>,
sender: &glib::Sender<util::MessageSerialThread>,
buf: &mut String,
) {
let status = match config.status.try_lock() {
Ok(a) => a.to_owned(),
Err(_) => { return; }
Err(_) => {
return;
}
};
match status {
@ -43,9 +45,11 @@ pub async fn serial_thread_work(
*bufread = None;
match config.status.lock() {
Ok(mut a) => *a = util::Status::SAYAN,
Err(_) => { return; }
Err(_) => {
return;
}
};
},
}
util::Status::JAGRIT => {
if let Some(read) = bufread {
if let Ok(_) = read.read_line(buf) {
@ -55,7 +59,7 @@ pub async fn serial_thread_work(
} else if line.starts_with("#") {
let mut points: Vec<(String, f64)> = Vec::new();
for (index, line) in line[1..].split(" ").enumerate() {
let part = line.split("=");
let part = line.split("=");
let part = part.into_iter().collect::<Vec<&str>>();
if part.len() == 1 {
let num = match part[0].trim().parse::<f64>() {
@ -67,13 +71,28 @@ pub async fn serial_thread_work(
points.push((index.to_string(), num));
} else if part.len() == 2 {
points.push((part[0].trim().to_owned(), part[1].parse::<f64>().unwrap()));
points.push((
part[0].trim().to_owned(),
part[1].parse::<f64>().unwrap(),
));
}
}
sender.send(util::MessageSerialThread::Points(points)).unwrap();
sender.send(util::MessageSerialThread::Msg(line.to_owned(), util::MessageSerialThreadMsgType::Point)).unwrap();
sender
.send(util::MessageSerialThread::Points(points))
.unwrap();
sender
.send(util::MessageSerialThread::Msg(
line.to_owned(),
util::MessageSerialThreadMsgType::Point,
))
.unwrap();
} else {
sender.send(util::MessageSerialThread::Msg(line.to_owned(), util::MessageSerialThreadMsgType::Log)).unwrap();
sender
.send(util::MessageSerialThread::Msg(
line.to_owned(),
util::MessageSerialThreadMsgType::Log,
))
.unwrap();
}
}
buf.clear();
@ -81,11 +100,13 @@ pub async fn serial_thread_work(
}
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
},
}
util::Status::PARIVARTIT => {
let port = match config.port.lock() {
Ok(a) => a.to_owned(),
Err(_) => { return; }
Err(_) => {
return;
}
};
let p = match serialport::new(&port, config.bondrate.load(Ordering::SeqCst)).open() {
Ok(p) => p,
@ -93,33 +114,35 @@ pub async fn serial_thread_work(
return;
}
};
*bufread = Some(BufReader::new(p));
match config.status.try_lock() {
Ok(mut a) => *a = util::Status::JAGRIT,
Err(_) => { return; }
Err(_) => {
return;
}
};
}
_ => {
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
},
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
}
}
}
// // Sends text through Serial Post to device
pub fn send_text(config: &Arc<Config>, entry: &gtk::Entry, bar: &gtk::Statusbar) {
pub(crate) fn send_text(config: &Arc<Properties>, entry: &gtk::Entry, bar: &gtk::Statusbar) {
let status = match config.status.try_lock() {
Ok(a) => a.to_owned(),
Err(_) => { return; }
Err(_) => {
return;
}
};
if let util::Status::JAGRIT = status {
let port = match config.port.lock() {
Ok(a) => a.to_owned(),
Err(_) => {
bar.push(1, "Failed to set port!");
return;
Err(_) => {
bar.push(1, "Failed to set port!");
return;
}
};
@ -132,9 +155,9 @@ pub fn send_text(config: &Arc<Config>, entry: &gtk::Entry, bar: &gtk::Statusbar)
};
unsafe {
p.write_all(entry.get_text().to_string().as_bytes_mut()).unwrap();
p.write_all(entry.text().to_string().as_bytes_mut())
.unwrap();
}
entry.set_text("");
}
}

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkAboutDialog" id="about_window">
<property name="can-focus">False</property>
<property name="title" translatable="yes">Tarangam</property>
<property name="icon">chitra.svg</property>
<property name="icon">chitra-small.png</property>
<property name="type-hint">dialog</property>
<property name="program-name">Tarangam (तरंगम्)</property>
<property name="comments" translatable="yes">A simple serial plotter.
@ -54,7 +54,7 @@
</object>
<object class="GtkFileChooserDialog" id="save_window">
<property name="can-focus">False</property>
<property name="icon">chitra.svg</property>
<property name="icon">chitra-small.png</property>
<property name="type-hint">dialog</property>
<property name="action">select-folder</property>
<signal name="close" handler="save_window_close" swapped="no"/>
@ -98,7 +98,7 @@
<property name="title" translatable="yes">Tarangam</property>
<property name="default-width">850</property>
<property name="default-height">600</property>
<property name="icon">chitra.svg</property>
<property name="icon">chitra-small.png</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>

View File

@ -21,48 +21,41 @@ use std::sync::{atomic::*, Mutex};
/// Status of Serial reading
#[derive(Debug, Clone, Copy)]
pub enum Status {
AVRODTIH, // Mode of being stopped
SAYAN, // Mode of Sleeping
JAGRIT, // Mode of Active
PARIVARTIT // Mode of being values modified
pub(crate) enum Status {
AVRODTIH, // Mode of being stopped
SAYAN, // Mode of Sleeping
JAGRIT, // Mode of Active
PARIVARTIT, // Mode of being values modified
}
#[derive(Debug)]
pub struct Config {
pub ui_file: String,
pub bondrate: AtomicU32,
pub port: Mutex<String>,
pub status: Mutex<Status>
pub(crate) struct Properties {
pub(crate) bondrate: AtomicU32,
pub(crate) port: Mutex<String>,
pub(crate) status: Mutex<Status>,
}
/// For communication between mpsc of graph and serial port
#[allow(dead_code)]
#[derive(Debug)]
pub enum MessageSerialThread {
pub(crate) enum MessageSerialThread {
Msg(String, MessageSerialThreadMsgType),
Points(Vec<(String, f64)>),
Status(String)
Status(String),
}
#[derive(Debug)]
pub enum MessageSerialThreadMsgType {
pub(crate) enum MessageSerialThreadMsgType {
Point,
Log
Log,
}
impl Config {
pub fn default() -> Self {
let ui_file = std::env::var("TARANGAM_UI_FILE");
Config {
ui_file: match ui_file {
Ok(val) => val,
Err(_) => std::env::current_exe().unwrap().parent().unwrap()
.join("ui.glade").to_str().unwrap().to_owned()
},
impl Properties {
pub(crate) fn default() -> Self {
Properties {
bondrate: AtomicU32::new(9600),
port: Mutex::new(String::new()),
status: Mutex::new(Status::AVRODTIH)
}
status: Mutex::new(Status::AVRODTIH),
}
}
}
}