generated from PlexSheep/rs-base
extract a font layer and reimplement the bricks font (#23)
* implement the font layer * run fmt * refactor
This commit is contained in:
parent
8f434e2d05
commit
25d6795d7e
13 changed files with 171 additions and 283 deletions
|
@ -6,9 +6,9 @@ mod timer;
|
|||
use std::cmp::min;
|
||||
use std::fmt::Write as _;
|
||||
|
||||
use crate::clock_text::BricksText;
|
||||
use chrono::Duration;
|
||||
pub(crate) use clock::Clock;
|
||||
use crate::bricks_text::BricksText;
|
||||
pub(crate) use countdown::Countdown;
|
||||
pub(crate) use stopwatch::Stopwatch;
|
||||
pub(crate) use timer::Timer;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::clock_text::BricksText;
|
||||
use chrono::{Local, Utc};
|
||||
use chrono_tz::Tz;
|
||||
use crate::bricks_text::BricksText;
|
||||
use tui::{layout::Rect, style::Style, widgets::Widget};
|
||||
|
||||
use super::render_centered;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::clock_text::BricksText;
|
||||
use chrono::{DateTime, Duration, Local};
|
||||
use crate::bricks_text::BricksText;
|
||||
use tui::{style::Style, widgets::Widget};
|
||||
|
||||
use super::{format_duration, render_centered, DurationFormat};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::clock_text::BricksText;
|
||||
use chrono::{DateTime, Duration, Local};
|
||||
use crate::bricks_text::BricksText;
|
||||
use tui::{buffer::Buffer, layout::Rect, style::Style, widgets::Widget};
|
||||
|
||||
use crate::app::Pause;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{cell::RefCell, process::Command};
|
||||
|
||||
use crate::clock_text::BricksText;
|
||||
use chrono::{DateTime, Duration, Local};
|
||||
use crate::bricks_text::BricksText;
|
||||
use tui::{buffer::Buffer, layout::Rect, style::Style, widgets::Widget};
|
||||
|
||||
use crate::app::Pause;
|
||||
|
|
|
@ -4,8 +4,8 @@ use std::{
|
|||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use clock_tui::app::Mode;
|
||||
use clap::Parser;
|
||||
use clock_tui::app::Mode;
|
||||
use crossterm::{
|
||||
event::{self, Event, KeyCode},
|
||||
execute,
|
||||
|
|
|
@ -1,265 +0,0 @@
|
|||
use std::{cmp::max, ops};
|
||||
use tui::{buffer::Buffer, layout::Rect, style::Style};
|
||||
|
||||
pub(crate) trait BricksChar {
|
||||
fn render(&self, size: u16, style: Style, area: Rect, buf: &mut Buffer);
|
||||
}
|
||||
|
||||
pub struct BrickChar(char);
|
||||
|
||||
impl BrickChar {
|
||||
const H_UNIT: u16 = 2;
|
||||
const V_UNIT: u16 = 1;
|
||||
const UNIT_SIZE: Point = Point(3 * Self::H_UNIT, 5 * Self::V_UNIT);
|
||||
|
||||
pub(crate) fn size(size: u16) -> Point {
|
||||
Self::UNIT_SIZE * size
|
||||
}
|
||||
|
||||
pub(crate) fn from(char: char) -> BrickChar {
|
||||
BrickChar(char)
|
||||
}
|
||||
|
||||
pub(crate) fn render(&self, size: u16, style: Style, area: Rect, buf: &mut Buffer) {
|
||||
let char_size = BrickChar::size(size);
|
||||
match self.0 {
|
||||
'0'..='9' => Self::draw_digital(self.0, size, style, area, buf),
|
||||
':' => {
|
||||
let start_x = area.x + size * Self::H_UNIT;
|
||||
let end_x = area.x + char_size.0 - size * Self::H_UNIT;
|
||||
let start_y = area.y + size * Self::V_UNIT;
|
||||
let start_y2 = area.y + (char_size.1 + size * Self::V_UNIT) / 2;
|
||||
let len = (char_size.1 - 3 * size * Self::V_UNIT) / 2;
|
||||
for x in (start_x..end_x).step_by((size * Self::H_UNIT) as usize) {
|
||||
Self::draw_line(
|
||||
size,
|
||||
Point(x, start_y),
|
||||
len,
|
||||
LineDir::Vertical,
|
||||
style,
|
||||
&area,
|
||||
buf,
|
||||
);
|
||||
Self::draw_line(
|
||||
size,
|
||||
Point(x, start_y2),
|
||||
len,
|
||||
LineDir::Vertical,
|
||||
style,
|
||||
&area,
|
||||
buf,
|
||||
);
|
||||
}
|
||||
}
|
||||
'-' => {
|
||||
let x = area.x;
|
||||
let y = area.y + (char_size.1 - size * Self::V_UNIT) / 2;
|
||||
Self::draw_line(
|
||||
size,
|
||||
Point(x, y),
|
||||
char_size.1,
|
||||
LineDir::Horizontal,
|
||||
style,
|
||||
&area,
|
||||
buf,
|
||||
);
|
||||
}
|
||||
'.' => {
|
||||
let x = area.x + char_size.0 - size * Self::H_UNIT;
|
||||
let y = area.y + char_size.1 - size * Self::V_UNIT;
|
||||
Self::draw_line(
|
||||
size,
|
||||
Point(x, y),
|
||||
size * Self::H_UNIT,
|
||||
LineDir::Horizontal,
|
||||
style,
|
||||
&area,
|
||||
buf,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_digital(d: char, size: u16, style: Style, area: Rect, buf: &mut Buffer) {
|
||||
let char_size = BrickChar::size(size);
|
||||
let mut draw_line =
|
||||
|x, y, len, dir| Self::draw_line(size, Point(x, y), len, dir, style, &area, buf);
|
||||
let x_start = area.x;
|
||||
let x_end = area.x + char_size.0 - size * Self::H_UNIT;
|
||||
let y_start = area.y;
|
||||
let y_end = area.y + char_size.1 - size * Self::V_UNIT;
|
||||
let y_center = area.y + (char_size.1 - size * Self::V_UNIT) / 2;
|
||||
let half_h = (char_size.1 + size * Self::V_UNIT) / 2;
|
||||
match d {
|
||||
'0' => {
|
||||
draw_line(x_start, y_start, half_h, LineDir::Vertical);
|
||||
draw_line(x_start, y_center, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_start, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_center, half_h, LineDir::Vertical);
|
||||
|
||||
draw_line(x_start, y_start, char_size.0, LineDir::Horizontal);
|
||||
// draw_line(x_start, y_center, char_size.0, LineDir::Horizontal);
|
||||
draw_line(x_start, y_end, char_size.0, LineDir::Horizontal);
|
||||
}
|
||||
'1' => {
|
||||
// draw_line(x_start, y_start, half_h, LineDir::Vertical);
|
||||
// draw_line(x_start, y_center, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_start, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_center, half_h, LineDir::Vertical);
|
||||
|
||||
// draw_line(x_start, y_start, char_size.0, LineDir::Horizontal);
|
||||
// draw_line(x_start, y_center, char_size.0, LineDir::Horizontal);
|
||||
// draw_line(x_start, y_end, char_size.0, LineDir::Horizontal);
|
||||
}
|
||||
'2' => {
|
||||
// draw_line(x_start, y_start, half_h, LineDir::Vertical);
|
||||
draw_line(x_start, y_center, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_start, half_h, LineDir::Vertical);
|
||||
// draw_line(x_end, y_center, half_h, LineDir::Vertical);
|
||||
|
||||
draw_line(x_start, y_start, char_size.0, LineDir::Horizontal);
|
||||
draw_line(x_start, y_center, char_size.0, LineDir::Horizontal);
|
||||
draw_line(x_start, y_end, char_size.0, LineDir::Horizontal);
|
||||
}
|
||||
'3' => {
|
||||
// draw_line(x_start, y_start, half_h, LineDir::Vertical);
|
||||
// draw_line(x_start, y_center, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_start, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_center, half_h, LineDir::Vertical);
|
||||
|
||||
draw_line(x_start, y_start, char_size.0, LineDir::Horizontal);
|
||||
draw_line(x_start, y_center, char_size.0, LineDir::Horizontal);
|
||||
draw_line(x_start, y_end, char_size.0, LineDir::Horizontal);
|
||||
}
|
||||
'4' => {
|
||||
draw_line(x_start, y_start, half_h, LineDir::Vertical);
|
||||
// draw_line(x_start, y_center, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_start, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_center, half_h, LineDir::Vertical);
|
||||
|
||||
// draw_line(x_start, y_start, char_size.0, LineDir::Horizontal);
|
||||
draw_line(x_start, y_center, char_size.0, LineDir::Horizontal);
|
||||
// draw_line(x_start, y_end, char_size.0, LineDir::Horizontal);
|
||||
}
|
||||
'5' => {
|
||||
draw_line(x_start, y_start, half_h, LineDir::Vertical);
|
||||
// draw_line(x_start, y_center, half_h, LineDir::Vertical);
|
||||
// draw_line(x_end, y_start, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_center, half_h, LineDir::Vertical);
|
||||
|
||||
draw_line(x_start, y_start, char_size.0, LineDir::Horizontal);
|
||||
draw_line(x_start, y_center, char_size.0, LineDir::Horizontal);
|
||||
draw_line(x_start, y_end, char_size.0, LineDir::Horizontal);
|
||||
}
|
||||
'6' => {
|
||||
draw_line(x_start, y_start, half_h, LineDir::Vertical);
|
||||
draw_line(x_start, y_center, half_h, LineDir::Vertical);
|
||||
// draw_line(x_end, y_start, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_center, half_h, LineDir::Vertical);
|
||||
|
||||
draw_line(x_start, y_start, char_size.0, LineDir::Horizontal);
|
||||
draw_line(x_start, y_center, char_size.0, LineDir::Horizontal);
|
||||
draw_line(x_start, y_end, char_size.0, LineDir::Horizontal);
|
||||
}
|
||||
'7' => {
|
||||
// draw_line(x_start, y_start, half_h, LineDir::Vertical);
|
||||
// draw_line(x_start, y_center, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_start, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_center, half_h, LineDir::Vertical);
|
||||
|
||||
draw_line(x_start, y_start, char_size.0, LineDir::Horizontal);
|
||||
// draw_line(x_start, y_center, char_size.0, LineDir::Horizontal);
|
||||
// draw_line(x_start, y_end, char_size.0, LineDir::Horizontal);
|
||||
}
|
||||
'8' => {
|
||||
draw_line(x_start, y_start, half_h, LineDir::Vertical);
|
||||
draw_line(x_start, y_center, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_start, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_center, half_h, LineDir::Vertical);
|
||||
|
||||
draw_line(x_start, y_start, char_size.0, LineDir::Horizontal);
|
||||
draw_line(x_start, y_center, char_size.0, LineDir::Horizontal);
|
||||
draw_line(x_start, y_end, char_size.0, LineDir::Horizontal);
|
||||
}
|
||||
'9' => {
|
||||
draw_line(x_start, y_start, half_h, LineDir::Vertical);
|
||||
// draw_line(x_start, y_center, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_start, half_h, LineDir::Vertical);
|
||||
draw_line(x_end, y_center, half_h, LineDir::Vertical);
|
||||
|
||||
draw_line(x_start, y_start, char_size.0, LineDir::Horizontal);
|
||||
draw_line(x_start, y_center, char_size.0, LineDir::Horizontal);
|
||||
draw_line(x_start, y_end, char_size.0, LineDir::Horizontal);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_line(
|
||||
size: u16,
|
||||
start: Point,
|
||||
len: u16,
|
||||
dir: LineDir,
|
||||
style: Style,
|
||||
area: &Rect,
|
||||
buf: &mut Buffer,
|
||||
) {
|
||||
let step = match dir {
|
||||
LineDir::Horizontal => Point(Self::H_UNIT, 0),
|
||||
LineDir::Vertical => Point(0, Self::V_UNIT),
|
||||
};
|
||||
|
||||
let line = match dir {
|
||||
LineDir::Horizontal => Point(0, Self::V_UNIT),
|
||||
LineDir::Vertical => Point(Self::H_UNIT, 0),
|
||||
};
|
||||
|
||||
let mut from = start;
|
||||
for _ in 0..size {
|
||||
let mut p = from;
|
||||
for _ in (0..len).step_by(max(step.0, step.1).into()) {
|
||||
if !p.in_area(area) {
|
||||
break;
|
||||
}
|
||||
// println!("p = {:?} area = {:?}", p, area);
|
||||
buf.get_mut(p.0, p.1).set_symbol("██").set_style(style);
|
||||
p = p + &step;
|
||||
}
|
||||
from = from + &line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum LineDir {
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) struct Point(pub u16, pub u16);
|
||||
|
||||
impl Point {
|
||||
pub(crate) fn in_area(&self, area: &Rect) -> bool {
|
||||
area.left() <= self.0
|
||||
&& self.0 < area.right()
|
||||
&& area.top() <= self.1
|
||||
&& self.1 < area.bottom()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Add<&Point> for Point {
|
||||
type Output = Point;
|
||||
|
||||
fn add(self, other: &Point) -> Point {
|
||||
Point(self.0 + other.0, self.1 + other.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul<u16> for Point {
|
||||
type Output = Point;
|
||||
|
||||
fn mul(self, other: u16) -> Point {
|
||||
Point(self.0 * other, self.1 * other)
|
||||
}
|
||||
}
|
|
@ -1,28 +1,31 @@
|
|||
use tui::{style::Style, widgets::Widget};
|
||||
|
||||
use self::chars::{BrickChar, Point};
|
||||
use self::font::bricks::Bricks;
|
||||
use self::font::Font;
|
||||
use self::point::Point;
|
||||
|
||||
mod chars;
|
||||
mod font;
|
||||
mod point;
|
||||
|
||||
pub struct BricksText {
|
||||
text: String,
|
||||
size: u16,
|
||||
space: u16,
|
||||
style: Style,
|
||||
font: Bricks,
|
||||
}
|
||||
|
||||
impl BricksText {
|
||||
pub fn new(text: &str, size: u16, space: u16, style: Style) -> BricksText {
|
||||
BricksText {
|
||||
text: text.to_string(),
|
||||
size,
|
||||
space,
|
||||
style,
|
||||
font: Bricks { size },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> (u16, u16) {
|
||||
let Point(w, h) = BrickChar::size(self.size);
|
||||
let Point(w, h) = self.font.size();
|
||||
let n_chars = self.text.chars().count() as u16;
|
||||
(w * n_chars + self.space * (n_chars - 1), h)
|
||||
}
|
||||
|
@ -32,9 +35,8 @@ impl Widget for &BricksText {
|
|||
fn render(self, area: tui::layout::Rect, buf: &mut tui::buffer::Buffer) {
|
||||
let mut area = area;
|
||||
for char in self.text.chars() {
|
||||
let Point(w, _) = BrickChar::size(self.size);
|
||||
let char = BrickChar::from(char);
|
||||
char.render(self.size, self.style, area, buf);
|
||||
let Point(w, _) = self.font.size();
|
||||
self.font.render(char, self.style, area, buf);
|
||||
let l = w + self.space;
|
||||
area.x += l;
|
||||
area.width = area.width.saturating_sub(l);
|
10
clock-tui/src/clock_text/font.rs
Normal file
10
clock-tui/src/clock_text/font.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
use tui::{buffer::Buffer, layout::Rect, style::Style};
|
||||
|
||||
use super::point::Point;
|
||||
|
||||
pub mod bricks;
|
||||
|
||||
pub(crate) trait Font {
|
||||
fn size(&self) -> Point;
|
||||
fn render(&self, char: char, style: Style, area: Rect, buf: &mut Buffer);
|
||||
}
|
121
clock-tui/src/clock_text/font/bricks.rs
Normal file
121
clock-tui/src/clock_text/font/bricks.rs
Normal file
|
@ -0,0 +1,121 @@
|
|||
use std::cmp::min;
|
||||
|
||||
use tui::{buffer::Buffer, layout::Rect, style::Style};
|
||||
|
||||
use super::Font;
|
||||
use crate::clock_text::point::Point;
|
||||
|
||||
pub struct Bricks {
|
||||
pub size: u16,
|
||||
}
|
||||
|
||||
impl Bricks {
|
||||
const UNIT_SIZE: Point = Point(6, 5);
|
||||
|
||||
/// each row is represented with a vector of numbers:
|
||||
/// the odd indexed items represent the lenght of "off",
|
||||
/// the even indexed items represent the lenght of "on".
|
||||
/// For exmaple:
|
||||
/// vec![0, 6] is "██████"
|
||||
/// vec![2, 2] is " ██"
|
||||
/// vec![0, 2, 2, 2] is "██ ██"
|
||||
fn draw_row(
|
||||
start: Point,
|
||||
row: Vec<u16>,
|
||||
size: u16,
|
||||
style: Style,
|
||||
area: &Rect,
|
||||
buf: &mut Buffer,
|
||||
) {
|
||||
let mut p = start;
|
||||
let mut on = false;
|
||||
for len in row {
|
||||
let len = len * size;
|
||||
if p.0 > area.right() {
|
||||
break;
|
||||
}
|
||||
|
||||
if on {
|
||||
let s = min(len, area.right() - p.0 + 1);
|
||||
let line = "█".repeat(s as usize);
|
||||
for r in 0..size {
|
||||
if p.1 > area.bottom() {
|
||||
break;
|
||||
}
|
||||
buf.set_string(p.0, p.1 + r, line.as_str(), style);
|
||||
}
|
||||
}
|
||||
|
||||
p.0 += len;
|
||||
on = !on;
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_matrix(mat: [Vec<u16>; 5], size: u16, style: Style, area: &Rect, buf: &mut Buffer) {
|
||||
let mut start = Point(area.x, area.y);
|
||||
for row in mat {
|
||||
Self::draw_row(start, row, size, style, area, buf);
|
||||
start.1 += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Font for Bricks {
|
||||
fn size(&self) -> Point {
|
||||
Self::UNIT_SIZE * self.size
|
||||
}
|
||||
|
||||
fn render(&self, char: char, style: Style, area: Rect, buf: &mut Buffer) {
|
||||
let size = self.size;
|
||||
let mut render_matrix = |mat: [Vec<u16>; 5]| {
|
||||
Bricks::draw_matrix(mat, size, style, &area, buf);
|
||||
};
|
||||
|
||||
match char {
|
||||
'0' => render_matrix([
|
||||
vec![0, 6],
|
||||
vec![0, 2, 2, 2],
|
||||
vec![0, 2, 2, 2],
|
||||
vec![0, 2, 2, 2],
|
||||
vec![0, 6],
|
||||
]),
|
||||
'1' => render_matrix([vec![0, 4], vec![2, 2], vec![2, 2], vec![2, 2], vec![0, 6]]),
|
||||
'2' => render_matrix([vec![0, 6], vec![4, 2], vec![0, 6], vec![0, 2], vec![0, 6]]),
|
||||
'3' => render_matrix([vec![0, 6], vec![4, 2], vec![0, 6], vec![4, 2], vec![0, 6]]),
|
||||
'4' => render_matrix([
|
||||
vec![0, 2, 2, 2],
|
||||
vec![0, 2, 2, 2],
|
||||
vec![0, 6],
|
||||
vec![4, 2],
|
||||
vec![4, 2],
|
||||
]),
|
||||
'5' => render_matrix([vec![0, 6], vec![0, 2], vec![0, 6], vec![4, 2], vec![0, 6]]),
|
||||
'6' => render_matrix([
|
||||
vec![0, 6],
|
||||
vec![0, 2],
|
||||
vec![0, 6],
|
||||
vec![0, 2, 2, 2],
|
||||
vec![0, 6],
|
||||
]),
|
||||
'7' => render_matrix([vec![0, 6], vec![4, 2], vec![4, 2], vec![4, 2], vec![4, 2]]),
|
||||
'8' => render_matrix([
|
||||
vec![0, 6],
|
||||
vec![0, 2, 2, 2],
|
||||
vec![0, 6],
|
||||
vec![0, 2, 2, 2],
|
||||
vec![0, 6],
|
||||
]),
|
||||
'9' => render_matrix([
|
||||
vec![0, 6],
|
||||
vec![0, 2, 2, 2],
|
||||
vec![0, 6],
|
||||
vec![4, 2],
|
||||
vec![0, 6],
|
||||
]),
|
||||
':' => render_matrix([vec![], vec![2, 2], vec![], vec![2, 2], vec![]]),
|
||||
'.' => render_matrix([vec![], vec![], vec![], vec![], vec![2, 2]]),
|
||||
'-' => render_matrix([vec![], vec![], vec![0, 6], vec![], vec![]]),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
20
clock-tui/src/clock_text/point.rs
Normal file
20
clock-tui/src/clock_text/point.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use std::ops;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Point(pub u16, pub u16);
|
||||
|
||||
impl ops::Add<&Point> for Point {
|
||||
type Output = Point;
|
||||
|
||||
fn add(self, other: &Point) -> Point {
|
||||
Point(self.0 + other.0, self.1 + other.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul<u16> for Point {
|
||||
type Output = Point;
|
||||
|
||||
fn mul(self, other: u16) -> Point {
|
||||
Point(self.0 * other, self.1 * other)
|
||||
}
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
pub mod app;
|
||||
pub mod bricks_text;
|
||||
pub mod clock_text;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use clap::{IntoApp, ArgEnum};
|
||||
use clap_complete::{Shell, generate_to};
|
||||
use clap::{ArgEnum, IntoApp};
|
||||
use clap_complete::{generate_to, Shell};
|
||||
use clap_mangen::Man;
|
||||
use clock_tui::app::App;
|
||||
use std::fs::File;
|
||||
use std::io::Result;
|
||||
use std::path::{PathBuf, Path};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{env, fs};
|
||||
|
||||
const BIN_NAME: &str = "tclock";
|
||||
|
|
Reference in a new issue