change: Refactor dd drawing code

This also slightly improves how we generate the widths/heights to be
less... terrible.

Note this is not done, unfortunately.  This requires tui-rs' wrapped
paragraph height PR to land and release so I can properly calculate the
height offsets.

See https://github.com/fdehau/tui-rs/pull/349 for details.
This commit is contained in:
ClementTsang 2020-08-12 00:27:02 -04:00
parent 60f4759494
commit 6e38d73116
4 changed files with 109 additions and 84 deletions

View File

@ -9,6 +9,7 @@
"Qudsi", "Qudsi",
"Tebibytes", "Tebibytes",
"Ungrouped", "Ungrouped",
"WASD",
"Wojnarowski", "Wojnarowski",
"andys", "andys",
"crossterm", "crossterm",

View File

@ -243,47 +243,74 @@ impl Painter {
self.draw_help_dialog(&mut f, app_state, middle_dialog_chunk[1]); self.draw_help_dialog(&mut f, app_state, middle_dialog_chunk[1]);
} else if app_state.delete_dialog_state.is_showing_dd { } else if app_state.delete_dialog_state.is_showing_dd {
let bordering = f.size().height.saturating_sub(7) / 2; // TODO: This needs the paragraph wrap feature from tui-rs to be pushed to complete... but for now it's pretty close!
// The main problem right now is that I cannot properly calculate the height offset since
// line-wrapping is NOT the same as taking the width of the text and dividing by width.
// So, I need the height AFTER wrapping.
// See: https://github.com/fdehau/tui-rs/pull/349. Land this after this pushes to release.
let dd_text = self.get_dd_spans(app_state);
let (text_width, text_height) = if let Some(dd_text) = &dd_text {
let width = if f.size().width < 100 {
f.size().width * 90 / 100
} else {
let min_possible_width = (f.size().width * 50 / 100) as usize;
let mut width = dd_text.width();
// This should theoretically never allow width to be 0... we can be safe and do an extra check though.
while width > (f.size().width as usize) && width / 2 > min_possible_width {
width /= 2;
}
std::cmp::max(width, min_possible_width) as u16
};
(
width,
(dd_text.height() + 2 + (dd_text.width() / width as usize)) as u16,
)
} else {
// AFAIK this shouldn't happen, unless something went wrong...
(
if f.size().width < 100 {
f.size().width * 90 / 100
} else {
f.size().width * 50 / 100
},
7,
)
};
let vertical_bordering = f.size().height.saturating_sub(text_height) / 2;
let vertical_dialog_chunk = Layout::default() let vertical_dialog_chunk = Layout::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.constraints( .constraints(
[ [
Constraint::Length(bordering), Constraint::Length(vertical_bordering),
Constraint::Length(7), Constraint::Length(text_height),
Constraint::Length(bordering), Constraint::Length(vertical_bordering),
] ]
.as_ref(), .as_ref(),
) )
.split(f.size()); .split(f.size());
let horizontal_bordering = f.size().width.saturating_sub(text_width) / 2;
let middle_dialog_chunk = Layout::default() let middle_dialog_chunk = Layout::default()
.direction(Direction::Horizontal) .direction(Direction::Horizontal)
.constraints( .constraints(
if f.size().width < 100 { [
// TODO: [REFACTOR] The point we start changing size at currently hard-coded in. Constraint::Length(horizontal_bordering),
[ Constraint::Length(text_width),
Constraint::Percentage(5), Constraint::Length(horizontal_bordering),
Constraint::Percentage(90), ]
Constraint::Percentage(5),
]
} else {
[
Constraint::Percentage(30),
Constraint::Percentage(40),
Constraint::Percentage(30),
]
}
.as_ref(), .as_ref(),
) )
.split(vertical_dialog_chunk[1]); .split(vertical_dialog_chunk[1]);
if let Some(dd_err) = &app_state.dd_err { // This is a bit nasty, but it works well... I guess.
self.draw_dd_error_dialog(&mut f, dd_err, middle_dialog_chunk[1]); app_state.delete_dialog_state.is_showing_dd =
} else { self.draw_dd_dialog(&mut f, dd_text, app_state, middle_dialog_chunk[1]);
// This is a bit nasty, but it works well... I guess.
app_state.delete_dialog_state.is_showing_dd =
self.draw_dd_dialog(&mut f, app_state, middle_dialog_chunk[1]);
}
} else if app_state.is_expanded { } else if app_state.is_expanded {
let rect = Layout::default() let rect = Layout::default()
.margin(0) .margin(0)

View File

@ -12,20 +12,23 @@ const DD_BASE: &str = " Confirm Kill Process ── Esc to close ";
const DD_ERROR_BASE: &str = " Error ── Esc to close "; const DD_ERROR_BASE: &str = " Error ── Esc to close ";
pub trait KillDialog { pub trait KillDialog {
fn draw_dd_dialog<B: Backend>( fn get_dd_spans(&self, app_state: &App) -> Option<Text<'_>>;
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect,
) -> bool;
fn draw_dd_error_dialog<B: Backend>(&self, f: &mut Frame<'_, B>, dd_err: &str, draw_loc: Rect); fn draw_dd_dialog<B: Backend>(
&self, f: &mut Frame<'_, B>, dd_text: Option<Text<'_>>, app_state: &App, draw_loc: Rect,
) -> bool;
} }
impl KillDialog for Painter { impl KillDialog for Painter {
fn draw_dd_dialog<B: Backend>( fn get_dd_spans(&self, app_state: &App) -> Option<Text<'_>> {
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, if let Some(dd_err) = &app_state.dd_err {
) -> bool { return Some(Text::from(Spans::from(format!(
if let Some(to_kill_processes) = app_state.get_to_delete_processes() { "\nFailure to properly kill the process - {}",
dd_err
))));
} else if let Some(to_kill_processes) = app_state.get_to_delete_processes() {
if let Some(first_pid) = to_kill_processes.1.first() { if let Some(first_pid) = to_kill_processes.1.first() {
let dd_text = Text::from(vec![ return Some(Text::from(vec![
Spans::from(vec![]), Spans::from(vec![]),
Spans::from(vec![ Spans::from(vec![
if app_state.is_grouped(app_state.current_widget.widget_id) { if app_state.is_grouped(app_state.current_widget.widget_id) {
@ -62,9 +65,31 @@ impl KillDialog for Painter {
Span::styled("No", self.colours.currently_selected_text_style) Span::styled("No", self.colours.currently_selected_text_style)
}, },
]), ]),
]); Spans::from(vec![]),
]));
}
}
let dd_title = Span::styled( None
}
fn draw_dd_dialog<B: Backend>(
&self, f: &mut Frame<'_, B>, dd_text: Option<Text<'_>>, app_state: &App, draw_loc: Rect,
) -> bool {
if let Some(dd_text) = dd_text {
let dd_title = if app_state.dd_err.is_some() {
Span::styled(
format!(
" Error ─{}─ Esc to close ",
"".repeat(
usize::from(draw_loc.width)
.saturating_sub(DD_ERROR_BASE.chars().count() + 2)
)
),
self.colours.border_style,
)
} else {
Span::styled(
format!( format!(
" Confirm Kill Process ─{}─ Esc to close ", " Confirm Kill Process ─{}─ Esc to close ",
"".repeat( "".repeat(
@ -72,23 +97,27 @@ impl KillDialog for Painter {
) )
), ),
self.colours.border_style, self.colours.border_style,
); )
};
f.render_widget( f.render_widget(
Paragraph::new(dd_text) Paragraph::new(dd_text)
.block( .block(
Block::default() Block::default()
.title(dd_title) .title(dd_title)
.style(self.colours.border_style) .style(self.colours.border_style)
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(self.colours.border_style), .border_style(self.colours.border_style),
) )
.style(self.colours.text_style) .style(self.colours.text_style)
.alignment(Alignment::Center) .alignment(Alignment::Center)
.wrap(Wrap { trim: true }), .wrap(Wrap { trim: true }),
draw_loc, draw_loc,
); );
if app_state.dd_err.is_some() {
return app_state.delete_dialog_state.is_showing_dd;
} else {
return true; return true;
} }
} }
@ -98,36 +127,4 @@ impl KillDialog for Painter {
// I don't really like this, and I find it ugly, but it works for now. // I don't really like this, and I find it ugly, but it works for now.
false false
} }
fn draw_dd_error_dialog<B: Backend>(&self, f: &mut Frame<'_, B>, dd_err: &str, draw_loc: Rect) {
let dd_text = Span::from(format!(
"\nFailure to properly kill the process - {}",
dd_err
));
let error_title = Span::styled(
format!(
" Error ─{}─ Esc to close ",
"".repeat(
usize::from(draw_loc.width).saturating_sub(DD_ERROR_BASE.chars().count() + 2)
)
),
self.colours.border_style,
);
f.render_widget(
Paragraph::new(dd_text)
.block(
Block::default()
.title(error_title)
.style(self.colours.border_style)
.borders(Borders::ALL)
.border_style(self.colours.border_style),
)
.style(self.colours.text_style)
.alignment(Alignment::Center)
.wrap(Wrap { trim: true }),
draw_loc,
);
}
} }

View File

@ -151,7 +151,7 @@ impl ProcessTableWidget for Painter {
let wps = "W/s".to_string(); let wps = "W/s".to_string();
let total_read = "Read".to_string(); let total_read = "Read".to_string();
let total_write = "Write".to_string(); let total_write = "Write".to_string();
let process_state = "State".to_string(); let process_state = "State ".to_string();
let direction_val = if proc_widget_state.process_sorting_reverse { let direction_val = if proc_widget_state.process_sorting_reverse {
"".to_string() "".to_string()