1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
use std::io::{self, stdout, Write};
use termion::raw::{IntoRawMode, RawTerminal};
use termion::screen::AlternateScreen;
pub struct Screen {
pub w: u16,
pub h: u16,
pub stdout: AlternateScreen<RawTerminal<io::Stdout>>,
}
#[derive(Debug)]
pub struct ScreenArea {
pub top: u16, // first line
pub bottom: u16, // last line, included
pub scroll: i32, // 0 for no scroll, positive if scrolled
pub content_length: i32,
pub width: u16,
}
impl Screen {
pub fn new() -> io::Result<Screen> {
let stdout = AlternateScreen::from(stdout().into_raw_mode()?);
let mut screen = Screen { w: 0, h: 0, stdout };
screen.read_size()?;
write!(screen.stdout, "{}", termion::cursor::Hide)?;
Ok(screen)
}
pub fn read_size(&mut self) -> io::Result<()> {
let (w, h) = termion::terminal_size()?;
self.w = w;
self.h = h;
Ok(())
}
}
impl Drop for Screen {
fn drop(&mut self) {
write!(self.stdout, "{}", termion::cursor::Show).unwrap();
// if we don't flush now, the standard screen may receive some
// unflushed data which was meant for the alternate screen.
self.stdout.flush().unwrap();
}
}
impl ScreenArea {
pub fn new(top: u16, bottom: u16, width: u16) -> ScreenArea {
ScreenArea {
top,
bottom,
scroll: 0,
content_length: 0,
width,
}
}
pub fn try_scroll(&mut self, dy: i32) {
self.scroll += dy;
if self.scroll < 0 {
self.scroll = 0;
} else if self.scroll >= self.content_length {
self.scroll = self.content_length - 1;
}
}
pub fn scrollbar(&self) -> Option<(u16, u16)> {
let h = (self.bottom as i32) - (self.top as i32) + 1;
if self.content_length <= h {
return None;
}
let sbh = h * h / self.content_length;
let sc = i32::from(self.top) + self.scroll * h / self.content_length;
Some((sc as u16, (sc + sbh - 1).min(i32::from(self.bottom)) as u16))
}
}
|