]> git.huck.website - cellseq.git/commitdiff
added: moveable cursor
authorHuck Boles <huck@huck.website>
Sun, 28 May 2023 23:18:51 +0000 (18:18 -0500)
committerHuck Boles <huck@huck.website>
Sun, 28 May 2023 23:18:51 +0000 (18:18 -0500)
src/cells.rs
src/graphics.rs
src/graphics/map.rs
src/graphics/point.rs
src/graphics/selector.rs [new file with mode: 0644]
src/main.rs

index c0fceb8fd588195771d88d2afb5a972c25860fef..9f24fcb6a9248346bb0a97ac91273939ad506808 100644 (file)
@@ -1,4 +1,5 @@
 use crate::{Map, Mask, Point};
+use crossterm::style::{Attribute, Color};
 use ndarray::Array2;
 use rand::{thread_rng, Rng};
 use std::{cell::Cell, ops::Deref};
@@ -84,10 +85,22 @@ impl Map<Cell<State>> for World {
         self.nrows()
     }
 
-    fn graphics(&self) -> (char, char) {
+    fn characters(&self) -> (char, char) {
         ('●', '◌')
     }
 
+    fn fg_colors(&self) -> (Color, Color) {
+        (Color::Green, Color::Grey)
+    }
+
+    fn bg_colors(&self) -> (Color, Color) {
+        (Color::Black, Color::Black)
+    }
+
+    fn styles(&self) -> (Attribute, Attribute) {
+        (Attribute::Bold, Attribute::Reset)
+    }
+
     fn try_point(&self, point: Point) -> bool {
         if let Some(cell) = self.get((point.y, point.x)) {
             if cell.get() == State::Alive {
index 44fc0dd571bf0e6a2e630279d1bfc5a5ddb9c79c..a5de1b1cba7af2b7a755d64e584cd33d81b348f7 100644 (file)
@@ -1,14 +1,13 @@
 mod map;
 mod point;
+mod selector;
 
 pub use map::*;
 pub use point::*;
+pub use selector::*;
 
-use crossterm::{
-    cursor, execute, queue,
-    style::{self, Stylize},
-    terminal, Result,
-};
+use crossterm::{cursor, execute, queue, style, terminal};
+use eyre::Result;
 use std::{
     io::{stdout, Write},
     thread,
@@ -18,31 +17,41 @@ use std::{
 pub struct Cursor {}
 
 pub fn draw_frame<T>(map: &mut impl Map<T>, offset: Point) -> Result<()> {
-    let (on, off) = map.graphics();
+    let (char_on, char_off) = map.characters();
+    let (fg_on, fg_off) = map.fg_colors();
+    let (bg_on, bg_off) = map.bg_colors();
+    let (style_on, style_off) = map.styles();
+
     for x in 1..(map.x_size() - 1) {
         for y in 1..(map.y_size() - 1) {
             let point = Point::new(x, y);
-            let offset = point + offset;
-            let x_off: u16 = offset.x.try_into().unwrap();
-            let y_off: u16 = offset.y.try_into().unwrap();
+            let (x_off, y_off) = point.u16_offset(offset)?;
+
             if map.try_point(point) {
                 queue!(
                     stdout(),
                     cursor::Hide,
                     cursor::MoveTo(x_off, y_off),
-                    style::PrintStyledContent(on.green())
+                    style::SetAttribute(style_on),
+                    style::SetForegroundColor(fg_on),
+                    style::SetBackgroundColor(bg_on),
+                    style::Print(char_on)
                 )?;
             } else {
                 queue!(
                     stdout(),
                     cursor::Hide,
                     cursor::MoveTo(x_off, y_off),
-                    style::PrintStyledContent(off.grey())
+                    style::SetAttribute(style_off),
+                    style::SetForegroundColor(fg_off),
+                    style::SetBackgroundColor(bg_off),
+                    style::Print(char_off)
                 )?;
             }
         }
     }
-    stdout().flush()
+    stdout().flush()?;
+    Ok(())
 }
 
 pub fn run_map<T>(map: &mut impl Map<T>, offset: Point, time: Duration) -> Result<()> {
index a003edc4cbda8e982f3b7ba51dfa164b2b62c8c5..6748e15a14e832170f37ba9a6d3a7a98dd5c8c95 100644 (file)
@@ -1,4 +1,5 @@
 use crate::Point;
+use crossterm::style::{Attribute, Color};
 use ndarray::Array2;
 use std::ops::Deref;
 
@@ -7,7 +8,10 @@ pub trait Map<T> {
     fn get_point(&self, point: Point) -> Option<T>;
     fn x_size(&self) -> usize;
     fn y_size(&self) -> usize;
-    fn graphics(&self) -> (char, char);
+    fn characters(&self) -> (char, char);
+    fn fg_colors(&self) -> (Color, Color);
+    fn bg_colors(&self) -> (Color, Color);
+    fn styles(&self) -> (Attribute, Attribute);
     fn update(&mut self);
 }
 
@@ -47,9 +51,21 @@ impl<T: Clone> Map<T> for Mask<T> {
         self.get((point.y, point.x)).cloned()
     }
 
-    fn graphics(&self) -> (char, char) {
+    fn characters(&self) -> (char, char) {
         ('■', '□')
     }
 
+    fn fg_colors(&self) -> (Color, Color) {
+        (Color::White, Color::Grey)
+    }
+
+    fn bg_colors(&self) -> (Color, Color) {
+        (Color::Black, Color::Black)
+    }
+
+    fn styles(&self) -> (Attribute, Attribute) {
+        (Attribute::Bold, Attribute::Reset)
+    }
+
     fn update(&mut self) {}
 }
index 2585d358a6b8817faae8b23672231d20b864fec2..3af27b3e6361b1e23ccbfd705352ef04f15973b1 100644 (file)
@@ -1,4 +1,5 @@
 use crossterm::style::{Attribute, Color};
+use eyre::Result;
 use std::ops::{Add, Div, Mul, Sub};
 
 pub struct Pixel {
@@ -19,6 +20,11 @@ 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 {
diff --git a/src/graphics/selector.rs b/src/graphics/selector.rs
new file mode 100644 (file)
index 0000000..51298d4
--- /dev/null
@@ -0,0 +1,115 @@
+use crate::Point;
+use crossterm::{
+    cursor,
+    event::{poll, read, Event, KeyCode, KeyEvent, KeyModifiers},
+    execute, queue,
+    style::{self, Attribute, Color},
+    terminal,
+};
+use eyre::Result;
+use std::{
+    io::stdout,
+    ops::{Deref, DerefMut},
+    time::Duration,
+};
+
+pub struct Cursor {
+    pub position: Point,
+    pub fg: Color,
+    pub bg: Color,
+    pub style: Attribute,
+    pub char: char,
+}
+
+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 Cursor {
+    pub fn new() -> Self {
+        Self {
+            position: Point::new(0, 0),
+            fg: Color::White,
+            bg: Color::Black,
+            char: '*',
+            style: Attribute::Reset,
+        }
+    }
+
+    pub fn render(&self) -> Result<()> {
+        queue!(
+            stdout(),
+            cursor::Hide,
+            cursor::MoveTo(self.x.try_into().unwrap(), self.y.try_into().unwrap()),
+            style::SetAttribute(self.style),
+            style::SetForegroundColor(self.fg),
+            style::SetBackgroundColor(self.bg),
+            style::Print(self.char.to_string())
+        )?;
+        Ok(())
+    }
+
+    pub fn update(&mut self, event: KeyEvent) -> Result<()> {
+        let key = event.code;
+        match event.modifiers {
+            KeyModifiers::NONE => match key {
+                KeyCode::Char(c) => match c {
+                    'j' => self.y += 1,
+                    'k' => {
+                        if self.y != 0 {
+                            self.y -= 1
+                        }
+                    }
+                    'h' => {
+                        if self.x != 0 {
+                            self.x -= 1
+                        }
+                    }
+                    'l' => self.x += 1,
+                    _ => {}
+                },
+                _ => {}
+            },
+            KeyModifiers::CONTROL => match key {
+                KeyCode::Char(c) => match c {
+                    'c' => std::process::exit(0),
+                    _ => {}
+                },
+                _ => {}
+            },
+            KeyModifiers::ALT => match key {
+                _ => {}
+            },
+            KeyModifiers::SHIFT => match key {
+                _ => {}
+            },
+            _ => {}
+        };
+        Ok(())
+    }
+}
+
+pub fn move_cursor() -> Result<()> {
+    let mut cursor = Cursor::new();
+    loop {
+        if poll(Duration::from_millis(10))? {
+            execute!(stdout(), terminal::Clear(terminal::ClearType::All))?;
+            match read()? {
+                Event::Key(event) => {
+                    cursor.update(event)?;
+                }
+                _ => continue,
+            }
+        }
+        cursor.render()?;
+    }
+}
index fe995fb8a3675e13226b8d764b168aebf8435110..069843a464f1ebeb7cb1f5ea75907b6915dae4a9 100644 (file)
@@ -2,13 +2,16 @@ use cellseq::*;
 use eyre::Result;
 
 fn main() -> Result<()> {
+    crossterm::terminal::enable_raw_mode()?;
+
     let mut mask: Mask<bool> = Mask::new(48, 24, false);
-    let mut map = World::new(48, 24);
+    let mut map = World::new(74, 32);
     map.randomize(0.75);
 
     let time = bpm_to_ms(120);
 
-    loop_map(&mut map, Point::new(10, 5), time, 32)?;
+    // loop_map(&mut map, Point::new(10, 2), time, 32)?;
     // edit_mask(&mask, (10, 5))?;
+    move_cursor()?;
     Ok(())
 }