ui: add overlay grid
Add second layer grid for overlays (messages, notifications)async
parent
333db9ed37
commit
4a4c8e265a
154
src/state.rs
154
src/state.rs
|
@ -176,10 +176,11 @@ pub struct State {
|
|||
rows: usize,
|
||||
|
||||
grid: CellBuffer,
|
||||
overlay_grid: CellBuffer,
|
||||
draw_rate_limit: RateLimit,
|
||||
stdout: Option<StateStdout>,
|
||||
child: Option<ForkType>,
|
||||
draw_horizontal_segment_fn: fn(&mut State, usize, usize, usize) -> (),
|
||||
draw_horizontal_segment_fn: fn(&mut CellBuffer, &mut StateStdout, usize, usize, usize) -> (),
|
||||
pub mode: UIMode,
|
||||
components: Vec<Box<dyn Component>>,
|
||||
pub context: Context,
|
||||
|
@ -269,6 +270,7 @@ impl State {
|
|||
cols,
|
||||
rows,
|
||||
grid: CellBuffer::new(cols, rows, Cell::with_char(' ')),
|
||||
overlay_grid: CellBuffer::new(cols, rows, Cell::with_char(' ')),
|
||||
stdout: None,
|
||||
child: None,
|
||||
mode: UIMode::Normal,
|
||||
|
@ -309,6 +311,7 @@ impl State {
|
|||
.set_value(std::time::Duration::from_millis(3));
|
||||
if s.context.settings.terminal.ascii_drawing {
|
||||
s.grid.set_ascii_drawing(true);
|
||||
s.overlay_grid.set_ascii_drawing(true);
|
||||
}
|
||||
|
||||
s.switch_to_alternate_screen();
|
||||
|
@ -434,6 +437,8 @@ impl State {
|
|||
self.cols = termcols.unwrap_or(72) as usize;
|
||||
self.rows = termrows.unwrap_or(120) as usize;
|
||||
self.grid.resize(self.cols, self.rows, Cell::with_char(' '));
|
||||
self.overlay_grid
|
||||
.resize(self.cols, self.rows, Cell::with_char(' '));
|
||||
|
||||
self.rcv_event(UIEvent::Resize);
|
||||
|
||||
|
@ -466,18 +471,36 @@ impl State {
|
|||
continue;
|
||||
}
|
||||
if let Some((x_start, x_end)) = segment.take() {
|
||||
(self.draw_horizontal_segment_fn)(self, x_start, x_end, y);
|
||||
(self.draw_horizontal_segment_fn)(
|
||||
&mut self.grid,
|
||||
self.stdout.as_mut().unwrap(),
|
||||
x_start,
|
||||
x_end,
|
||||
y,
|
||||
);
|
||||
}
|
||||
match segment {
|
||||
ref mut s @ None => {
|
||||
*s = Some((*x_start, *x_end));
|
||||
}
|
||||
ref mut s @ Some(_) if s.unwrap().1 < *x_start => {
|
||||
(self.draw_horizontal_segment_fn)(self, s.unwrap().0, s.unwrap().1, y);
|
||||
(self.draw_horizontal_segment_fn)(
|
||||
&mut self.grid,
|
||||
self.stdout.as_mut().unwrap(),
|
||||
s.unwrap().0,
|
||||
s.unwrap().1,
|
||||
y,
|
||||
);
|
||||
*s = Some((*x_start, *x_end));
|
||||
}
|
||||
ref mut s @ Some(_) if s.unwrap().1 < *x_end => {
|
||||
(self.draw_horizontal_segment_fn)(self, s.unwrap().0, s.unwrap().1, y);
|
||||
(self.draw_horizontal_segment_fn)(
|
||||
&mut self.grid,
|
||||
self.stdout.as_mut().unwrap(),
|
||||
s.unwrap().0,
|
||||
s.unwrap().1,
|
||||
y,
|
||||
);
|
||||
*s = Some((s.unwrap().1, *x_end));
|
||||
}
|
||||
Some((_, ref mut x)) => {
|
||||
|
@ -486,16 +509,111 @@ impl State {
|
|||
}
|
||||
}
|
||||
if let Some((x_start, x_end)) = segment {
|
||||
(self.draw_horizontal_segment_fn)(self, x_start, x_end, y);
|
||||
(self.draw_horizontal_segment_fn)(
|
||||
&mut self.grid,
|
||||
self.stdout.as_mut().unwrap(),
|
||||
x_start,
|
||||
x_end,
|
||||
y,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if self.display_messages_active {
|
||||
if let Some(DisplayMessage {
|
||||
ref timestamp,
|
||||
ref msg,
|
||||
..
|
||||
}) = self.display_messages.get(self.display_messages_pos)
|
||||
{
|
||||
let noto_colors = crate::conf::value(&self.context, "status.notification");
|
||||
use crate::melib::text_processing::{Reflow, TextProcessing};
|
||||
|
||||
let msg_lines = msg.split_lines_reflow(Reflow::All, Some(self.cols / 3));
|
||||
let width = msg_lines
|
||||
.iter()
|
||||
.map(|line| line.grapheme_len() + 4)
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
|
||||
let displ_area = place_in_area(
|
||||
(
|
||||
(0, 0),
|
||||
(self.cols.saturating_sub(1), self.rows.saturating_sub(1)),
|
||||
),
|
||||
(width, std::cmp::min(self.rows, msg_lines.len() + 4)),
|
||||
false,
|
||||
false,
|
||||
);
|
||||
for row in self.overlay_grid.bounds_iter(displ_area) {
|
||||
for c in row {
|
||||
self.overlay_grid[c]
|
||||
.set_ch(' ')
|
||||
.set_fg(noto_colors.fg)
|
||||
.set_bg(noto_colors.bg)
|
||||
.set_attrs(noto_colors.attrs);
|
||||
}
|
||||
}
|
||||
let ((x, mut y), box_displ_area_bottom_right) =
|
||||
create_box(&mut self.overlay_grid, displ_area);
|
||||
for line in msg_lines
|
||||
.into_iter()
|
||||
.chain(Some(String::new()))
|
||||
.chain(Some(melib::datetime::timestamp_to_string(*timestamp, None)))
|
||||
{
|
||||
write_string_to_grid(
|
||||
&line,
|
||||
&mut self.overlay_grid,
|
||||
noto_colors.fg,
|
||||
noto_colors.bg,
|
||||
noto_colors.attrs,
|
||||
((x, y), box_displ_area_bottom_right),
|
||||
Some(x),
|
||||
);
|
||||
y += 1;
|
||||
}
|
||||
|
||||
if self.display_messages.len() > 1 {
|
||||
write_string_to_grid(
|
||||
if self.display_messages_pos == 0 {
|
||||
"Next: >"
|
||||
} else if self.display_messages_pos + 1 == self.display_messages.len() {
|
||||
"Prev: <"
|
||||
} else {
|
||||
"Prev: <, Next: >"
|
||||
},
|
||||
&mut self.overlay_grid,
|
||||
noto_colors.fg,
|
||||
noto_colors.bg,
|
||||
noto_colors.attrs,
|
||||
((x, y), box_displ_area_bottom_right),
|
||||
Some(x),
|
||||
);
|
||||
}
|
||||
for y in get_y(upper_left!(displ_area))..=get_y(bottom_right!(displ_area)) {
|
||||
(self.draw_horizontal_segment_fn)(
|
||||
&mut self.overlay_grid,
|
||||
self.stdout.as_mut().unwrap(),
|
||||
get_x(upper_left!(displ_area)),
|
||||
get_x(bottom_right!(displ_area)),
|
||||
y,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.flush();
|
||||
}
|
||||
|
||||
/// Draw only a specific `area` on the screen.
|
||||
fn draw_horizontal_segment(&mut self, x_start: usize, x_end: usize, y: usize) {
|
||||
fn draw_horizontal_segment(
|
||||
grid: &mut CellBuffer,
|
||||
stdout: &mut StateStdout,
|
||||
x_start: usize,
|
||||
x_end: usize,
|
||||
y: usize,
|
||||
) {
|
||||
write!(
|
||||
self.stdout(),
|
||||
stdout,
|
||||
"{}",
|
||||
cursor::Goto(x_start as u16 + 1, (y + 1) as u16)
|
||||
)
|
||||
|
@ -503,12 +621,6 @@ impl State {
|
|||
let mut current_fg = Color::Default;
|
||||
let mut current_bg = Color::Default;
|
||||
let mut current_attrs = Attr::Default;
|
||||
let Self {
|
||||
ref grid,
|
||||
ref mut stdout,
|
||||
..
|
||||
} = self;
|
||||
let stdout = stdout.as_mut().unwrap();
|
||||
write!(stdout, "\x1B[m").unwrap();
|
||||
for x in x_start..=x_end {
|
||||
let c = &grid[(x, y)];
|
||||
|
@ -530,20 +642,20 @@ impl State {
|
|||
}
|
||||
}
|
||||
|
||||
fn draw_horizontal_segment_no_color(&mut self, x_start: usize, x_end: usize, y: usize) {
|
||||
fn draw_horizontal_segment_no_color(
|
||||
grid: &mut CellBuffer,
|
||||
stdout: &mut StateStdout,
|
||||
x_start: usize,
|
||||
x_end: usize,
|
||||
y: usize,
|
||||
) {
|
||||
write!(
|
||||
self.stdout(),
|
||||
stdout,
|
||||
"{}",
|
||||
cursor::Goto(x_start as u16 + 1, (y + 1) as u16)
|
||||
)
|
||||
.unwrap();
|
||||
let mut current_attrs = Attr::Default;
|
||||
let Self {
|
||||
ref grid,
|
||||
ref mut stdout,
|
||||
..
|
||||
} = self;
|
||||
let stdout = stdout.as_mut().unwrap();
|
||||
write!(stdout, "\x1B[m").unwrap();
|
||||
for x in x_start..=x_end {
|
||||
let c = &grid[(x, y)];
|
||||
|
|
Loading…
Reference in New Issue