249 lines
5.2 KiB
Rust
249 lines
5.2 KiB
Rust
use ratatui::{
|
|
buffer::Buffer,
|
|
layout::{Position, Rect},
|
|
widgets::Widget,
|
|
};
|
|
|
|
pub const DIGIT_SIZE: usize = 5;
|
|
pub const DIGIT_WIDTH: u16 = DIGIT_SIZE as u16;
|
|
pub const DIGIT_HEIGHT: u16 = DIGIT_SIZE as u16 + 1 /* border height */;
|
|
pub const COLON_WIDTH: u16 = 4; // incl. padding left + padding right
|
|
pub const DOT_WIDTH: u16 = 4; // incl. padding left + padding right
|
|
pub const DIGIT_SPACE_WIDTH: u16 = 1; // space between digits
|
|
|
|
#[rustfmt::skip]
|
|
const DIGIT_0: [u8; DIGIT_SIZE * DIGIT_SIZE] = [
|
|
1, 1, 1, 1, 1,
|
|
1, 1, 0, 1, 1,
|
|
1, 1, 0, 1, 1,
|
|
1, 1, 0, 1, 1,
|
|
1, 1, 1, 1, 1,
|
|
];
|
|
|
|
#[rustfmt::skip]
|
|
const DIGIT_1: [u8; DIGIT_SIZE * DIGIT_SIZE] = [
|
|
0, 0, 0, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
];
|
|
|
|
#[rustfmt::skip]
|
|
const DIGIT_2: [u8; DIGIT_SIZE * DIGIT_SIZE] = [
|
|
1, 1, 1, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
1, 1, 1, 1, 1,
|
|
1, 1, 0, 0, 0,
|
|
1, 1, 1, 1, 1,
|
|
];
|
|
|
|
#[rustfmt::skip]
|
|
const DIGIT_3: [u8; DIGIT_SIZE * DIGIT_SIZE] = [
|
|
1, 1, 1, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
1, 1, 1, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
1, 1, 1, 1, 1,
|
|
];
|
|
|
|
#[rustfmt::skip]
|
|
const DIGIT_4: [u8; DIGIT_SIZE * DIGIT_SIZE] = [
|
|
1, 1, 0, 1, 1,
|
|
1, 1, 0, 1, 1,
|
|
1, 1, 1, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
];
|
|
|
|
#[rustfmt::skip]
|
|
const DIGIT_5: [u8; DIGIT_SIZE * DIGIT_SIZE] = [
|
|
1, 1, 1, 1, 1,
|
|
1, 1, 0, 0, 0,
|
|
1, 1, 1, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
1, 1, 1, 1, 1,
|
|
];
|
|
|
|
#[rustfmt::skip]
|
|
const DIGIT_6: [u8; DIGIT_SIZE * DIGIT_SIZE] = [
|
|
1, 1, 1, 1, 1,
|
|
1, 1, 0, 0, 0,
|
|
1, 1, 1, 1, 1,
|
|
1, 1, 0, 1, 1,
|
|
1, 1, 1, 1, 1,
|
|
];
|
|
|
|
#[rustfmt::skip]
|
|
const DIGIT_7: [u8; DIGIT_SIZE * DIGIT_SIZE] = [
|
|
1, 1, 1, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
];
|
|
|
|
#[rustfmt::skip]
|
|
const DIGIT_8: [u8; DIGIT_SIZE * DIGIT_SIZE] = [
|
|
1, 1, 1, 1, 1,
|
|
1, 1, 0, 1, 1,
|
|
1, 1, 1, 1, 1,
|
|
1, 1, 0, 1, 1,
|
|
1, 1, 1, 1, 1,
|
|
];
|
|
|
|
#[rustfmt::skip]
|
|
const DIGIT_9: [u8; DIGIT_SIZE * DIGIT_SIZE] = [
|
|
1, 1, 1, 1, 1,
|
|
1, 1, 0, 1, 1,
|
|
1, 1, 1, 1, 1,
|
|
0, 0, 0, 1, 1,
|
|
1, 1, 1, 1, 1,
|
|
];
|
|
|
|
#[rustfmt::skip]
|
|
const CHAR_E: [u8; DIGIT_SIZE * DIGIT_SIZE] = [
|
|
1, 1, 1, 1, 1,
|
|
1, 1, 0, 0, 0,
|
|
1, 1, 1, 1, 0,
|
|
1, 1, 0, 0, 0,
|
|
1, 1, 1, 1, 1,
|
|
];
|
|
|
|
pub struct Digit<'a> {
|
|
digit: u64,
|
|
with_border: bool,
|
|
symbol: &'a str,
|
|
}
|
|
|
|
impl<'a> Digit<'a> {
|
|
pub fn new(digit: u64, with_border: bool, symbol: &'a str) -> Self {
|
|
Self {
|
|
digit,
|
|
with_border,
|
|
symbol,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Widget for Digit<'_> {
|
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
|
let left = area.left();
|
|
let top = area.top();
|
|
|
|
let patterns = match self.digit {
|
|
0 => DIGIT_0,
|
|
1 => DIGIT_1,
|
|
2 => DIGIT_2,
|
|
3 => DIGIT_3,
|
|
4 => DIGIT_4,
|
|
5 => DIGIT_5,
|
|
6 => DIGIT_6,
|
|
7 => DIGIT_7,
|
|
8 => DIGIT_8,
|
|
9 => DIGIT_9,
|
|
_ => CHAR_E,
|
|
};
|
|
|
|
patterns.iter().enumerate().for_each(|(i, item)| {
|
|
let x = i % DIGIT_SIZE;
|
|
let y = i / DIGIT_SIZE;
|
|
if *item == 1 {
|
|
let p = Position {
|
|
x: left + x as u16,
|
|
y: top + y as u16,
|
|
};
|
|
if let Some(cell) = buf.cell_mut(p) {
|
|
cell.set_symbol(self.symbol);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Add border at the bottom
|
|
if self.with_border {
|
|
for x in 0..area.width {
|
|
let p = Position {
|
|
x: left + x,
|
|
y: top + area.height - 1,
|
|
};
|
|
if let Some(cell) = buf.cell_mut(p) {
|
|
cell.set_symbol("─");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Dot<'a> {
|
|
symbol: &'a str,
|
|
}
|
|
|
|
impl<'a> Dot<'a> {
|
|
pub fn new(symbol: &'a str) -> Self {
|
|
Self { symbol }
|
|
}
|
|
}
|
|
|
|
impl Widget for Dot<'_> {
|
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
|
let positions = [
|
|
Position {
|
|
x: area.left() + 1,
|
|
y: area.top() + area.height - 2,
|
|
},
|
|
Position {
|
|
x: area.left() + 2,
|
|
y: area.top() + area.height - 2,
|
|
},
|
|
];
|
|
|
|
for pos in positions {
|
|
if let Some(cell) = buf.cell_mut(pos) {
|
|
cell.set_symbol(self.symbol);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Colon<'a> {
|
|
symbol: &'a str,
|
|
}
|
|
|
|
impl<'a> Colon<'a> {
|
|
pub fn new(symbol: &'a str) -> Self {
|
|
Self { symbol }
|
|
}
|
|
}
|
|
|
|
impl Widget for Colon<'_> {
|
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
|
let left = area.left();
|
|
let top = area.top();
|
|
|
|
let positions = [
|
|
Position {
|
|
x: left + 1,
|
|
y: top + 1,
|
|
},
|
|
Position {
|
|
x: left + 2,
|
|
y: top + 1,
|
|
},
|
|
Position {
|
|
x: left + 1,
|
|
y: top + 3,
|
|
},
|
|
Position {
|
|
x: left + 2,
|
|
y: top + 3,
|
|
},
|
|
];
|
|
|
|
for pos in positions {
|
|
if let Some(cell) = buf.cell_mut(pos) {
|
|
cell.set_symbol(self.symbol);
|
|
}
|
|
}
|
|
}
|
|
}
|