fix(rendering): fix out of bounds render crashes app

This commit is contained in:
Pihkaal
2024-03-23 02:51:50 +01:00
parent eff3db47dc
commit 02ff709718
4 changed files with 54 additions and 29 deletions

View File

@@ -162,8 +162,8 @@ fn render_frame(
rendering::draw_time(&elapsed, color)?;
// Display lapses
let (width, height) = terminal::size()?;
let y = height / 2 + symbols::SYMBOL_HEIGHT as u16 / 2 + 2;
let (width, height) = rendering::get_terminal_size()?;
let y = height / 2 + symbols::SYMBOL_HEIGHT as i16 / 2 + 2;
let max_items = min(10, height - y - 1) as usize;
if lapses.len() <= max_items {
@@ -188,18 +188,18 @@ fn render_frame(
delta,
time
);
let x = width / 2 - (lapse.len() as u16) / 2;
rendering::draw_text(&lapse, x, y + i as u16, color)?;
let x = width / 2 - (lapse.len() as i16) / 2;
rendering::draw_text(&lapse, x, y + i as i16, color)?;
}
// Display pause state
if chronometer.is_paused() {
let text = "[PAUSE]";
let x = width / 2 - (text.len() as u16) / 2;
let x = width / 2 - (text.len() as i16) / 2;
rendering::draw_text(
text,
x,
y - symbols::SYMBOL_HEIGHT as u16 - symbols::SYMBOL_HEIGHT as u16 / 2,
y - symbols::SYMBOL_HEIGHT as i16 - symbols::SYMBOL_HEIGHT as i16 / 2,
color,
)?;
}

View File

@@ -68,10 +68,10 @@ fn render_frame(config: &Config) -> io::Result<()> {
.format(&config.date_format.to_owned())
.to_string();
let (width, height) = terminal::size()?;
let x = width / 2 - (date.len() as u16) / 2;
let y = height / 2 + symbols::SYMBOL_HEIGHT as u16 / 2 + 2;
rendering::draw_text(&date, x, y, color)?;
let (width, height) = rendering::get_terminal_size()?;
let x = width / 2 - (date.len() as i16) / 2;
let y = height / 2 + symbols::SYMBOL_HEIGHT as i16 / 2 + 2;
rendering::draw_text(&date, x, y - 1, color)?;
return Ok(());
}

View File

@@ -127,28 +127,28 @@ fn render_frame(config: &Config, timer: &Timer) -> io::Result<()> {
rendering::draw_time(&remaining, color)?;
// Display pause state
let (width, height) = terminal::size()?;
let y = height / 2 + symbols::SYMBOL_HEIGHT as u16 / 2 + 2;
let (width, height) = rendering::get_terminal_size()?;
let y = height / 2 + symbols::SYMBOL_HEIGHT as i16 / 2 + 2;
if timer.is_paused() {
let text = "[PAUSE]";
let x = width / 2 - (text.len() as u16) / 2;
let x = width / 2 - (text.len() as i16) / 2;
rendering::draw_text(
text,
x,
y - symbols::SYMBOL_HEIGHT as u16 - symbols::SYMBOL_HEIGHT as u16 / 2,
y - symbols::SYMBOL_HEIGHT as i16 - symbols::SYMBOL_HEIGHT as i16 / 2,
color,
)?;
}
// Display finish state
else if timer.is_finished() {
let text = "[FINISHED]";
let x = width / 2 - (text.len() as u16) / 2;
let x = width / 2 - (text.len() as i16) / 2;
rendering::draw_text(
text,
x,
y - symbols::SYMBOL_HEIGHT as u16 - symbols::SYMBOL_HEIGHT as u16 / 2,
y - symbols::SYMBOL_HEIGHT as i16 - symbols::SYMBOL_HEIGHT as i16 / 2,
color,
)?;
}

View File

@@ -1,4 +1,8 @@
use std::io::{self, Write};
use std::{
cmp::min,
i16,
io::{self, Write},
};
use crossterm::{
cursor, queue,
@@ -9,14 +13,20 @@ use crossterm::{
pub mod color;
pub mod symbols;
pub fn draw_time(time: &str, color: Color) -> io::Result<()> {
pub fn get_terminal_size() -> io::Result<(i16, i16)> {
let (width, height) = terminal::size()?;
Ok((width as i16, height as i16))
}
pub fn draw_time(time: &str, color: Color) -> io::Result<()> {
let (width, height) = get_terminal_size()?;
let text_width = draw_time_width(&time);
let text_height = 5;
let mut x = width / 2 - text_width / 2;
let y = height / 2 - text_height / 2;
let mut x = width / 2 - text_width / 2 - 1;
let y = height / 2 - text_height / 2 - 1;
for c in time.chars() {
if c == ':' {
x -= 1;
@@ -33,21 +43,30 @@ pub fn draw_time(time: &str, color: Color) -> io::Result<()> {
return Ok(());
}
pub fn draw_text(string: &str, x: u16, y: u16, color: Color) -> io::Result<()> {
pub fn draw_text(mut string: &str, mut x: i16, y: i16, color: Color) -> io::Result<()> {
let mut stdout = io::stdout();
let (width, _) = get_terminal_size()?;
let offset = if x < 0 {
let ret = -x as usize;
x = 0;
ret
} else {
0
};
string = &string[offset..min(string.len(), offset + width as usize)];
queue!(
stdout,
cursor::MoveTo(x, y),
cursor::MoveTo(x as u16, y as u16),
style::SetForegroundColor(color),
style::SetAttribute(Attribute::Bold)
)?;
write!(stdout, "{}", string)?;
return Ok(());
}
fn draw_time_width(time: &str) -> u16 {
fn draw_time_width(time: &str) -> i16 {
if time.len() == 0 {
return 0;
}
@@ -62,24 +81,30 @@ fn draw_time_width(time: &str) -> u16 {
}
w -= if time.len() == 1 { 1 } else { 2 };
return w.try_into().unwrap();
w.try_into().unwrap()
}
fn draw_time_symbol(symbol: char, x: u16, y: u16, color: Color) -> io::Result<()> {
fn draw_time_symbol(symbol: char, x: i16, y: i16, color: Color) -> io::Result<()> {
let mut stdout = io::stdout();
let (width, height) = get_terminal_size()?;
let data = symbols::symbol_to_render_data(symbol);
for oy in 0..data.len() {
for ox in 0..data[oy].len() {
if data[oy][ox] {
let cx = ox as u16;
let cy = oy as u16;
let cx = x + ox as i16;
let cy = y + oy as i16;
if cx < 0 || cx >= width || cy < 0 || cy >= height {
continue;
}
// Render cursor at position by setting background color and using space
queue!(
stdout,
cursor::MoveTo(x + cx, y + cy),
cursor::MoveTo(cx as u16, cy as u16),
style::SetBackgroundColor(color)
)?;
write!(stdout, " ")?;