]> git.huck.website - cellseq.git/commitdiff
reset: getting async setup
authorHuck Boles <huck@huck.website>
Mon, 12 Jun 2023 02:17:30 +0000 (21:17 -0500)
committerHuck Boles <huck@huck.website>
Mon, 12 Jun 2023 02:17:30 +0000 (21:17 -0500)
21 files changed:
Cargo.lock
Cargo.toml
src/cells.rs
src/graphics.rs
src/graphics/actions.rs [deleted file]
src/graphics/area.rs [deleted file]
src/graphics/keys.rs [deleted file]
src/graphics/layout.rs [deleted file]
src/graphics/map.rs [deleted file]
src/graphics/point.rs [deleted file]
src/graphics/render.rs [deleted file]
src/graphics/selector.rs [deleted file]
src/lib.rs
src/main.rs
src/music.rs [deleted file]
src/music/scale.rs [deleted file]
src/music/transport.rs [deleted file]
src/state.rs [deleted file]
src/state/transport.rs [deleted file]
src/tests.rs [new file with mode: 0644]
src/transport.rs [deleted file]

index e52137ca2283dd9f7f64b54722a82942179880b0..7cdf62e1a227743e415a968219cdbb901a0402aa 100644 (file)
@@ -14,15 +14,21 @@ version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
+[[package]]
+name = "bytes"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
+
 [[package]]
 name = "cellseq"
 version = "0.1.0"
 dependencies = [
- "crossbeam",
  "crossterm",
  "eyre",
  "ndarray",
  "rand",
+ "tokio",
 ]
 
 [[package]]
