2021-04-05 21:07:00 +02:00
|
|
|
use std::sync::Arc;
|
|
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
2021-04-05 12:20:24 +02:00
|
|
|
use crate::Config;
|
|
|
|
use crate::common::*;
|
|
|
|
|
|
|
|
// If screen size falls below these values we skip computation of new
|
|
|
|
// positions.
|
|
|
|
const MIN_WIDTH: u16 = DIGIT_WIDTH * 6 + 13;
|
|
|
|
const MIN_HEIGHT: u16 = DIGIT_HEIGHT + 2;
|
|
|
|
|
|
|
|
pub struct Position {
|
|
|
|
pub line: u16,
|
|
|
|
pub col: u16,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Layout {
|
|
|
|
pub force_redraw: bool, // Redraw elements on screen.
|
2021-04-05 21:07:00 +02:00
|
|
|
pub force_recalc: Arc<AtomicBool>, // Recalculate position of elements.
|
2021-04-05 12:20:24 +02:00
|
|
|
pub plain: bool, // Plain style clock.
|
|
|
|
pub width: u16,
|
|
|
|
pub height: u16,
|
|
|
|
pub clock_sec: Position,
|
|
|
|
pub clock_colon0: Position,
|
|
|
|
pub clock_min: Position,
|
|
|
|
pub clock_colon1: Position,
|
|
|
|
pub clock_hr: Position,
|
|
|
|
pub clock_days: Position,
|
|
|
|
pub roster: Position,
|
|
|
|
pub roster_width: u16,
|
|
|
|
pub roster_height: u16,
|
|
|
|
pub buffer: Position,
|
|
|
|
pub error: Position,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Layout {
|
|
|
|
pub fn new(config: &Config) -> Layout {
|
|
|
|
Layout {
|
|
|
|
force_redraw: true,
|
2021-04-05 21:07:00 +02:00
|
|
|
// May be set by signal handler (SIGWINCH).
|
|
|
|
force_recalc: Arc::new(AtomicBool::new(true)),
|
2021-04-05 12:20:24 +02:00
|
|
|
plain: config.plain,
|
|
|
|
width: 0,
|
|
|
|
height: 0,
|
|
|
|
clock_sec: Position {col: 0, line: 0},
|
|
|
|
clock_colon0: Position {col: 0, line: 0},
|
|
|
|
clock_min: Position {col: 0, line: 0},
|
|
|
|
clock_colon1: Position {col: 0, line: 0},
|
|
|
|
clock_hr: Position {col: 0, line: 0},
|
|
|
|
clock_days: Position {col: 0, line: 0},
|
|
|
|
roster: Position {col: 1, line: 3},
|
|
|
|
roster_width: 0,
|
|
|
|
roster_height: 0,
|
|
|
|
buffer: Position {col: 0, line: 0},
|
|
|
|
error: Position {col: 0, line: 0},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-06 16:36:01 +02:00
|
|
|
pub fn update(&mut self, display_hours: bool, force: bool) {
|
|
|
|
if self.force_recalc.swap(false, Ordering::Relaxed) || force {
|
2021-04-05 21:07:00 +02:00
|
|
|
let (width, height) = termion::terminal_size()
|
|
|
|
.expect("Could not read terminal size!");
|
2021-04-05 12:20:24 +02:00
|
|
|
self.width = width;
|
|
|
|
self.height = height;
|
|
|
|
self.compute(display_hours);
|
|
|
|
self.force_redraw = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute the position of various elements based on the size of the
|
|
|
|
// terminal.
|
|
|
|
fn compute(&mut self, display_hours: bool) {
|
2021-04-08 12:32:37 +02:00
|
|
|
// Prevent integer overflow at very low screen sizes.
|
2021-04-05 12:20:24 +02:00
|
|
|
if self.width < MIN_WIDTH || self.height < MIN_HEIGHT { return; }
|
|
|
|
|
2021-04-08 12:32:37 +02:00
|
|
|
let middle: u16 = self.height / 2 - 1;
|
|
|
|
|
2021-04-05 12:20:24 +02:00
|
|
|
if display_hours {
|
|
|
|
// Seconds digits.
|
|
|
|
self.clock_sec.col = (self.width + self.roster_width) / 2 + DIGIT_WIDTH + 6;
|
|
|
|
// Colon separating minutes from seconds.
|
|
|
|
self.clock_colon0.col = (self.width + self.roster_width) / 2 + DIGIT_WIDTH + 3;
|
|
|
|
// Minute digits.
|
|
|
|
self.clock_min.col = (self.width + self.roster_width) / 2 - DIGIT_WIDTH;
|
|
|
|
|
|
|
|
// Colon separating hours from minutes.
|
|
|
|
self.clock_colon1 = Position {
|
|
|
|
col: (self.width + self.roster_width) / 2 - (DIGIT_WIDTH + 3),
|
|
|
|
line: middle,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Hour digits.
|
|
|
|
self.clock_hr = Position {
|
|
|
|
col: (self.width + self.roster_width) / 2 - (DIGIT_WIDTH * 3 + 6),
|
|
|
|
line: middle,
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
// Seconds digits.
|
|
|
|
self.clock_sec.col = (self.width + self.roster_width) / 2 + 3;
|
|
|
|
// Colon separating minutes from seconds.
|
|
|
|
self.clock_colon0.col = (self.width + self.roster_width) / 2;
|
|
|
|
// Minute digits.
|
|
|
|
self.clock_min.col = (self.width + self.roster_width) / 2 - (DIGIT_WIDTH * 2 + 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.clock_sec.line = middle;
|
|
|
|
self.clock_colon0.line = middle;
|
|
|
|
self.clock_min.line = middle;
|
|
|
|
|
|
|
|
// Days (based on position of seconds).
|
|
|
|
self.clock_days = Position {
|
2021-04-08 07:59:11 +02:00
|
|
|
line: self.clock_sec.line + DIGIT_HEIGHT,
|
2021-04-05 12:20:24 +02:00
|
|
|
col: self.clock_sec.col,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Alarm roster height.
|
|
|
|
self.roster_height = self.height - self.roster.line - 1;
|
|
|
|
|
|
|
|
// Input buffer.
|
|
|
|
self.buffer = Position {
|
|
|
|
line: self.height,
|
|
|
|
col: 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Error messages.
|
|
|
|
self.error = Position {
|
|
|
|
line: self.height,
|
|
|
|
col: 12,
|
|
|
|
};
|
|
|
|
}
|
2021-04-08 09:46:36 +02:00
|
|
|
|
|
|
|
pub fn set_roster_width(&mut self, width: u16) {
|
|
|
|
if self.width != width {
|
|
|
|
self.roster_width = width;
|
|
|
|
self.force_recalc.store(true, Ordering::Relaxed);
|
|
|
|
}
|
|
|
|
}
|
2021-04-05 12:20:24 +02:00
|
|
|
}
|
|
|
|
|