Skip to content

Commit

Permalink
checkpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
neonphog committed Sep 9, 2023
1 parent b9cb688 commit 441b7b3
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 46 deletions.
74 changes: 49 additions & 25 deletions crates/tx5-pipe/examples/textboard/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ fn run_event(state: Arc<State>) -> std::io::Result<()> {
&& event.modifiers.contains(KeyModifiers::CONTROL))
{
state.quit();
} else if let KeyCode::Backspace = event.code {
state.backspace();
} else if let KeyCode::Char(c) = event.code {
state.write(state::Node {
fg: state::WHITE as u32 as u8,
bg: state::BLACK as u32 as u8,
val: c,
});
}
}
_ => (),
Expand Down Expand Up @@ -173,7 +181,7 @@ fn run_board(
crossterm::execute!(
stdout,
crossterm::terminal::EnterAlternateScreen,
//crossterm::terminal::DisableLineWrap,
crossterm::terminal::DisableLineWrap,
crossterm::cursor::Hide,
)?;
}
Expand All @@ -192,8 +200,10 @@ fn run_board(
let mut block = [[state::Node::default(); state::BLOCK]; state::BLOCK];

loop {
{
if let Some(cursors) = state.should_draw() {
let (width, height) = crossterm::terminal::size()?;
let width = width as i32;
let height = height as i32;

let mut stdout = std::io::stdout().lock();

Expand All @@ -215,47 +225,61 @@ fn run_board(
cy -= state::BLOCK_I32;
}

for x in (cx..offset_x + width as i32).step_by(state::BLOCK) {
for y in (cy..offset_y + height as i32).step_by(state::BLOCK) {
/*
crossterm::queue!(
stdout,
crossterm::style::Print(format!("(B{x},{y})")),
)?;
*/

for x in (cx..offset_x + width).step_by(state::BLOCK) {
for y in (cy..offset_y + height).step_by(state::BLOCK) {
state.fill_block(x, y, &mut block);

for iy in 0..state::BLOCK_I32 {
if iy - offset_y < 0 ||
iy - offset_y > height as i32
{
let sy = y + iy - offset_y;
if sy < 0 || sy >= height {
continue;
}

let mut set_pos = false;
for ix in 0..state::BLOCK_I32 {
if ix - offset_x < 0 ||
ix - offset_x > width as i32
{
let sx = x + ix - offset_x;
if sx < 0 || sx >= width {
continue;
}

if !set_pos {
set_pos = true;
crossterm::queue!(
stdout,
crossterm::cursor::MoveTo(ix as u16, iy as u16),
crossterm::cursor::MoveTo(sx as u16, sy as u16),
)?;
}

let mut cursor = false;

for (cur_x, cur_y, _nick) in cursors.iter() {
let cur_x = cur_x - offset_x;
let cur_y = cur_y - offset_y;
if cur_x == sx && cur_y == sy {
cursor = true;
break;
}
}

if cursor {
crossterm::queue!(
stdout,
crossterm::style::SetForegroundColor(crossterm::style::Color::Black),
crossterm::style::SetBackgroundColor(crossterm::style::Color::White),
)?;
}

crossterm::queue!(
stdout,
crossterm::style::Print(block[ix as usize][iy as usize].val),
)?;
/*
crossterm::queue!(
stdout,
crossterm::style::Print(format!("(I{ix},{iy})")),
)?;
*/

if cursor {
crossterm::queue!(
stdout,
crossterm::style::ResetColor,
)?;
}
}
}
}
Expand All @@ -267,7 +291,7 @@ fn run_board(
crossterm::style::SetForegroundColor(crossterm::style::Color::Black),
crossterm::style::SetBackgroundColor(crossterm::style::Color::White),
crossterm::style::Print("━".repeat(width as usize)),
crossterm::cursor::MoveTo(0, height - 1),
crossterm::cursor::MoveTo(0, (height - 1) as u16),
crossterm::style::Print("━".repeat(width as usize)),
crossterm::style::ResetColor,
crossterm::cursor::MoveTo(0, 0),
Expand Down
105 changes: 84 additions & 21 deletions crates/tx5-pipe/examples/textboard/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,15 @@ impl Node {

pub struct State {
exit: atomic::AtomicBool,
dirty: atomic::AtomicBool,
ver: Mutex<i32>,
hnd: DynStateHnd,
cli_url: String,
nick: Mutex<String>,
rem_host: Mutex<Option<String>>,
blocks: Mutex<HashMap<(i32, i32), Arc<Mutex<[[Node; BLOCK]; BLOCK]>>>>,
overlay: Mutex<HashMap<(i32, i32), (Node, i32)>>,
this_cur: Mutex<(i32, i32)>,
}

impl std::fmt::Debug for State {
Expand All @@ -179,12 +182,15 @@ impl State {

let this = Arc::new(Self {
exit: atomic::AtomicBool::new(false),
dirty: atomic::AtomicBool::new(true),
ver: Mutex::new(0),
hnd,
cli_url,
nick: Mutex::new("noname".to_string()),
rem_host: Mutex::new(None),
blocks: Mutex::new(HashMap::new()),
overlay: Mutex::new(HashMap::new()),
this_cur: Mutex::new((0, 0)),
});

this.clone().prompt_nick();
Expand All @@ -198,24 +204,7 @@ impl State {
offset_y: i32,
block: &mut [[Node; BLOCK]; BLOCK],
) {
if (offset_x / BLOCK_I32) * BLOCK_I32 != offset_x {
panic!("invalid offset_x not divisible by block size");
}
if (offset_y / BLOCK_I32) * BLOCK_I32 != offset_y {
panic!("invalid offset_y not divisible by BLOCK");
}
{
let sblock = self
.blocks
.lock()
.unwrap()
.entry((offset_x, offset_y))
.or_insert_with(|| {
Arc::new(Mutex::new([[Node::default(); BLOCK]; BLOCK]))
})
.clone();
*block = *sblock.lock().unwrap();
}
*block = *self.get_block(offset_x, offset_y).lock().unwrap();
let overlay_lock = self.overlay.lock().unwrap();
for x in 0..BLOCK_I32 {
for y in 0..BLOCK_I32 {
Expand All @@ -224,9 +213,6 @@ impl State {
{
block[x as usize][y as usize] = *n;
}
if x == 0 || y == 0 {
block[x as usize][y as usize].val = '.';
}
}
}
}
Expand All @@ -235,13 +221,90 @@ impl State {
self.exit.load(atomic::Ordering::Relaxed)
}

pub fn should_draw(&self) -> Option<Vec<(i32, i32, String)>> {
if self.dirty.swap(false, atomic::Ordering::Relaxed) {
let (x, y) = *self.this_cur.lock().unwrap();
let nick = self.nick.lock().unwrap().clone();
Some(vec![(x, y, nick)])
} else {
None
}
}

pub fn quit(&self) {
self.exit.store(true, atomic::Ordering::Relaxed);
self.hnd.quit();
}

pub fn write(&self, node: Node) {
let (x, y) = {
let mut c_lock = self.this_cur.lock().unwrap();
let out = *c_lock;
(*c_lock).0 += 1;
out
};
/*
let mut offset_x = (x / BLOCK_I32) * BLOCK_I32;
if offset_x > x {
offset_x -= BLOCK_I32;
}
let mut offset_y = (y / BLOCK_I32) * BLOCK_I32;
if offset_y > y {
offset_y -= BLOCK_I32;
}
let block = self.get_block(offset_x, offset_y);
let ix = x - offset_x;
let iy = y - offset_y;
block.lock().unwrap()[ix as usize][iy as usize] = node;
*/
let ver = *self.ver.lock().unwrap();
self.overlay.lock().unwrap().insert((x, y), (node, ver));
self.set_dirty();
}

pub fn backspace(&self) {
let (x, y) = {
let mut c_lock = self.this_cur.lock().unwrap();
(*c_lock).0 -= 1;
*c_lock
};
let ver = *self.ver.lock().unwrap();
self.overlay.lock().unwrap().insert((x, y), (Node {
fg: WHITE as u32 as u8,
bg: BLACK as u32 as u8,
val: ' ',
}, ver));
self.set_dirty();
}

// -- private -- //

fn set_dirty(&self) {
self.dirty.store(true, atomic::Ordering::Relaxed);
}

fn get_block(
&self,
offset_x: i32,
offset_y: i32,
) -> Arc<Mutex<[[Node; BLOCK]; BLOCK]>> {
if (offset_x / BLOCK_I32) * BLOCK_I32 != offset_x {
panic!("invalid offset_x not divisible by block size");
}
if (offset_y / BLOCK_I32) * BLOCK_I32 != offset_y {
panic!("invalid offset_y not divisible by BLOCK");
}
self
.blocks
.lock()
.unwrap()
.entry((offset_x, offset_y))
.or_insert_with(|| {
Arc::new(Mutex::new([[Node::default(); BLOCK]; BLOCK]))
})
.clone()
}

fn prompt_nick(self: Arc<Self>) {
tokio::task::spawn(async move {
let nick = self.hnd.prompt(&self, "nickname> ".to_string()).await;
Expand Down

0 comments on commit 441b7b3

Please sign in to comment.