@@ -31,73 +37,6 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
-[[package]]
-name = "crossbeam"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c"
-dependencies = [
- "cfg-if",
- "crossbeam-channel",
- "crossbeam-deque",
- "crossbeam-epoch",
- "crossbeam-queue",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-channel"
-version = "0.5.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
-dependencies = [
- "cfg-if",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-deque"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
-dependencies = [
- "cfg-if",
- "crossbeam-epoch",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-epoch"
-version = "0.9.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
-dependencies = [
- "autocfg",
- "cfg-if",
- "crossbeam-utils",
- "memoffset",
- "scopeguard",
-]
-
-[[package]]
-name = "crossbeam-queue"
-version = "0.3.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add"
-dependencies = [
- "cfg-if",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.8.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
-dependencies = [
- "cfg-if",
-]
-
 [[package]]
 name = "crossterm"
 version = "0.26.1"
@@ -135,15 +74,24 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.9"
+version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
 dependencies = [
  "cfg-if",
  "libc",
  "wasi",
 ]
 
+[[package]]
+name = "hermit-abi"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "indenter"
 version = "0.3.3"
@@ -152,15 +100,15 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
 
 [[package]]
 name = "libc"
-version = "0.2.144"
+version = "0.2.146"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
 
 [[package]]
 name = "lock_api"
-version = "0.4.9"
+version = "0.4.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
+checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -168,9 +116,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.18"
+version = "0.4.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
+checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
 
 [[package]]
 name = "matrixmultiply"
@@ -182,15 +130,6 @@ dependencies = [
  "rawpointer",
 ]
 
-[[package]]
-name = "memoffset"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
-dependencies = [
- "autocfg",
-]
-
 [[package]]
 name = "mio"
 version = "0.8.8"
@@ -200,7 +139,7 @@ dependencies = [
  "libc",
  "log",
  "wasi",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -244,11 +183,21 @@ dependencies = [
  "autocfg",
 ]
 
+[[package]]
+name = "num_cpus"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
 [[package]]
 name = "once_cell"
-version = "1.17.2"
+version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
 
 [[package]]
 name = "parking_lot"
@@ -262,23 +211,47 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.7"
+version = "0.9.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
+checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
 dependencies = [
  "cfg-if",
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-sys 0.45.0",
+ "windows-targets",
 ]
 
+[[package]]
+name = "pin-project-lite"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
+
 [[package]]
 name = "ppv-lite86"
 version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
+[[package]]
+name = "proc-macro2"
+version = "1.0.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
+dependencies = [
+ "proc-macro2",
+]
+
 [[package]]
 name = "rand"
 version = "0.8.5"
@@ -317,9 +290,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
 
 [[package]]
 name = "redox_syscall"
-version = "0.2.16"
+version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
 dependencies = [
  "bitflags",
 ]
@@ -366,6 +339,63 @@ version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
 
+[[package]]
+name = "socket2"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tokio"
+version = "1.28.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2"
+dependencies = [
+ "autocfg",
+ "bytes",
+ "libc",
+ "mio",
+ "num_cpus",
+ "parking_lot",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2",
+ "tokio-macros",
+ "windows-sys",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
+
 [[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
@@ -394,37 +424,13 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
-[[package]]
-name = "windows-sys"
-version = "0.45.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
-dependencies = [
- "windows-targets 0.42.2",
-]
-
 [[package]]
 name = "windows-sys"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
 dependencies = [
- "windows-targets 0.48.0",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
-dependencies = [
- "windows_aarch64_gnullvm 0.42.2",
- "windows_aarch64_msvc 0.42.2",
- "windows_i686_gnu 0.42.2",
- "windows_i686_msvc 0.42.2",
- "windows_x86_64_gnu 0.42.2",
- "windows_x86_64_gnullvm 0.42.2",
- "windows_x86_64_msvc 0.42.2",
+ "windows-targets",
 ]
 
 [[package]]
@@ -433,93 +439,51 @@ version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
 dependencies = [
- "windows_aarch64_gnullvm 0.48.0",
- "windows_aarch64_msvc 0.48.0",
- "windows_i686_gnu 0.48.0",
- "windows_i686_msvc 0.48.0",
- "windows_x86_64_gnu 0.48.0",
- "windows_x86_64_gnullvm 0.48.0",
- "windows_x86_64_msvc 0.48.0",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
 ]
 
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
-
 [[package]]
 name = "windows_aarch64_gnullvm"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
 
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
-
 [[package]]
 name = "windows_aarch64_msvc"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
 
-[[package]]
-name = "windows_i686_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
-
 [[package]]
 name = "windows_i686_gnu"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
 
-[[package]]
-name = "windows_i686_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
-
 [[package]]
 name = "windows_i686_msvc"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
 
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
-
 [[package]]
 name = "windows_x86_64_gnu"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
 
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
-
 [[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
 
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
-
 [[package]]
 name = "windows_x86_64_msvc"
 version = "0.48.0"
index 6dc1a4971793cf97dfc2844f118457187a6ea1f2..317d0c8f2c7aad17e45235764ea7b90d8496fc19 100644 (file)
@@ -10,4 +10,4 @@ ndarray = "0.15"
 rand = "0.8"
 crossterm = "0.26"
 eyre = "0.6"
-crossbeam = "0.8.2"
+tokio = { version = "1", features = ["full"] }
index f04e9b30d30ceead7600767828632cd7c7d06e25..f2ee6b03f76f3fe5361739e797d109800a0bd616 100644 (file)
@@ -1,12 +1,15 @@
-use crate::{Map, Point};
-use crossterm::style::{
-    Attribute, Attributes,
-    Color::{Black, Green, Grey},
-    Colors,
+use crossterm::{
+    cursor::MoveTo,
+    queue,
+    style::{
+        Attribute::{Bold, Reset},
+        Color::{Black, Green, Grey},
+        ContentStyle, Print, SetStyle,
+    },
 };
 use ndarray::Array2;
 use rand::{thread_rng, Rng};
-use std::{cell::Cell, ops::Deref};
+use std::{cell::Cell, io::stdout, ops::Deref};
 
 use super::*;
 
@@ -19,12 +22,13 @@ pub enum State {
 #[derive(Debug, Clone)]
 pub struct World {
     pub map: Array2<Cell<State>>,
+    pub area: Area,
 }
 
 impl World {
     pub fn new(area: Area) -> Self {
         let map = Array2::from_elem((area.width(), area.height()), Cell::new(State::Dead));
-        Self { map }
+        Self { map, area }
     }
 
     pub fn randomize(&mut self, val: f64) {
@@ -47,15 +51,13 @@ impl World {
             };
         }
 
-        wrap!(self.column(0), self.column(self.x_size() - 2));
-        wrap!(self.column(self.x_size() - 1), self.column(1));
-        wrap!(self.row(0), self.row(self.y_size() - 2));
-        wrap!(self.row(self.y_size() - 1), self.row(1));
+        wrap!(self.column(0), self.column(self.area.width() - 2));
+        wrap!(self.column(self.area.width() - 1), self.column(1));
+        wrap!(self.row(0), self.row(self.area.height() - 2));
+        wrap!(self.row(self.area.height() - 1), self.row(1));
     }
-}
 
-impl Map<Cell<State>> for World {
-    fn update(&mut self) {
+    pub fn update(&mut self) {
         let mut previous = self.clone();
         previous.wrap_walls();
         for (next, prev) in self
@@ -82,36 +84,33 @@ impl Map<Cell<State>> for World {
         }
     }
 
-    fn x_size(&self) -> usize {
-        self.ncols()
-    }
-
-    fn y_size(&self) -> usize {
-        self.nrows()
-    }
-
-    fn characters(&self) -> (char, char) {
-        ('●', '◌')
-    }
-
-    fn colors(&self) -> (Colors, Colors) {
-        (Colors::new(Green, Black), Colors::new(Grey, Black))
-    }
-
-    fn styles(&self) -> (Attributes, Attributes) {
-        (Attribute::Bold.into(), Attribute::Reset.into())
-    }
-
-    fn draw_point(&self, point: Point) -> Option<char> {
-        if let Some(cell) = self.get((point.y, point.x)) {
+    fn draw_point(&self, point: Point, offset: Point) -> Result<()> {
+        let mut style = ContentStyle {
+            foreground_color: None,
+            background_color: Some(Black),
+            underline_color: None,
+            attributes: Reset.into(),
+        };
+        let char = if let Some(cell) = self.get::<(usize, usize)>(point.into()) {
             if cell.get() == State::Alive {
-                return Some('●');
+                style.foreground_color = Some(Green);
+                style.attributes = Bold.into();
+                '●'
             } else {
-                return Some('◌');
+                style.background_color = Some(Grey);
+                '◌'
             }
         } else {
-            return None;
-        }
+            ' '
+        };
+
+        queue!(
+            stdout(),
+            MoveTo(offset.x, offset.y),
+            SetStyle(style),
+            Print(char)
+        )?;
+        Ok(())
     }
 }
 
index 5415c8cdb44381ab57b4a55aedf9c3a1453f58c8..d224b4bc2df231334dae3c3eb2568041fd8d0dea 100644 (file)
-mod actions;
-mod area;
-mod keys;
-mod layout;
-mod map;
-mod point;
-mod render;
-mod selector;
-
-pub use actions::*;
-pub use area::*;
-pub use keys::*;
-pub use layout::*;
-pub use map::*;
-pub use point::*;
-pub use render::*;
-pub use selector::*;
-
 use super::*;
 
-use crossterm::{
-    cursor::MoveTo,
-    event::{read, Event},
-    execute, queue,
-    style::{Print, SetAttributes, SetColors},
-    terminal,
-};
-use eyre::Result;
-use std::{
-    io::{stdout, Write},
-    sync::{Arc, Mutex},
-    thread,
-    time::Duration,
-};
-
-pub fn draw_map<T>(map: &impl Map<T>, area: &Area) -> Result<()> {
-    let ((x_zero, y_zero), (x_max, y_max)) = area.to_u16()?;
-
-    let origin = Point::new(x_zero.into(), y_zero.into());
-
-    let (char_on, char_off) = map.characters();
-    let (on_colors, off_colors) = map.colors();
-    let (style_on, style_off) = map.styles();
-
-    for x in 0..=(map.x_size()) {
-        for y in 0..=(map.y_size()) {
-            let point = Point::new(x, y);
-            let char = map.draw_point(point).unwrap_or(' ');
-            let (x_off, y_off) = origin.u16_offset(point)?;
-
-            if x_off <= x_zero || x_off >= x_max || y_off <= y_zero || y_off >= y_max - 1 {
-                continue;
-            }
-
-            queue!(
-                stdout(),
-                MoveTo(x_off, y_off),
-                SetAttributes(style_on),
-                SetColors(on_colors),
-                Print(char)
-            )?;
+use std::ops::{Add, Sub};
+
+#[derive(Clone, Debug, Copy, PartialEq, Eq)]
+pub struct Point {
+    pub x: u16,
+    pub y: u16,
+}
+
+impl Point {
+    pub fn new(x: u16, y: u16) -> Self {
+        Self { x, y }
+    }
+}
+
+impl Add for Point {
+    type Output = Self;
+    fn add(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x + rhs.x,
+            y: self.y + rhs.y,
+        }
+    }
+}
+
+impl Sub for Point {
+    type Output = Self;
+    fn sub(self, rhs: Self) -> Self::Output {
+        Self {
+            x: if rhs.x < self.x { self.x - rhs.x } else { 0 },
+            y: if rhs.y < self.y { self.y - rhs.y } else { 0 },
         }
     }
+}
+
+impl From<(usize, usize)> for Point {
+    fn from(value: (usize, usize)) -> Self {
+        Self {
+            x: value.0.try_into().unwrap_or(0),
+            y: value.1.try_into().unwrap_or(0),
+        }
+    }
+}
+
+impl Into<(usize, usize)> for Point {
+    fn into(self) -> (usize, usize) {
+        (
+            self.x.try_into().unwrap_or(0),
+            self.y.try_into().unwrap_or(0),
+        )
+    }
+}
 
-    area.outline_area()?;
+#[derive(Clone, Debug, Copy, PartialEq, Eq)]
+pub struct Area {
+    pub origin: Point,
+    pub max: Point,
+}
 
-    stdout().flush()?;
+impl Area {
+    pub fn new(origin: Point, max: Point) -> Self {
+        Self { origin, max }
+    }
+
+    pub fn contains(&self, point: Point) -> bool {
+        point.x >= self.origin.x
+            && point.y >= self.origin.y
+            && point.x <= self.max.x
+            && point.y <= self.max.y
+    }
+
+    pub fn height(&self) -> usize {
+        (self.max.y - self.origin.y).try_into().unwrap_or(0)
+    }
+
+    pub fn width(&self) -> usize {
+        (self.max.x - self.origin.x).try_into().unwrap_or(0)
+    }
+}
 
-    Ok(())
+impl From<(Point, Point)> for Area {
+    fn from(value: (Point, Point)) -> Self {
+        Self {
+            origin: value.0,
+            max: value.1,
+        }
+    }
 }
 
-pub fn loop_map<T>(
-    map: &(impl Map<T> + Clone),
-    area: &Area,
-    time: Duration,
-    steps: usize,
-) -> Result<()> {
-    loop {
-        let mut tmp = map.clone();
-        for _ in 0..steps {
-            execute!(stdout(), terminal::Clear(terminal::ClearType::All))?;
-            draw_map(&tmp, area)?;
-            stdout().flush()?;
-            tmp.update();
-            thread::sleep(time);
+impl From<(u16, u16, u16, u16)> for Area {
+    fn from(value: (u16, u16, u16, u16)) -> Self {
+        Self {
+            origin: Point::new(value.0, value.1),
+            max: Point::new(value.2, value.3),
         }
     }
 }
+
+impl Into<(Point, Point)> for Area {
+    fn into(self) -> (Point, Point) {
+        (self.origin, self.max)
+    }
+}
+
+impl Into<(u16, u16, u16, u16)> for Area {
+    fn into(self) -> (u16, u16, u16, u16) {
+        (self.origin.x, self.origin.y, self.max.x, self.max.y)
+    }
+}
diff --git a/src/graphics/actions.rs b/src/graphics/actions.rs
deleted file mode 100644 (file)
index 15f734c..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-use super::*;
-
-#[derive(Debug)]
-pub enum Action {
-    None,
-    Move(Direction),
-    Clock(Clock),
-    Channel(usize),
-    Select,
-    SelectArea,
-    SwitchPanel,
-    Reload,
-    Randomize,
-    Exit,
-    Help,
-    Edit,
-}
-
-#[derive(Debug)]
-pub enum Clock {
-    Stop,
-    Start,
-    Pause,
-    Faster(usize),
-    Slower(usize),
-}
-
-#[derive(Debug)]
-pub enum Direction {
-    Up,
-    Down,
-    Left,
-    Right,
-}
-
-pub fn action(action: Action, state: ArcState) -> Result<()> {
-    match action {
-        Action::None => Ok(()),
-        Action::Exit => exit(),
-        Action::Move(direction) => move_cursor(direction, state),
-        Action::Clock(clock) => transport_action(clock, state),
-        Action::Channel(n) => change_channel(n, state),
-        Action::Select => Ok(()),
-        Action::SelectArea => Ok(()),
-        Action::Reload => Ok(()),
-        Action::Randomize => Ok(()),
-        Action::Help => Ok(()),
-        Action::Edit => Ok(()),
-        Action::SwitchPanel => switch_panel(state),
-    }
-}
-
-fn transport_action(clock: Clock, state: ArcState) -> Result<()> {
-    let mut state = state.lock().unwrap();
-    match clock {
-        Clock::Stop => state.transport.running = false,
-        Clock::Start => state.transport.running = true,
-        Clock::Pause => state.transport.running = !state.transport.running,
-        Clock::Faster(n) => state.transport.bpm += n,
-        Clock::Slower(n) => state.transport.bpm -= n,
-    };
-    Ok(())
-}
-
-fn move_cursor(direction: Direction, state: ArcState) -> Result<()> {
-    let mut state = state.lock().unwrap();
-    match direction {
-        Direction::Up => {
-            if state.cursor.position.y > 1 {
-                state.cursor.position.y -= 1
-            }
-        }
-        Direction::Down => {
-            if state.cursor.position.y < state.cursor.area.height() {
-                state.cursor.position.y += 1
-            }
-        }
-        Direction::Left => {
-            if state.cursor.position.x > 1 {
-                state.cursor.position.x -= 1
-            }
-        }
-        Direction::Right => {
-            if state.cursor.position.x < state.cursor.area.width() {
-                state.cursor.position.x += 1
-            }
-        }
-    }
-    Ok(())
-}
-
-fn switch_panel(state: ArcState) -> Result<()> {
-    let mut mutex = state.lock().unwrap();
-    mutex.cursor.area = if mutex.cursor.area == mutex.layout.mask {
-        mutex.layout.cells
-    } else {
-        mutex.layout.mask
-    };
-    Ok(())
-}
-
-fn change_channel(channel: usize, state: ArcState) -> Result<()> {
-    let mut mutex = state.lock().unwrap();
-    mutex.channels.0 = channel;
-    draw_map(&mutex.mask[channel], &mutex.layout.mask)?;
-    Ok(())
-}
diff --git a/src/graphics/area.rs b/src/graphics/area.rs
deleted file mode 100644 (file)
index b9b12f0..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-use crossterm::{
-    cursor::MoveTo,
-    queue,
-    style::{
-        Color::{Black, White},
-        Colors, SetColors,
-    },
-};
-use eyre::Result;
-
-use super::*;
-
-#[derive(Clone, Debug, PartialEq, Eq, Copy)]
-pub struct Area {
-    pub origin: Point,
-    pub max: Point,
-}
-
-impl From<(Point, Point)> for Area {
-    fn from(value: (Point, Point)) -> Self {
-        Self {
-            origin: value.0,
-            max: value.1,
-        }
-    }
-}
-
-impl Area {
-    pub fn new(x_zero: usize, y_zero: usize, x_max: usize, y_max: usize) -> Self {
-        Self {
-            origin: Point::new(x_zero, y_zero),
-            max: Point::new(x_max, y_max),
-        }
-    }
-
-    pub fn to_u16(&self) -> Result<((u16, u16), (u16, u16))> {
-        Ok((
-            (self.origin.x.try_into()?, self.origin.y.try_into()?),
-            (self.max.x.try_into()?, self.max.y.try_into()?),
-        ))
-    }
-
-    pub fn width(&self) -> usize {
-        self.max.y - self.origin.y
-    }
-
-    pub fn height(&self) -> usize {
-        self.max.x - self.origin.x
-    }
-
-    pub fn outline_area(&self) -> Result<()> {
-        let colors = Colors::new(White, Black);
-        let ((x_zero, y_zero), (x_max, y_max)) = self.to_u16()?;
-
-        for y in y_zero + 1..y_max - 1 {
-            queue!(
-                stdout(),
-                MoveTo(x_zero, y),
-                SetColors(colors),
-                Print("┃"),
-                MoveTo(x_max, y),
-                SetColors(colors),
-                Print("┃")
-            )?;
-        }
-
-        for x in x_zero + 1..x_max {
-            queue!(
-                stdout(),
-                MoveTo(x, y_zero),
-                SetColors(colors),
-                Print("━"),
-                MoveTo(x, y_max - 1),
-                SetColors(colors),
-                Print("━")
-            )?;
-        }
-
-        for ((x, y), c) in [
-            (x_zero, y_zero),
-            (x_max, y_zero),
-            (x_zero, y_max - 1),
-            (x_max, y_max - 1),
-        ]
-        .iter()
-        .zip(['┏', '┓', '┗', '┛'].iter())
-        {
-            queue!(stdout(), MoveTo(*x, *y), SetColors(colors), Print(c))?;
-        }
-
-        Ok(())
-    }
-}
diff --git a/src/graphics/keys.rs b/src/graphics/keys.rs
deleted file mode 100644 (file)
index b91ee0f..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
-
-use super::*;
-use crate::Clock;
-
-pub fn key_event(event: KeyEvent) -> Action {
-    match event.modifiers {
-        KeyModifiers::NONE => match_normal_key(event.code),
-        KeyModifiers::CONTROL => match_ctl_key(event.code),
-        KeyModifiers::SHIFT => match_shift_key(event.code),
-        _ => Action::None,
-    }
-}
-
-pub fn match_normal_key(key: KeyCode) -> Action {
-    match key {
-        KeyCode::Enter => Action::Clock(Clock::Pause),
-        KeyCode::Esc => Action::Exit,
-        KeyCode::Tab => Action::SwitchPanel,
-        KeyCode::Up => Action::Move(Direction::Up),
-        KeyCode::Down => Action::Move(Direction::Down),
-        KeyCode::Right => Action::Move(Direction::Right),
-        KeyCode::Left => Action::Move(Direction::Left),
-        KeyCode::Char(c) => match c {
-            '?' => Action::Help,
-            ' ' => Action::Select,
-            '[' => Action::Clock(Clock::Slower(1)),
-            ']' => Action::Clock(Clock::Faster(1)),
-            '{' => Action::Clock(Clock::Slower(5)),
-            '}' => Action::Clock(Clock::Faster(5)),
-            'q' => Action::Exit,
-            'r' => Action::Reload,
-            'j' => Action::Move(Direction::Down),
-            'k' => Action::Move(Direction::Up),
-            'h' => Action::Move(Direction::Left),
-            'l' => Action::Move(Direction::Right),
-            '1' => Action::Channel(1),
-            '2' => Action::Channel(2),
-            '3' => Action::Channel(3),
-            '4' => Action::Channel(4),
-            '5' => Action::Channel(5),
-            '6' => Action::Channel(6),
-            '7' => Action::Channel(7),
-            '8' => Action::Channel(8),
-            '9' => Action::Channel(9),
-            '0' => Action::Channel(10),
-            _ => Action::None,
-        },
-        _ => Action::None,
-    }
-}
-
-pub fn match_ctl_key(key: KeyCode) -> Action {
-    match key {
-        KeyCode::Char('c') => Action::Exit,
-        _ => Action::None,
-    }
-}
-
-pub fn match_shift_key(key: KeyCode) -> Action {
-    match key {
-        KeyCode::Enter => Action::Clock(Clock::Stop),
-        KeyCode::Char(c) => match c {
-            ' ' => Action::SelectArea,
-            'r' => Action::Randomize,
-            _ => Action::None,
-        },
-        _ => Action::None,
-    }
-}
diff --git a/src/graphics/layout.rs b/src/graphics/layout.rs
deleted file mode 100644 (file)
index 2f5fc7d..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-use crossterm::terminal;
-use eyre::Result;
-
-use super::*;
-
-#[derive(Clone, Debug)]
-pub struct Layout {
-    pub screen: Area,
-    pub cells: Area,
-    pub mask: Area,
-    pub channels: Area,
-    pub transport: Area,
-}
-
-impl Layout {
-    pub fn build() -> Result<Self> {
-        let (col, row) = terminal::size()?;
-
-        let col: usize = col.into();
-        let row: usize = row.into();
-
-        let screen = Area::new(0, 0, col, row);
-        let cells = Area::new(1, 0, col / 2 - 6, row / 2 - 1);
-        let mask = Area::new(col / 2 + 6, 0, col - 2, row / 2 - 1);
-        let channels = Area::new(1, row / 2 + 1, col - 2, row - 1);
-        let transport = Area::new(col / 2 - 5, 4, col / 2 + 5, 9);
-
-        Ok(Self {
-            screen,
-            cells,
-            mask,
-            channels,
-            transport,
-        })
-    }
-
-    pub fn draw_outlines(&self) -> Result<()> {
-        self.cells.outline_area()?;
-        self.mask.outline_area()?;
-        self.channels.outline_area()?;
-        self.transport.outline_area()?;
-        Ok(())
-    }
-}
diff --git a/src/graphics/map.rs b/src/graphics/map.rs
deleted file mode 100644 (file)
index 61db0d8..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-use crate::Point;
-use crossterm::style::{
-    Attribute, Attributes,
-    Color::{Black, White},
-    Colors,
-};
-use ndarray::Array2;
-use rand::{thread_rng, Rng};
-use std::ops::{Deref, DerefMut};
-
-use super::*;
-
-pub trait Map<T> {
-    fn draw_point(&self, point: Point) -> Option<char>;
-    fn x_size(&self) -> usize;
-    fn y_size(&self) -> usize;
-    fn characters(&self) -> (char, char);
-    fn colors(&self) -> (Colors, Colors);
-    fn styles(&self) -> (Attributes, Attributes);
-    fn update(&mut self);
-}
-
-#[derive(Debug, Clone)]
-pub struct Mask {
-    pub mask: Array2<Note>,
-    pub colors: (Colors, Colors),
-}
-
-impl Mask {
-    pub fn new(area: Area) -> Self {
-        let mask = Array2::from_elem((area.width(), area.height()), Note::Off);
-        Self {
-            mask,
-            colors: (Colors::new(White, Black), Colors::new(Black, Black)),
-        }
-    }
-
-    pub fn randomize(&mut self, val: f64, scale: Scale) {
-        let mut rng = thread_rng();
-        for f in self.iter_mut() {
-            if rng.gen::<f64>() > val {
-                let notes = scale.to_notes();
-                *f = notes[rng.gen::<usize>() % notes.len()];
-            }
-        }
-    }
-}
-
-impl Deref for Mask {
-    type Target = Array2<Note>;
-    fn deref(&self) -> &Self::Target {
-        &self.mask
-    }
-}
-
-impl DerefMut for Mask {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.mask
-    }
-}
-
-impl Map<Note> for Mask {
-    fn x_size(&self) -> usize {
-        self.ncols()
-    }
-
-    fn y_size(&self) -> usize {
-        self.nrows()
-    }
-
-    fn draw_point(&self, point: Point) -> Option<char> {
-        self.get((point.y, point.x)).map(|n| n.to_char())
-    }
-
-    fn characters(&self) -> (char, char) {
-        ('■', '□')
-    }
-
-    fn colors(&self) -> (Colors, Colors) {
-        self.colors
-    }
-
-    fn styles(&self) -> (Attributes, Attributes) {
-        let on = Attributes::from(Attribute::Bold);
-        let off = Attributes::from(Attribute::Reset);
-        (on, off)
-    }
-
-    fn update(&mut self) {}
-}
diff --git a/src/graphics/point.rs b/src/graphics/point.rs
deleted file mode 100644 (file)
index dcb78fd..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-use crossterm::style::{Attribute, Color};
-use eyre::Result;
-use std::ops::{Add, Div, Mul, Sub};
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct Pixel {
-    pub location: Point,
-    pub value: char,
-    pub fg: Color,
-    pub bg: Color,
-    pub style: Attribute,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
-pub struct Point {
-    pub x: usize,
-    pub y: usize,
-}
-
-impl Point {
-    pub fn new(x: usize, y: usize) -> Self {
-        Self { x, y }
-    }
-
-    pub fn u16_offset(&self, offset: Point) -> Result<(u16, u16)> {
-        let output = *self + offset;
-        Ok((output.x.try_into()?, output.y.try_into()?))
-    }
-}
-
-impl Add for Point {
-    type Output = Self;
-    fn add(self, rhs: Self) -> Self::Output {
-        Self {
-            x: self.x + rhs.x,
-            y: self.y + rhs.y,
-        }
-    }
-}
-
-impl Sub for Point {
-    type Output = Self;
-    fn sub(self, rhs: Self) -> Self::Output {
-        Self {
-            x: self.x - rhs.x,
-            y: self.y - rhs.y,
-        }
-    }
-}
-
-impl Mul for Point {
-    type Output = Self;
-    fn mul(self, rhs: Self) -> Self::Output {
-        Self {
-            x: self.x * rhs.x,
-            y: self.y * rhs.y,
-        }
-    }
-}
-
-impl Div for Point {
-    type Output = Self;
-    fn div(self, rhs: Self) -> Self::Output {
-        Self {
-            x: self.x / rhs.x,
-            y: self.y / rhs.y,
-        }
-    }
-}
diff --git a/src/graphics/render.rs b/src/graphics/render.rs
deleted file mode 100644 (file)
index b911bc5..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-use super::*;
-
-use crossbeam::channel::{bounded, Receiver, Sender};
-
-pub type ArcState = Arc<Mutex<GlobalState>>;
-
-pub fn main_loop(state: GlobalState) -> Result<()> {
-    execute!(stdout(), terminal::Clear(terminal::ClearType::All))?;
-
-    state.layout.draw_outlines()?;
-
-    let (clock, sync) = bounded::<()>(0);
-    let state = Arc::new(Mutex::new(state));
-
-    let timer_state = Arc::clone(&state);
-    let world_state = Arc::clone(&state);
-    let action_state = Arc::clone(&state);
-    // let cursor_state = Arc::clone(&state);
-
-    let timer = std::thread::spawn(move || timer_loop(timer_state, clock));
-    let world = std::thread::spawn(move || world_loop(world_state, sync));
-    let action = std::thread::spawn(move || action_loop(action_state));
-    // let cursor = std::thread::spawn(move || cursor_loop(cursor_state));
-
-    timer.join().unwrap()?;
-    world.join().unwrap()?;
-    action.join().unwrap()?;
-    // cursor.join().unwrap()?;
-
-    Ok(())
-}
-
-fn timer_loop(state: ArcState, clock: Sender<()>) -> Result<()> {
-    loop {
-        let tick = state.lock().unwrap().tick();
-        thread::sleep(tick);
-        clock.send(())?;
-    }
-}
-
-pub fn world_loop(state: ArcState, sync: Receiver<()>) -> Result<()> {
-    loop {
-        let mutex = state.lock().unwrap();
-        if mutex.transport.running {
-            let mut world = mutex.world.clone();
-            let mask = mutex.mask[mutex.channels.0].clone();
-            let world_layout = mutex.layout.cells;
-            let mask_layout = mutex.layout.mask;
-            drop(mutex);
-
-            world.update();
-            draw_map(&world, &world_layout)?;
-            draw_map(&mask, &mask_layout)?;
-            sync.recv()?;
-            state.lock().as_mut().unwrap().world = world;
-        } else {
-            drop(mutex);
-            sync.recv()?;
-        }
-    }
-}
-
-pub fn action_loop(state: ArcState) -> Result<()> {
-    while let Ok(event) = read() {
-        match event {
-            Event::Key(key) => action(key_event(key), state.clone())?,
-            Event::Resize(_, _) => state.lock().unwrap().layout = Layout::build()?,
-            _ => (),
-        }
-    }
-    Ok(())
-}
-
-pub fn cursor_loop(state: ArcState) -> Result<()> {
-    loop {
-        state.lock().unwrap().cursor.render()?;
-        std::thread::sleep(Duration::from_millis(100))
-    }
-}
-
-// pub fn render_loop(state: &mut GlobalState) -> Result<()> {
-//     execute!(stdout(), terminal::Clear(terminal::ClearType::All))?;
-
-//     state.layout.draw_outlines()?;
-
-//     let world = Arc::new(Mutex::new(state.world.clone()));
-//     let state_arc = Arc::new(Mutex::new(state));
-
-//     loop {
-//         let arc = Arc::clone(&state_arc);
-//         let tick = arc.lock().unwrap().tick();
-//         let timer = std::thread::spawn(move || thread::sleep(tick));
-
-//         let event = std::thread::spawn(move || {
-//             if poll(tick).unwrap() {
-//                 match read().unwrap() {
-//                     Event::Key(key) => key_event(key),
-//                     _ => Action::None,
-//                 }
-//             } else {
-//                 Action::None
-//             }
-//         });
-
-//         let mut maps = std::thread::spawn(|| {});
-//         if arc.lock().unwrap().transport.running {
-//             let map = world.clone();
-//             let mut mask = arc.lock().unwrap().mask.clone();
-//             let cell_area = arc.lock().unwrap().layout.cells;
-//             let mask_area = arc.lock().unwrap().layout.mask;
-
-//             maps = std::thread::spawn(move || {
-//                 let mut map = map.lock().unwrap();
-//                 map.update();
-//                 let tmp = map.clone();
-//                 draw_map(&tmp, &cell_area).unwrap();
-//                 mask[0].update();
-//                 let tmp = mask[0].clone();
-//                 draw_map(&tmp, &mask_area).unwrap();
-//             });
-//         }
-
-//         let area = arc.lock().unwrap().layout.transport;
-
-//         arc.lock().unwrap().transport.render(area)?;
-
-//         action(event.join().unwrap(), arc.clone())?;
-//         maps.join().unwrap();
-
-//         arc.lock().unwrap().cursor.render()?;
-
-//         timer.join().unwrap();
-//         stdout().flush()?;
-//     }
-// }
diff --git a/src/graphics/selector.rs b/src/graphics/selector.rs
deleted file mode 100644 (file)
index becfb27..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-use crate::Point;
-use crossterm::{
-    cursor, queue,
-    style::{self, Attribute, Attributes, Color, Colors},
-};
-use eyre::Result;
-use std::{
-    io::stdout,
-    ops::{Deref, DerefMut},
-};
-
-use super::*;
-
-#[derive(Debug, Clone, Copy)]
-pub struct Cursor {
-    pub position: Point,
-    pub color: Colors,
-    pub style: Attributes,
-    pub char: char,
-    pub area: Area,
-}
-
-impl Deref for Cursor {
-    type Target = Point;
-    fn deref(&self) -> &Self::Target {
-        &self.position
-    }
-}
-
-impl DerefMut for Cursor {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.position
-    }
-}
-
-impl Default for Cursor {
-    fn default() -> Self {
-        Self::new(Area::new(0, 0, 0, 0))
-    }
-}
-
-impl Cursor {
-    pub fn new(area: Area) -> Self {
-        Self {
-            position: Point::new(1, 1),
-            color: Colors::new(Color::White, Color::Black),
-            char: '█',
-            style: Attributes::from(Attribute::Bold),
-            area,
-        }
-    }
-
-    pub fn render(&self) -> Result<()> {
-        let offset = self.area.origin + self.position;
-        queue!(
-            stdout(),
-            cursor::Hide,
-            cursor::MoveTo(offset.x.try_into().unwrap(), offset.y.try_into().unwrap()),
-            style::SetAttributes(self.style),
-            style::SetColors(self.color),
-            cursor::Show,
-            style::Print(self.char.to_string())
-        )?;
-        Ok(())
-    }
-}
index 97a4a32f02fba63b52443b508cd39d7f3ef44982..20d18d0f65a349364626241d3b53536efd3a35d1 100644 (file)
@@ -1,23 +1,10 @@
 mod cells;
 mod graphics;
-mod music;
-mod state;
 
 pub use cells::*;
 pub use graphics::*;
-pub use music::*;
-pub use state::*;
 
-use eyre::Result;
-use std::time::Duration;
-
-pub fn exit() -> Result<()> {
-    crossterm::terminal::disable_raw_mode()?;
-    crossterm::execute!(std::io::stdout(), crossterm::cursor::Show)?;
-    std::process::exit(0);
-}
+#[cfg(test)]
+mod tests;
 
-pub fn bpm_to_ms(bpm: usize) -> Duration {
-    let ms = 60000 / bpm;
-    Duration::from_millis(ms.try_into().unwrap())
-}
+use eyre::Result;
index c53dab30e63a1b49599b8f73f9e21c3809fc3f7e..a3a92f49730dc6ab812919b967d246c79d535de8 100644 (file)
@@ -1,22 +1,6 @@
-use cellseq::*;
-use crossterm::{cursor::Hide, execute, terminal};
 use eyre::Result;
-use std::io::stdout;
 
-fn main() -> Result<()> {
-    terminal::enable_raw_mode()?;
-    execute!(stdout(), Hide)?;
-
-    let mut state = GlobalState::build()?;
-
-    state.world.randomize(0.75);
-    state.mask[0].randomize(0.75, Scale::Aeolian);
-
-    match main_loop(state) {
-        Ok(_) => exit(),
-        Err(e) => {
-            eprintln!("{}", e);
-            exit()
-        }
-    }
+#[tokio::main]
+async fn main() -> Result<()> {
+    todo!()
 }
diff --git a/src/music.rs b/src/music.rs
deleted file mode 100644 (file)
index 409a579..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-mod scale;
-mod transport;
-
-pub use scale::*;
-pub use transport::*;
-
-use std::{fmt::Display, ops::Deref};
-
-#[derive(Clone, Copy, Debug)]
-pub struct TimeSignature {
-    pub top: usize,
-    pub bottom: usize,
-}
-
-impl From<(usize, usize)> for TimeSignature {
-    fn from(value: (usize, usize)) -> Self {
-        Self {
-            top: value.0,
-            bottom: value.1,
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub enum Note {
-    Off,
-    A(Acc),
-    B(Acc),
-    C(Acc),
-    D(Acc),
-    E(Acc),
-    F(Acc),
-    G(Acc),
-}
-
-impl Display for Note {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        let str = match self {
-            Note::Off => "".to_string(),
-            Note::A(a) => format!("A{a}"),
-            Note::B(a) => format!("B{a}"),
-            Note::C(a) => format!("C{a}"),
-            Note::D(a) => format!("D{a}"),
-            Note::E(a) => format!("E{a}"),
-            Note::F(a) => format!("F{a}"),
-            Note::G(a) => format!("G{a}"),
-        };
-
-        write!(f, "{str}")
-    }
-}
-
-impl Note {
-    pub fn to_char(&self) -> char {
-        match self {
-            Note::Off => ' ',
-            Note::A(_) => 'a',
-            Note::B(_) => 'b',
-            Note::C(_) => 'c',
-            Note::D(_) => 'd',
-            Note::E(_) => 'e',
-            Note::F(_) => 'f',
-            Note::G(_) => 'g',
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub enum Acc {
-    Flt,
-    Nat,
-    Shp,
-}
-
-impl Display for Acc {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        let str = match self {
-            Acc::Flt => "b",
-            Acc::Nat => "",
-            Acc::Shp => "#",
-        };
-
-        write!(f, "{str}")
-    }
-}
diff --git a/src/music/scale.rs b/src/music/scale.rs
deleted file mode 100644 (file)
index 486bfbd..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-use super::*;
-
-use super::{
-    Acc::{Nat, Shp},
-    Note::{A, B, C, D, E, F, G},
-};
-
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub enum Scale {
-    Ionian,
-    Dorian,
-    Phrygian,
-    Lydian,
-    Mixolydian,
-    Aeolian,
-    Locrian,
-    MajPent,
-    SusEgypt,
-    BlueMajPent,
-    BlueMinPen,
-    MinPent,
-    WholeTone,
-    Chromatic,
-}
-
-impl Scale {
-    pub fn to_notes(&self) -> Vec<Note> {
-        let octave = [
-            C(Nat),
-            C(Shp),
-            D(Nat),
-            D(Shp),
-            E(Nat),
-            F(Nat),
-            F(Shp),
-            G(Nat),
-            G(Shp),
-            A(Nat),
-            A(Shp),
-            B(Nat),
-        ];
-
-        let diatonic = [1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1];
-        let pentatonic = [1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0];
-        let whole_tone = [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0];
-
-        fn mask_scale(notes: &[Note; 12], mask: [u8; 12]) -> Vec<Note> {
-            notes
-                .iter()
-                .zip(mask.iter())
-                .filter_map(|(note, mask)| if *mask == 1 { Some(*note) } else { None })
-                .collect()
-        }
-
-        macro_rules! rotate {
-            ($s:expr,r,$n:expr) => {{
-                $s.rotate_right($n);
-                $s
-            }};
-            ($s:expr,l,$n:expr) => {{
-                $s.rotate_left($n);
-                $s
-            }};
-        }
-
-        match self {
-            Scale::Ionian => mask_scale(&octave, diatonic),
-            Scale::Dorian => rotate!(mask_scale(&octave, diatonic), l, 2),
-            Scale::Phrygian => rotate!(mask_scale(&octave, diatonic), l, 4),
-            Scale::Lydian => rotate!(mask_scale(&octave, diatonic), l, 5),
-            Scale::Mixolydian => rotate!(mask_scale(&octave, diatonic), r, 5),
-            Scale::Aeolian => rotate!(mask_scale(&octave, diatonic), r, 3),
-            Scale::Locrian => rotate!(mask_scale(&octave, diatonic), r, 1),
-            Scale::MajPent => mask_scale(&octave, pentatonic),
-            Scale::SusEgypt => rotate!(mask_scale(&octave, pentatonic), l, 2),
-            Scale::BlueMinPen => rotate!(mask_scale(&octave, pentatonic), l, 4),
-            Scale::BlueMajPent => rotate!(mask_scale(&octave, pentatonic), r, 5),
-            Scale::MinPent => rotate!(mask_scale(&octave, pentatonic), r, 3),
-            Scale::WholeTone => mask_scale(&octave, whole_tone),
-            Scale::Chromatic => octave.to_vec(),
-        }
-    }
-}
diff --git a/src/music/transport.rs b/src/music/transport.rs
deleted file mode 100644 (file)
index 415f2e2..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-use super::*;
-
-#[derive(Clone, Copy, Debug)]
-pub struct Song {
-    pub key: Option<Note>,
-    pub scale: Option<Scale>,
-}
-
-impl Song {
-    pub fn new(key: Option<Note>, scale: Option<Scale>) -> Self {
-        Self { key, scale }
-    }
-}
diff --git a/src/state.rs b/src/state.rs
deleted file mode 100644 (file)
index 159c265..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-mod transport;
-
-pub use transport::*;
-
-use crossbeam::channel::{bounded, Receiver, Sender};
-
-use super::*;
-
-#[derive(Debug, Clone)]
-pub struct GlobalState {
-    pub world: World,
-    pub layout: Layout,
-    pub transport: Transport,
-    pub song: Song,
-    pub mask: Vec<Mask>,
-    pub channels: (usize, Vec<MidiChannel>),
-    pub cursor: Cursor,
-    pub update_mask: (Sender<usize>, Receiver<usize>),
-}
-
-impl GlobalState {
-    pub fn build() -> Result<Self> {
-        let layout = Layout::build()?;
-
-        let world = World::new(layout.cells);
-
-        let channels = Vec::with_capacity(10);
-        let mut mask: Vec<Mask> = Vec::with_capacity(10);
-
-        for _ in 0..10 {
-            mask.push(Mask::new(layout.mask));
-        }
-
-        let transport = Transport::new(4, 4, 120);
-
-        let cursor = Cursor::new(layout.mask);
-
-        let song = Song::new(None, None);
-
-        let update_mask = bounded::<usize>(0);
-
-        Ok(Self {
-            world,
-            layout,
-            transport,
-            song,
-            mask,
-            channels: (0, channels),
-            cursor,
-            update_mask,
-        })
-    }
-
-    pub fn tick(&self) -> Duration {
-        bpm_to_ms(self.transport.bpm)
-    }
-}
-
-#[derive(Clone, Copy, Debug)]
-pub struct MidiChannel {
-    pub num: usize,
-    pub poly_num: usize,
-}
diff --git a/src/state/transport.rs b/src/state/transport.rs
deleted file mode 100644 (file)
index b230928..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-use super::*;
-
-use crossterm::{
-    cursor::MoveTo,
-    queue,
-    style::{Attribute, Color, Colors, Print, SetAttributes, SetColors},
-};
-use std::io::stdout;
-
-#[derive(Debug, Clone, Copy)]
-pub struct Transport {
-    pub running: bool,
-    pub bpm: usize,
-    pub sig: TimeSignature,
-    pub repeat: usize,
-}
-
-impl Transport {
-    pub fn new(top: usize, bottom: usize, bpm: usize) -> Self {
-        Self {
-            sig: TimeSignature { top, bottom },
-            bpm,
-            running: true,
-            repeat: 0,
-        }
-    }
-
-    pub fn render(&self, area: Area) -> Result<()> {
-        let ((x_zero, y_zero), (_, _)) = area.to_u16()?;
-
-        let bpm = format!("bpm: {}", self.bpm);
-        let sig = format!("sig: {}/{}", self.sig.top, self.sig.bottom);
-        let rep = format!("rep: {}", self.repeat);
-
-        queue!(
-            stdout(),
-            MoveTo(x_zero + 1, y_zero + 1),
-            SetAttributes(Attribute::Bold.into()),
-            SetColors(Colors::new(Color::White, Color::Black)),
-            Print(bpm),
-            MoveTo(x_zero + 1, y_zero + 2),
-            SetAttributes(Attribute::Bold.into()),
-            SetColors(Colors::new(Color::White, Color::Black)),
-            Print(sig),
-            MoveTo(x_zero + 1, y_zero + 3),
-            SetAttributes(Attribute::Bold.into()),
-            SetColors(Colors::new(Color::White, Color::Black)),
-            Print(rep),
-        )?;
-
-        Ok(())
-    }
-}
diff --git a/src/tests.rs b/src/tests.rs
new file mode 100644 (file)
index 0000000..b4351ab
--- /dev/null
@@ -0,0 +1,39 @@
+use super::*;
+
+#[test]
+fn area_tests() -> Result<()> {
+    let origin = Point::new(5, 5);
+    let max = Point::new(35, 25);
+    let area = Area::new(origin, max);
+
+    assert_eq!(area.height(), 20);
+    assert_eq!(area.width(), 30);
+
+    assert!(area.contains(Point::new(20, 20)));
+    assert!(area.contains(Point::new(5, 10)));
+    assert!(area.contains(Point::new(24, 25)));
+    assert!(area.contains(Point::new(35, 25)));
+    assert!(area.contains(Point::new(5, 5)));
+
+    assert!(!area.contains(Point::new(0, 10)));
+    assert!(!area.contains(Point::new(15, 0)));
+    assert!(!area.contains(Point::new(55, 24)));
+    assert!(!area.contains(Point::new(15, 60)));
+
+    assert_eq!(area, Area::from((Point::new(5, 5), Point::new(35, 25))));
+    assert_eq!(area, Area::from((5, 5, 35, 25)));
+    assert_ne!(area, Area::from((5, 55, 35, 25)));
+    Ok(())
+}
+
+#[test]
+fn point_tests() -> Result<()> {
+    let p1 = Point::new(10, 10);
+    let p2 = Point::new(15, 30);
+
+    assert_eq!(p2 - p1, Point::new(5, 20));
+    assert_eq!(p1 - p2, Point::new(0, 0));
+
+    assert_eq!(Point::new(5, 5), Point::from((5, 5)));
+    Ok(())
+}
diff --git a/src/transport.rs b/src/transport.rs
deleted file mode 100644 (file)
index a9c46cb..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-use super::*;
-
-pub struct Transport {
-    pub running: bool,
-    pub bpm: usize,
-    pub sig: TimeSignature,
-    pub repeat: usize,
-}
-
-impl Transport {
-    pub fn new(top: usize, bottom: usize, bpm: usize) -> Self {
-        Self {
-            sig: TimeSignature { top, bottom },
-            bpm,
-            running: true,
-            repeat: 0,
-        }
-    }
-}