parent
d56434f2de
commit
9bfe4e528b
@ -1,11 +1,12 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
args::Args,
|
args::Args,
|
||||||
|
common::Style,
|
||||||
constants::TICK_VALUE_MS,
|
constants::TICK_VALUE_MS,
|
||||||
events::{Event, EventHandler, Events},
|
events::{Event, EventHandler, Events},
|
||||||
storage::AppStorage,
|
storage::AppStorage,
|
||||||
terminal::Terminal,
|
terminal::Terminal,
|
||||||
widgets::{
|
widgets::{
|
||||||
clock::{self, Clock, ClockArgs, Style},
|
clock::{self, Clock, ClockArgs},
|
||||||
countdown::{Countdown, CountdownWidget},
|
countdown::{Countdown, CountdownWidget},
|
||||||
footer::Footer,
|
footer::Footer,
|
||||||
header::Header,
|
header::Header,
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use color_eyre::{
|
|||||||
};
|
};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::{app::Content, widgets::clock::Style};
|
use crate::{app::Content, common::Style};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
|
|||||||
51
src/common.rs
Normal file
51
src/common.rs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
use clap::ValueEnum;
|
||||||
|
use ratatui::symbols::shade;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, ValueEnum, Default, Serialize, Deserialize)]
|
||||||
|
pub enum Style {
|
||||||
|
#[default]
|
||||||
|
#[value(name = "full", alias = "f")]
|
||||||
|
Full,
|
||||||
|
#[value(name = "light", alias = "l")]
|
||||||
|
Light,
|
||||||
|
#[value(name = "medium", alias = "m")]
|
||||||
|
Medium,
|
||||||
|
#[value(name = "dark", alias = "d")]
|
||||||
|
Dark,
|
||||||
|
#[value(name = "thick", alias = "t")]
|
||||||
|
Thick,
|
||||||
|
#[value(name = "cross", alias = "c")]
|
||||||
|
Cross,
|
||||||
|
/// https://en.wikipedia.org/wiki/Braille_Patterns
|
||||||
|
/// Note: Might not be supported in all terminals
|
||||||
|
/// see https://docs.rs/ratatui/latest/src/ratatui/symbols.rs.html#150
|
||||||
|
#[value(name = "braille", alias = "b")]
|
||||||
|
Braille,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Style {
|
||||||
|
pub fn next(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
Style::Full => Style::Dark,
|
||||||
|
Style::Dark => Style::Medium,
|
||||||
|
Style::Medium => Style::Light,
|
||||||
|
Style::Light => Style::Braille,
|
||||||
|
Style::Braille => Style::Thick,
|
||||||
|
Style::Thick => Style::Cross,
|
||||||
|
Style::Cross => Style::Full,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_digit_symbol(&self) -> &str {
|
||||||
|
match &self {
|
||||||
|
Style::Full => shade::FULL,
|
||||||
|
Style::Light => shade::LIGHT,
|
||||||
|
Style::Medium => shade::MEDIUM,
|
||||||
|
Style::Dark => shade::DARK,
|
||||||
|
Style::Cross => "╬",
|
||||||
|
Style::Thick => "┃",
|
||||||
|
Style::Braille => "⣿",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
mod app;
|
mod app;
|
||||||
|
mod common;
|
||||||
mod config;
|
mod config;
|
||||||
mod constants;
|
mod constants;
|
||||||
mod events;
|
mod events;
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::Content,
|
app::Content, common::Style, constants::APP_NAME, widgets::pomodoro::Mode as PomodoroMode,
|
||||||
constants::APP_NAME,
|
|
||||||
widgets::{clock::Style, pomodoro::Mode as PomodoroMode},
|
|
||||||
};
|
};
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
pub mod clock;
|
pub mod clock;
|
||||||
|
pub mod clock_elements;
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod clock_elements_test;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod clock_test;
|
pub mod clock_test;
|
||||||
pub mod countdown;
|
pub mod countdown;
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
use clap::ValueEnum;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -7,17 +5,20 @@ use strum::Display;
|
|||||||
|
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
buffer::Buffer,
|
buffer::Buffer,
|
||||||
layout::{Constraint, Layout, Position, Rect},
|
layout::{Constraint, Layout, Rect},
|
||||||
symbols::shade,
|
widgets::{StatefulWidget, Widget},
|
||||||
widgets::StatefulWidget,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
common::Style,
|
||||||
duration::{
|
duration::{
|
||||||
DurationEx, MINS_PER_HOUR, ONE_DECI_SECOND, ONE_HOUR, ONE_MINUTE, ONE_SECOND,
|
DurationEx, MINS_PER_HOUR, ONE_DECI_SECOND, ONE_HOUR, ONE_MINUTE, ONE_SECOND,
|
||||||
SECS_PER_MINUTE,
|
SECS_PER_MINUTE,
|
||||||
},
|
},
|
||||||
utils::center_horizontal,
|
utils::center_horizontal,
|
||||||
|
widgets::clock_elements::{
|
||||||
|
Colon, Digit, Dot, COLON_WIDTH, DIGIT_HEIGHT, DIGIT_WIDTH, DOT_WIDTH,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// max. 99:59:59
|
// max. 99:59:59
|
||||||
@ -71,42 +72,6 @@ pub enum Format {
|
|||||||
HhMmSs,
|
HhMmSs,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, ValueEnum, Default, Serialize, Deserialize)]
|
|
||||||
pub enum Style {
|
|
||||||
#[default]
|
|
||||||
#[value(name = "full", alias = "f")]
|
|
||||||
Full,
|
|
||||||
#[value(name = "light", alias = "l")]
|
|
||||||
Light,
|
|
||||||
#[value(name = "medium", alias = "m")]
|
|
||||||
Medium,
|
|
||||||
#[value(name = "dark", alias = "d")]
|
|
||||||
Dark,
|
|
||||||
#[value(name = "thick", alias = "t")]
|
|
||||||
Thick,
|
|
||||||
#[value(name = "cross", alias = "c")]
|
|
||||||
Cross,
|
|
||||||
/// https://en.wikipedia.org/wiki/Braille_Patterns
|
|
||||||
/// Note: Might not be supported in all terminals
|
|
||||||
/// see https://docs.rs/ratatui/latest/src/ratatui/symbols.rs.html#150
|
|
||||||
#[value(name = "braille", alias = "b")]
|
|
||||||
Braille,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Style {
|
|
||||||
pub fn next(&self) -> Self {
|
|
||||||
match self {
|
|
||||||
Style::Full => Style::Dark,
|
|
||||||
Style::Dark => Style::Medium,
|
|
||||||
Style::Medium => Style::Light,
|
|
||||||
Style::Light => Style::Braille,
|
|
||||||
Style::Braille => Style::Thick,
|
|
||||||
Style::Thick => Style::Cross,
|
|
||||||
Style::Cross => Style::Full,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Clock<T> {
|
pub struct Clock<T> {
|
||||||
initial_value: DurationEx,
|
initial_value: DurationEx,
|
||||||
@ -494,111 +459,8 @@ impl Clock<Timer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DIGIT_SIZE: usize = 5;
|
|
||||||
const DIGIT_WIDTH: u16 = DIGIT_SIZE as u16;
|
|
||||||
const DIGIT_HEIGHT: u16 = DIGIT_SIZE as u16 + 1 /* border height */;
|
|
||||||
const COLON_WIDTH: u16 = 4; // incl. padding left + padding right
|
|
||||||
const SPACE_WIDTH: u16 = 1;
|
const SPACE_WIDTH: u16 = 1;
|
||||||
|
|
||||||
#[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 DIGIT_ERROR: [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 ClockWidget<T>
|
pub struct ClockWidget<T>
|
||||||
where
|
where
|
||||||
T: std::fmt::Debug,
|
T: std::fmt::Debug,
|
||||||
@ -616,23 +478,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_digit_symbol(&self, style: &Style) -> &str {
|
|
||||||
match &style {
|
|
||||||
Style::Full => shade::FULL,
|
|
||||||
Style::Light => shade::LIGHT,
|
|
||||||
Style::Medium => shade::MEDIUM,
|
|
||||||
Style::Dark => shade::DARK,
|
|
||||||
Style::Cross => "╬",
|
|
||||||
Style::Thick => "┃",
|
|
||||||
Style::Braille => "⣿",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_horizontal_lengths(&self, format: &Format, with_decis: bool) -> Vec<u16> {
|
fn get_horizontal_lengths(&self, format: &Format, with_decis: bool) -> Vec<u16> {
|
||||||
let add_decis = |mut lengths: Vec<u16>, with_decis: bool| -> Vec<u16> {
|
let add_decis = |mut lengths: Vec<u16>, with_decis: bool| -> Vec<u16> {
|
||||||
if with_decis {
|
if with_decis {
|
||||||
lengths.extend_from_slice(&[
|
lengths.extend_from_slice(&[
|
||||||
COLON_WIDTH, // .
|
DOT_WIDTH, // .
|
||||||
DIGIT_WIDTH, // ds
|
DIGIT_WIDTH, // ds
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
@ -716,108 +566,6 @@ where
|
|||||||
pub fn get_height(&self) -> u16 {
|
pub fn get_height(&self) -> u16 {
|
||||||
DIGIT_HEIGHT
|
DIGIT_HEIGHT
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_digit(
|
|
||||||
&self,
|
|
||||||
number: u64,
|
|
||||||
symbol: &str,
|
|
||||||
with_border: bool,
|
|
||||||
area: Rect,
|
|
||||||
buf: &mut Buffer,
|
|
||||||
) {
|
|
||||||
let left = area.left();
|
|
||||||
let top = area.top();
|
|
||||||
|
|
||||||
let symbols = match number {
|
|
||||||
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,
|
|
||||||
_ => DIGIT_ERROR,
|
|
||||||
};
|
|
||||||
|
|
||||||
symbols.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(symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add border at the bottom
|
|
||||||
if 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("─");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_colon(&self, symbol: &str, 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(symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_dot(&self, symbol: &str, 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(symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> StatefulWidget for ClockWidget<T>
|
impl<T> StatefulWidget for ClockWidget<T>
|
||||||
@ -829,7 +577,7 @@ where
|
|||||||
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
||||||
let with_decis = state.with_decis;
|
let with_decis = state.with_decis;
|
||||||
let format = state.format;
|
let format = state.format;
|
||||||
let symbol = self.get_digit_symbol(&state.style);
|
let symbol = state.style.get_digit_symbol();
|
||||||
let widths = self.get_horizontal_lengths(&format, with_decis);
|
let widths = self.get_horizontal_lengths(&format, with_decis);
|
||||||
let area = center_horizontal(
|
let area = center_horizontal(
|
||||||
area,
|
area,
|
||||||
@ -838,346 +586,154 @@ where
|
|||||||
let edit_hours = matches!(state.mode, Mode::Editable(Time::Hours, _));
|
let edit_hours = matches!(state.mode, Mode::Editable(Time::Hours, _));
|
||||||
let edit_minutes = matches!(state.mode, Mode::Editable(Time::Minutes, _));
|
let edit_minutes = matches!(state.mode, Mode::Editable(Time::Minutes, _));
|
||||||
let edit_secs = matches!(state.mode, Mode::Editable(Time::Seconds, _));
|
let edit_secs = matches!(state.mode, Mode::Editable(Time::Seconds, _));
|
||||||
let edit_deci = matches!(state.mode, Mode::Editable(Time::Decis, _));
|
let edit_decis = matches!(state.mode, Mode::Editable(Time::Decis, _));
|
||||||
match format {
|
match format {
|
||||||
Format::HhMmSs if with_decis => {
|
Format::HhMmSs if with_decis => {
|
||||||
let [hh, _, h, c_hm, mm, _, m, c_ms, ss, _, s, d, ds] =
|
let [hh, _, h, c_hm, mm, _, m, c_ms, ss, _, s, d, ds] =
|
||||||
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.hours() / 10, edit_hours, symbol).render(hh, buf);
|
||||||
state.current_value.hours() / 10,
|
Digit::new(state.current_value.hours() % 10, edit_hours, symbol).render(h, buf);
|
||||||
symbol,
|
Colon::new(symbol).render(c_hm, buf);
|
||||||
edit_hours,
|
Digit::new(state.current_value.minutes_mod() / 10, edit_minutes, symbol)
|
||||||
hh,
|
.render(mm, buf);
|
||||||
buf,
|
Digit::new(state.current_value.minutes_mod() % 10, edit_minutes, symbol)
|
||||||
);
|
.render(m, buf);
|
||||||
self.render_digit(state.current_value.hours() % 10, symbol, edit_hours, h, buf);
|
Colon::new(symbol).render(c_ms, buf);
|
||||||
self.render_colon(symbol, c_hm, buf);
|
Digit::new(state.current_value.seconds_mod() / 10, edit_secs, symbol)
|
||||||
self.render_digit(
|
.render(ss, buf);
|
||||||
state.current_value.minutes_mod() / 10,
|
Digit::new(state.current_value.seconds_mod() % 10, edit_secs, symbol)
|
||||||
symbol,
|
.render(s, buf);
|
||||||
edit_minutes,
|
Dot::new(symbol).render(d, buf);
|
||||||
mm,
|
Digit::new(state.current_value.decis(), edit_decis, symbol).render(ds, buf);
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.minutes_mod() % 10,
|
|
||||||
symbol,
|
|
||||||
edit_minutes,
|
|
||||||
m,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_colon(symbol, c_ms, buf);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() / 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
ss,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() % 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
s,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_dot(symbol, d, buf);
|
|
||||||
self.render_digit(state.current_value.decis(), symbol, edit_deci, ds, buf);
|
|
||||||
}
|
}
|
||||||
Format::HhMmSs => {
|
Format::HhMmSs => {
|
||||||
let [hh, _, h, c_hm, mm, _, m, c_ms, ss, _, s] =
|
let [hh, _, h, c_hm, mm, _, m, c_ms, ss, _, s] =
|
||||||
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.hours() / 10, edit_hours, symbol).render(hh, buf);
|
||||||
state.current_value.hours() / 10,
|
Digit::new(state.current_value.hours() % 10, edit_hours, symbol).render(h, buf);
|
||||||
symbol,
|
Colon::new(symbol).render(c_hm, buf);
|
||||||
edit_hours,
|
Digit::new(state.current_value.minutes_mod() / 10, edit_minutes, symbol)
|
||||||
hh,
|
.render(mm, buf);
|
||||||
buf,
|
Digit::new(state.current_value.minutes_mod() % 10, edit_minutes, symbol)
|
||||||
);
|
.render(m, buf);
|
||||||
self.render_digit(state.current_value.hours() % 10, symbol, edit_hours, h, buf);
|
Colon::new(symbol).render(c_ms, buf);
|
||||||
self.render_colon(symbol, c_hm, buf);
|
Digit::new(state.current_value.seconds_mod() / 10, edit_secs, symbol)
|
||||||
self.render_digit(
|
.render(ss, buf);
|
||||||
state.current_value.minutes_mod() / 10,
|
Digit::new(state.current_value.seconds_mod() % 10, edit_secs, symbol)
|
||||||
symbol,
|
.render(s, buf);
|
||||||
edit_minutes,
|
|
||||||
mm,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.minutes_mod() % 10,
|
|
||||||
symbol,
|
|
||||||
edit_minutes,
|
|
||||||
m,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_colon(symbol, c_ms, buf);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() / 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
ss,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() % 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
s,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Format::HMmSs if with_decis => {
|
Format::HMmSs if with_decis => {
|
||||||
let [h, c_hm, mm, _, m, c_ms, ss, _, s, d, ds] =
|
let [h, c_hm, mm, _, m, c_ms, ss, _, s, d, ds] =
|
||||||
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
||||||
self.render_digit(state.current_value.hours() % 10, symbol, edit_hours, h, buf);
|
Digit::new(state.current_value.hours() % 10, edit_hours, symbol).render(h, buf);
|
||||||
self.render_colon(symbol, c_hm, buf);
|
Colon::new(symbol).render(c_hm, buf);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.minutes_mod() / 10, edit_minutes, symbol)
|
||||||
state.current_value.minutes_mod() / 10,
|
.render(mm, buf);
|
||||||
symbol,
|
Digit::new(state.current_value.minutes_mod() % 10, edit_minutes, symbol)
|
||||||
edit_minutes,
|
.render(m, buf);
|
||||||
mm,
|
Colon::new(symbol).render(c_ms, buf);
|
||||||
buf,
|
Digit::new(state.current_value.seconds_mod() / 10, edit_secs, symbol)
|
||||||
);
|
.render(ss, buf);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.seconds_mod() % 10, edit_secs, symbol)
|
||||||
state.current_value.minutes_mod() % 10,
|
.render(s, buf);
|
||||||
symbol,
|
Dot::new(symbol).render(d, buf);
|
||||||
edit_minutes,
|
Digit::new(state.current_value.decis(), edit_decis, symbol).render(ds, buf);
|
||||||
m,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_colon(symbol, c_ms, buf);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() / 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
ss,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() % 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
s,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_dot(symbol, d, buf);
|
|
||||||
self.render_digit(state.current_value.decis(), symbol, edit_deci, ds, buf);
|
|
||||||
}
|
}
|
||||||
Format::HMmSs => {
|
Format::HMmSs => {
|
||||||
let [h, c_hm, mm, _, m, c_ms, ss, _, s] =
|
let [h, c_hm, mm, _, m, c_ms, ss, _, s] =
|
||||||
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
||||||
self.render_digit(state.current_value.hours() % 10, symbol, edit_hours, h, buf);
|
Digit::new(state.current_value.hours() % 10, edit_hours, symbol).render(h, buf);
|
||||||
self.render_colon(symbol, c_hm, buf);
|
Colon::new(symbol).render(c_hm, buf);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.minutes_mod() / 10, edit_minutes, symbol)
|
||||||
state.current_value.minutes_mod() / 10,
|
.render(mm, buf);
|
||||||
symbol,
|
Digit::new(state.current_value.minutes_mod() % 10, edit_minutes, symbol)
|
||||||
edit_minutes,
|
.render(m, buf);
|
||||||
mm,
|
Colon::new(symbol).render(c_ms, buf);
|
||||||
buf,
|
Digit::new(state.current_value.seconds_mod() / 10, edit_secs, symbol)
|
||||||
);
|
.render(ss, buf);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.seconds_mod() % 10, edit_secs, symbol)
|
||||||
state.current_value.minutes_mod() % 10,
|
.render(s, buf);
|
||||||
symbol,
|
|
||||||
edit_minutes,
|
|
||||||
m,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_colon(symbol, c_ms, buf);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() / 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
ss,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() % 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
s,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Format::MmSs if with_decis => {
|
Format::MmSs if with_decis => {
|
||||||
let [mm, _, m, c_ms, ss, _, s, d, ds] =
|
let [mm, _, m, c_ms, ss, _, s, d, ds] =
|
||||||
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.minutes_mod() / 10, edit_minutes, symbol)
|
||||||
state.current_value.minutes_mod() / 10,
|
.render(mm, buf);
|
||||||
symbol,
|
Digit::new(state.current_value.minutes_mod() % 10, edit_minutes, symbol)
|
||||||
edit_minutes,
|
.render(m, buf);
|
||||||
mm,
|
Colon::new(symbol).render(c_ms, buf);
|
||||||
buf,
|
Digit::new(state.current_value.seconds_mod() / 10, edit_secs, symbol)
|
||||||
);
|
.render(ss, buf);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.seconds_mod() % 10, edit_secs, symbol)
|
||||||
state.current_value.minutes_mod() % 10,
|
.render(s, buf);
|
||||||
symbol,
|
Dot::new(symbol).render(d, buf);
|
||||||
edit_minutes,
|
Digit::new(state.current_value.decis(), edit_decis, symbol).render(ds, buf);
|
||||||
m,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_colon(symbol, c_ms, buf);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() / 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
ss,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() % 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
s,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_dot(symbol, d, buf);
|
|
||||||
self.render_digit(state.current_value.decis(), symbol, edit_deci, ds, buf);
|
|
||||||
}
|
}
|
||||||
Format::MmSs => {
|
Format::MmSs => {
|
||||||
let [mm, _, m, c_ms, ss, _, s] =
|
let [mm, _, m, c_ms, ss, _, s] =
|
||||||
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.minutes_mod() / 10, edit_minutes, symbol)
|
||||||
state.current_value.minutes_mod() / 10,
|
.render(mm, buf);
|
||||||
symbol,
|
Digit::new(state.current_value.minutes_mod() % 10, edit_minutes, symbol)
|
||||||
edit_minutes,
|
.render(m, buf);
|
||||||
mm,
|
Colon::new(symbol).render(c_ms, buf);
|
||||||
buf,
|
Digit::new(state.current_value.seconds_mod() / 10, edit_secs, symbol)
|
||||||
);
|
.render(ss, buf);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.seconds_mod() % 10, edit_secs, symbol)
|
||||||
state.current_value.minutes_mod() % 10,
|
.render(s, buf);
|
||||||
symbol,
|
|
||||||
edit_minutes,
|
|
||||||
m,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_colon(symbol, c_ms, buf);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() / 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
ss,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() % 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
s,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Format::MSs if with_decis => {
|
Format::MSs if with_decis => {
|
||||||
let [m, c_ms, ss, _, s, d, ds] =
|
let [m, c_ms, ss, _, s, d, ds] =
|
||||||
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.minutes_mod() % 10, edit_minutes, symbol)
|
||||||
state.current_value.minutes_mod() % 10,
|
.render(m, buf);
|
||||||
symbol,
|
Colon::new(symbol).render(c_ms, buf);
|
||||||
edit_minutes,
|
Digit::new(state.current_value.seconds_mod() / 10, edit_secs, symbol)
|
||||||
m,
|
.render(ss, buf);
|
||||||
buf,
|
Digit::new(state.current_value.seconds_mod() % 10, edit_secs, symbol)
|
||||||
);
|
.render(s, buf);
|
||||||
self.render_colon(symbol, c_ms, buf);
|
Dot::new(symbol).render(d, buf);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.decis(), edit_decis, symbol).render(ds, buf);
|
||||||
state.current_value.seconds_mod() / 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
ss,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() % 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
s,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_dot(symbol, d, buf);
|
|
||||||
self.render_digit(state.current_value.decis(), symbol, edit_deci, ds, buf);
|
|
||||||
}
|
}
|
||||||
Format::MSs => {
|
Format::MSs => {
|
||||||
let [m, c_ms, ss, _, s] =
|
let [m, c_ms, ss, _, s] =
|
||||||
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.minutes_mod() % 10, edit_minutes, symbol)
|
||||||
state.current_value.minutes_mod() % 10,
|
.render(m, buf);
|
||||||
symbol,
|
Colon::new(symbol).render(c_ms, buf);
|
||||||
edit_minutes,
|
Digit::new(state.current_value.seconds_mod() / 10, edit_secs, symbol)
|
||||||
m,
|
.render(ss, buf);
|
||||||
buf,
|
Digit::new(state.current_value.seconds_mod() % 10, edit_secs, symbol)
|
||||||
);
|
.render(s, buf);
|
||||||
self.render_colon(symbol, c_ms, buf);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() / 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
ss,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() % 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
s,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Format::Ss if state.with_decis => {
|
Format::Ss if state.with_decis => {
|
||||||
let [ss, _, s, d, ds] =
|
let [ss, _, s, d, ds] =
|
||||||
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.seconds_mod() / 10, edit_secs, symbol)
|
||||||
state.current_value.seconds_mod() / 10,
|
.render(ss, buf);
|
||||||
symbol,
|
Digit::new(state.current_value.seconds_mod() % 10, edit_secs, symbol)
|
||||||
edit_secs,
|
.render(s, buf);
|
||||||
ss,
|
Dot::new(symbol).render(d, buf);
|
||||||
buf,
|
Digit::new(state.current_value.decis(), edit_decis, symbol).render(ds, buf);
|
||||||
);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() % 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
s,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_dot(symbol, d, buf);
|
|
||||||
self.render_digit(state.current_value.decis(), symbol, edit_deci, ds, buf);
|
|
||||||
}
|
}
|
||||||
Format::Ss => {
|
Format::Ss => {
|
||||||
let [ss, _, s] = Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
let [ss, _, s] = Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.seconds_mod() / 10, edit_secs, symbol)
|
||||||
state.current_value.seconds_mod() / 10,
|
.render(ss, buf);
|
||||||
symbol,
|
Digit::new(state.current_value.seconds_mod() % 10, edit_secs, symbol)
|
||||||
edit_secs,
|
.render(s, buf);
|
||||||
ss,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_digit(
|
|
||||||
state.current_value.seconds_mod() % 10,
|
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
s,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Format::S if with_decis => {
|
Format::S if with_decis => {
|
||||||
let [s, d, ds] = Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
let [s, d, ds] = Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.seconds_mod() % 10, edit_secs, symbol)
|
||||||
state.current_value.seconds_mod() % 10,
|
.render(s, buf);
|
||||||
symbol,
|
Dot::new(symbol).render(d, buf);
|
||||||
edit_secs,
|
Digit::new(state.current_value.decis(), edit_decis, symbol).render(ds, buf);
|
||||||
s,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
self.render_dot(symbol, d, buf);
|
|
||||||
self.render_digit(state.current_value.decis(), symbol, edit_deci, ds, buf);
|
|
||||||
}
|
}
|
||||||
Format::S => {
|
Format::S => {
|
||||||
let [s] = Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
let [s] = Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
|
||||||
self.render_digit(
|
Digit::new(state.current_value.seconds_mod() % 10, edit_secs, symbol)
|
||||||
state.current_value.seconds_mod() % 10,
|
.render(s, buf);
|
||||||
symbol,
|
|
||||||
edit_secs,
|
|
||||||
s,
|
|
||||||
buf,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
247
src/widgets/clock_elements.rs
Normal file
247
src/widgets/clock_elements.rs
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
#[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<'a> Widget for Digit<'a> {
|
||||||
|
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<'a> Widget for Dot<'a> {
|
||||||
|
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<'a> Widget for Colon<'a> {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
92
src/widgets/clock_elements_test.rs
Normal file
92
src/widgets/clock_elements_test.rs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
use crate::widgets::clock_elements::*;
|
||||||
|
use ratatui::{buffer::Buffer, layout::Rect, widgets::Widget};
|
||||||
|
|
||||||
|
const D_RECT: Rect = Rect::new(0, 0, DIGIT_WIDTH, DIGIT_HEIGHT);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_d1() {
|
||||||
|
let mut b = Buffer::empty(D_RECT);
|
||||||
|
Digit::new(1, false, "█").render(D_RECT, &mut b);
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let expected = Buffer::with_lines([
|
||||||
|
" ██",
|
||||||
|
" ██",
|
||||||
|
" ██",
|
||||||
|
" ██",
|
||||||
|
" ██",
|
||||||
|
" ",
|
||||||
|
]);
|
||||||
|
assert_eq!(b, expected, "w/o border");
|
||||||
|
|
||||||
|
Digit::new(1, true, "█").render(D_RECT, &mut b);
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let expected = Buffer::with_lines([
|
||||||
|
" ██",
|
||||||
|
" ██",
|
||||||
|
" ██",
|
||||||
|
" ██",
|
||||||
|
" ██",
|
||||||
|
"─────",
|
||||||
|
]);
|
||||||
|
assert_eq!(b, expected, "w/ border");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_d2() {
|
||||||
|
let mut b = Buffer::empty(D_RECT);
|
||||||
|
Digit::new(2, false, "█").render(D_RECT, &mut b);
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let expected = Buffer::with_lines([
|
||||||
|
"█████",
|
||||||
|
" ██",
|
||||||
|
"█████",
|
||||||
|
"██ ",
|
||||||
|
"█████",
|
||||||
|
" ",
|
||||||
|
]);
|
||||||
|
assert_eq!(b, expected, "w/o border");
|
||||||
|
|
||||||
|
Digit::new(2, true, "█").render(D_RECT, &mut b);
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let expected = Buffer::with_lines([
|
||||||
|
"█████",
|
||||||
|
" ██",
|
||||||
|
"█████",
|
||||||
|
"██ ",
|
||||||
|
"█████",
|
||||||
|
"─────",
|
||||||
|
]);
|
||||||
|
assert_eq!(b, expected, "w/ border");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dot() {
|
||||||
|
let mut b = Buffer::empty(D_RECT);
|
||||||
|
Dot::new("█").render(D_RECT, &mut b);
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let expected = Buffer::with_lines([
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ██ ",
|
||||||
|
" ",
|
||||||
|
]);
|
||||||
|
assert_eq!(b, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_colon() {
|
||||||
|
let mut b = Buffer::empty(D_RECT);
|
||||||
|
Colon::new("█").render(D_RECT, &mut b);
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let expected = Buffer::with_lines([
|
||||||
|
" ",
|
||||||
|
" ██ ",
|
||||||
|
" ",
|
||||||
|
" ██ ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
]);
|
||||||
|
assert_eq!(b, expected);
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
common::Style,
|
||||||
duration::{ONE_DECI_SECOND, ONE_HOUR, ONE_MINUTE, ONE_SECOND},
|
duration::{ONE_DECI_SECOND, ONE_HOUR, ONE_MINUTE, ONE_SECOND},
|
||||||
widgets::clock::*,
|
widgets::clock::*,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,9 +8,10 @@ use ratatui::{
|
|||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
common::Style,
|
||||||
events::{Event, EventHandler},
|
events::{Event, EventHandler},
|
||||||
utils::center,
|
utils::center,
|
||||||
widgets::clock::{self, Clock, ClockWidget, Style},
|
widgets::clock::{self, Clock, ClockWidget},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
common::Style,
|
||||||
constants::TICK_VALUE_MS,
|
constants::TICK_VALUE_MS,
|
||||||
events::{Event, EventHandler},
|
events::{Event, EventHandler},
|
||||||
utils::center,
|
utils::center,
|
||||||
widgets::clock::{Clock, ClockWidget, Countdown, Style},
|
widgets::clock::{Clock, ClockWidget, Countdown},
|
||||||
};
|
};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
buffer::Buffer,
|
buffer::Buffer,
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
common::Style,
|
||||||
events::{Event, EventHandler},
|
events::{Event, EventHandler},
|
||||||
utils::center,
|
utils::center,
|
||||||
widgets::clock::{self, Clock, ClockWidget, Style},
|
widgets::clock::{self, Clock, ClockWidget},
|
||||||
};
|
};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
buffer::Buffer,
|
buffer::Buffer,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user