summaryrefslogtreecommitdiffstats
path: root/src/canvas.rs
diff options
context:
space:
mode:
authorClementTsang <cjhtsang@uwaterloo.ca>2020-03-07 23:47:53 -0500
committerClementTsang <cjhtsang@uwaterloo.ca>2020-03-07 23:47:53 -0500
commit03ec52c5b16d8968e14e1a648bd2ef4b9489380e (patch)
tree2de0ee608bbf72255be03b3fab35f87ab14fd11a /src/canvas.rs
parent132a5a2170294f0d5c463ecba77de1aab32183db (diff)
Split up widgets to make it a bit easier to work with.
Diffstat (limited to 'src/canvas.rs')
-rw-r--r--src/canvas.rs1394
1 files changed, 4 insertions, 1390 deletions
diff --git a/src/canvas.rs b/src/canvas.rs
index 8c0c9545..aa7e8478 100644
--- a/src/canvas.rs
+++ b/src/canvas.rs
@@ -1,19 +1,16 @@
-use std::cmp::{max, min};
+use std::cmp::max;
use std::collections::HashMap;
use tui::{
backend::Backend,
layout::{Alignment, Constraint, Direction, Layout, Rect},
- style::{Color, Style},
terminal::Frame,
- widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Paragraph, Row, Table, Text, Widget},
+ widgets::{Block, Borders, Paragraph, Text, Widget},
Terminal,
};
-use unicode_segmentation::UnicodeSegmentation;
-use unicode_width::UnicodeWidthStr;
use canvas_colours::*;
-use drawing_utils::*;
+use widgets::*;
use crate::{
app::{self, data_harvester::processes::ProcessHarvest, WidgetPosition},
@@ -24,45 +21,7 @@ use crate::{
mod canvas_colours;
mod drawing_utils;
-
-// Headers
-const CPU_LEGEND_HEADER: [&str; 2] = ["CPU", "Use%"];
-const CPU_SELECT_LEGEND_HEADER: [&str; 2] = ["CPU", "Show (Space)"];
-const DISK_HEADERS: [&str; 7] = ["Disk", "Mount", "Used", "Free", "Total", "R/s", "W/s"];
-const TEMP_HEADERS: [&str; 2] = ["Sensor", "Temp"];
-const MEM_HEADERS: [&str; 3] = ["Mem", "Usage", "Use%"];
-const NETWORK_HEADERS: [&str; 4] = ["RX", "TX", "Total RX", "Total TX"];
-const FORCE_MIN_THRESHOLD: usize = 5;
-
-lazy_static! {
- static ref SIDE_BORDERS: Borders = Borders::from_bits_truncate(20);
- static ref DEFAULT_TEXT_STYLE: Style = Style::default().fg(Color::Gray);
- static ref DEFAULT_HEADER_STYLE: Style = Style::default().fg(Color::LightBlue);
- static ref DISK_HEADERS_LENS: Vec<usize> = DISK_HEADERS
- .iter()
- .map(|entry| max(FORCE_MIN_THRESHOLD, entry.len()))
- .collect::<Vec<_>>();
- static ref CPU_LEGEND_HEADER_LENS: Vec<usize> = CPU_LEGEND_HEADER
- .iter()
- .map(|entry| max(FORCE_MIN_THRESHOLD, entry.len()))
- .collect::<Vec<_>>();
- static ref CPU_SELECT_LEGEND_HEADER_LENS: Vec<usize> = CPU_SELECT_LEGEND_HEADER
- .iter()
- .map(|entry| max(FORCE_MIN_THRESHOLD, entry.len()))
- .collect::<Vec<_>>();
- static ref TEMP_HEADERS_LENS: Vec<usize> = TEMP_HEADERS
- .iter()
- .map(|entry| max(FORCE_MIN_THRESHOLD, entry.len()))
- .collect::<Vec<_>>();
- static ref MEM_HEADERS_LENS: Vec<usize> = MEM_HEADERS
- .iter()
- .map(|entry| max(FORCE_MIN_THRESHOLD, entry.len()))
- .collect::<Vec<_>>();
- static ref NETWORK_HEADERS_LENS: Vec<usize> = NETWORK_HEADERS
- .iter()
- .map(|entry| max(FORCE_MIN_THRESHOLD, entry.len()))
- .collect::<Vec<_>>();
-}
+mod widgets;
#[derive(Default)]
pub struct DisplayableData {
@@ -585,1349 +544,4 @@ impl Painter {
Ok(())
}
-
- fn draw_process_and_search<B: Backend>(
- &self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, draw_border: bool,
- ) {
- let search_width = if draw_border { 5 } else { 3 };
-
- if app_state.is_searching() {
- let processes_chunk = Layout::default()
- .direction(Direction::Vertical)
- .constraints([Constraint::Min(0), Constraint::Length(search_width)].as_ref())
- .split(draw_loc);
-
- self.draw_processes_table(f, app_state, processes_chunk[0], draw_border);
- self.draw_search_field(f, app_state, processes_chunk[1], draw_border);
- } else {
- self.draw_processes_table(f, app_state, draw_loc, draw_border);
- }
- }
-
- fn draw_cpu_graph<B: Backend>(
- &self, f: &mut Frame<'_, B>, app_state: &app::App, draw_loc: Rect,
- ) {
- let cpu_data: &[ConvertedCpuData] = &app_state.canvas_data.cpu_data;
-
- // CPU usage graph
- let x_axis: Axis<'_, String> = Axis::default().bounds([0.0, TIME_STARTS_FROM as f64]);
- let y_axis = Axis::default()
- .style(self.colours.graph_style)
- .labels_style(self.colours.graph_style)
- .bounds([-0.5, 100.5])
- .labels(&["0%", "100%"]);
-
- let dataset_vector: Vec<Dataset<'_>> = cpu_data
- .iter()
- .enumerate()
- .rev()
- .filter_map(|(itx, cpu)| {
- if app_state.cpu_state.core_show_vec[itx] {
- Some(
- Dataset::default()
- .marker(if app_state.app_config_fields.use_dot {
- Marker::Dot
- } else {
- Marker::Braille
- })
- .style(
- if app_state.app_config_fields.show_average_cpu && itx == 0 {
- self.colours.avg_colour_style
- } else {
- self.colours.cpu_colour_styles
- [itx % self.colours.cpu_colour_styles.len()]
- },
- )
- .data(&cpu.cpu_data[..]),
- )
- } else {
- None
- }
- })
- .collect();
-
- let title = if app_state.is_expanded && !app_state.cpu_state.is_showing_tray {
- const TITLE_BASE: &str = " CPU ── Esc to go back ";
- let repeat_num = max(
- 0,
- draw_loc.width as i32 - TITLE_BASE.chars().count() as i32 - 2,
- );
- let result_title =
- format!(" CPU ─{}─ Esc to go back ", "─".repeat(repeat_num as usize));
-
- result_title
- } else {
- " CPU ".to_string()
- };
-
- Chart::default()
- .block(
- Block::default()
- .title(&title)
- .title_style(if app_state.is_expanded {
- self.colours.highlighted_border_style
- } else {
- self.colours.widget_title_style
- })
- .borders(Borders::ALL)
- .border_style(match app_state.current_widget_selected {
- WidgetPosition::Cpu | WidgetPosition::BasicCpu => {
- self.colours.highlighted_border_style
- }
- _ => self.colours.border_style,
- }),
- )
- .x_axis(x_axis)
- .y_axis(y_axis)
- .datasets(&dataset_vector)
- .render(f, draw_loc);
- }
-
- fn draw_cpu_legend<B: Backend>(
- &self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect,
- ) {
- let cpu_data: &[ConvertedCpuData] = &app_state.canvas_data.cpu_data;
-
- let num_rows = max(0, i64::from(draw_loc.height) - 5) as u64;
- let start_position = get_start_position(
- num_rows,
- &app_state.app_scroll_positions.scroll_direction,
- &mut app_state
- .app_scroll_positions
- .cpu_scroll_state
- .previous_scroll_position,
- app_state
- .app_scroll_positions
- .cpu_scroll_state
- .current_scroll_position,
- app_state.is_resized,
- );
-
- let sliced_cpu_data = &cpu_data[start_position as usize..];
- let mut stringified_cpu_data: Vec<Vec<String>> = Vec::new();
-
- for (itx, cpu) in sliced_cpu_data.iter().enumerate() {
- if app_state.cpu_state.is_showing_tray {
- stringified_cpu_data.push(vec![
- cpu.cpu_name.clone(),
- if app_state.cpu_state.core_show_vec[itx + start_position as usize] {
- "[*]".to_string()
- } else {
- "[ ]".to_string()
- },
- ]);
- } else if let Some(cpu_data) = cpu.cpu_data.last() {
- if app_state.app_config_fields.show_disabled_data
- || app_state.cpu_state.core_show_vec[itx]
- {
- stringified_cpu_data.push(vec![
- cpu.cpu_name.clone(),
- format!("{:.0}%", cpu_data.1.round()),
- ]);
- }
- }
- }
-
- let cpu_rows = stringified_cpu_data
- .iter()
- .enumerate()
- .map(|(itx, cpu_string_row)| {
- Row::StyledData(
- cpu_string_row.iter(),
- match app_state.current_widget_selected {
- WidgetPosition::Cpu => {
- if itx as u64
- == app_state
- .app_scroll_positions
- .cpu_scroll_state
- .current_scroll_position
- - start_position
- {
- self.colours.currently_selected_text_style
- } else if app_state.app_config_fields.show_average_cpu && itx == 0 {
- self.colours.avg_colour_style
- } else {
- self.colours.cpu_colour_styles[itx
- + start_position as usize
- % self.colours.cpu_colour_styles.len()]
- }
- }
- _ => {
- if app_state.app_config_fields.show_average_cpu && itx == 0 {
- self.colours.avg_colour_style
- } else {
- self.colours.cpu_colour_styles[itx
- + start_position as usize
- % self.colours.cpu_colour_styles.len()]
- }
- }
- },
- )
- });
-
- // Calculate widths
- let width = f64::from(draw_loc.width);
- let width_ratios = vec![0.5, 0.5];
-
- let variable_intrinsic_results = get_variable_intrinsic_widths(
- width as u16,
- &width_ratios,
- if app_state.cpu_state.is_showing_tray {
- &CPU_SELECT_LEGEND_HEADER_LENS
- } else {
- &CPU_LEGEND_HEADER_LENS
- },
- );
- let intrinsic_widths = &(variable_intrinsic_results.0)[0..variable_intrinsic_results.1];
-
- let title = if app_state.cpu_state.is_showing_tray {
- const TITLE_BASE: &str = " Esc to close ";
- let repeat_num = max(
- 0,
- draw_loc.width as i32 - TITLE_BASE.chars().count() as i32 - 2,
- );
- let result_title = format!("{} Esc to close ", "─".repeat(repeat_num as usize));
-
- result_title
- } else {
- "".to_string()
- };
-
- // Draw
- Table::new(
- if app_state.cpu_state.is_showing_tray {
- CPU_SELECT_LEGEND_HEADER
- } else {
- CPU_LEGEND_HEADER
- }
- .iter(),
- cpu_rows,
- )
- .block(
- Block::default()
- .title(&title)
- .title_style(if app_state.is_expanded {
- self.colours.highlighted_border_style
- } else {
- match app_state.current_widget_selected {
- WidgetPosition::Cpu => self.colours.highlighted_border_style,
- _ => self.colours.border_style,
- }
- })
- .borders(Borders::ALL)
- .border_style(match app_state.current_widget_selected {
- WidgetPosition::Cpu => self.colours.highlighted_border_style,
- _ => self.colours.border_style,
- }),
- )
- .header_style(self.colours.table_header_style)
- .widths(
- &(intrinsic_widths
- .iter()
- .map(|calculated_width| Constraint::Length(*calculated_width as u16))
- .collect::<Vec<_>>()),
- )
- .render(f, draw_loc);
- }
-
- fn draw_memory_graph<B: Backend>(
- &self, f: &mut Frame<'_, B>, app_state: &app::App, draw_loc: Rect,
- ) {
- let mem_data: &[(f64, f64)] = &app_state.canvas_data.mem_data;
- let swap_data: &[(f64, f64)] = &app_state.canvas_data.swap_data;
-
- let x_axis: Axis<'_, String> = Axis::default().bounds([0.0, TIME_STARTS_FROM as f64]);
-
- // Offset as the zero value isn't drawn otherwise...
- let y_axis: Axis<'_, &str> = Axis::default()
- .style(self.colours.graph_style)
- .labels_style(self.colours.graph_style)
- .bounds([-0.5, 100.5])
- .labels(&["0%", "100%"]);
-
- let mem_canvas_vec: Vec<Dataset<'_>> = vec![
- Dataset::default()
- .name(&app_state.canvas_data.mem_label)
- .marker(if app_state.app_config_fields.use_dot {
- Marker::Dot
- } else {
- Marker::Braille
- })
- .style(self.colours.ram_style)
- .data(&mem_data),
- Dataset::default()
- .name(&app_state.canvas_data.swap_label)
- .marker(if app_state.app_config_fields.use_dot {
- Marker::Dot
- } else {
- Marker::Braille
- })
- .style(self.colours.swap_style)
- .data(&swap_data),
- ];
-
- let title = if app_state.is_expanded {
- const TITLE_BASE: &str = " Memory ── Esc to go back ";
- let repeat_num = max(
- 0,
- draw_loc.width as i32 - TITLE_BASE.chars().count() as i32 - 2,
- );
- let result_title = format!(
- " Memory ─{}─ Esc to go back ",
- "─".repeat(repeat_num as usize)
- );
-
- result_title
- } else {
- " Memory ".to_string()
- };
-
- Chart::default()
- .block(
- Block::default()
- .title(&title)
- .title_style(if app_state.is_expanded {
- self.colours.highlighted_border_style
- } else {
- self.colours.widget_title_style
- })
- .borders(Borders::ALL)
- .border_style(match app_state.current_widget_selected {
- WidgetPosition::Mem | WidgetPosition::BasicMem => {
- self.colours.highlighted_border_style
- }
- _ => self.colours.border_style,
- }),
- )
- .x_axis(x_axis)
- .y_axis(y_axis)
- .datasets(&mem_canvas_vec)
- .render(f, draw_loc);
- }
-
- fn draw_network_graph<B: Backend>(
- &self, f: &mut Frame<'_, B>, app_state: &app::App, draw_loc: Rect,
- ) {
- let network_data_rx: &[(f64, f64)] = &app_state.canvas_data.network_data_rx;
- let network_data_tx: &[(f64, f64)] = &app_state.canvas_data.network_data_tx;
-
- let x_axis: Axis<'_, String> = Axis::default().bounds([0.0, 60_000.0]);
- let y_axis: Axis<'_, &str> = Axis::default()
- .style(self.colours.graph_style)
- .labels_style(self.colours.graph_style)
- .bounds([-0.5, 30_f64])
- .labels(&["0B", "1KiB", "1MiB", "1GiB"]);
-
- let title = if app_state.is_expanded {
- const TITLE_BASE: &str = " Network ── Esc to go back ";
- let repeat_num = max(
- 0,
- draw_loc.width as i32 - TITLE_BASE.chars().count() as i32 - 2,
- );
- let result_title = format!(
- " Network ─{}─ Esc to go back ",
- "─".repeat(repeat_num as usize)
- );
-
- result_title
- } else {
- " Network ".to_string()
- };
-
- Chart::default()
- .block(
- Block::default()
- .title(&title)
- .title_style(if app_state.is_expanded {
- self.colours.highlighted_border_style
- } else {
- self.colours.widget_title_style
- })
- .borders(Borders::ALL)
- .border_style(match app_state.current_widget_selected {
- WidgetPosition::Network | WidgetPosition::BasicNet => {
- self.colours.highlighted_border_style
- }
- _ => self.colours.border_style,
- }),
- )
- .x_axis(x_axis)
- .y_axis(y_axis)
- .datasets(&[
- Dataset::default()
- .name(&format!("RX: {:7}", app_state.canvas_data.rx_display))
- .marker(if app_state.app_config_fields.use_dot {
- Marker::Dot
- } else {
- Marker::Braille
- })
- .style(self.colours.rx_style)
- .data(&network_data_rx),
- Dataset::default()
- .name(&format!("TX: {:7}", app_state.canvas_data.tx_display))
- .marker(if app_state.app_config_fields.use_dot {
- Marker::Dot
- } else {
- Marker::Braille
- })
- .style(self.colours.tx_style)
- .data(&network_data_tx),
- Dataset::default()
- .name(&format!(
- "Total RX: {:7}",
- app_state.canvas_data.total_rx_display
- ))
- .style(self.colours.total_rx_style),
- Dataset::default()
- .name(&format!(
- "Total TX: {:7}",
- app_state.canvas_data.total_tx_display
- ))
- .style(self.colours.total_tx_style),
- ])
- .render(f, draw_loc);
- }
-
- fn draw_network_labels<B: Backend>(
- &self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect,
- ) {
- let rx_display = &app_state.canvas_data.rx_display;
- let tx_display = &app_state.canvas_data.tx_display;
- let total_rx_display = &app_state.canvas_data.total_rx_display;
- let total_tx_display = &app_state.canvas_data.total_tx_display;
-
- // Gross but I need it to work...
- let total_network = vec![vec![
- rx_display,
- tx_display,
- total_rx_display,
- total_tx_display,
- ]];
- let mapped_network = total_network
- .iter()
- .map(|val| Row::StyledData(val.iter(), self.colours.text_style));
-
- // Calculate widths
- let width_ratios: Vec<f64> = vec![0.25, 0.25, 0.25, 0.25];
- let lens: &[usize] = &NETWORK_HEADERS_LENS;
- let width = f64::from(draw_loc.width);
-
- let variable_intrinsic_results =
- get_variable_intrinsic_widths(width as u16, &width_ratios, lens);
- let intrinsic_widths = &(variable_intrinsic_results.0)[0..variable_intrinsic_results.1];
-
- // Draw
- Table::new(NETWORK_HEADERS.iter(), mapped_network)
- .block(Block::default().borders(Borders::ALL).border_style(
- match app_state.current_widget_selected {
- WidgetPosition::Network => self.colours.highlighted_border_style,
- _ => self.colours.border_style,
- },
- ))
- .header_style(self.colours.table_header_style)
- .style(self.colours.text_style)
- .widths(
- &(intrinsic_widths
- .iter()
- .map(|calculated_width| Constraint::Length(*calculated_width as u16))
- .collect::<Vec<_>>()),
- )
- .render(f, draw_loc);
- }
-
- fn draw_temp_table<B: Backend>(
- &self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, draw_border: bool,
- ) {
- let temp_sensor_data: &[Vec<String>] = &app_state.canvas_data.temp_sensor_data;
-
- let num_rows = max(0, i64::from(draw_loc.height) - 5) as u64;
- let start_position = get_start_position(
- num_rows,
- &app_state.app_scroll_positions.scroll_direction,
- &mut app_state
- .app_scroll_positions
- .temp_scroll_state
- .previous_scroll_position,
- app_state
- .app_scroll_positions
- .temp_scroll_state
- .current_scroll_position,
- app_state.is_resized,
- );
-
- let sliced_vec = &temp_sensor_data[start_position as usize..];
- let mut temp_row_counter: i64 = 0;
-
- let temperature_rows = sliced_vec.iter().map(|temp_row| {
- Row::StyledData(
- temp_row.iter(),
- match app_state.current_widget_selected {
- WidgetPosition::Temp => {
- if temp_row_counter as u64
- == app_state
- .app_scroll_positions
- .temp_scroll_state
- .current_scroll_position
- - start_position
- {
- temp_row_counter = -1;
- self.colours.currently_selected_text_style
- } else {
- if temp_row_counter >= 0 {
- temp_row_counter += 1;
- }
- self.colours.text_style
- }
- }
- _ => self.colours.text_style,
- },
- )
- });
-
- // Calculate widths
- let width = f64::from(draw_loc.width);
- let width_ratios = [0.5, 0.5];
- let variable_intrinsic_results =
- get_variable_intrinsic_widths(width as u16, &width_ratios, &TEMP_HEADERS_LENS);
- let intrinsic_widths = &(variable_intrinsic_results.0)[0..variable_intrinsic_results.1];
-
- let title = if app_state.is_expanded {
- const TITLE_BASE: &str = " Temperatures ── Esc to go back ";
- let repeat_num = max(
- 0,
- draw_loc.width as i32 - TITLE_BASE.chars().count() as i32 - 2,
- );
- let result_title = format!(
- " Temperatures ─{}─ Esc to go back ",
- "─".repeat(repeat_num as usize)
- );
-
- result_title
- } else if app_state.app_config_fields.use_basic_mode {
- String::new()
- } else {
- " Temperatures ".to_string()
- };
-
- let temp_block = if draw_border {
- Block::default()
- .title(&title)
- .title_style(if app_state.is_expanded {
- match app_state.current_widget_selected {
- WidgetPosition::Temp => self.colours.highlighted_border_style,
- _ => self.colours.border_style,
- }
- } else {
- self.colours.widget_title_style
- })
- .borders(Borders::ALL)
- .border_style(match app_state.current_widget_selected {
- WidgetPosition::Temp => self.colours.highlighted_border_style,
- _ => self.colours.border_style,
- })
- } else {
- match app_state.current_widget_selected {
- WidgetPosition::Temp => Block::default()
- .borders(*SIDE_BORDERS)
- .border_style(self.colours.highlighted_border_style),
- _ => Block::default().borders(Borders::NONE),
- }
- };
-
- let margined_draw_loc = Layout::default()
- .constraints([Constraint::Percentage(100)].as_ref())
- .horizontal_margin(match app_state.current_widget_selected {
- WidgetPosition::Temp => 0,
- _ if !draw_border => 1,
- _ => 0,
- })
- .direction(Direction::Horizontal)
- .split(draw_loc);
-
- // Draw
- Table::new(TEMP_HEADERS.iter(), temperature_rows)
- .block(temp_block)
- .header_style(self.colours.table_header_style)
- .widths(
- &(intrinsic_widths
- .iter()
- .map(|calculated_width| Constraint::Length(*calculated_width as u16))
- .collect::<Vec<_>>()),
- )
- .render(f, margined_draw_loc[0]);
- }
-
- fn draw_disk_table<B: Backend>(
- &self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, draw_border: bool,
- ) {
- let disk_data: &[Vec<String>] = &app_state.canvas_data.disk_data;
- let num_rows = max(0, i64::from(draw_loc.height) - 5) as u64;
- let start_position = get_start_position(
- num_rows,
- &app_state.app_scroll_positions.scroll_direction,
- &mut app_state
- .app_scroll_positions
- .disk_scroll_state
- .previous_scroll_position,
- app_state
- .app_scroll_positions
- .disk_scroll_state
- .current_scroll_position,
- app_state.is_resized,
- );
-
- let sliced_vec = &disk_data[start_position as usize..];
- let mut disk_counter: i64 = 0;
-
- let disk_rows = sliced_vec.iter().map(|disk| {
- Row::StyledData(
- disk.iter(),
- match app_state.current_widget_selected {
- WidgetPosition::Disk => {
- if disk_counter as u64
- == app_state
- .app_scroll_positions
- .disk_scroll_state
- .current_scroll_position
- - start_position
- {
- disk_counter = -1;
- self.colours.currently_selected_text_style
- } else {
- if disk_counter >= 0 {
- disk_counter += 1;
- }
- self.colours.text_style
- }
- }
- _ => self.colours.text_style,
- },
- )
- });
-
- // Calculate widths
- // TODO: [PRETTY] Ellipsis on strings?
- let width = f64::from(draw_loc.width);
- let width_ratios = [0.2, 0.15, 0.13, 0.13, 0.13, 0.13, 0.13];
- let variable_intrinsic_results =
- get_variable_intrinsic_widths(width as u16, &width_ratios, &DISK_HEADERS_LENS);
- let intrinsic_widths = &variable_intrinsic_results.0[0..variable_intrinsic_results.1];
-
- let title = if app_state.is_expanded {
- const TITLE_BASE: &str = " Disk ── Esc to go back ";
- let repeat_num = max(
- 0,
- draw_loc.width as i32 - TITLE_BASE.chars().count() as i32 - 2,
- );
- let result_title = format!(
- " Disk ─{}─ Esc to go back ",
- "─".repeat(repeat_num as usize)
- );
- result_title
- } else if app_state.app_config_fields.use_basic_mode {
- String::new()
- } else {
- " Disk ".to_string()
- };
-
- let disk_block = if draw_border {
- Block::default()
- .title(&title)
- .title_style(if app_state.is_expanded {
- match app_state.current_widget_selected {
- WidgetPosition::Disk => self.colours.highlighted_border_style,
- _ => self.colours.border_style,
- }
- } else {
- self.colours.widget_title_style
- })
- .borders(Borders::ALL)
- .border_style(match app_state.current_widget_selected {
- WidgetPosition::Disk => self.colours.highlighted_border_style,
- _ => self.colours.border_style,
- })
- } else {
- match app_state.current_widget_selected {
- WidgetPosition::Disk => Block::default()
- .borders(*SIDE_BORDERS)
- .border_style(self.colours.highlighted_border_style),
- _ => Block::default().borders(Borders::NONE),
- }
- };
-
- let margined_draw_loc = Layout::default()
- .constraints([Constraint::Percentage(100)].as_ref())
- .horizontal_margin(match app_state.current_widget_selected {
- WidgetPosition::Disk => 0,
- _ if !draw_border => 1,
- _ => 0,
- })
- .direction(Direction::Horizontal)
- .split(draw_loc);
-
- // Draw!
- Table::new(DISK_HEADERS.iter(), disk_rows)
- .block(disk_block)
- .header_style(self.colours.table_header_style)
- .widths(
- &(intrinsic_widths
- .iter()
- .map(|calculated_width| Constraint::Length(*calculated_width as u16))
- .collect::<Vec<_>>()),
- )
- .render(f, margined_draw_loc[0]);
- }
-
- fn draw_search_field<B: Backend>(
- &self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, draw_border: bool,
- ) {
- let pid_search_text = "Search by PID (Tab for Name): ";
- let name_search_text = "Search by Name (Tab for PID): ";
- let grouped_search_text = "Search by Name: ";
- let num_columns = draw_loc.width as usize;
-
- let chosen_text = if app_state.is_grouped() {
- grouped_search_text
- } else if app_state.process_search_state.is_searching_with_pid {
- pid_search_text
- } else {
- name_search_text
- };
-
- let search_title: &str = if chosen_text.len() == min(num_columns / 2, chosen_text.len()) {
- chosen_text
- } else if chosen_text.is_empty() {
- ""
- } else {
- "> "
- };
-
- let num_chars_for_text = search_title.len();
-
- let mut search_text = vec![Text::styled(search_title, self.colours.table_header_style)];
-
- let cursor_position = app_state.get_cursor_position();
- let current_cursor_position = app_state.get_char_cursor_position();
-
- let start_position: usize = get_search_start_position(
- num_columns - num_chars_for_text - 5,
- &app_state.process_search_state.search_state.cursor_direction,
- &mut app_state.process_search_state.search_state.cursor_bar,
- current_cursor_position,
- app_state.is_resized,
- );
-
- let query = app_state.get_current_search_query().as_str();
- let grapheme_indices = UnicodeSegmentation::grapheme_indices(query, true);
- let mut current_grapheme_posn = 0;
- let query_with_cursor: Vec<Text<'_>> =
- if let WidgetPosition::ProcessSearch = app_state.current_widget_selected {
- let mut res = grapheme_indices
- .filter_map(|grapheme| {
- current_grapheme_posn += UnicodeWidthStr::width(grapheme.1);
-
- if current_grapheme_posn <= start_position {
- None
- } else {
- let styled = if grapheme.0 == cursor_position {
- Text::styled(grapheme.1, self.colours.currently_selected_text_style)
- } else {
- Text::styled(grapheme.1, self.colours.text_style)
- };
- Some(styled)
- }
- })
- .collect::<Vec<_>>();
-
- if cursor_position >= query.len() {
- res.push(Text::styled(
- " ",
- self.colours.currently_selected_text_style,
- ))
- }
-
- res
- } else {
- // This is easier - we just need to get a range of graphemes, rather than
- // dealing with possibly inserting a cursor (as none is shown!)
- grapheme_indices
- .filter_map(|grapheme| {
- current_grapheme_posn += UnicodeWidthStr::width(grapheme.1);
- if current_grapheme_posn <= start_position {
- None
- } else {
- let styled = Text::styled(grapheme.1, self.colours.text_style);
- Some(styled)
- }
- })
- .collect::<Vec<_>>()
- };
-
- // Text options shamelessly stolen from VS Code.
- let mut option_text = vec![];
- let case_style = if !app_state.process_search_state.is_ignoring_case {
- self.colours.currently_selected_text_style
- } else {
- self.colours.text_style
- };
-
- let whole_word_style = if app_state.process_search_state.is_searching_whole_word {
- self.colours.currently_selected_text_style
- } else {
- self.colours.text_style
- };
-
- let regex_style = if app_state.process_search_state.is_searching_with_regex {
- self.colours.currently_selected_text_style
- } else {
- self.colours.text_style
- };
-
- let case_text = format!(
- "Match Case ({})[{}]",
- if self.is_mac_os { "F1" } else { "Alt+C" },
- if !app_state.process_search_state.is_ignoring_case {
- "*"
- } else {
- " "
- }
- );
-
- let whole_text = format!(
- "Match Whole Word ({})[{}]",
- if self.is_mac_os { "F2" } else { "Alt+W" },
- if app_state.process_search_state.is_searching_whole_word {
- "*"
- } else {
- " "
- }
- );
-
- let regex_text = format!(
- "Use Regex ({})[{}]",
- if self.is_mac_os { "F3" } else { "Alt+R" },
- if app_state.process_search_state.is_searching_with_regex {
- "*"
- } else {
- " "
- }
- );
-
- let option_row = vec![
- Text::raw("\n\n"),
- Text::styled(&case_text, case_style),
- Text::raw(" "),
- Text::styled(&whole_text, whole_word_style),
- Text::raw(" "),
- Text::styled(&regex_text, regex_style),
- ];
- option_text.extend(option_row);
-
- search_text.extend(query_with_cursor);
- search_text.extend(option_text);
-
- let current_border_style: Style = if app_state
- .process_search_state
- .search_state
- .is_invalid_search
- {
- Style::default().fg(Color::Rgb(255, 0, 0))
- } els