use crate::{Map, Mask, Point};
+use crossterm::style::{Attribute, Color};
use ndarray::Array2;
use rand::{thread_rng, Rng};
use std::{cell::Cell, ops::Deref};
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 {
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,
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<()> {
use crate::Point;
+use crossterm::style::{Attribute, Color};
use ndarray::Array2;
use std::ops::Deref;
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);
}
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) {}
}
use crossterm::style::{Attribute, Color};
+use eyre::Result;
use std::ops::{Add, Div, Mul, Sub};
pub struct Pixel {
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 {
--- /dev/null
+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()?;
+ }
+}
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(())
}