Refactored clock code.

This commit is contained in:
shy 2021-04-12 08:26:26 +02:00
parent 557358a4c0
commit 5eef3dd811
5 changed files with 296 additions and 275 deletions

View file

@ -1,9 +1,11 @@
pub mod font;
use std::time; use std::time;
use std::io::Write; use std::io::Write;
use termion::{color, cursor, style}; use termion::{color, cursor, style};
use termion::raw::RawTerminal; use termion::raw::RawTerminal;
use crate::consts::COLOR; use crate::consts::COLOR;
use crate::consts::digits::*; use crate::Config;
use crate::layout::{Layout, Position}; use crate::layout::{Layout, Position};
pub struct Clock { pub struct Clock {
@ -13,10 +15,11 @@ pub struct Clock {
pub paused: bool, pub paused: bool,
paused_at: Option<time::Instant>, paused_at: Option<time::Instant>,
pub color_index: Option<usize>, pub color_index: Option<usize>,
font: font::Font,
} }
impl Clock { impl Clock {
pub fn new() -> Clock { pub fn new(config: &Config) -> Clock {
Clock { Clock {
start: time::Instant::now(), start: time::Instant::now(),
elapsed: 0, elapsed: 0,
@ -24,6 +27,10 @@ impl Clock {
paused: false, paused: false,
paused_at: None, paused_at: None,
color_index: None, color_index: None,
font: match config.plain {
false => font::NORMAL,
true => font::PLAIN,
},
} }
} }
@ -81,13 +88,14 @@ impl Clock {
&mut self, &mut self,
mut stdout: &mut RawTerminal<W>, mut stdout: &mut RawTerminal<W>,
layout: &Layout, layout: &Layout,
) { ) -> Result<(), std::io::Error>
{
// Setup style and color if appropriate. // Setup style and color if appropriate.
if self.paused { if self.paused {
write!(stdout, "{}", style::Faint).unwrap(); write!(stdout, "{}", style::Faint)?;
} }
if let Some(c) = self.color_index { if let Some(c) = self.color_index {
write!(stdout, "{}", color::Fg(COLOR[c])).unwrap(); write!(stdout, "{}", color::Fg(COLOR[c]))?;
} }
// Draw hours if necessary. // Draw hours if necessary.
@ -96,14 +104,12 @@ impl Clock {
self.draw_digit_pair( self.draw_digit_pair(
&mut stdout, &mut stdout,
self.elapsed / 3600, self.elapsed / 3600,
&layout.clock_hr, &layout.clock_hr)?;
layout.plain);
// Draw colon. // Draw colon.
self.draw_colon( self.draw_colon(
&mut stdout, &mut stdout,
&layout.clock_colon1, &layout.clock_colon1)?;
layout.plain);
} }
// Draw days. // Draw days.
@ -119,8 +125,7 @@ impl Clock {
layout.clock_days.col, layout.clock_days.col,
layout.clock_days.line, layout.clock_days.line,
), ),
day_count) day_count)?;
.unwrap();
} }
} }
@ -129,33 +134,30 @@ impl Clock {
self.draw_digit_pair( self.draw_digit_pair(
&mut stdout, &mut stdout,
(self.elapsed % 3600) / 60, (self.elapsed % 3600) / 60,
&layout.clock_min, &layout.clock_min)?;
layout.plain);
} }
// Draw colon if necessary. // Draw colon if necessary.
if layout.force_redraw { if layout.force_redraw {
self.draw_colon( self.draw_colon(
&mut stdout, &mut stdout,
&layout.clock_colon0, &layout.clock_colon0)?;
layout.plain);
} }
// Draw seconds. // Draw seconds.
self.draw_digit_pair( self.draw_digit_pair(
&mut stdout, &mut stdout,
self.elapsed % 60, self.elapsed % 60,
&layout.clock_sec, &layout.clock_sec)?;
layout.plain);
// Reset color and style. // Reset color and style.
if self.paused || self.color_index != None { if self.paused || self.color_index != None {
write!(stdout, write!(stdout,
"{}{}", "{}{}",
style::NoFaint, style::NoFaint,
color::Fg(color::Reset)) color::Fg(color::Reset))?;
.unwrap();
} }
Ok(())
} }
fn draw_digit_pair<W: Write>( fn draw_digit_pair<W: Write>(
@ -163,37 +165,35 @@ impl Clock {
stdout: &mut RawTerminal<W>, stdout: &mut RawTerminal<W>,
value: u32, value: u32,
pos: &Position, pos: &Position,
plain: bool, ) -> Result<(), std::io::Error>
) { {
let digits = if plain { DIGITS_PLAIN } else { DIGITS }; for l in 0..self.font.height {
for l in 0..DIGIT_HEIGHT {
write!(stdout, write!(stdout,
"{}{} {}", "{}{} {}",
cursor::Goto(pos.col, pos.line + l), cursor::Goto(pos.col, pos.line + l),
// First digit. // First digit.
digits[(value / 10) as usize][l as usize], self.font.digits[(value / 10) as usize][l as usize],
// Second digit. // Second digit.
digits[(value % 10) as usize][l as usize]) self.font.digits[(value % 10) as usize][l as usize]
.unwrap(); )?;
} }
Ok(())
} }
fn draw_colon<W: Write>( fn draw_colon<W: Write>(
&self, &self,
stdout: &mut RawTerminal<W>, stdout: &mut RawTerminal<W>,
pos: &Position, pos: &Position,
plain: bool, ) -> Result<(), std::io::Error>
) { {
let dot = if plain {'█'} else {'■'};
write!(stdout, write!(stdout,
"{}{}{}{}", "{}{}{}{}",
cursor::Goto(pos.col, pos.line + 1), cursor::Goto(pos.col, pos.line + 1),
dot, self.font.dot,
cursor::Goto(pos.col, pos.line + 3), cursor::Goto(pos.col, pos.line + 3),
dot) self.font.dot,
.unwrap(); )?;
Ok(())
} }
} }

