From 53314e6154760c20b0d17ea206bfa084ed911e81 Mon Sep 17 00:00:00 2001 From: hachem Date: Sun, 29 Sep 2024 18:45:29 +0200 Subject: Line connections and nodes --- libpsi-visualizer/src/cli/renderer.rs | 236 +++++++++++++++++++++++++++++++--- 1 file changed, 216 insertions(+), 20 deletions(-) (limited to 'libpsi-visualizer/src/cli/renderer.rs') diff --git a/libpsi-visualizer/src/cli/renderer.rs b/libpsi-visualizer/src/cli/renderer.rs index d95d609..ba5a28b 100644 --- a/libpsi-visualizer/src/cli/renderer.rs +++ b/libpsi-visualizer/src/cli/renderer.rs @@ -1,3 +1,4 @@ +#[derive(Clone, Copy)] pub struct Quad { pub x: usize, pub y: usize, @@ -27,16 +28,7 @@ impl CLIRenderer { } } - pub fn to_string(&self) -> String { - self.buffer - .clone() - .into_iter() - .map(|inner| inner.into_iter().collect::()) - .collect::>() - .join("\n") - } - - pub fn place(&mut self, x: usize, y: usize, character: char) { + fn expand(&mut self, x: usize, y: usize) { if y >= self.buffer.len() { self.buffer.resize( y + 1, @@ -47,30 +39,37 @@ impl CLIRenderer { if x >= self.buffer[y].len() { self.buffer[y].resize(x + 1, ' '); } + } + + pub fn to_string(&self) -> String { + self.buffer + .clone() + .into_iter() + .map(|inner| inner.into_iter().collect::()) + .collect::>() + .join("\n") + } + + pub fn place(&mut self, x: usize, y: usize, character: char) { + self.expand(x, y); self.buffer[y][x] = character; } pub fn get(&mut self, x: usize, y: usize) -> char { - if y >= self.buffer.len() { - self.buffer.resize( - y + 1, - vec![' '; self.buffer.get(0).map_or(0, |row| row.len())], - ); - } - - if x >= self.buffer[y].len() { - self.buffer[y].resize(x + 1, ' '); - } + self.expand(x, y); self.buffer[y][x] } pub fn draw_text(&mut self, x: usize, y: usize, text: &'static str) { + self.expand(x + text.len(), y); for i in 0..text.len() { self.place(x + i, y, text.as_bytes()[i].into()); } } pub fn draw_vline(&mut self, x: usize, y: usize, height: usize, thick: bool) { + self.expand(x, y + height); + for i in y..y + height { if self.get(x, i) == '─' { self.place(x, i, if thick { '╫' } else { '┼' }); @@ -83,6 +82,8 @@ impl CLIRenderer { } pub fn draw_hline(&mut self, x: usize, y: usize, width: usize, thick: bool) { + self.expand(x + width, y); + for i in x..x + width { if self.get(i, y) == '│' { self.place(i, y, if thick { '╪' } else { '┼' }); @@ -95,6 +96,8 @@ impl CLIRenderer { } pub fn draw_quad(&mut self, quad: Quad, thick: bool) { + self.expand(quad.x + quad.width, quad.y + quad.height); + for x in quad.x..quad.x + quad.width { for y in quad.y..quad.y + quad.height { if x == quad.x && y == quad.y { @@ -113,4 +116,197 @@ impl CLIRenderer { } } } + + pub fn connect(&mut self, quad: Quad, point: (usize, usize)) { + enum Directions { + Bottom, + BottomLeft, + BottomRight, + + Top, + TopLeft, + TopRight, + + Right, + Left, + None, + } + + let center_x = (((quad.x + quad.width) as f32 / 2.0).ceil()) as usize; + let center_y = (((quad.y + quad.height) as f32 / 2.0).ceil()) as usize; + + let point_x = point.0; + let point_y = point.1; + + let mut edge_midpoint_x = 0usize; + let mut edge_midpoint_y = 0usize; + + let line_midpoint_x = center_x; + let line_midpoint_y = point_y; + + let mut direction = Directions::None; + + if point_y > center_y && point_x == center_x { + edge_midpoint_x = center_x; + edge_midpoint_y = quad.y + quad.height - 1; + direction = Directions::Bottom; + } else if point_y > center_y && point_x < center_x { + edge_midpoint_x = center_x; + edge_midpoint_y = quad.y + quad.height - 1; + direction = Directions::BottomLeft; + } else if point_y > center_y && point_x > center_x { + edge_midpoint_x = center_x; + edge_midpoint_y = quad.y + quad.height - 1; + direction = Directions::BottomRight; + } else if point_y < center_y && point_x == center_x { + edge_midpoint_x = center_x; + edge_midpoint_y = quad.y; + direction = Directions::Top; + } else if point_y < center_y && point_x < center_x { + edge_midpoint_x = center_x; + edge_midpoint_y = quad.y; + direction = Directions::TopLeft; + } else if point_y < center_y && point_x > center_x { + edge_midpoint_x = center_x; + edge_midpoint_y = quad.y; + direction = Directions::TopRight; + } else if point_x > center_x && point_y == center_y { + edge_midpoint_x = quad.x + quad.width - 1; + edge_midpoint_y = center_y; + direction = Directions::Right; + } else if point_x < center_x && point_y == center_y { + edge_midpoint_x = quad.x; + edge_midpoint_y = center_y; + + direction = Directions::Left; + } + + match direction { + Directions::Bottom | Directions::BottomRight | Directions::BottomLeft => { + let character = self.get(edge_midpoint_x, edge_midpoint_y); + self.place( + edge_midpoint_x, + edge_midpoint_y, + if character == '─' { '┬' } else { '╤' }, + ); + } + + Directions::Top | Directions::TopRight | Directions::TopLeft => { + let character = self.get(edge_midpoint_x, edge_midpoint_y); + self.place( + edge_midpoint_x, + edge_midpoint_y, + if character == '─' { '┴' } else { '╧' }, + ); + } + + Directions::Right => { + let character = self.get(edge_midpoint_x, edge_midpoint_y); + self.place( + edge_midpoint_x, + edge_midpoint_y, + if character == '│' { '├' } else { '╟' }, + ); + } + + Directions::Left => { + let character = self.get(edge_midpoint_x, edge_midpoint_y); + self.place( + edge_midpoint_x, + edge_midpoint_y, + if character == '│' { '┤' } else { '╢' }, + ); + } + + Directions::None => {} + } + + match direction { + Directions::Top => { + self.draw_vline(edge_midpoint_x, point_y, edge_midpoint_y - point_y, false); + } + + Directions::Bottom => { + self.draw_vline( + edge_midpoint_x, + edge_midpoint_y + 1, + point_y - edge_midpoint_y - 1, + false, + ); + } + + Directions::Right => { + self.draw_hline( + edge_midpoint_x + 1, + edge_midpoint_y, + point_x - edge_midpoint_x - 1, + false, + ); + } + + Directions::Left => { + self.draw_hline( + point_x + 1, + edge_midpoint_y, + edge_midpoint_x - point_x - 1, + false, + ); + } + + Directions::BottomRight => { + self.place(line_midpoint_x, line_midpoint_y, '└'); + self.draw_hline( + line_midpoint_x + 1, + line_midpoint_y, + point_x - line_midpoint_x - 1, + false, + ); + self.draw_vline( + edge_midpoint_x, + edge_midpoint_y + 1, + point_y - edge_midpoint_y - 1, + false, + ); + } + Directions::BottomLeft => { + self.place(line_midpoint_x, line_midpoint_y, '┘'); + self.draw_hline(point_x, point_y, line_midpoint_x - point_x, false); + self.draw_vline( + edge_midpoint_x, + edge_midpoint_y + 1, + point_y - edge_midpoint_y - 1, + false, + ); + } + Directions::TopRight => { + self.place(line_midpoint_x, line_midpoint_y, '┌'); + self.draw_hline( + line_midpoint_x + 1, + line_midpoint_y, + point_x - line_midpoint_x - 1, + false, + ); + + self.draw_vline( + edge_midpoint_x, + point_y + 1, + edge_midpoint_y - point_y - 1, + false, + ); + } + Directions::TopLeft => { + self.place(line_midpoint_x, line_midpoint_y, '┐'); + self.draw_hline(point_x, point_y, line_midpoint_x - point_x, false); + self.draw_vline( + edge_midpoint_x, + point_y + 1, + edge_midpoint_y - point_y - 1, + false, + ); + } + _ => {} + } + + self.place(point_x, point_y, '■'); + } } -- cgit v1.3