Browse Source

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 1 year ago
parent
commit
393c5d0d53
Signed by: epilys GPG Key ID: 73627C2F690DF710
  1. 190
      src/state.rs

190
src/state.rs

@ -190,7 +190,10 @@ pub struct State {
display_messages: SmallVec<[DisplayMessage; 8]>,
display_messages_expiration_start: Option<UnixTimestamp>,
display_messages_active: bool,
display_messages_dirty: bool,
display_messages_initialised: bool,
display_messages_pos: usize,
display_messages_area: Area,
}
#[derive(Debug)]
@ -335,7 +338,9 @@ impl State {
display_messages_expiration_start: None,
display_messages_pos: 0,
display_messages_active: false,
display_messages_dirty: false,
display_messages_initialised: false,
display_messages_area: ((0, 0), (0, 0)),
context: Context {
accounts,
settings: settings.clone(),
@ -522,6 +527,9 @@ impl State {
.resize(self.cols, self.rows, Cell::with_char(' '));
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.
self.context.dirty_areas.clear();
@ -546,6 +554,8 @@ impl State {
.unwrap_or(false)
{
self.display_messages_active = false;
self.display_messages_dirty = true;
self.display_messages_initialised = false;
self.display_messages_expiration_start = None;
areas.push((
(0, 0),
@ -556,6 +566,18 @@ impl State {
/* 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());
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 */
let rows = self.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 {
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);
if !self.display_messages_initialised {
{
/* 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,
);
}
}
}
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),
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,
);
y += 1;
}
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),
);
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)(
&mut self.overlay_grid,
self.stdout.as_mut().unwrap(),
get_x(upper_left!(displ_area)),
get_x(bottom_right!(displ_area)),
get_x(upper_left!(self.display_messages_area)),
get_x(bottom_right!(self.display_messages_area)),
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() {
let area = center_area(
@ -1092,12 +1146,16 @@ impl State {
UIEvent::Input(Key::Alt('<')) => {
self.display_messages_expiration_start = Some(melib::datetime::now());
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);
return;
}
UIEvent::Input(Key::Alt('>')) => {
self.display_messages_expiration_start = Some(melib::datetime::now());
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.len().saturating_sub(1),
self.display_messages_pos + 1,
@ -1110,6 +1168,8 @@ impl State {
msg: msg.clone(),
});
self.display_messages_active = true;
self.display_messages_initialised = false;
self.display_messages_dirty = true;
self.display_messages_expiration_start = None;
self.display_messages_pos = self.display_messages.len() - 1;
self.redraw();

Loading…
Cancel
Save