243
src/clock/font.rs Normal file
View file

@ -0,0 +1,243 @@
pub const DIGIT_HEIGHT: u16 = 5;
pub const DIGIT_WIDTH: u16 = 5;
pub struct Font {
pub height: u16,
pub width: u16,
pub dot: char,
pub digits: [[&'static str; DIGIT_HEIGHT as usize]; 10],
}
pub const NORMAL: Font = Font {
height: DIGIT_HEIGHT,
width: 5,
dot: '',
digits: [[
// 0
"█▀▀▀█",
"█ █",
"█ █",
"█ █",
"█▄▄▄█",
], [
// 1
" ▀█ ",
"",
"",
"",
""
], [
// 2
"▀▀▀▀█",
"",
"█▀▀▀▀",
"",
"█▄▄▄▄"
], [
// 3
"▀▀▀▀█",
"",
" ▀▀▀█",
"",
"▄▄▄▄█"
], [
// 4
"",
"█ █ ",
"▀▀▀█▀",
"",
""
], [
// 5
"█▀▀▀▀",
"",
"▀▀▀▀█",
"",
"▄▄▄▄█"
], [
// 6
"",
"",
"█▀▀▀█",
"█ █",
"█▄▄▄█"
], [
// 7
"▀▀▀▀█",
"",
"",
"",
"",
], [
// 8
"█▀▀▀█",
"█ █",
"█▀▀▀█",
"█ █",
"█▄▄▄█"
], [
// 9
"█▀▀▀█",
"█ █",
"▀▀▀▀█",
"",
""
]],
};
pub const PLAIN: Font = Font {
height: DIGIT_HEIGHT,
width: 5,
dot: '',
digits: [[
// 0
"█████",
"█ █",
"█ █",
"█ █",
"█████"
], [
// 1
" ██ ",
"",
"",
"",
""
], [
// 2
"█████",
"",
"█████",
"",
"█████"
], [
// 3
"█████",
"",
" ████",
"",
"█████"
], [
// 4
"",
"█ █ ",
"█████",
"",
""
], [
// 5
"█████",
"",
"█████",
"",
"█████"
], [
// 6
"",
"",
"█████",
"█ █",
"█████"
], [
// 7
"█████",
"",
"",
"",
""
], [
// 8
"█████",
"█ █",
"█████",
"█ █",
"█████"
], [
// 9
"█████",
"█ █",
"█████",
"",
""
]],
};
/*
pub const FANCE: Font = Font {
height: DIGIT_HEIGHT,
width: 5,
dot: '',
digits: [[
// 0
"█▀▀▀█",
"█ █",
"▀ ▀",
"🮐 🮐",
"🮐🮏🮏🮏🮐",
], [
// 1
" ▀█ ",
"",
"",
" 🮐 ",
" 🮐 "
], [
// 2
"▀▀▀▀█",
"",
"▀▀▀▀▀",
"🮐 ",
"🮐🮏🮏🮏🮏"
], [
// 3
"▀▀▀▀█",
"",
" ▀▀▀▀",
" 🮐",
"🮏🮏🮏🮏🮐"
], [
// 4
"",
"█ █ ",
"▀▀▀▀▀",
" 🮐 ",
" 🮐 "
], [
// 5
"█▀▀▀▀",
"",
"▀▀▀▀▀",
" 🮐",
"🮏🮏🮏🮏🮐"
], [
// 6
"",
"",
"▀▀▀▀▀",
"🮐 🮐",
"🮐🮏🮏🮏🮐"
], [
// 7
"▀▀▀▀█",
"",
"",
" 🮐 ",
" 🮐 ",
], [
// 8
"█▀▀▀█",
"█ █",
"▀▀▀▀▀",
"🮐 🮐",
"🮐🮏🮏🮏🮐"
], [
// 9
"█▀▀▀█",
"█ █",
"▀▀▀▀▀",
" 🮐",
" 🮐"
]],
};
*/

View file

@ -9,7 +9,7 @@ pub const COLOR: [&dyn termion::color::Color; 6] = [
]; ];
// Maximum length of labels. // Maximum length of labels.
pub const LABEL_SIZE_LIMIT: usize = 48; pub const LABEL_SIZE_LIMIT: usize = 42;
pub mod ui { pub mod ui {
pub const NAME: &str = env!("CARGO_PKG_NAME"); pub const NAME: &str = env!("CARGO_PKG_NAME");
@ -40,229 +40,3 @@ SIGNALS: <SIGUSR1> Reset clock.
"Format: HH:MM:SS/LABEL [ENTER] Accept [ESC] Cancel [CTR-C] Quit"; "Format: HH:MM:SS/LABEL [ENTER] Accept [ESC] Cancel [CTR-C] Quit";
} }
pub mod digits {
pub const DIGIT_HEIGHT: u16 = 5;
pub const DIGIT_WIDTH: u16 = 5;
pub const DIGITS: [[&str; DIGIT_HEIGHT as usize]; 10] = [
[
// 0
"█▀▀▀█",
"█ █",
"█ █",
"█ █",
"█▄▄▄█",
], [
// 1
" ▀█ ",
"",
"",
"",
""
], [
// 2
"▀▀▀▀█",
"",
"█▀▀▀▀",
"",
"█▄▄▄▄"
], [
// 3
"▀▀▀▀█",
"",
" ▀▀▀█",
"",
"▄▄▄▄█"
], [
// 4
"",
"█ █ ",
"▀▀▀█▀",
"",
""
], [
// 5
"█▀▀▀▀",
"",
"▀▀▀▀█",
"",
"▄▄▄▄█"
], [
// 6
"",
"",
"█▀▀▀█",
"█ █",
"█▄▄▄█"
], [
// 7
"▀▀▀▀█",
"",
"",
"",
"",
], [
// 8
"█▀▀▀█",
"█ █",
"█▀▀▀█",
"█ █",
"█▄▄▄█"
], [
// 9
"█▀▀▀█",
"█ █",
"▀▀▀▀█",
"",
""
]
];
pub const _DIGITS_FANCY: [[&str; DIGIT_HEIGHT as usize]; 10] = [
[
// 0
"█▀▀▀█",
"█ █",
"▀ ▀",
"🮐 🮐",
"🮐🮏🮏🮏🮐",
], [
// 1
" ▀█ ",
"",
"",
" 🮐 ",
" 🮐 "
], [
// 2
"▀▀▀▀█",
"",
"▀▀▀▀▀",
"🮐 ",
"🮐🮏🮏🮏🮏"
], [
// 3
"▀▀▀▀█",
"",
" ▀▀▀▀",
" 🮐",
"🮏🮏🮏🮏🮐"
], [
// 4
"",
"█ █ ",
"▀▀▀▀▀",
" 🮐 ",
" 🮐 "
], [
// 5
"█▀▀▀▀",
"",
"▀▀▀▀▀",
" 🮐",
"🮏🮏🮏🮏🮐"
], [
// 6
"",
"",
"▀▀▀▀▀",
"🮐 🮐",
"🮐🮏🮏🮏🮐"
], [
// 7
"▀▀▀▀█",
"",
"",
" 🮐 ",
" 🮐 ",
], [
// 8
"█▀▀▀█",
"█ █",
"▀▀▀▀▀",
"🮐 🮐",
"🮐🮏🮏🮏🮐"
], [
// 9
"█▀▀▀█",
"█ █",
"▀▀▀▀▀",
" 🮐",
" 🮐"
]
];
pub const DIGITS_PLAIN: [[&str; DIGIT_HEIGHT as usize]; 10] = [
[
// 0
"█████",
"█ █",
"█ █",
"█ █",
"█████"
], [
// 1
" ██ ",
"",
"",
"",
""
], [
// 2
"█████",
"",
"█████",
"",
"█████"
], [
// 3
"█████",
"",
" ████",
"",
"█████"
], [
// 4
"",
"█ █ ",
"█████",
"",
""
], [
// 5
"█████",
"",
"█████",
"",
"█████"
], [
// 6
"",
"",
"█████",
"█ █",
"█████"
], [
// 7
"█████",
"",
"",
"",
""
], [
// 8
"█████",
"█ █",
"█████",
"█ █",
"█████"
], [
// 9
"█████",
"█ █",
"█████",
"",
""
]
];
}

View file

@ -1,7 +1,7 @@
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use crate::Config; use crate::Config;
use crate::consts::digits::*; use crate::clock::font::*;
// If screen size falls below these values we skip computation of new // If screen size falls below these values we skip computation of new
// positions. // positions.

View file

@ -45,7 +45,7 @@ pub fn run(
layout.force_recalc = sigwinch; layout.force_recalc = sigwinch;
// Initialise roster_width. // Initialise roster_width.
layout.set_roster_width(alarm_roster.width()); layout.set_roster_width(alarm_roster.width());
let mut clock = Clock::new(); let mut clock = Clock::new(&config);
let mut countdown = Countdown::new(); let mut countdown = Countdown::new();
let mut buffer = Buffer::new(); let mut buffer = Buffer::new();
@ -182,7 +182,7 @@ pub fn run(
buffer.draw(&mut stdout, &mut layout)?; buffer.draw(&mut stdout, &mut layout)?;
} }
clock.draw(&mut stdout, &layout); clock.draw(&mut stdout, &layout)?;
// Display countdown. // Display countdown.
if countdown.value > 0 { if countdown.value > 0 {
@ -392,33 +392,37 @@ impl Config {
// for process::Command::new(). // for process::Command::new().
fn parse_to_command(input: &str) -> Vec<String> { fn parse_to_command(input: &str) -> Vec<String> {
let mut command: Vec<String> = Vec::new(); let mut command: Vec<String> = Vec::new();
let mut buffer: String = String::new(); let mut segment: String = String::new();
let mut quoted = false; let mut quoted = false;
let mut escaped = false; let mut escaped = false;
for byte in input.chars() { for c in input.chars() {
match byte { match c {
'\\' if !escaped => { '\\' if !escaped => {
// Next char is escaped. // Next char is escaped. (If not escaped itself.)
escaped = true; escaped = true;
continue; continue;
}, },
' ' if escaped || quoted => { &buffer.push(' '); }, // Keep spaces when escaped or quoted.
' ' if escaped || quoted => { &segment.push(' '); },
// Otherwise end the current segment.
' ' => { ' ' => {
if !&buffer.is_empty() { if !&segment.is_empty() {
command.push(buffer.clone()); command.push(segment.clone());
&buffer.clear(); &segment.clear();
} }
}, },
// Quotation marks toggle quote.
'"' | '\'' if !escaped => quoted = !quoted, '"' | '\'' if !escaped => quoted = !quoted,
// Carry everything else. Escape if found escaped.
_ => { _ => {
if escaped { &buffer.push('\\'); } if escaped { &segment.push('\\'); }
&buffer.push(byte); &segment.push(c);
}, },
} }
escaped = false; escaped = false;
} }
command.push(buffer); command.push(segment);
command.shrink_to_fit(); command.shrink_to_fit();
command command
} }