Compare commits
13 Commits
main
...
timeline-w
Author | SHA1 | Date |
---|---|---|
Viv Lim | ccc0928012 | |
Viv Lim | 1723ced8b0 | |
Vivian Lim | 249bf0d86f | |
Vivian Lim | 929cb1a3cd | |
Vivian Lim | c3e48eb227 | |
Vivian Lim | 1f563ffdfe | |
Vivian Lim | 164907f618 | |
Vivian Lim | 0e0a1e9ebd | |
Vivian Lim | 201d5c4deb | |
Vivian Lim | 957e8a0895 | |
Viv Lim | 60ae315915 | |
Vivian Lim | 83da5bdc55 | |
Vivian Lim | 56f733cd44 |
|
@ -60,6 +60,26 @@
|
|||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug example 'timeline'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--example=timeline_demo",
|
||||
"--package=conrod_branching_timeline",
|
||||
"--all-features"
|
||||
],
|
||||
"filter": {
|
||||
"name": "timeline_demo",
|
||||
"kind": "example"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"env": { "RUST_BACKTRACE": "1"},
|
||||
},
|
||||
]
|
||||
}
|
|
@ -10,9 +10,9 @@ checksum = "d9fe5e32de01730eb1f6b7f5b51c17e03e2325bf40a74f754f04f130043affff"
|
|||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.15.2"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a"
|
||||
checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
@ -75,13 +75,19 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.11"
|
||||
name = "array-init"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||
checksum = "6945cc5422176fc5e602e590c2878d2c2acd9a4fe20a4baa7c28022521698ec6"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"termion",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
|
@ -93,9 +99,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
|||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.59"
|
||||
version = "0.3.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744"
|
||||
checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
|
@ -112,6 +118,27 @@ version = "0.2.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b"
|
||||
|
||||
[[package]]
|
||||
name = "binrw"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b0f3cc2adaa681a84668ad5e42b49116c510b001bba7e951001a5804eca2aa9"
|
||||
dependencies = [
|
||||
"array-init",
|
||||
"binrw_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "binrw_derive"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fe45c260fcd0a35d65092c24a78449f28b61b626b826fbb30286020a66ff0c9"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
|
@ -148,9 +175,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.69"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
|
||||
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -228,6 +255,35 @@ dependencies = [
|
|||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "compress"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82e83686a9e089326caa89170e9ae386b478494636a3610ca7776bcde8adc55e"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"log",
|
||||
"num",
|
||||
"rand 0.7.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "conrod_branching_timeline"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"conrod_core",
|
||||
"conrod_derive",
|
||||
"conrod_glium",
|
||||
"conrod_winit",
|
||||
"find_folder",
|
||||
"glium",
|
||||
"glutin",
|
||||
"multitrack_recorder",
|
||||
"rand 0.3.23",
|
||||
"serde_json",
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "conrod_core"
|
||||
version = "0.74.0"
|
||||
|
@ -248,7 +304,7 @@ name = "conrod_derive"
|
|||
version = "0.74.0"
|
||||
source = "git+https://github.com/vivlim/conrod#87f33ff73817cf54b0567e740a32f70bd678cf12"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
]
|
||||
|
@ -532,7 +588,7 @@ checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
|
|||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"strsim 0.9.3",
|
||||
"syn",
|
||||
|
@ -546,7 +602,7 @@ checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36"
|
|||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"strsim 0.10.0",
|
||||
"syn",
|
||||
|
@ -580,7 +636,7 @@ version = "2.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
]
|
||||
|
@ -601,7 +657,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "66e616858f6187ed828df7c64a6d71720d83767a7f19740b2d1b6fe6327b36e5"
|
||||
dependencies = [
|
||||
"darling 0.12.4",
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
]
|
||||
|
@ -668,35 +724,25 @@ version = "0.1.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ferretro"
|
||||
version = "0.1.0"
|
||||
source = "git+ssh://git@vvn.space:2222/cinnabon/rustro.git?branch=matriarch#d8d00386437960309d8fb21d4a107a65d42f942b"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"failure",
|
||||
"libloading 0.5.2",
|
||||
"libretro-sys",
|
||||
"num_enum 0.4.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ferretro-dev-gui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"binrw",
|
||||
"cc",
|
||||
"compress",
|
||||
"conrod_core",
|
||||
"conrod_glium",
|
||||
"conrod_winit",
|
||||
"crossbeam-channel 0.4.4",
|
||||
"failure",
|
||||
"ferretro",
|
||||
"ferretro_base",
|
||||
"find_folder",
|
||||
"gilrs",
|
||||
"glium",
|
||||
|
@ -705,10 +751,22 @@ dependencies = [
|
|||
"libloading 0.5.2",
|
||||
"meval",
|
||||
"mini_gl_fb",
|
||||
"multitrack_recorder",
|
||||
"structopt",
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ferretro_base"
|
||||
version = "0.1.0"
|
||||
source = "git+ssh://git@vvn.space:2222/cinnabon/rustro.git?branch=matriarch#409bd036213afca2c0f1dec0f2be2c1ba213fcf5"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libloading 0.5.2",
|
||||
"libretro-sys",
|
||||
"num_enum 0.4.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find_folder"
|
||||
version = "0.3.0"
|
||||
|
@ -742,6 +800,23 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gilrs"
|
||||
version = "0.8.1"
|
||||
|
@ -766,7 +841,7 @@ dependencies = [
|
|||
"libc",
|
||||
"libudev-sys",
|
||||
"log",
|
||||
"nix 0.20.0",
|
||||
"nix 0.20.1",
|
||||
"rusty-xinput",
|
||||
"stdweb",
|
||||
"uuid",
|
||||
|
@ -776,9 +851,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.24.0"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189"
|
||||
checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
|
||||
|
||||
[[package]]
|
||||
name = "gl"
|
||||
|
@ -813,9 +888,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "glium"
|
||||
version = "0.30.1"
|
||||
version = "0.30.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6dfaf64eee4e23d1d5429945816ab083cb94b44e00c3c5f9f9aebfd09ec63df"
|
||||
checksum = "506a2aa1564891d447ae5d1ba37519a8efd6d01ea3e7952da81aa30430c90007"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"fnv",
|
||||
|
@ -950,9 +1025,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.7"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "jni-sys"
|
||||
|
@ -980,9 +1055,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.98"
|
||||
version = "0.2.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
|
||||
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
|
@ -1050,9 +1125,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
|||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.4"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb"
|
||||
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
@ -1092,9 +1167,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
|||
|
||||
[[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 = "memmap"
|
||||
|
@ -1154,6 +1229,12 @@ dependencies = [
|
|||
"rustic_gl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c835948974f68e0bd58636fc6c5b1fbff7b297e3046f11b3b3c18bbac012c6d"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.4"
|
||||
|
@ -1198,6 +1279,20 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multitrack_recorder"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"compress",
|
||||
"failure",
|
||||
"find_folder",
|
||||
"gilrs",
|
||||
"hex",
|
||||
"meval",
|
||||
"structopt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.3.0"
|
||||
|
@ -1206,7 +1301,7 @@ checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab"
|
|||
dependencies = [
|
||||
"jni-sys",
|
||||
"ndk-sys",
|
||||
"num_enum 0.5.2",
|
||||
"num_enum 0.5.4",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
@ -1232,7 +1327,7 @@ checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d"
|
|||
dependencies = [
|
||||
"darling 0.10.2",
|
||||
"proc-macro-crate 0.1.5",
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
]
|
||||
|
@ -1270,14 +1365,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.20.0"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a"
|
||||
checksum = "df8e5e343312e7fbeb2a52139114e9e702991ef9c2aea6817ff2440b35647d56"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"memoffset 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1288,11 +1384,12 @@ checksum = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
|
|||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "6.2.1"
|
||||
version = "7.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6"
|
||||
checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
|
@ -1321,9 +1418,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d0a3d5e207573f948a9e5376662aa743a2ea13f7c50a554d7af443a73fbfeba"
|
||||
checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
|
@ -1403,12 +1500,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.5.2"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5adf0198d427ee515335639f275e806ca01acf9f07d7cf14bb36a10532a6169"
|
||||
checksum = "3f9bd055fb730c4f8f4f57d45d35cd6b3f0980535b056dc7ff119cee6a66ed6f"
|
||||
dependencies = [
|
||||
"derivative",
|
||||
"num_enum_derive 0.5.2",
|
||||
"num_enum_derive 0.5.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1418,29 +1515,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d"
|
||||
dependencies = [
|
||||
"proc-macro-crate 0.1.5",
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.5.2"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1def5a3f69d4707d8a040b12785b98029a39e8c610ae685c7f6265669767482"
|
||||
checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9"
|
||||
dependencies = [
|
||||
"proc-macro-crate 1.0.0",
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "numtoa"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
||||
|
||||
[[package]]
|
||||
name = "objc"
|
||||
version = "0.2.7"
|
||||
|
@ -1472,9 +1563,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.24.0"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170"
|
||||
checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
|
@ -1511,9 +1605,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.1"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
|
@ -1522,9 +1616,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.3"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"instant",
|
||||
|
@ -1582,6 +1676,12 @@ version = "0.3.19"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "0.1.5"
|
||||
|
@ -1608,7 +1708,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
"version_check",
|
||||
|
@ -1620,7 +1720,7 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"version_check",
|
||||
]
|
||||
|
@ -1636,9 +1736,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.28"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612"
|
||||
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.2",
|
||||
]
|
||||
|
@ -1658,7 +1758,86 @@ version = "1.0.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.3.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand 0.4.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
|
||||
dependencies = [
|
||||
"fuchsia-cprng",
|
||||
"libc",
|
||||
"rand_core 0.3.1",
|
||||
"rdrand",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core 0.5.1",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||
dependencies = [
|
||||
"rand_core 0.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1671,28 +1850,28 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.9"
|
||||
name = "rdrand"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee"
|
||||
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_termios"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f"
|
||||
dependencies = [
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.20"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49"
|
||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
|
@ -1808,26 +1987,26 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.127"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8"
|
||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.127"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc"
|
||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.66"
|
||||
version = "1.0.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127"
|
||||
checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -1932,7 +2111,7 @@ version = "0.5.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
|
@ -1946,7 +2125,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
|
||||
dependencies = [
|
||||
"base-x",
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
|
@ -1981,9 +2160,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
version = "0.3.22"
|
||||
version = "0.3.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71"
|
||||
checksum = "bf9d950ef167e25e0bdb073cf1d68e9ad2795ac826f2f3f59647817cf23c0bfa"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"lazy_static",
|
||||
|
@ -1992,24 +2171,24 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "structopt-derive"
|
||||
version = "0.4.15"
|
||||
version = "0.4.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10"
|
||||
checksum = "134d838a2c9943ac3125cf6df165eda53493451b719f3255b2a26b85f772d0ba"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.74"
|
||||
version = "1.0.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c"
|
||||
checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"unicode-xid 0.2.2",
|
||||
]
|
||||
|
@ -2020,7 +2199,7 @@ version = "0.12.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
"unicode-xid 0.2.2",
|
||||
|
@ -2032,18 +2211,6 @@ version = "0.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36ae8932fcfea38b7d3883ae2ab357b0d57a02caaa18ebb4f5ece08beaec4aa0"
|
||||
|
||||
[[package]]
|
||||
name = "termion"
|
||||
version = "1.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"numtoa",
|
||||
"redox_syscall",
|
||||
"redox_termios",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
|
@ -2055,20 +2222,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.26"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
|
||||
checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.26"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
|
||||
checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
]
|
||||
|
@ -2148,10 +2315,16 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.75"
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b608ecc8f4198fe8680e2ed18eccab5f0cd4caaf3d83516fa5fb2e927fda2586"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce9b1b516211d33767048e5d47fa2a381ed8b76fc48d2ce4aa39877f9f183e0"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen-macro",
|
||||
|
@ -2159,14 +2332,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.75"
|
||||
version = "0.2.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "580aa3a91a63d23aac5b6b267e2d13cb4f363e31dce6c352fca4752ae12e479f"
|
||||
checksum = "cfe8dc78e2326ba5f845f4b5bf548401604fa20b1dd1d365fb73b6c1d6364041"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
|
@ -2174,9 +2347,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.75"
|
||||
version = "0.2.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "171ebf0ed9e1458810dfcb31f2e766ad6b3a89dbda42d8901f2b268277e5f09c"
|
||||
checksum = "44468aa53335841d9d6b6c023eaab07c0cd4bddbcfdee3e2bb1e8d2cb8069fef"
|
||||
dependencies = [
|
||||
"quote 1.0.9",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -2184,11 +2357,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.75"
|
||||
version = "0.2.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c2657dd393f03aa2a659c25c6ae18a13a4048cebd220e147933ea837efc589f"
|
||||
checksum = "0195807922713af1e67dc66132c7328206ed9766af3858164fb583eedc25fbad"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
|
@ -2197,9 +2370,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.75"
|
||||
version = "0.2.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e0c4a743a309662d45f4ede961d7afa4ba4131a59a639f29b0069c3798bbcc2"
|
||||
checksum = "acdb075a845574a1fa5f09fd77e43f7747599301ea3417a9fbffdeedfc1f4a29"
|
||||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
|
@ -2225,7 +2398,7 @@ dependencies = [
|
|||
"bitflags",
|
||||
"downcast-rs",
|
||||
"libc",
|
||||
"nix 0.20.0",
|
||||
"nix 0.20.1",
|
||||
"scoped-tls",
|
||||
"wayland-commons 0.28.6",
|
||||
"wayland-scanner 0.28.6",
|
||||
|
@ -2248,7 +2421,7 @@ version = "0.28.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a21817947c7011bbd0a27e11b17b337bfd022e8544b071a2641232047966fbda"
|
||||
dependencies = [
|
||||
"nix 0.20.0",
|
||||
"nix 0.20.1",
|
||||
"once_cell",
|
||||
"smallvec",
|
||||
"wayland-sys 0.28.6",
|
||||
|
@ -2260,7 +2433,7 @@ version = "0.28.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be610084edd1586d45e7bdd275fe345c7c1873598caa464c4fb835dee70fa65a"
|
||||
dependencies = [
|
||||
"nix 0.20.0",
|
||||
"nix 0.20.1",
|
||||
"wayland-client 0.28.6",
|
||||
"xcursor",
|
||||
]
|
||||
|
@ -2316,7 +2489,7 @@ version = "0.28.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce923eb2deb61de332d1f356ec7b6bf37094dc5573952e1c8936db03b54c03f1"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.28",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"xml-rs 0.8.4",
|
||||
]
|
||||
|
@ -2438,11 +2611,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "xcursor"
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a9a231574ae78801646617cefd13bfe94be907c0e4fa979cfd8b770aa3c5d08"
|
||||
checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7"
|
||||
dependencies = [
|
||||
"nom 6.2.1",
|
||||
"nom 7.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
35
Cargo.toml
35
Cargo.toml
|
@ -1,29 +1,6 @@
|
|||
[package]
|
||||
name = "ferretro-dev-gui"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
authors = ["viv <vvnl+git@protonmail.com>"]
|
||||
|
||||
[build-dependencies]
|
||||
cc = "^1"
|
||||
|
||||
[dependencies]
|
||||
crossbeam-channel = "^0.4"
|
||||
structopt = "^0.3"
|
||||
ferretro = { git = "ssh://git@vvn.space:2222/cinnabon/rustro.git", branch = "matriarch" }
|
||||
failure = "^0.1"
|
||||
libloading = "^0.5"
|
||||
|
||||
mini_gl_fb = { git = "https://github.com/vivlim/mini_gl_fb" } # bumped glutin version to 0.27.0 to match the glium i have
|
||||
|
||||
conrod_glium = { git = "https://github.com/vivlim/conrod" } # bumped version of glium to 0.30.1 to use winit 0.24 which fixes https://github.com/rust-windowing/winit/issues/1782
|
||||
conrod_winit = { git = "https://github.com/vivlim/conrod" } # bumped version of glium to 0.30.1 to use winit 0.24 which fixes https://github.com/rust-windowing/winit/issues/1782
|
||||
conrod_core = { git = "https://github.com/vivlim/conrod" }
|
||||
glium = "0.30.1"
|
||||
glutin = "0.27.0"
|
||||
winit = "0.25"
|
||||
|
||||
gilrs = "0.8.1"
|
||||
find_folder="0.3.0"
|
||||
hex = "0.4.3"
|
||||
meval = "0.2.0"
|
||||
[workspace]
|
||||
members = [
|
||||
"ferretro-dev-gui",
|
||||
"multitrack_recorder",
|
||||
"conrod_branching_timeline",
|
||||
]
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/target/
|
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "conrod_branching_timeline"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
authors = ["viv <vvnl+git@protonmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
conrod_derive = { git = "https://github.com/vivlim/conrod" }
|
||||
conrod_core = { git = "https://github.com/vivlim/conrod" }
|
||||
multitrack_recorder = { path = "../multitrack_recorder" }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.3.12"
|
||||
serde_json = "1.0"
|
||||
|
||||
conrod_glium = { git = "https://github.com/vivlim/conrod" } # bumped version of glium to 0.30.1 to use winit 0.24 which fixes https://github.com/rust-windowing/winit/issues/1782
|
||||
conrod_winit = { git = "https://github.com/vivlim/conrod" } # bumped version of glium to 0.30.1 to use winit 0.24 which fixes https://github.com/rust-windowing/winit/issues/1782
|
||||
conrod_core = { git = "https://github.com/vivlim/conrod" }
|
||||
find_folder="0.3.0"
|
||||
glium = "0.30.1"
|
||||
glutin = "0.27.0"
|
||||
winit = "0.25"
|
||||
multitrack_recorder = { path = "../multitrack_recorder" }
|
|
@ -0,0 +1,142 @@
|
|||
//! A simple example that demonstrates using conrod within a basic `winit` window loop, using
|
||||
//! `glium` to render the `conrod_core::render::Primitives` to screen.
|
||||
|
||||
#[macro_use]
|
||||
extern crate conrod_core;
|
||||
extern crate conrod_glium;
|
||||
#[macro_use]
|
||||
extern crate conrod_winit;
|
||||
extern crate find_folder;
|
||||
extern crate glium;
|
||||
extern crate multitrack_recorder;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use conrod_core::{widget, Colorable, Positionable, Widget, Sizeable};
|
||||
use glium::Surface;
|
||||
use multitrack_recorder::recorder::new_vectrack_recorder;
|
||||
use multitrack_recorder::traits::*;
|
||||
|
||||
const WIDTH: u32 = 1024;
|
||||
const HEIGHT: u32 = 1024;
|
||||
|
||||
mod helpers {
|
||||
// support functions, provides convert_event
|
||||
conrod_winit::v023_conversion_fns!();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Build the window.
|
||||
let event_loop = glium::glutin::event_loop::EventLoop::new();
|
||||
let window = glium::glutin::window::WindowBuilder::new()
|
||||
.with_title("Hello Conrod!")
|
||||
.with_inner_size(glium::glutin::dpi::LogicalSize::new(WIDTH, HEIGHT));
|
||||
let context = glium::glutin::ContextBuilder::new()
|
||||
.with_vsync(true)
|
||||
.with_multisampling(4);
|
||||
let display = glium::Display::new(window, context, &event_loop).unwrap();
|
||||
|
||||
let mut rec = Arc::new(Mutex::new(new_vectrack_recorder()));
|
||||
{
|
||||
let mut rec = rec.lock().unwrap();
|
||||
for i in 0..10 {
|
||||
rec.push(i);
|
||||
}
|
||||
rec.move_insertion_head(3);
|
||||
for i in 3..8 {
|
||||
rec.push(i*10);
|
||||
}
|
||||
rec.move_insertion_head(5);
|
||||
for i in 3..8 {
|
||||
rec.push(i*10);
|
||||
}
|
||||
rec.move_insertion_head(1);
|
||||
for i in 3..8 {
|
||||
rec.push(i*10);
|
||||
}
|
||||
rec.move_insertion_head(2);
|
||||
for i in 3..8 {
|
||||
rec.push(i*10);
|
||||
}
|
||||
}
|
||||
|
||||
// construct our `Ui`.
|
||||
let mut ui = conrod_core::UiBuilder::new([WIDTH as f64, HEIGHT as f64]).build();
|
||||
|
||||
// Generate the widget identifiers.
|
||||
widget_ids!(struct Ids { timeline });
|
||||
let ids = Ids::new(ui.widget_id_generator());
|
||||
|
||||
// Add a `Font` to the `Ui`'s `font::Map` from file.
|
||||
let assets = find_folder::Search::KidsThenParents(3, 5)
|
||||
.for_folder("assets")
|
||||
.unwrap();
|
||||
let font_path = assets.join("libre-franklin.ttf");
|
||||
ui.fonts.insert_from_file(font_path).unwrap();
|
||||
|
||||
// A type used for converting `conrod_core::render::Primitives` into `Command`s that can be used
|
||||
// for drawing to the glium `Surface`.
|
||||
let mut renderer = conrod_glium::Renderer::new(&display).unwrap();
|
||||
|
||||
// The image map describing each of our widget->image mappings (in our case, none).
|
||||
let image_map = conrod_core::image::Map::<glium::texture::Texture2d>::new();
|
||||
|
||||
let mut should_update_ui = true;
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
// Break from the loop upon `Escape` or closed window.
|
||||
match &event {
|
||||
glium::glutin::event::Event::WindowEvent { event, .. } => match event {
|
||||
// Break from the loop upon `Escape`.
|
||||
glium::glutin::event::WindowEvent::CloseRequested
|
||||
| glium::glutin::event::WindowEvent::KeyboardInput {
|
||||
input:
|
||||
glium::glutin::event::KeyboardInput {
|
||||
virtual_keycode: Some(glium::glutin::event::VirtualKeyCode::Escape),
|
||||
..
|
||||
},
|
||||
..
|
||||
} => *control_flow = glium::glutin::event_loop::ControlFlow::Exit,
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Use the `winit` backend feature to convert the winit event to a conrod one.
|
||||
if let Some(event) = helpers::convert_event(&event, &display.gl_window().window()) {
|
||||
ui.handle_event(event);
|
||||
should_update_ui = true;
|
||||
}
|
||||
|
||||
match &event {
|
||||
glium::glutin::event::Event::MainEventsCleared => {
|
||||
if should_update_ui {
|
||||
should_update_ui = false;
|
||||
|
||||
// Set the widgets.
|
||||
let ui = &mut ui.set_widgets();
|
||||
|
||||
// "Hello World!" in the middle of the screen.
|
||||
|
||||
let context = conrod_branching_timeline::recorder_timeline::RecorderTimeline::new(rec.clone())
|
||||
.wh_of(ui.window)
|
||||
.middle_of(ui.window)
|
||||
.set(ids.timeline, ui);
|
||||
|
||||
// Request redraw if the `Ui` has changed.
|
||||
display.gl_window().window().request_redraw();
|
||||
}
|
||||
}
|
||||
glium::glutin::event::Event::RedrawRequested(_) => {
|
||||
// Draw the `Ui` if it has changed.
|
||||
let primitives = ui.draw();
|
||||
|
||||
renderer.fill(&display, primitives, &image_map);
|
||||
let mut target = display.draw();
|
||||
target.clear_color(0.0, 0.0, 0.0, 1.0);
|
||||
renderer.draw(&display, &mut target, &image_map).unwrap();
|
||||
target.finish().unwrap();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#[macro_use]
|
||||
extern crate conrod_core;
|
||||
#[macro_use]
|
||||
extern crate conrod_derive;
|
||||
extern crate multitrack_recorder;
|
||||
|
||||
pub mod recorder_timeline;
|
|
@ -0,0 +1,285 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::ops::Sub;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use conrod_core::{Labelable, Widget, event::Text};
|
||||
use conrod_core::{Borderable, Color, Colorable, FontSize, Positionable, Scalar, Sizeable, WidgetCommon, builder_method, builder_methods, widget, widget_ids};
|
||||
use multitrack_recorder::recorder::ArcBoxRecorder;
|
||||
use multitrack_recorder::vec_track::VecTrack;
|
||||
|
||||
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct RecorderTimeline<TData, TTime>
|
||||
where TData: Clone, TTime: Borrow<usize> + Sub<usize> {
|
||||
#[conrod(common_builder)]
|
||||
common: conrod_core::widget::CommonBuilder,
|
||||
style: Style,
|
||||
recorder: Arc<Mutex<ArcBoxRecorder<VecTrack<TData, TTime>, TData, TTime>>>,
|
||||
}
|
||||
|
||||
impl<TData, TTime> RecorderTimeline<TData, TTime>
|
||||
where TData: Clone, TTime: Borrow<usize> + Sub<usize> {
|
||||
pub fn new(recorder: Arc<Mutex<ArcBoxRecorder<VecTrack<TData, TTime>, TData, TTime>>>) -> Self {
|
||||
RecorderTimeline {
|
||||
common: conrod_core::widget::CommonBuilder::default(),
|
||||
style: Style::default(),
|
||||
recorder: recorder.clone()
|
||||
}
|
||||
}
|
||||
|
||||
builder_methods! {
|
||||
pub font_size { style.font_size = Some(FontSize) }
|
||||
pub text_color { style.text_color = Some(Color) }
|
||||
}
|
||||
}
|
||||
//fn map_time_to_track_x<TData, TTime>(recorder: ArcBoxRecorder<VecTrack<TData, TTime>, TData, TTime>, time: TTime, track_index: usize) -> Scalar
|
||||
|
||||
fn map_time_to_track_x<TTime>(time: TTime, (window_start, window_end): (TTime, TTime)) -> Option<Scalar>
|
||||
where TTime: Sub<TTime> + PartialOrd + Into<usize> + Copy, usize: From<<TTime as Sub>::Output>{
|
||||
// if it is past the bounds then just set it to the end
|
||||
if time < window_start {
|
||||
return None
|
||||
} else if time > window_end {
|
||||
return None
|
||||
}
|
||||
|
||||
let window_length: usize = (window_end - window_start).into();
|
||||
let time_within_window: usize = (time - window_start).into();
|
||||
|
||||
Some(time_within_window as f64 / window_length as f64)
|
||||
}
|
||||
|
||||
impl<TData> Widget for RecorderTimeline<TData, usize> // time needs to be sendable and static lifetime for State
|
||||
where TData: Clone {
|
||||
type State = State<usize>;
|
||||
|
||||
type Style = Style;
|
||||
|
||||
type Event = Vec<Event>;
|
||||
|
||||
fn init_state(&self, id_gen: conrod_core::widget::id::Generator) -> Self::State {
|
||||
// start with the entire time range
|
||||
let all_tracks_duration = self.recorder.lock().unwrap().tracks.iter().map(|t| t.start_time + t.track.data.len()).max().unwrap();
|
||||
State {
|
||||
ids: Ids::new(id_gen),
|
||||
start: Default::default(),
|
||||
end: all_tracks_duration.into()
|
||||
}
|
||||
}
|
||||
|
||||
fn style(&self) -> Self::Style {
|
||||
self.style.clone()
|
||||
}
|
||||
|
||||
fn update(mut self, args: conrod_core::widget::UpdateArgs<Self>) -> Self::Event {
|
||||
let conrod_core::widget::UpdateArgs {
|
||||
id,
|
||||
state,
|
||||
rect,
|
||||
style,
|
||||
ui,
|
||||
..
|
||||
} = args;
|
||||
|
||||
let mut events = Vec::new();
|
||||
|
||||
let text_color = style.text_color(ui.theme());
|
||||
let color = style.color(ui.theme());
|
||||
let border_color = style.border_color(ui.theme());
|
||||
let font_size = style.font_size(ui.theme());
|
||||
|
||||
let wh = rect.w_h();
|
||||
let row_height = 32.0;
|
||||
|
||||
let mut recorder = self.recorder.lock().unwrap();
|
||||
let (mut row_items, scrollbar) = widget::List::flow_down(recorder.tracks.len())
|
||||
.xy(rect.xy())
|
||||
.item_size(row_height)
|
||||
.set(state.ids.label, ui);
|
||||
|
||||
if state.ids.tracks.len() < recorder.tracks.len() {
|
||||
let id_gen = &mut ui.widget_id_generator();
|
||||
state.update(|state| state.ids.tracks.resize(recorder.tracks.len(), id_gen));
|
||||
}
|
||||
|
||||
let mut track_ids_iter = state.ids.tracks.iter();
|
||||
|
||||
while let Some(row_item) = row_items.next(ui) {
|
||||
let track = &mut recorder.tracks[row_item.i];
|
||||
// derive track width
|
||||
let track_left = map_time_to_track_x(track.start_time, (state.start, state.end));
|
||||
let track_right = map_time_to_track_x(track.start_time + track.track.data.len(), (state.start, state.end));
|
||||
let num_visible_time_units = usize::min(state.end, track.track.data.len() + track.start_time) - usize::max(state.start, track.start_time);
|
||||
|
||||
match (track_left, track_right) {
|
||||
(Some(left), Some(right)) => {
|
||||
let width = (right - left) * wh.1;
|
||||
let row_widget = widget::Rectangle::fill([0.0, 0.0 /* dimensions are ignored */])
|
||||
//.left(left)
|
||||
.color(conrod_core::color::GRAY);
|
||||
|
||||
row_item.set(row_widget, ui);
|
||||
|
||||
let track_widget_id = *track_ids_iter.next().unwrap();
|
||||
|
||||
let color = if recorder.current_track == row_item.i { conrod_core::color::GREEN } else { conrod_core::color::YELLOW };
|
||||
widget::Rectangle::fill([120.0, row_height])
|
||||
.x_y_relative_to(row_item.widget_id, left * wh.1, 0.0)
|
||||
.w_h(width, row_height)
|
||||
//.left(left)
|
||||
.color(color)
|
||||
.set(track_widget_id, ui);
|
||||
|
||||
let input = ui.widget_input(track_widget_id);
|
||||
let mouse_interaction = input.mouse().map_or(Interaction::Idle, |mouse| {
|
||||
if mouse.buttons.left().is_down() {
|
||||
if ui.global_input().current.widget_under_mouse == Some(track_widget_id) {
|
||||
Interaction::Press((mouse.rel_xy()))
|
||||
} else {
|
||||
Interaction::Idle
|
||||
}
|
||||
} else {
|
||||
println!("hover at {:?}", mouse.rel_xy());
|
||||
Interaction::Hover((mouse.rel_xy()))
|
||||
}
|
||||
});
|
||||
match mouse_interaction {
|
||||
Interaction::Hover([x, y]) => {
|
||||
let [track_widget_x, track_widget_y]= ui.xy_of(track_widget_id).unwrap();
|
||||
let [track_widget_w, track_widget_h]= ui.wh_of(track_widget_id).unwrap();
|
||||
let width_per_time_unit = track_widget_w / num_visible_time_units as f64;
|
||||
let hovered_time_unit = f64::floor((x + (track_widget_w / 2.0)) / width_per_time_unit) as usize;
|
||||
println!("hovered unit: {}", hovered_time_unit);
|
||||
|
||||
let x_of_time_unit = width_per_time_unit * hovered_time_unit as f64 - (track_widget_w / 2.0);
|
||||
// coords are relative to center of widget.
|
||||
|
||||
widget::Line::new([track_widget_x + x_of_time_unit, track_widget_y - (row_height / 2.0)], [track_widget_x + x_of_time_unit, track_widget_y + (row_height / 2.0)])
|
||||
.thickness(2.0)
|
||||
.color(conrod_core::color::RED)
|
||||
.set(state.ids.hover_line, ui);
|
||||
|
||||
}
|
||||
Interaction::Press([x, y]) => {
|
||||
let [track_widget_x, track_widget_y]= ui.xy_of(track_widget_id).unwrap();
|
||||
let [track_widget_w, track_widget_h]= ui.wh_of(track_widget_id).unwrap();
|
||||
let width_per_time_unit = track_widget_w / num_visible_time_units as f64;
|
||||
let hovered_time_unit = f64::floor((x + (track_widget_w / 2.0)) / width_per_time_unit) as usize;
|
||||
println!("hovered unit: {}", hovered_time_unit);
|
||||
if row_item.i != recorder.current_track {
|
||||
recorder.switch_track(row_item.i);
|
||||
}
|
||||
recorder.move_insertion_head(hovered_time_unit);
|
||||
|
||||
},
|
||||
Interaction::Idle => (),
|
||||
}
|
||||
/*
|
||||
let interaction = match mouse_interaction {
|
||||
Interaction::Idle | Interaction::Hover([x, y]) => {
|
||||
let is_touch_press = ui
|
||||
.global_input()
|
||||
.current
|
||||
.touch
|
||||
.values()
|
||||
.any(|t| t.start.widget == Some(track_widget_id) && t.widget == Some(track_widget_id));
|
||||
if is_touch_press {
|
||||
Interaction::Press
|
||||
} else {
|
||||
mouse_interaction
|
||||
}
|
||||
}
|
||||
Interaction::Press => Interaction::Press,
|
||||
};*/
|
||||
|
||||
},
|
||||
(_, _) => {
|
||||
let width = wh.1;
|
||||
let row_widget = widget::Rectangle::fill([width, row_height])
|
||||
.color(conrod_core::color::GRAY);
|
||||
|
||||
row_item.set(row_widget, ui);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// draw current position
|
||||
let [tracks_x, tracks_y]= ui.xy_of(state.ids.label).unwrap();
|
||||
let [tracks_w, tracks_h] = ui.wh_of(state.ids.label).unwrap();
|
||||
|
||||
let current_x = map_time_to_track_x(recorder.current_time, (state.start, state.end)).unwrap() * tracks_w / 2.0;
|
||||
|
||||
widget::Line::new([tracks_x + current_x, tracks_y - (tracks_h / 2.0)], [tracks_x + current_x, tracks_y + (tracks_h / 2.0)])
|
||||
.thickness(2.0)
|
||||
.color(conrod_core::color::ORANGE)
|
||||
.set(state.ids.current_pos_line, ui);
|
||||
|
||||
events
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
widget_ids! {
|
||||
struct Ids {
|
||||
label,
|
||||
tracks[],
|
||||
current_pos_line,
|
||||
hover_line,
|
||||
hover_details,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct State<TTime> {
|
||||
ids: Ids,
|
||||
start: TTime,
|
||||
end: TTime,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, conrod_core::WidgetStyle)]
|
||||
pub struct Style {
|
||||
/// The color of the text in the `TextEdit` widget.
|
||||
#[conrod(default = "theme.label_color")]
|
||||
pub text_color: Option<Color>,
|
||||
/// The color of the `TextEdit` widget.
|
||||
#[conrod(default = "theme.label_color")]
|
||||
pub color: Option<Color>,
|
||||
/// The font size for the text.
|
||||
#[conrod(default = "theme.font_size_medium")]
|
||||
pub font_size: Option<FontSize>,
|
||||
/// The width of the bounding `BorderedRectangle` border.
|
||||
#[conrod(default = "theme.border_width")]
|
||||
pub border: Option<Scalar>,
|
||||
/// The color of the `BorderedRecangle`'s border.
|
||||
#[conrod(default = "theme.border_color")]
|
||||
pub border_color: Option<Color>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Event {
|
||||
Edit(usize, u8)
|
||||
}
|
||||
|
||||
impl<TData, TTime> Borderable for RecorderTimeline<TData, TTime>
|
||||
where TData: Clone, TTime: Borrow<usize> + Sub<usize> {
|
||||
builder_methods! {
|
||||
border { style.border = Some(Scalar) }
|
||||
border_color { style.border_color = Some(Color) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<TData, TTime> Colorable for RecorderTimeline<TData, TTime>
|
||||
where TData: Clone, TTime: Borrow<usize> + Sub<usize> {
|
||||
builder_method!(color {
|
||||
style.color = Some(Color)
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Interaction {
|
||||
Idle,
|
||||
Hover([f64; 2]),
|
||||
Press([f64; 2]),
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,34 @@
|
|||
[package]
|
||||
name = "ferretro-dev-gui"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
authors = ["viv <vvnl+git@protonmail.com>"]
|
||||
|
||||
[build-dependencies]
|
||||
cc = "^1"
|
||||
|
||||
[dependencies]
|
||||
crossbeam-channel = "^0.4"
|
||||
structopt = "^0.3"
|
||||
ferretro_base = { git = "ssh://git@vvn.space:2222/cinnabon/rustro.git", branch = "matriarch" }
|
||||
failure = "^0.1"
|
||||
libloading = "^0.5"
|
||||
|
||||
multitrack_recorder = { path = "../multitrack_recorder" }
|
||||
|
||||
mini_gl_fb = { git = "https://github.com/vivlim/mini_gl_fb" } # bumped glutin version to 0.27.0 to match the glium i have
|
||||
|
||||
conrod_glium = { git = "https://github.com/vivlim/conrod" } # bumped version of glium to 0.30.1 to use winit 0.24 which fixes https://github.com/rust-windowing/winit/issues/1782
|
||||
conrod_winit = { git = "https://github.com/vivlim/conrod" } # bumped version of glium to 0.30.1 to use winit 0.24 which fixes https://github.com/rust-windowing/winit/issues/1782
|
||||
conrod_core = { git = "https://github.com/vivlim/conrod" }
|
||||
glium = "0.30.1"
|
||||
glutin = "0.27.0"
|
||||
winit = "0.25"
|
||||
|
||||
gilrs = "0.8.1"
|
||||
find_folder="0.3.0"
|
||||
hex = "0.4.3"
|
||||
meval = "0.2.0"
|
||||
compress = "0.2.1"
|
||||
|
||||
binrw = "0.6.0"
|
Binary file not shown.
|
@ -190,22 +190,23 @@ impl MyEmulator {
|
|||
|
||||
|
||||
pub fn serialize(&self) -> Fallible<()> {
|
||||
let data = self.retro.serialize()?;
|
||||
panic!("not implemented");
|
||||
// let data = self.retro.serialize()?;
|
||||
|
||||
if let Some(game_path) = self.game_path.borrow() {
|
||||
let filename = build_savestate_filename(game_path);
|
||||
// if let Some(game_path) = self.game_path.borrow() {
|
||||
// let filename = build_savestate_filename(game_path);
|
||||
|
||||
match std::fs::File::create(filename.clone()) {
|
||||
Ok(mut f) => {
|
||||
f.write_all(&data)?;
|
||||
println!("State written to {:?}.", filename.into_os_string().into_string());
|
||||
Ok(())
|
||||
},
|
||||
Err(e) => Err(e.into())
|
||||
}
|
||||
} else {
|
||||
Err(failure::err_msg("Game filename is not set, cannot determine serialized target filename"))
|
||||
}
|
||||
// match std::fs::File::create(filename.clone()) {
|
||||
// Ok(mut f) => {
|
||||
// f.write_all(&data)?;
|
||||
// println!("State written to {:?}.", filename.into_os_string().into_string());
|
||||
// Ok(())
|
||||
// },
|
||||
// Err(e) => Err(e.into())
|
||||
// }
|
||||
// } else {
|
||||
// Err(failure::err_msg("Game filename is not set, cannot determine serialized target filename"))
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn unserialize_newest(&mut self) -> Fallible<()> {
|
||||
|
@ -220,14 +221,14 @@ impl MyEmulator {
|
|||
}
|
||||
|
||||
pub fn unserialize(&mut self, state: impl AsRef<Path>) -> Fallible<()> {
|
||||
let path = state.as_ref();
|
||||
let mut v = Vec::new();
|
||||
if let Ok(mut f) = std::fs::File::open(path) {
|
||||
if f.read_to_end(&mut v).is_ok(){
|
||||
return self.retro.unserialize(v.as_ref());
|
||||
}
|
||||
}
|
||||
Err(failure::err_msg("Couldn't read file to unserialize"))
|
||||
panic!("not reimplemented");
|
||||
// let path = state.as_ref();
|
||||
// let mut v = Vec::new();
|
||||
// if let Ok(mut f) = std::fs::File::open(path) {
|
||||
// if f.read_to_end(&mut v).is_ok(){
|
||||
// return self.retro.unserialize(v.as_ref());
|
||||
// }
|
||||
// Err(failure::err_msg("Couldn't read file to unserialize"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,12 +237,13 @@ impl Drop for MyEmulator {
|
|||
retro::wrapper::unset_handler();
|
||||
}
|
||||
}
|
||||
|
||||
impl retro::wrapper::Handler for MyEmulator {
|
||||
impl retro::wrapper::LibretroWrapperAccess for MyEmulator {
|
||||
fn libretro_core(&mut self) -> &mut LibretroWrapper {
|
||||
&mut self.retro
|
||||
}
|
||||
}
|
||||
|
||||
impl retro::wrapper::RetroCallbacks for MyEmulator {
|
||||
fn video_refresh(&mut self, data: &[u8], width: u32, height: u32, pitch: u32) {
|
||||
|
||||
if let None = self.video_buffer {
|
||||
|
@ -330,13 +332,11 @@ impl retro::wrapper::Handler for MyEmulator {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_can_dupe(&mut self) -> Option<bool> { Some(true) }
|
||||
|
||||
fn get_system_directory(&mut self) -> Option<PathBuf> {
|
||||
self.sys_path.clone()
|
||||
}
|
||||
|
||||
fn set_pixel_format(&mut self, pix_fmt: retro::ffi::PixelFormat) -> bool {
|
||||
fn set_pixel_format(&mut self, pix_fmt: retro::ffi::PixelFormat) -> Option<bool> {
|
||||
let bytes_per_pixel = match pix_fmt {
|
||||
retro::ffi::PixelFormat::ARGB1555 => 2,
|
||||
retro::ffi::PixelFormat::ARGB8888 => 4,
|
||||
|
@ -354,7 +354,7 @@ impl retro::wrapper::Handler for MyEmulator {
|
|||
bytes_per_pixel,
|
||||
glium_pixel_format,
|
||||
});
|
||||
true
|
||||
Some(true)
|
||||
}
|
||||
fn get_variable(&mut self, key: &str) -> Option<String> {
|
||||
match key {
|
||||
|
@ -365,11 +365,11 @@ impl retro::wrapper::Handler for MyEmulator {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_variables(&mut self, variables: Vec<Variable2>) -> bool {
|
||||
for v in variables {
|
||||
fn set_variables(&mut self, variables: &Vec<Variable2>) -> Option<bool> {
|
||||
for v in variables {&
|
||||
eprintln!("{:?}", v);
|
||||
}
|
||||
true
|
||||
Some(true)
|
||||
}
|
||||
|
||||
fn get_libretro_path(&mut self) -> Option<PathBuf> {
|
||||
|
@ -385,18 +385,18 @@ impl retro::wrapper::Handler for MyEmulator {
|
|||
Some(std::env::temp_dir())
|
||||
}
|
||||
|
||||
fn set_system_av_info(&mut self, av_info: SystemAvInfo) -> bool {
|
||||
self.set_geometry(av_info.geometry.clone());
|
||||
self.av_info = av_info;
|
||||
true
|
||||
fn set_system_av_info(&mut self, av_info: &SystemAvInfo) -> Option<bool> {
|
||||
self.set_geometry(&av_info.geometry);
|
||||
self.av_info = av_info.clone();
|
||||
Some(true)
|
||||
}
|
||||
|
||||
fn set_subsystem_info(&mut self, subsystem_info: Vec<SubsystemInfo2>) -> bool {
|
||||
fn set_subsystem_info(&mut self, subsystem_info: &Vec<SubsystemInfo2>) -> Option<bool> {
|
||||
println!("subsystem info: {:?}", subsystem_info);
|
||||
true
|
||||
Some(true)
|
||||
}
|
||||
|
||||
fn set_controller_info(&mut self, controller_info: Vec<ControllerDescription2>) -> bool {
|
||||
fn set_controller_info(&mut self, controller_info: &Vec<ControllerDescription2>) -> Option<bool> {
|
||||
for ci in controller_info {
|
||||
// so we can have analog support in beetle/mednafen saturn
|
||||
if ci.name.as_str() == "3D Control Pad" {
|
||||
|
@ -404,31 +404,31 @@ impl retro::wrapper::Handler for MyEmulator {
|
|||
break;
|
||||
}
|
||||
}
|
||||
true
|
||||
Some(true)
|
||||
}
|
||||
|
||||
fn set_input_descriptors(&mut self, descriptors: Vec<InputDescriptor2>) -> bool {
|
||||
fn set_input_descriptors(&mut self, descriptors: &Vec<InputDescriptor2>) -> Option<bool> {
|
||||
for id in descriptors {
|
||||
println!("{:?}", id);
|
||||
}
|
||||
true
|
||||
Some(true)
|
||||
}
|
||||
|
||||
fn set_geometry(&mut self, geom: GameGeometry) -> bool {
|
||||
fn set_geometry(&mut self, geom: &GameGeometry) -> Option<bool> {
|
||||
/*
|
||||
let _ = self.canvas.window_mut().set_size(geom.base_width, geom.base_height);
|
||||
let _ = self.canvas.set_logical_size(geom.base_width, geom.base_height);
|
||||
self.av_info.geometry = geom;
|
||||
*/
|
||||
true
|
||||
Some(true)
|
||||
}
|
||||
|
||||
fn log_print(&mut self, level: retro::ffi::LogLevel, msg: &str) {
|
||||
eprint!("[{:?}] {}", level, msg);
|
||||
}
|
||||
|
||||
fn set_memory_maps(&mut self, ffi_memory_map: MemoryMap) -> bool {
|
||||
fn set_memory_maps(&mut self, ffi_memory_map: &MemoryMap) -> Option<bool> {
|
||||
self.memory_map = Some(LibRetroMemoryMap::create(&ffi_memory_map));
|
||||
true
|
||||
Some(true)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
extern crate crossbeam_channel;
|
||||
extern crate ferretro;
|
||||
extern crate ferretro_base as ferretro;
|
||||
extern crate mini_gl_fb;
|
||||
extern crate conrod_glium;
|
||||
extern crate conrod_winit;
|
|
@ -0,0 +1,258 @@
|
|||
use conrod_core::{Labelable, Widget, event::Text};
|
||||
use conrod_core::{Borderable, Color, Colorable, FontSize, Positionable, Scalar, Sizeable, WidgetCommon, builder_method, builder_methods, widget, widget_ids};
|
||||
|
||||
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct ByteGrid {
|
||||
#[conrod(common_builder)]
|
||||
common: conrod_core::widget::CommonBuilder,
|
||||
style: Style,
|
||||
start_index: usize,
|
||||
content: Vec<u8>,
|
||||
columns: usize,
|
||||
rows: usize,
|
||||
}
|
||||
|
||||
impl ByteGrid {
|
||||
pub fn new(label: String) -> Self {
|
||||
ByteGrid {
|
||||
common: conrod_core::widget::CommonBuilder::default(),
|
||||
style: Style::default(),
|
||||
start_index: 0,
|
||||
columns: 16,
|
||||
rows: 5,
|
||||
content: vec![]
|
||||
}
|
||||
}
|
||||
|
||||
fn map_xy_to_data_index(&self, x: usize, y: usize) -> usize {
|
||||
y * self.columns + x
|
||||
}
|
||||
|
||||
pub fn refresh_data(mut self, start_index: usize, source: &[u8]) -> ByteGrid {
|
||||
if self.content.len() != source.len() {
|
||||
self.content.resize(source.len(), 0u8);
|
||||
}
|
||||
self.start_index = start_index;
|
||||
self.rows = source.len() / self.columns + 1;
|
||||
self.content.copy_from_slice(source);
|
||||
self
|
||||
}
|
||||
|
||||
builder_methods! {
|
||||
pub font_size { style.font_size = Some(FontSize) }
|
||||
pub text_color { style.text_color = Some(Color) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for ByteGrid {
|
||||
type State = State;
|
||||
|
||||
type Style = Style;
|
||||
|
||||
type Event = Vec<Event>;
|
||||
|
||||
fn init_state(&self, id_gen: conrod_core::widget::id::Generator) -> Self::State {
|
||||
State {
|
||||
ids: Ids::new(id_gen),
|
||||
textbox_value: String::default(),
|
||||
uncommitted_edits: vec![None; 0],
|
||||
}
|
||||
}
|
||||
|
||||
fn style(&self) -> Self::Style {
|
||||
self.style.clone()
|
||||
}
|
||||
|
||||
fn update(mut self, args: conrod_core::widget::UpdateArgs<Self>) -> Self::Event {
|
||||
let conrod_core::widget::UpdateArgs {
|
||||
id,
|
||||
state,
|
||||
rect,
|
||||
style,
|
||||
ui,
|
||||
..
|
||||
} = args;
|
||||
|
||||
let mut events = Vec::new();
|
||||
|
||||
let text_color = style.text_color(ui.theme());
|
||||
let color = style.color(ui.theme());
|
||||
let border_color = style.border_color(ui.theme());
|
||||
let font_size = style.font_size(ui.theme());
|
||||
|
||||
let wh = rect.w_h();
|
||||
let first_col_width = 72.0;
|
||||
let col_width = 28.0;
|
||||
let first_row_height = 8.0;
|
||||
let row_height = 18.0;
|
||||
|
||||
let (mut row_items, scrollbar) = widget::List::flow_down(self.rows+2)
|
||||
.xy(rect.xy())
|
||||
.w_h(wh.0, wh.1)
|
||||
.set(state.ids.label, ui);
|
||||
|
||||
if state.uncommitted_edits.len() != self.content.len() {
|
||||
state.update(|state| {
|
||||
state.uncommitted_edits.resize(self.content.len(), None);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
while let Some(row_item) = row_items.next(ui) {
|
||||
|
||||
let column_widget = widget::List::flow_right(self.columns+1)
|
||||
//.item_size(32.0)
|
||||
.w_h(first_col_width + (col_width * self.columns as f64), row_height);
|
||||
let (mut column_items, scrollbar) = row_item.set(column_widget, ui);
|
||||
|
||||
|
||||
while let Some(column_item) = column_items.next(ui) {
|
||||
match (row_item.i, column_item.i) {
|
||||
// WEIRD BUG: the 0th row is not drawn! so I draw the label row on the 1st row instead...
|
||||
(0, _) => (),
|
||||
(1, 0) => { // corner. needed to space the cells the headings over their cells
|
||||
let label_control = conrod_core::widget::Text::new(":o")
|
||||
.color(conrod_core::color::BLACK)
|
||||
.w_h(first_col_width, first_row_height)
|
||||
.font_size(12);
|
||||
column_item.set(label_control, ui);
|
||||
}
|
||||
(1, col_index) => { // top row: column labels
|
||||
let col_label = (self.start_index + col_index - 1) as u8;
|
||||
let data = format!("{:02x}", col_label);
|
||||
let label_control = conrod_core::widget::Text::new(data.as_str())
|
||||
.color(conrod_core::color::WHITE)
|
||||
.w_h(col_width, first_row_height)
|
||||
.font_size(12);
|
||||
column_item.set(label_control, ui);
|
||||
},
|
||||
(row_index, 0) => { // left column: row labels
|
||||
let row_label = (row_index - 2) * self.columns + self.start_index;
|
||||
let data = format!("{:08x}", row_label);
|
||||
let label_control = conrod_core::widget::Text::new(data.as_str())
|
||||
.color(conrod_core::color::WHITE)
|
||||
.w_h(first_col_width, row_height)
|
||||
.font_size(12);
|
||||
column_item.set(label_control, ui);
|
||||
},
|
||||
(row_index, col_index) => { // Cells
|
||||
// Offset coordinates to account for the label rows.
|
||||
let x = col_index - 1;
|
||||
let y = row_index - 2; // because of the WEIRD BUG i mentioned above
|
||||
|
||||
let data_index = self.map_xy_to_data_index(x, y);
|
||||
|
||||
if data_index >= self.content.len() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Label is either the underlying byte, or an uncommitted edit if one is typed.
|
||||
let label = match &state.uncommitted_edits[data_index] {
|
||||
Some(edit) => edit.clone(),
|
||||
None => format!("{:02x}", self.content[data_index])
|
||||
};
|
||||
let color = match &state.uncommitted_edits[data_index] {
|
||||
Some(_) => conrod_core::color::LIGHT_ORANGE,
|
||||
None => conrod_core::color::WHITE,
|
||||
};
|
||||
|
||||
let textbox = conrod_core::widget::TextBox::new(&label)
|
||||
.w_h(col_width, row_height)
|
||||
.font_size(13)
|
||||
.border(1.0)
|
||||
.color(color);
|
||||
|
||||
for event in column_item.set(textbox, ui) {
|
||||
// handle changes in text box and any other events
|
||||
match event {
|
||||
conrod_core::widget::text_box::Event::Enter => {
|
||||
match &state.uncommitted_edits[data_index] {
|
||||
Some(uncommitted_edit) => {
|
||||
// try to parse it as hex
|
||||
match u8::from_str_radix(uncommitted_edit, 16) {
|
||||
Ok(typed_byte) => {
|
||||
state.update(|state| {
|
||||
state.uncommitted_edits[data_index] = None;
|
||||
});
|
||||
events.push(Event::Edit(self.start_index + data_index, typed_byte));
|
||||
}
|
||||
Err(_) => {
|
||||
// don't do anything, basically just reject the typed character
|
||||
}
|
||||
}
|
||||
},
|
||||
None => () // don't do anything if there's nothing to commit
|
||||
}
|
||||
}
|
||||
conrod_core::widget::text_box::Event::Update(string) => {
|
||||
state.update(|state| {
|
||||
state.uncommitted_edits[data_index] = Some(string);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
events
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
widget_ids! {
|
||||
struct Ids {
|
||||
label,
|
||||
text_box,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
ids: Ids,
|
||||
textbox_value: String,
|
||||
uncommitted_edits: Vec<Option<String>>
|
||||
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, conrod_core::WidgetStyle)]
|
||||
pub struct Style {
|
||||
/// The color of the text in the `TextEdit` widget.
|
||||
#[conrod(default = "theme.label_color")]
|
||||
pub text_color: Option<Color>,
|
||||
/// The color of the `TextEdit` widget.
|
||||
#[conrod(default = "theme.label_color")]
|
||||
pub color: Option<Color>,
|
||||
/// The font size for the text.
|
||||
#[conrod(default = "theme.font_size_medium")]
|
||||
pub font_size: Option<FontSize>,
|
||||
/// The width of the bounding `BorderedRectangle` border.
|
||||
#[conrod(default = "theme.border_width")]
|
||||
pub border: Option<Scalar>,
|
||||
/// The color of the `BorderedRecangle`'s border.
|
||||
#[conrod(default = "theme.border_color")]
|
||||
pub border_color: Option<Color>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Event {
|
||||
Edit(usize, u8)
|
||||
}
|
||||
|
||||
impl Borderable for ByteGrid {
|
||||
builder_methods! {
|
||||
border { style.border = Some(Scalar) }
|
||||
border_color { style.border_color = Some(Color) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Colorable for ByteGrid {
|
||||
builder_method!(color {
|
||||
style.color = Some(Color)
|
||||
});
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
use std::{cell::RefCell, collections::HashSet, io::{Read, Write}, pin::Pin, rc::Rc};
|
||||
|
||||
use compress::{lz4, rle};
|
||||
use conrod_core::{Borderable, Colorable, Dimensions, Labelable, Positionable, Sizeable, Widget, position::Place, widget, widget_ids};
|
||||
use find_folder::SearchFolder;
|
||||
use glium::Surface;
|
||||
|
@ -7,7 +8,7 @@ use glutin::{dpi::LogicalSize, event::{ElementState, Event, KeyboardInput, Virtu
|
|||
use meval::Context;
|
||||
use mini_gl_fb::{config, get_fancy};
|
||||
|
||||
use crate::{MyEmulator, memory::search::{MemorySearch, SearchTerm}, ui::{labelled_textbox::LabelledTextbox, memory_watch::remove_temporary_watches}};
|
||||
use crate::{MyEmulator, memory::search::{MemorySearch, SearchTerm}, ui::{byte_grid::ByteGrid, labelled_textbox::LabelledTextbox, memory_watch::{WatchDataType, remove_temporary_watches}}};
|
||||
|
||||
use super::{helpers, memory_watch::MemoryWatch, multi_window::TrackedWindow};
|
||||
|
||||
|
@ -26,6 +27,9 @@ widget_ids!(struct Ids {
|
|||
watch_background,
|
||||
add_watch_textbox,
|
||||
override_watch_textbox,
|
||||
byte_grid,
|
||||
byte_grid_start,
|
||||
byte_grid_length,
|
||||
});
|
||||
|
||||
pub struct DebugWindow {
|
||||
|
@ -40,11 +44,13 @@ pub struct DebugWindow {
|
|||
watches: Vec<MemoryWatch>,
|
||||
watches_selected: HashSet<usize>,
|
||||
step_backward_states: Vec<Vec<u8>>,
|
||||
byte_grid_start: usize,
|
||||
byte_grid_length: usize
|
||||
}
|
||||
impl DebugWindow {
|
||||
pub fn new(event_loop: &EventLoop<()>, emu: &Rc<RefCell<Pin<Box<MyEmulator>>>>) -> Box<Self> {
|
||||
let config = config! {
|
||||
window_title: "rustro debugger".to_string(),
|
||||
window_title: "ferretro debugger".to_string(),
|
||||
window_size: LogicalSize::new(1024.0, 768.0)
|
||||
};
|
||||
let mut ui = conrod_core::UiBuilder::new([config.window_size.width, config.window_size.height]).build();
|
||||
|
@ -75,6 +81,8 @@ impl DebugWindow {
|
|||
watches: Vec::new(),
|
||||
watches_selected: HashSet::new(),
|
||||
step_backward_states: Vec::new(),
|
||||
byte_grid_start: 0,
|
||||
byte_grid_length: 0,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -170,7 +178,12 @@ impl TrackedWindow for DebugWindow {
|
|||
.was_clicked()
|
||||
{
|
||||
match emu.retro.serialize() {
|
||||
Ok(data) => self.step_backward_states.push(data),
|
||||
Ok(data) => {
|
||||
let mut compressed_data = vec![];
|
||||
let mut enc = rle::Encoder::new(&mut compressed_data);
|
||||
enc.write_all(&data);
|
||||
self.step_backward_states.push(compressed_data)
|
||||
},
|
||||
Err(e) => eprintln!("Problem serializing backward state {:?}", e),
|
||||
}
|
||||
emu.frames_to_run_before_pause = Some(1);
|
||||
|
@ -188,7 +201,10 @@ impl TrackedWindow for DebugWindow {
|
|||
match self.step_backward_states.pop() {
|
||||
Some(data) => {
|
||||
match self.step_backward_states.pop() {
|
||||
Some(data) => {
|
||||
Some(compressed_data) => {
|
||||
let mut dec = rle::Decoder::new(compressed_data.as_slice());
|
||||
let mut data = vec![];
|
||||
dec.read_to_end(&mut data);
|
||||
emu.retro.unserialize(data.as_slice());
|
||||
emu.frames_to_run_before_pause = Some(1);
|
||||
emu.paused = false;
|
||||
|
@ -307,7 +323,7 @@ impl TrackedWindow for DebugWindow {
|
|||
remove_temporary_watches(&mut self.watches, &mut self.watches_selected);
|
||||
|
||||
for candidate in &self.search.candidates {
|
||||
self.watches.push(MemoryWatch::new(*candidate, watch_length, Some("search".to_string()), None, true));
|
||||
self.watches.push(MemoryWatch::new(*candidate, WatchDataType::U8, Some("search".to_string()), None, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -415,7 +431,7 @@ impl TrackedWindow for DebugWindow {
|
|||
|
||||
for event in LabelledTextbox::new(String::from("Add Watch"))
|
||||
.down_from(self.ids.search_box, 8.0)
|
||||
.font_size(16)
|
||||
.font_size(12)
|
||||
.w_h(230.0, 30.0)
|
||||
.border(2.0)
|
||||
.border_color(conrod_core::color::BLACK)
|
||||
|
@ -428,7 +444,7 @@ impl TrackedWindow for DebugWindow {
|
|||
match usize::from_str_radix(&value, 16) {
|
||||
Ok(address) => {
|
||||
if address < memory.len() {
|
||||
self.watches.push(MemoryWatch::new(address, 1, None, None, false));
|
||||
self.watches.push(MemoryWatch::new(address, WatchDataType::U32BE, None, None, false));
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
|
@ -439,6 +455,72 @@ impl TrackedWindow for DebugWindow {
|
|||
}
|
||||
}
|
||||
|
||||
for event in LabelledTextbox::new(String::from("Start index"))
|
||||
.down_from(self.ids.save_button, 32.0)
|
||||
.font_size(12)
|
||||
.w_h(230.0, 30.0)
|
||||
.border(2.0)
|
||||
.border_color(conrod_core::color::BLACK)
|
||||
.color(conrod_core::color::WHITE)
|
||||
.text_color(conrod_core::color::BLACK)
|
||||
.set(self.ids.byte_grid_start, &mut ui)
|
||||
{
|
||||
match event {
|
||||
crate::ui::labelled_textbox::Event::Enter(value) => {
|
||||
match usize::from_str_radix(&value, 16) {
|
||||
Ok(address) => {
|
||||
self.byte_grid_start = address;
|
||||
},
|
||||
Err(e) => {
|
||||
println!("couldn't parse address, is it a hex string? {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for event in LabelledTextbox::new(String::from("Length (hex)"))
|
||||
.right_from(self.ids.byte_grid_start, 32.0)
|
||||
.font_size(12)
|
||||
.w_h(230.0, 30.0)
|
||||
.border(2.0)
|
||||
.border_color(conrod_core::color::BLACK)
|
||||
.color(conrod_core::color::WHITE)
|
||||
.text_color(conrod_core::color::BLACK)
|
||||
.set(self.ids.byte_grid_length, &mut ui)
|
||||
{
|
||||
match event {
|
||||
crate::ui::labelled_textbox::Event::Enter(value) => {
|
||||
match usize::from_str_radix(&value, 16) {
|
||||
Ok(length) => {
|
||||
self.byte_grid_length = length;
|
||||
},
|
||||
Err(e) => {
|
||||
println!("couldn't parse length, is it a hex string? {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for event in ByteGrid::new(String::from("Memory Search"))
|
||||
.down_from(self.ids.byte_grid_start, 32.0)
|
||||
.font_size(16)
|
||||
.w_h(600.0, 600.0)
|
||||
.border(2.0)
|
||||
.border_color(conrod_core::color::BLACK)
|
||||
.color(conrod_core::color::WHITE)
|
||||
.text_color(conrod_core::color::BLACK)
|
||||
.refresh_data(self.byte_grid_start, &memory[self.byte_grid_start..self.byte_grid_start + self.byte_grid_length])
|
||||
.set(self.ids.byte_grid, &mut ui)
|
||||
{
|
||||
match event {
|
||||
crate::ui::byte_grid::Event::Edit(new_index, new_data) => {
|
||||
self.watches.push(MemoryWatch::new(new_index, WatchDataType::U8, None, Some(format!("{:0x}", new_data)), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
self.display.gl_window().window().request_redraw();
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
use std::{collections::HashSet, fmt::Display};
|
||||
use std::{collections::HashSet, fmt::Display, io::Cursor};
|
||||
use binrw::prelude::*;
|
||||
|
||||
use meval::{Context, Expr};
|
||||
|
||||
|
||||
pub struct MemoryWatch {
|
||||
pub start: usize,
|
||||
pub length: usize,
|
||||
pub data_type: WatchDataType,
|
||||
pub last_seen_value: Option<Vec<u8>>,
|
||||
pub label: Option<String>,
|
||||
pub user_input: Option<String>,
|
||||
|
@ -14,10 +15,10 @@ pub struct MemoryWatch {
|
|||
}
|
||||
|
||||
impl MemoryWatch {
|
||||
pub fn new(start: usize, length: usize, label: Option<String>, user_input: Option<String>, temporary: bool) -> Self {
|
||||
pub fn new(start: usize, data_type: WatchDataType, label: Option<String>, user_input: Option<String>, temporary: bool) -> Self {
|
||||
MemoryWatch {
|
||||
start,
|
||||
length,
|
||||
data_type,
|
||||
last_seen_value: None,
|
||||
label,
|
||||
user_input,
|
||||
|
@ -27,18 +28,19 @@ impl MemoryWatch {
|
|||
}
|
||||
|
||||
pub fn refresh(&mut self, data: &mut [u8], meval_context: &Context) {
|
||||
if self.start + self.length > data.len() {
|
||||
let slice_len = get_slice_len(&self.data_type);
|
||||
if self.start + slice_len > data.len() {
|
||||
self.last_seen_value = None;
|
||||
self.status = WatchStatus::OutOfBounds;
|
||||
return;
|
||||
}
|
||||
|
||||
if let None = self.last_seen_value {
|
||||
self.last_seen_value = Some(vec![0; self.length]);
|
||||
self.last_seen_value = Some(vec![0; slice_len]);
|
||||
}
|
||||
|
||||
if let Some(user_input) = &self.user_input {
|
||||
if user_input.starts_with("=") && self.length == 1{ // only support one byte for expressions for now
|
||||
if let (Some(user_input), WatchDataType::U8) = (&self.user_input, &self.data_type) {
|
||||
if user_input.starts_with("=") { // only support one byte for expressions for now
|
||||
// evaluate formula
|
||||
match &user_input[1..].parse::<Expr>() {
|
||||
Ok(expr) => {
|
||||
|
@ -64,8 +66,8 @@ impl MemoryWatch {
|
|||
else { // it's data
|
||||
match hex::decode(user_input) {
|
||||
Ok(user_input_bytes) => {
|
||||
if user_input_bytes.len() == self.length {
|
||||
data[self.start..self.start + self.length].copy_from_slice(user_input_bytes.as_slice());
|
||||
if user_input_bytes.len() == slice_len {
|
||||
data[self.start..self.start + slice_len].copy_from_slice(user_input_bytes.as_slice());
|
||||
self.status = WatchStatus::Ok;
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +77,7 @@ impl MemoryWatch {
|
|||
}
|
||||
|
||||
if let Some(last_seen_value) = &mut self.last_seen_value {
|
||||
last_seen_value.copy_from_slice(&data[self.start..self.start + self.length]);
|
||||
last_seen_value.copy_from_slice(&data[self.start..self.start + slice_len]);
|
||||
}
|
||||
else {
|
||||
self.status = WatchStatus::Idk;
|
||||
|
@ -88,10 +90,13 @@ impl Display for MemoryWatch {
|
|||
if let Some(label) = &self.label {
|
||||
write!(f, "{} ", label)?;
|
||||
}
|
||||
write!(f, "{:X}[{}]", self.start, self.length)?;
|
||||
write!(f, "{:X}", self.start)?;
|
||||
|
||||
write!(f, " = {}", match &self.last_seen_value {
|
||||
Some(last_seen_value) => hex::encode(last_seen_value),
|
||||
Some(last_seen_value) => match display_datatype(&self.data_type, &last_seen_value) {
|
||||
Ok(display_str) => display_str,
|
||||
Err(e) => format!("err: {:?}", e),
|
||||
},
|
||||
None => "???".to_string()
|
||||
})?;
|
||||
Ok(())
|
||||
|
@ -116,4 +121,33 @@ pub fn remove_temporary_watches(watches: &mut Vec<MemoryWatch>, watches_selected
|
|||
watches_selected.remove(&i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum WatchDataType {
|
||||
U8,
|
||||
U8Array(usize),
|
||||
U32BE,
|
||||
}
|
||||
fn get_slice_len(data_type: &WatchDataType) -> usize {
|
||||
match data_type {
|
||||
WatchDataType::U8 => 1,
|
||||
WatchDataType::U8Array(size) => *size,
|
||||
WatchDataType::U32BE => 4,
|
||||
}
|
||||
}
|
||||
|
||||
fn display_datatype(data_type: &WatchDataType, data: &Vec<u8>) -> Result<String, binrw::Error> {
|
||||
match data_type {
|
||||
WatchDataType::U8 => Ok(hex::encode(data)),
|
||||
WatchDataType::U8Array(_) => Ok(hex::encode(data)),
|
||||
_ => { /* binread types to display as debug */
|
||||
// set up a cursor
|
||||
let mut reader = Cursor::new(data);
|
||||
|
||||
Ok(format!("{:?}", match data_type {
|
||||
WatchDataType::U8 | WatchDataType::U8Array(_) => panic!("shouldn't reach here"),
|
||||
WatchDataType::U32BE => reader.read_be::<u32>()?
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,4 +2,5 @@ pub mod debug_window;
|
|||
pub mod helpers;
|
||||
pub mod multi_window;
|
||||
pub mod memory_watch;
|
||||
pub mod labelled_textbox;
|
||||
pub mod labelled_textbox;
|
||||
pub mod byte_grid;
|
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "multitrack_recorder"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
authors = ["viv <vvnl+git@protonmail.com>"]
|
||||
|
||||
[build-dependencies]
|
||||
cc = "^1"
|
||||
|
||||
[dependencies]
|
||||
structopt = "^0.3"
|
||||
failure = "^0.1"
|
||||
|
||||
gilrs = "0.8.1"
|
||||
find_folder="0.3.0"
|
||||
hex = "0.4.3"
|
||||
meval = "0.2.0"
|
||||
compress = "0.2.1"
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
pub mod recorder;
|
||||
pub mod traits;
|
||||
pub mod vec_track;
|
|
@ -0,0 +1,210 @@
|
|||
use std::{fmt::{Debug, Display}, marker::PhantomData, ops::{AddAssign, Index}, sync::Arc};
|
||||
|
||||
use super::{traits::{Incrementable, LinearSink, LinearSource}, vec_track::VecTrack};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ArcBoxRecorder<Track: LinearSink<TData, TTime> + LinearSource<Arc<Box<TData>>, TTime>, TData, TTime> {
|
||||
pub is_recording: bool,
|
||||
pub record_frequency: u64,
|
||||
pub current_track: usize,
|
||||
pub current_time: TTime,
|
||||
pub tracks: Vec<TrackWithMetadata<Track, TTime>>, /// Tracks and the index of the track which spawned them (if any)
|
||||
track_data_marker: PhantomData<TData>,
|
||||
track_time_marker: PhantomData<TTime>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TrackWithMetadata<TTrack, TTime> {
|
||||
pub track: TTrack,
|
||||
pub parent_track_id: Option<usize>,
|
||||
pub start_time: TTime
|
||||
}
|
||||
|
||||
impl<Track, TData, TTime> ArcBoxRecorder<Track, TData, TTime>
|
||||
where Track: LinearSink<TData, TTime> + LinearSource<Arc<Box<TData>>, TTime> + Default, TTime: Default + Copy {
|
||||
pub fn new() -> Self {
|
||||
ArcBoxRecorder {
|
||||
is_recording: false,
|
||||
record_frequency: 60,
|
||||
current_track: 0,
|
||||
current_time: TTime::default(),
|
||||
tracks: vec![
|
||||
TrackWithMetadata {
|
||||
track: Track::default(),
|
||||
parent_track_id: None,
|
||||
start_time: TTime::default()
|
||||
}
|
||||
],
|
||||
track_data_marker: PhantomData,
|
||||
track_time_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
pub fn switch_track(&mut self, track_num: usize) {
|
||||
while track_num >= self.tracks.len() {
|
||||
self.tracks.push(TrackWithMetadata {
|
||||
track: Track::default(),
|
||||
parent_track_id: Some(self.current_track),
|
||||
start_time: self.current_time,
|
||||
});
|
||||
}
|
||||
self.current_track = track_num;
|
||||
}
|
||||
|
||||
pub fn move_insertion_head(&mut self, new_time: TTime) {
|
||||
// todo: check if it's beyond the end, decide what should happen.
|
||||
// todo: NEED some way to seek to the end of the current track.
|
||||
|
||||
self.current_time = new_time;
|
||||
}
|
||||
}
|
||||
|
||||
impl<Track, TData, TTime> LinearSink<TData, TTime> for ArcBoxRecorder<Track, TData, TTime>
|
||||
where Track: LinearSink<TData, TTime> + LinearSource<Arc<Box<TData>>, TTime> + Default,
|
||||
TTime: Default + Copy + AddAssign + Incrementable {
|
||||
fn push(&mut self, data: TData) {
|
||||
if self.time_is_leaf(self.current_time) {
|
||||
self.tracks[self.current_track].track.push(data);
|
||||
}
|
||||
else {
|
||||
// go to a new track, and push to there.
|
||||
self.switch_track(self.tracks.len());
|
||||
self.tracks[self.current_track].track.push(data);
|
||||
}
|
||||
self.current_time += TTime::one_step();
|
||||
}
|
||||
|
||||
fn time_is_leaf(&self, when: TTime) -> bool {
|
||||
self.tracks[self.current_track].track.time_is_leaf(when)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Track, TData, TTime> LinearSource<Arc<Box<TData>>, TTime> for ArcBoxRecorder<Track, TData, TTime>
|
||||
where
|
||||
Track: LinearSink<TData, TTime> + LinearSource<Arc<Box<TData>>, TTime> + Default + Debug,
|
||||
TTime: Default + Display + Debug {
|
||||
fn get(&self, when: &TTime) -> Arc<Box<TData>> {
|
||||
let mut current_track = &self.tracks[self.current_track];
|
||||
while !current_track.track.check_starts_after(when) {
|
||||
// Does the current track have a parent
|
||||
match ¤t_track.parent_track_id {
|
||||
Some(parent_id) => {
|
||||
current_track = &self.tracks[*parent_id]
|
||||
}
|
||||
None => {
|
||||
panic!("Can't get data at time {} because there is no parent for track {:?}", when, current_track);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
current_track.track.get(when)
|
||||
}
|
||||
|
||||
fn check_starts_after(&self, when: &TTime) -> bool {
|
||||
panic!("not implemented for ArcBoxRecorder")
|
||||
}
|
||||
|
||||
fn get_from_start_to_time(&self, when: &TTime) -> Vec<Arc<Box<TData>>> {
|
||||
// get current track and all parent tracks, and how many items to take from each.
|
||||
let mut slices = vec![];
|
||||
let mut current_track = &self.tracks[self.current_track];
|
||||
let mut when_until = when;
|
||||
|
||||
// tracks between current track and the root track
|
||||
while match current_track.parent_track_id {
|
||||
Some(parent_track_id) => {
|
||||
slices.push(current_track.track.get_from_start_to_time(when_until));
|
||||
when_until = ¤t_track.start_time;
|
||||
current_track = &self.tracks[parent_track_id];
|
||||
true
|
||||
},
|
||||
None => {
|
||||
slices.push(current_track.track.get_from_start_to_time(when_until));
|
||||
false
|
||||
}
|
||||
} {}
|
||||
|
||||
slices.into_iter().rev().flatten().map(|rc| rc.clone()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<Track, TData, TTime> Default for ArcBoxRecorder<Track, TData, TTime>
|
||||
where Track: LinearSink<TData, TTime> + LinearSource<Arc<Box<TData>>, TTime> + Default,
|
||||
TData: Clone,
|
||||
TTime: Copy + Default{
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_vectrack_recorder<TData: Clone>() -> ArcBoxRecorder<VecTrack<TData, usize>, TData, usize>{
|
||||
Default::default()
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{traits::LinearSource, vec_track::VecTrack};
|
||||
use crate::traits::LinearSink;
|
||||
|
||||
use super::{ArcBoxRecorder, new_vectrack_recorder};
|
||||
|
||||
|
||||
#[test]
|
||||
fn push_single_track() {
|
||||
let mut rec = new_vectrack_recorder();
|
||||
for i in 0..10 {
|
||||
rec.push(i);
|
||||
}
|
||||
println!("Recorder: {:?}", rec);
|
||||
compare_track(&rec.tracks[rec.current_track].track, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||
|
||||
// test this function too
|
||||
let from_start_to_time: Vec<i32> = rec.get_from_start_to_time(&15 /* intentionally past the end*/).into_iter().map(|d| **d).collect();
|
||||
assert_eq!(from_start_to_time.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diverge() {
|
||||
let mut rec = new_vectrack_recorder();
|
||||
for i in 0..10 {
|
||||
rec.push(i);
|
||||
}
|
||||
rec.move_insertion_head(3);
|
||||
for i in 3..8 {
|
||||
rec.push(i*10);
|
||||
}
|
||||
println!("Recorder: {:?}", rec);
|
||||
//compare_track(&rec.tracks[rec.current_track].track, &[0, 1, 2, 30, 40, 50, 60, 70, 80, 90]);
|
||||
//compare_track(&rec.tracks[0].track, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||
|
||||
// test this function too
|
||||
let mut from_start_to_time: Vec<i32> = rec.get_from_start_to_time(&15 /* intentionally past the end*/).into_iter().map(|d| **d).collect();
|
||||
assert_eq!(from_start_to_time.as_slice(), &[0, 1, 2, 30, 40, 50, 60, 70]);
|
||||
|
||||
rec.switch_track(2); // create a new track that doesn't exist, it should contain the same
|
||||
from_start_to_time = rec.get_from_start_to_time(&15 /* intentionally past the end*/).into_iter().map(|d| **d).collect();
|
||||
assert_eq!(from_start_to_time.as_slice(), &[0, 1, 2, 30, 40, 50, 60, 70]);
|
||||
|
||||
rec.switch_track(0); // go to the root track
|
||||
from_start_to_time = rec.get_from_start_to_time(&15 /* intentionally past the end*/).into_iter().map(|d| **d).collect();
|
||||
assert_eq!(from_start_to_time.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||
|
||||
rec.switch_track(3); // and create a new track based on the root one at the current position
|
||||
from_start_to_time = rec.get_from_start_to_time(&15 /* intentionally past the end*/).into_iter().map(|d| **d).collect();
|
||||
assert_eq!(from_start_to_time.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7]);
|
||||
}
|
||||
|
||||
fn compare_track(track: &VecTrack<i32, usize>, expected: &[i32]){
|
||||
// copy the values out and then compare
|
||||
let mut track_data = vec![];
|
||||
for i in &track.data {
|
||||
track_data.push(***i);
|
||||
}
|
||||
|
||||
assert_eq!(track_data.as_slice(), expected, "expected: {:?}, actual: {:?}", expected, track_data.as_slice());
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
pub trait LinearSink<TData, TTime> {
|
||||
fn push(&mut self, data: TData);
|
||||
fn time_is_leaf(&self, start: TTime) -> bool;
|
||||
}
|
||||
|
||||
pub trait LinearSource<TDataRef, TTime> {
|
||||
fn get(&self, when: &TTime) -> TDataRef;
|
||||
fn get_from_start_to_time(&self, when: &TTime) -> Vec<TDataRef>;
|
||||
|
||||
/// Returns true if this track begins at or after the provided time.
|
||||
fn check_starts_after(&self, when: &TTime) -> bool;
|
||||
}
|
||||
|
||||
pub trait ConstructAtTime {
|
||||
fn new_at_time(time: usize) -> Self;
|
||||
}
|
||||
|
||||
pub trait Incrementable {
|
||||
fn one_step() -> Self;
|
||||
}
|
||||
|
||||
impl Incrementable for usize {
|
||||
fn one_step() -> Self {
|
||||
1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
use std::{borrow::Borrow, marker::PhantomData, ops::{Index, Sub}, slice::SliceIndex, sync::Arc};
|
||||
|
||||
use super::traits::{ConstructAtTime, LinearSink, LinearSource};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VecTrack<TData, TTime> {
|
||||
pub start: usize,
|
||||
pub data: Vec<Arc<Box<TData>>>,
|
||||
_time_type: PhantomData<TTime>
|
||||
}
|
||||
|
||||
impl<TData, TTime> VecTrack<TData, TTime>
|
||||
where TData: Clone, TTime: Borrow<usize> {
|
||||
fn begin_new(start: usize) -> Self {
|
||||
VecTrack {
|
||||
start,
|
||||
data: vec![],
|
||||
_time_type: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<TData: Clone, TTime: Borrow<usize> + Default> Default for VecTrack<TData, TTime> {
|
||||
fn default() -> Self {
|
||||
Self::new_at_time(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<TData: Clone, TTime: Borrow<usize>> ConstructAtTime for VecTrack<TData, TTime> {
|
||||
|
||||
fn new_at_time(time: usize) -> Self {
|
||||
Self::begin_new(time)
|
||||
}
|
||||
}
|
||||
|
||||
impl<TData: Clone, TTime: Borrow<usize>> LinearSink<TData, TTime> for VecTrack<TData, TTime> {
|
||||
|
||||
fn push(&mut self, new_data: TData) {
|
||||
self.data.push(Arc::new(Box::new(new_data)))
|
||||
}
|
||||
|
||||
fn time_is_leaf(&self, start: TTime) -> bool {
|
||||
*start.borrow() >= self.data.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<TData, TTime: Borrow<usize> + Sub<usize>> LinearSource<Arc<Box<TData>>, TTime> for VecTrack<TData, TTime> {
|
||||
fn get(&self, when: &TTime) -> Arc<Box<TData>> {
|
||||
self.data[when.borrow() - self.start].clone()
|
||||
}
|
||||
|
||||
fn get_from_start_to_time(&self, when: &TTime) -> Vec<Arc<Box<TData>>> {
|
||||
let when_index = usize::min(self.data.len(), when.borrow() - self.start);
|
||||
self.data[..when_index].to_vec()
|
||||
}
|
||||
|
||||
fn check_starts_after(&self, when: &TTime) -> bool {
|
||||
*when.borrow() >= self.start
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue