mirror of
https://github.com/ClementTsang/bottom.git
synced 2025-07-25 22:55:06 +02:00
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:
parent
60f4759494
commit
6e38d73116
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -9,6 +9,7 @@
|
|||||||
"Qudsi",
|
"Qudsi",
|
||||||
"Tebibytes",
|
"Tebibytes",
|
||||||
"Ungrouped",
|
"Ungrouped",
|
||||||
|
"WASD",
|
||||||
"Wojnarowski",
|
"Wojnarowski",
|
||||||
"andys",
|
"andys",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user