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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
use super::*;
use time::{Duration, Instant};
/// The cursor structure used in the terminal.
/// A cursor is a special symbol shown in the text box of a terminal. It indicates the position of character where the next input would be put or the delete operation works on.
/// Terminal invokes its `display` method in a loop to let a cursor blink.
pub struct Cursor {
/// Whether the cursor is enabled in the terminal.
enabled: bool,
/// The blinking frequency.
freq: Duration,
/// The last time it blinks.
time: Instant,
/// The current blinking state show/hidden
show: bool,
/// The color of the cursor
color: Color,
/// The position of the cursor relative to the end of terminal text in number of characters.
pub offset_from_end: usize,
/// The underlying character at the position of the cursor.
/// It is shown when the cursor is unseen.
pub underlying_char: u8,
}
impl Cursor {
/// Reset the state of the cursor as unseen
pub fn reset(&mut self) {
self.show = true;
self.time = Instant::now();
}
/// Enable a cursor
pub fn enable(&mut self) {
self.enabled = true;
self.reset();
}
/// Disable a cursor
pub fn disable(&mut self) {
self.enabled = false;
}
/// Let a cursor blink. It is invoked in a loop.
pub fn blink(&mut self) -> bool {
if self.enabled {
let time = Instant::now();
if time >= self.time + self.freq {
self.time = time;
self.show = !self.show;
return true;
}
}
true
}
/// Whether a cursor is seen
pub fn show(&self) -> bool {
self.enabled && self.show
}
/// Display a cursor in a framebuffer
/// # Arguments
/// * `coordinate`: the start point of a textarea in the framebuffer.
/// * `column`: the column of the cursor in the textarea.
/// * `line`: the line of the cursor in the textarea.
/// * `framebuffer`: the framebuffer to display the cursor in.
///
/// Returns a bounding box which wraps the cursor.
pub fn display<P: Pixel>(
&mut self,
coordinate: Coord,
column: usize,
line: usize,
framebuffer: &mut Framebuffer<P>,
) -> Result<Rectangle, &'static str> where Color: Into<P> {
if self.blink() {
if self.show() {
framebuffer_drawer::fill_rectangle(
framebuffer,
coordinate
+ (
(column * CHARACTER_WIDTH) as isize,
(line * CHARACTER_HEIGHT) as isize,
)
+ (0, 1),
CHARACTER_WIDTH,
CHARACTER_HEIGHT - 2,
self.color.into(),
);
} else {
framebuffer_printer::print_ascii_character(
framebuffer,
self.underlying_char,
FONT_FOREGROUND_COLOR.into(),
FONT_BACKGROUND_COLOR.into(),
coordinate,
column,
line,
)
}
}
let top_left = coordinate
+ (
(column * CHARACTER_WIDTH) as isize,
(line * CHARACTER_HEIGHT) as isize,
);
let bounding_box = Rectangle {
top_left,
bottom_right: top_left + (CHARACTER_WIDTH as isize, CHARACTER_HEIGHT as isize),
};
Ok(bounding_box)
}
/// Sets the position of the cursor relative to the end of the command
pub fn set_offset_from_end(&mut self, offset: usize) {
self.offset_from_end = offset;
}
/// Gets the position of the cursor relative to the end of the command
pub fn offset_from_end(&self) -> usize {
self.offset_from_end
}
/// Sets the character at the position of the cursor
pub fn set_underlying_char(&mut self, c: u8) {
self.underlying_char = c;
}
/// Gets the character at the position of the cursor
pub fn underlying_char(&self) -> u8 {
self.underlying_char
}
}
impl Default for Cursor {
fn default() -> Self {
Cursor {
enabled: true,
freq: DEFAULT_CURSOR_FREQ,
time: Instant::now(),
show: true,
color: FONT_FOREGROUND_COLOR,
offset_from_end: 0,
underlying_char: 0,
}
}
}