diff --git a/.vscode/settings.json b/.vscode/settings.json index 610580f6..eb755c66 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,7 @@ "Qudsi", "Tebibytes", "Ungrouped", + "WASD", "Wojnarowski", "andys", "crossterm", diff --git a/src/canvas.rs b/src/canvas.rs index cb6dc819..e44f0ac0 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -243,47 +243,74 @@ impl Painter { self.draw_help_dialog(&mut f, app_state, middle_dialog_chunk[1]); } 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() .direction(Direction::Vertical) .constraints( [ - Constraint::Length(bordering), - Constraint::Length(7), - Constraint::Length(bordering), + Constraint::Length(vertical_bordering), + Constraint::Length(text_height), + Constraint::Length(vertical_bordering), ] .as_ref(), ) .split(f.size()); + let horizontal_bordering = f.size().width.saturating_sub(text_width) / 2; let middle_dialog_chunk = Layout::default() .direction(Direction::Horizontal) .constraints( - if f.size().width < 100 { - // TODO: [REFACTOR] The point we start changing size at currently hard-coded in. - [ - Constraint::Percentage(5), - Constraint::Percentage(90), - Constraint::Percentage(5), - ] - } else { - [ - Constraint::Percentage(30), - Constraint::Percentage(40), - Constraint::Percentage(30), - ] - } + [ + Constraint::Length(horizontal_bordering), + Constraint::Length(text_width), + Constraint::Length(horizontal_bordering), + ] .as_ref(), ) .split(vertical_dialog_chunk[1]); - if let Some(dd_err) = &app_state.dd_err { - self.draw_dd_error_dialog(&mut f, dd_err, middle_dialog_chunk[1]); - } else { - // 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]); - } + // 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, dd_text, app_state, middle_dialog_chunk[1]); } else if app_state.is_expanded { let rect = Layout::default() .margin(0) diff --git a/src/canvas/dialogs/dd_dialog.rs b/src/canvas/dialogs/dd_dialog.rs index 8a63a6e6..17c3371a 100644 --- a/src/canvas/dialogs/dd_dialog.rs +++ b/src/canvas/dialogs/dd_dialog.rs @@ -12,20 +12,23 @@ const DD_BASE: &str = " Confirm Kill Process ── Esc to close "; const DD_ERROR_BASE: &str = " Error ── Esc to close "; pub trait KillDialog { - fn draw_dd_dialog( - &self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, - ) -> bool; + fn get_dd_spans(&self, app_state: &App) -> Option>; - fn draw_dd_error_dialog(&self, f: &mut Frame<'_, B>, dd_err: &str, draw_loc: Rect); + fn draw_dd_dialog( + &self, f: &mut Frame<'_, B>, dd_text: Option>, app_state: &App, draw_loc: Rect, + ) -> bool; } impl KillDialog for Painter { - fn draw_dd_dialog( - &self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, - ) -> bool { - if let Some(to_kill_processes) = app_state.get_to_delete_processes() { + fn get_dd_spans(&self, app_state: &App) -> Option> { + if let Some(dd_err) = &app_state.dd_err { + return Some(Text::from(Spans::from(format!( + "\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() { - let dd_text = Text::from(vec![ + return Some(Text::from(vec![ Spans::from(vec![]), Spans::from(vec![ 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) }, ]), - ]); + Spans::from(vec![]), + ])); + } + } - let dd_title = Span::styled( + None + } + + fn draw_dd_dialog( + &self, f: &mut Frame<'_, B>, dd_text: Option>, 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!( " Confirm Kill Process ─{}─ Esc to close ", "─".repeat( @@ -72,23 +97,27 @@ impl KillDialog for Painter { ) ), self.colours.border_style, - ); + ) + }; - f.render_widget( - Paragraph::new(dd_text) - .block( - Block::default() - .title(dd_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, - ); + f.render_widget( + Paragraph::new(dd_text) + .block( + Block::default() + .title(dd_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, + ); + if app_state.dd_err.is_some() { + return app_state.delete_dialog_state.is_showing_dd; + } else { 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. false } - - fn draw_dd_error_dialog(&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, - ); - } } diff --git a/src/canvas/widgets/process_table.rs b/src/canvas/widgets/process_table.rs index 3faab2ba..2f041a16 100644 --- a/src/canvas/widgets/process_table.rs +++ b/src/canvas/widgets/process_table.rs @@ -151,7 +151,7 @@ impl ProcessTableWidget for Painter { let wps = "W/s".to_string(); let total_read = "Read".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 { "▼".to_string()