state: cull redraws of floating notifications

Cull redraws by keeping track of whether the floating box has been
initialised and whether its area has been drawn over by other dirty areas.
jmap-eventsource
Manos Pitsidianakis 2020-10-15 21:28:28 +03:00
parent 4c1a9b2485
commit 393c5d0d53
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
1 changed files with 125 additions and 65 deletions

View File

@ -190,7 +190,10 @@ pub struct State {
display_messages: SmallVec<[DisplayMessage; 8]>, display_messages: SmallVec<[DisplayMessage; 8]>,
display_messages_expiration_start: Option<UnixTimestamp>, display_messages_expiration_start: Option<UnixTimestamp>,
display_messages_active: bool, display_messages_active: bool,
display_messages_dirty: bool,
display_messages_initialised: bool,
display_messages_pos: usize, display_messages_pos: usize,
display_messages_area: Area,
} }
#[derive(Debug)] #[derive(Debug)]
@ -335,7 +338,9 @@ impl State {
display_messages_expiration_start: None, display_messages_expiration_start: None,
display_messages_pos: 0, display_messages_pos: 0,
display_messages_active: false, display_messages_active: false,
display_messages_dirty: false,
display_messages_initialised: false,
display_messages_area: ((0, 0), (0, 0)),
context: Context { context: Context {
accounts, accounts,
settings: settings.clone(), settings: settings.clone(),
@ -522,6 +527,9 @@ impl State {
.resize(self.cols, self.rows, Cell::with_char(' ')); .resize(self.cols, self.rows, Cell::with_char(' '));
self.rcv_event(UIEvent::Resize); self.rcv_event(UIEvent::Resize);
self.display_messages_dirty = true;
self.display_messages_initialised = false;
self.display_messages_area = ((0, 0), (0, 0));
// Invalidate dirty areas. // Invalidate dirty areas.
self.context.dirty_areas.clear(); self.context.dirty_areas.clear();
@ -546,6 +554,8 @@ impl State {
.unwrap_or(false) .unwrap_or(false)
{ {
self.display_messages_active = false; self.display_messages_active = false;
self.display_messages_dirty = true;
self.display_messages_initialised = false;
self.display_messages_expiration_start = None; self.display_messages_expiration_start = None;
areas.push(( areas.push((
(0, 0), (0, 0),
@ -556,6 +566,18 @@ impl State {
/* Sort by x_start, ie upper_left corner's x coordinate */ /* Sort by x_start, ie upper_left corner's x coordinate */
areas.sort_by(|a, b| (a.0).0.partial_cmp(&(b.0).0).unwrap()); areas.sort_by(|a, b| (a.0).0.partial_cmp(&(b.0).0).unwrap());
if self.display_messages_active {
/* Check if any dirty area intersects with the area occupied by floating notification
* box */
let (displ_top, displ_bot) = self.display_messages_area;
for &((top_x, top_y), (bottom_x, bottom_y)) in &areas {
self.display_messages_dirty |= !(bottom_y < displ_top.1
|| displ_bot.1 < top_y
|| bottom_x < displ_top.0
|| displ_bot.0 < top_x);
}
}
/* draw each dirty area */ /* draw each dirty area */
let rows = self.rows; let rows = self.rows;
for y in 0..rows { for y in 0..rows {
@ -613,87 +635,119 @@ impl State {
} }
} }
if self.display_messages_active { if self.display_messages_dirty && self.display_messages_active {
if let Some(DisplayMessage { if let Some(DisplayMessage {
ref timestamp, ref timestamp,
ref msg, ref msg,
.. ..
}) = self.display_messages.get(self.display_messages_pos) }) = self.display_messages.get(self.display_messages_pos)
{ {
let noto_colors = crate::conf::value(&self.context, "status.notification"); if !self.display_messages_initialised {
use crate::melib::text_processing::{Reflow, TextProcessing}; {
/* Clear area previously occupied by floating notification box */
let msg_lines = msg.split_lines_reflow(Reflow::All, Some(self.cols / 3)); let displ_area = self.display_messages_area;
let width = msg_lines for y in get_y(upper_left!(displ_area))..=get_y(bottom_right!(displ_area)) {
.iter() (self.draw_horizontal_segment_fn)(
.map(|line| line.grapheme_len() + 4) &mut self.grid,
.max() self.stdout.as_mut().unwrap(),
.unwrap_or(0); get_x(upper_left!(displ_area)),
get_x(bottom_right!(displ_area)),
let displ_area = place_in_area( y,
( );
(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 noto_colors = crate::conf::value(&self.context, "status.notification");
let ((x, mut y), box_displ_area_bottom_right) = use crate::melib::text_processing::{Reflow, TextProcessing};
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 { let msg_lines = msg.split_lines_reflow(Reflow::All, Some(self.cols / 3));
write_string_to_grid( let width = msg_lines
if self.display_messages_pos == 0 { .iter()
"Next: >" .map(|line| line.grapheme_len() + 4)
} else if self.display_messages_pos + 1 == self.display_messages.len() { .max()
"Prev: <" .unwrap_or(0);
} else {
"Prev: <, Next: >" let displ_area = place_in_area(
}, (
&mut self.overlay_grid, (0, 0),
noto_colors.fg, (self.cols.saturating_sub(1), self.rows.saturating_sub(1)),
noto_colors.bg, ),
noto_colors.attrs, (width, std::cmp::min(self.rows, msg_lines.len() + 4)),
((x, y), box_displ_area_bottom_right), false,
Some(x), 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),
);
}
self.display_messages_area = displ_area;
} }
for y in get_y(upper_left!(displ_area))..=get_y(bottom_right!(displ_area)) { for y in get_y(upper_left!(self.display_messages_area))
..=get_y(bottom_right!(self.display_messages_area))
{
(self.draw_horizontal_segment_fn)( (self.draw_horizontal_segment_fn)(
&mut self.overlay_grid, &mut self.overlay_grid,
self.stdout.as_mut().unwrap(), self.stdout.as_mut().unwrap(),
get_x(upper_left!(displ_area)), get_x(upper_left!(self.display_messages_area)),
get_x(bottom_right!(displ_area)), get_x(bottom_right!(self.display_messages_area)),
y, y,
); );
} }
} }
self.display_messages_dirty = false;
} else if self.display_messages_dirty {
/* Clear area previously occupied by floating notification box */
let displ_area = self.display_messages_area;
for y in get_y(upper_left!(displ_area))..=get_y(bottom_right!(displ_area)) {
(self.draw_horizontal_segment_fn)(
&mut self.grid,
self.stdout.as_mut().unwrap(),
get_x(upper_left!(displ_area)),
get_x(bottom_right!(displ_area)),
y,
);
}
self.display_messages_dirty = false;
} }
if !self.overlay.is_empty() { if !self.overlay.is_empty() {
let area = center_area( let area = center_area(
@ -1092,12 +1146,16 @@ impl State {
UIEvent::Input(Key::Alt('<')) => { UIEvent::Input(Key::Alt('<')) => {
self.display_messages_expiration_start = Some(melib::datetime::now()); self.display_messages_expiration_start = Some(melib::datetime::now());
self.display_messages_active = true; self.display_messages_active = true;
self.display_messages_initialised = false;
self.display_messages_dirty = true;
self.display_messages_pos = self.display_messages_pos.saturating_sub(1); self.display_messages_pos = self.display_messages_pos.saturating_sub(1);
return; return;
} }
UIEvent::Input(Key::Alt('>')) => { UIEvent::Input(Key::Alt('>')) => {
self.display_messages_expiration_start = Some(melib::datetime::now()); self.display_messages_expiration_start = Some(melib::datetime::now());
self.display_messages_active = true; self.display_messages_active = true;
self.display_messages_initialised = false;
self.display_messages_dirty = true;
self.display_messages_pos = std::cmp::min( self.display_messages_pos = std::cmp::min(
self.display_messages.len().saturating_sub(1), self.display_messages.len().saturating_sub(1),
self.display_messages_pos + 1, self.display_messages_pos + 1,
@ -1110,6 +1168,8 @@ impl State {
msg: msg.clone(), msg: msg.clone(),
}); });
self.display_messages_active = true; self.display_messages_active = true;
self.display_messages_initialised = false;
self.display_messages_dirty = true;
self.display_messages_expiration_start = None; self.display_messages_expiration_start = None;
self.display_messages_pos = self.display_messages.len() - 1; self.display_messages_pos = self.display_messages.len() - 1;
self.redraw(); self.redraw();