summaryrefslogtreecommitdiffstats
path: root/src/canvas/widgets/disk_table.rs
blob: fda54d97353bb85565498f7e9677f34ceb5ed988 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use lazy_static::lazy_static;
use std::cmp::max;
use tui::{
    backend::Backend,
    layout::{Constraint, Direction, Layout, Rect},
    terminal::Frame,
    widgets::{Block, Borders, Row, Table},
};

use crate::{
    app,
    canvas::{
        drawing_utils::{get_start_position, get_variable_intrinsic_widths},
        Painter,
    },
    constants::*,
};

const DISK_HEADERS: [&str; 7] = ["Disk", "Mount", "Used", "Free", "Total", "R/s", "W/s"];

lazy_static! {
    static ref DISK_HEADERS_LENS: Vec<usize> = DISK_HEADERS
        .iter()
        .map(|entry| max(FORCE_MIN_THRESHOLD, entry.len()))
        .collect::<Vec<_>>();
}

pub trait DiskTableWidget {
    fn draw_disk_table<B: Backend>(
        &self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, draw_border: bool,
        widget_id: u64,
    );
}

impl DiskTableWidget for Painter {
    fn draw_disk_table<B: Backend>(
        &self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, draw_border: bool,
        widget_id: u64,
    ) {
        if let Some(disk_widget_state) = app_state.disk_state.widget_states.get_mut(&widget_id) {
            let disk_data: &mut [Vec<String>] = &mut app_state.canvas_data.disk_data;
            let num_rows = max(0, i64::from(draw_loc.height) - self.table_height_offset) as u64;
            let start_position = get_start_position(
                num_rows,
                &disk_widget_state.scroll_state.scroll_direction,
                &mut disk_widget_state.scroll_state.previous_scroll_position,
                disk_widget_state.scroll_state.current_scroll_position,
                app_state.is_force_redraw,
            );
            let is_on_widget = app_state.current_widget.widget_id == widget_id;
            let disk_table_state = &mut disk_widget_state.scroll_state.table_state;
            disk_table_state.select(Some(
                (disk_widget_state.scroll_state.current_scroll_position - start_position) as usize,
            ));

            let sliced_vec = &mut disk_data[start_position as usize..];
            let disk_rows = sliced_vec.iter().map(|disk| Row::Data(disk.iter()));

            // 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 (border_and_title_style, highlight_style) = if is_on_widget {
                (
                    self.colours.highlighted_border_style,
                    self.colours.currently_selected_text_style,
                )
            } else {
                (self.colours.border_style, self.colours.text_style)
            };

            let disk_block = if draw_border {
                Block::default()
                    .title(&title)
                    .title_style(if app_state.is_expanded {
                        border_and_title_style
                    } else {
                        self.colours.widget_title_style
                    })
                    .borders(Borders::ALL)
                    .border_style(border_and_title_style)
            } else if is_on_widget {
                Block::default()
                    .borders(*SIDE_BORDERS)
                    .border_style(self.colours.highlighted_border_style)
            } else {
                Block::default().borders(Borders::NONE)
            };

            let margined_draw_loc = Layout::default()
                .constraints([Constraint::Percentage(100)].as_ref())
                .horizontal_margin(if is_on_widget || draw_border { 0 } else { 1 })
                .direction(Direction::Horizontal)
                .split(draw_loc);

            // Draw!
            f.render_stateful_widget(
                Table::new(DISK_HEADERS.iter(), disk_rows)
                    .block(disk_block)
                    .header_style(self.colours.table_header_style)
                    .highlight_style(highlight_style)
                    .style(self.colours.text_style)
                    .widths(
                        &(intrinsic_widths
                            .iter()
                            .map(|calculated_width| Constraint::Length(*calculated_width as u16))
                            .collect::<Vec<_>>()),
                    )
                    .header_gap(app_state.app_config_fields.table_gap),
                margined_draw_loc[0],
                disk_table_state,
            );
        }
    }
}