2020-04-07 03:04:04 +00:00
use itertools ::izip ;
2020-11-15 10:16:47 +00:00
use std ::{ collections ::HashMap , str ::FromStr } ;
2020-02-29 03:24:24 +00:00
2019-12-06 05:57:04 +00:00
use tui ::{
2020-02-29 23:47:30 +00:00
backend ::Backend ,
2020-04-07 03:38:00 +00:00
layout ::{ Constraint , Direction , Layout , Rect } ,
2020-09-27 00:04:34 +00:00
text ::{ Span , Spans } ,
2020-10-18 03:26:03 +00:00
widgets ::Paragraph ,
2020-04-07 03:38:00 +00:00
Frame , Terminal ,
2019-09-11 03:37:20 +00:00
} ;
2019-09-12 02:10:49 +00:00
2020-02-08 23:00:50 +00:00
use canvas_colours ::* ;
2020-03-08 17:56:18 +00:00
use dialogs ::* ;
2020-09-22 22:12:36 +00:00
use screens ::* ;
2020-03-08 04:47:53 +00:00
use widgets ::* ;
2020-02-10 02:34:44 +00:00
2020-02-29 03:24:24 +00:00
use crate ::{
2020-04-02 00:31:43 +00:00
app ::{
self ,
2020-04-07 03:38:00 +00:00
layout_manager ::{ BottomColRow , BottomLayout , BottomWidgetType } ,
App ,
2020-04-02 00:31:43 +00:00
} ,
2020-02-29 22:07:47 +00:00
constants ::* ,
2020-04-17 00:06:50 +00:00
data_conversion ::{ ConvertedBatteryData , ConvertedCpuData , ConvertedProcessData } ,
2020-09-22 22:12:36 +00:00
options ::Config ,
2020-02-29 22:07:47 +00:00
utils ::error ,
2020-11-15 10:16:47 +00:00
utils ::error ::BottomError ,
2020-11-18 06:28:53 +00:00
Pid ,
2020-02-29 03:24:24 +00:00
} ;
mod canvas_colours ;
2020-03-08 17:56:18 +00:00
mod dialogs ;
2020-02-10 02:34:44 +00:00
mod drawing_utils ;
2020-09-22 22:12:36 +00:00
mod screens ;
2020-03-08 04:47:53 +00:00
mod widgets ;
2019-09-12 02:10:49 +00:00
2020-08-28 20:30:24 +00:00
/// Point is of time, data
type Point = ( f64 , f64 ) ;
2019-09-12 02:10:49 +00:00
#[ derive(Default) ]
2020-02-02 04:49:44 +00:00
pub struct DisplayableData {
2020-02-29 22:05:01 +00:00
pub rx_display : String ,
pub tx_display : String ,
pub total_rx_display : String ,
pub total_tx_display : String ,
2020-08-28 20:30:24 +00:00
pub network_data_rx : Vec < Point > ,
pub network_data_tx : Vec < Point > ,
2020-02-29 22:05:01 +00:00
pub disk_data : Vec < Vec < String > > ,
pub temp_sensor_data : Vec < Vec < String > > ,
2020-11-18 06:28:53 +00:00
pub single_process_data : HashMap < Pid , ConvertedProcessData > , // Contains single process data, key is PID
pub finalized_process_data_map : HashMap < u64 , Vec < ConvertedProcessData > > , // What's actually displayed, key is the widget ID.
pub stringified_process_data_map : HashMap < u64 , Vec < ( Vec < ( String , Option < String > ) > , bool ) > > , // Represents the row and whether it is disabled, key is the widget ID
2020-12-22 06:12:13 +00:00
pub mem_labels : Option < ( String , String ) > ,
pub swap_labels : Option < ( String , String ) > ,
2020-08-28 20:30:24 +00:00
pub mem_data : Vec < Point > ,
pub swap_data : Vec < Point > ,
2021-03-13 01:03:25 +00:00
pub load_avg_data : [ f32 ; 3 ] ,
2020-02-29 22:05:01 +00:00
pub cpu_data : Vec < ConvertedCpuData > ,
2020-04-17 00:06:50 +00:00
pub battery_data : Vec < ConvertedBatteryData > ,
2019-09-12 02:10:49 +00:00
}
2020-11-15 10:16:47 +00:00
#[ derive(Debug) ]
pub enum ColourScheme {
Default ,
DefaultLight ,
Gruvbox ,
GruvboxLight ,
2021-02-15 19:12:43 +00:00
Nord ,
NordLight ,
2020-11-15 10:16:47 +00:00
Custom ,
}
impl FromStr for ColourScheme {
type Err = BottomError ;
fn from_str ( s : & str ) -> error ::Result < Self > {
let lower_case = s . to_lowercase ( ) ;
match lower_case . as_str ( ) {
" default " = > Ok ( ColourScheme ::Default ) ,
" default-light " = > Ok ( ColourScheme ::DefaultLight ) ,
" gruvbox " = > Ok ( ColourScheme ::Gruvbox ) ,
" gruvbox-light " = > Ok ( ColourScheme ::GruvboxLight ) ,
2021-02-15 19:12:43 +00:00
" nord " = > Ok ( ColourScheme ::Nord ) ,
" nord-light " = > Ok ( ColourScheme ::NordLight ) ,
2020-11-15 10:16:47 +00:00
_ = > Err ( BottomError ::ConfigError ( format! (
" \" {} \" is an invalid built-in color scheme. " ,
s
) ) ) ,
}
}
}
2020-02-08 19:28:19 +00:00
/// Handles the canvas' state. TODO: [OPT] implement this.
2020-02-05 04:21:44 +00:00
pub struct Painter {
2020-04-02 00:31:43 +00:00
pub colours : CanvasColours ,
2020-02-29 22:05:01 +00:00
height : u16 ,
width : u16 ,
2020-09-27 00:04:34 +00:00
styled_help_text : Vec < Spans < 'static > > ,
2020-12-09 03:34:21 +00:00
is_mac_os : bool , // FIXME: This feels out of place...
2020-04-02 00:31:43 +00:00
row_constraints : Vec < Constraint > ,
col_constraints : Vec < Vec < Constraint > > ,
col_row_constraints : Vec < Vec < Vec < Constraint > > > ,
layout_constraints : Vec < Vec < Vec < Vec < Constraint > > > > ,
2020-04-07 03:38:00 +00:00
derived_widget_draw_locs : Vec < Vec < Vec < Vec < Rect > > > > ,
2020-09-22 22:12:36 +00:00
widget_layout : BottomLayout ,
2020-05-07 05:09:24 +00:00
table_height_offset : u16 ,
2020-02-08 19:28:19 +00:00
}
2020-02-05 03:44:49 +00:00
impl Painter {
2020-09-22 22:12:36 +00:00
pub fn init (
widget_layout : BottomLayout , table_gap : u16 , is_basic_mode : bool , config : & Config ,
2020-11-15 10:16:47 +00:00
colour_scheme : ColourScheme ,
2020-09-22 22:12:36 +00:00
) -> anyhow ::Result < Self > {
2020-04-02 00:31:43 +00:00
// Now for modularity; we have to also initialize the base layouts!
// We want to do this ONCE and reuse; after this we can just construct
// based on the console size.
let mut row_constraints = Vec ::new ( ) ;
let mut col_constraints = Vec ::new ( ) ;
let mut col_row_constraints = Vec ::new ( ) ;
let mut layout_constraints = Vec ::new ( ) ;
widget_layout . rows . iter ( ) . for_each ( | row | {
if row . canvas_handle_height {
row_constraints . push ( Constraint ::Length ( 0 ) ) ;
} else {
row_constraints . push ( Constraint ::Ratio (
row . row_height_ratio ,
widget_layout . total_row_height_ratio ,
) ) ;
}
let mut new_col_constraints = Vec ::new ( ) ;
let mut new_widget_constraints = Vec ::new ( ) ;
let mut new_col_row_constraints = Vec ::new ( ) ;
row . children . iter ( ) . for_each ( | col | {
if col . canvas_handle_width {
new_col_constraints . push ( Constraint ::Length ( 0 ) ) ;
} else {
new_col_constraints
. push ( Constraint ::Ratio ( col . col_width_ratio , row . total_col_ratio ) ) ;
}
let mut new_new_col_row_constraints = Vec ::new ( ) ;
let mut new_new_widget_constraints = Vec ::new ( ) ;
col . children . iter ( ) . for_each ( | col_row | {
if col_row . canvas_handle_height {
new_new_col_row_constraints . push ( Constraint ::Length ( 0 ) ) ;
} else if col_row . flex_grow {
new_new_col_row_constraints . push ( Constraint ::Min ( 0 ) ) ;
} else {
new_new_col_row_constraints . push ( Constraint ::Ratio (
col_row . col_row_height_ratio ,
col . total_col_row_ratio ,
) ) ;
}
let mut new_new_new_widget_constraints = Vec ::new ( ) ;
col_row . children . iter ( ) . for_each ( | widget | {
if widget . canvas_handle_width {
new_new_new_widget_constraints . push ( Constraint ::Length ( 0 ) ) ;
} else if widget . flex_grow {
new_new_new_widget_constraints . push ( Constraint ::Min ( 0 ) ) ;
} else {
new_new_new_widget_constraints . push ( Constraint ::Ratio (
widget . width_ratio ,
col_row . total_widget_ratio ,
) ) ;
}
} ) ;
new_new_widget_constraints . push ( new_new_new_widget_constraints ) ;
} ) ;
new_col_row_constraints . push ( new_new_col_row_constraints ) ;
new_widget_constraints . push ( new_new_widget_constraints ) ;
} ) ;
col_row_constraints . push ( new_col_row_constraints ) ;
layout_constraints . push ( new_widget_constraints ) ;
col_constraints . push ( new_col_constraints ) ;
} ) ;
2020-09-22 22:12:36 +00:00
let mut painter = Painter {
2020-04-02 00:31:43 +00:00
colours : CanvasColours ::default ( ) ,
height : 0 ,
width : 0 ,
2020-08-12 00:22:39 +00:00
styled_help_text : Vec ::default ( ) ,
2020-12-09 03:34:21 +00:00
is_mac_os : cfg ! ( target_os = " macos " ) ,
2020-04-02 00:31:43 +00:00
row_constraints ,
col_constraints ,
col_row_constraints ,
layout_constraints ,
widget_layout ,
2020-08-12 00:22:39 +00:00
derived_widget_draw_locs : Vec ::default ( ) ,
2020-08-29 22:54:18 +00:00
table_height_offset : if is_basic_mode { 2 } else { 4 } + table_gap ,
2020-09-22 22:12:36 +00:00
} ;
2020-11-15 10:16:47 +00:00
if let ColourScheme ::Custom = colour_scheme {
painter . generate_config_colours ( config ) ? ;
} else {
painter . generate_colour_scheme ( colour_scheme ) ? ;
}
2020-09-22 22:12:36 +00:00
painter . complete_painter_init ( ) ;
Ok ( painter )
}
2020-11-15 10:16:47 +00:00
fn generate_config_colours ( & mut self , config : & Config ) -> anyhow ::Result < ( ) > {
2020-09-22 22:12:36 +00:00
if let Some ( colours ) = & config . colors {
2020-11-15 10:16:47 +00:00
self . colours . set_colours_from_palette ( colours ) ? ;
}
2020-09-22 22:12:36 +00:00
2020-11-15 10:16:47 +00:00
Ok ( ( ) )
}
2020-09-22 22:12:36 +00:00
2020-11-15 10:16:47 +00:00
fn generate_colour_scheme ( & mut self , colour_scheme : ColourScheme ) -> anyhow ::Result < ( ) > {
match colour_scheme {
ColourScheme ::Default = > {
// Don't have to do anything.
2020-09-22 22:12:36 +00:00
}
2020-11-15 10:16:47 +00:00
ColourScheme ::DefaultLight = > {
2020-09-22 22:12:36 +00:00
self . colours
2020-11-15 10:16:47 +00:00
. set_colours_from_palette ( & * DEFAULT_LIGHT_MODE_COLOUR_PALETTE ) ? ;
2020-09-22 22:12:36 +00:00
}
2020-11-15 10:16:47 +00:00
ColourScheme ::Gruvbox = > {
2020-09-22 22:12:36 +00:00
self . colours
2020-11-15 10:16:47 +00:00
. set_colours_from_palette ( & * GRUVBOX_COLOUR_PALETTE ) ? ;
2020-09-22 22:12:36 +00:00
}
2020-11-15 10:16:47 +00:00
ColourScheme ::GruvboxLight = > {
2020-09-22 22:12:36 +00:00
self . colours
2020-11-15 10:16:47 +00:00
. set_colours_from_palette ( & * GRUVBOX_LIGHT_COLOUR_PALETTE ) ? ;
2020-09-22 22:12:36 +00:00
}
2021-02-15 19:12:43 +00:00
ColourScheme ::Nord = > {
self . colours
. set_colours_from_palette ( & * NORD_COLOUR_PALETTE ) ? ;
}
ColourScheme ::NordLight = > {
self . colours
. set_colours_from_palette ( & * NORD_LIGHT_COLOUR_PALETTE ) ? ;
}
2020-11-15 10:16:47 +00:00
ColourScheme ::Custom = > {
// This case should never occur, just do nothing.
2020-09-22 22:12:36 +00:00
}
2020-04-02 00:31:43 +00:00
}
2020-09-22 22:12:36 +00:00
Ok ( ( ) )
2020-04-02 00:31:43 +00:00
}
2020-02-29 22:05:01 +00:00
/// Must be run once before drawing, but after setting colours.
/// This is to set some remaining styles and text.
2020-09-22 22:12:36 +00:00
fn complete_painter_init ( & mut self ) {
2020-08-12 00:22:39 +00:00
let mut styled_help_spans = Vec ::new ( ) ;
2020-02-29 22:05:01 +00:00
2020-04-24 23:17:58 +00:00
// Init help text:
2020-04-25 21:32:31 +00:00
( * HELP_TEXT ) . iter ( ) . enumerate ( ) . for_each ( | ( itx , section ) | {
if itx = = 0 {
2020-08-12 00:22:39 +00:00
styled_help_spans . extend (
2020-04-25 21:32:31 +00:00
section
. iter ( )
2020-09-27 00:04:34 +00:00
. map ( | & text | Span ::styled ( text , self . colours . text_style ) )
2020-04-25 21:32:31 +00:00
. collect ::< Vec < _ > > ( ) ,
) ;
} else {
// Not required check but it runs only a few times... so whatever ig, prevents me from
// being dumb and leaving a help text section only one line long.
if section . len ( ) > 1 {
2020-09-27 00:04:34 +00:00
styled_help_spans . push ( Span ::raw ( " " ) ) ;
2020-08-12 00:22:39 +00:00
styled_help_spans
2020-09-27 00:04:34 +00:00
. push ( Span ::styled ( section [ 0 ] , self . colours . table_header_style ) ) ;
2020-08-12 00:22:39 +00:00
styled_help_spans . extend (
2020-04-25 21:32:31 +00:00
section [ 1 .. ]
. iter ( )
2020-09-27 00:04:34 +00:00
. map ( | & text | Span ::styled ( text , self . colours . text_style ) )
2020-04-25 21:32:31 +00:00
. collect ::< Vec < _ > > ( ) ,
) ;
}
}
} ) ;
2020-08-12 00:22:39 +00:00
2020-09-27 00:04:34 +00:00
self . styled_help_text = styled_help_spans . into_iter ( ) . map ( Spans ::from ) . collect ( ) ;
2020-02-29 22:05:01 +00:00
}
2020-09-22 22:12:36 +00:00
// FIXME: [CONFIG] write this, should call painter init and any changed colour functions...
pub fn update_painter_colours ( & mut self ) { }
2020-10-18 03:26:03 +00:00
fn draw_frozen_indicator < B : Backend > ( & self , f : & mut Frame < '_ , B > , draw_loc : Rect ) {
f . render_widget (
Paragraph ::new ( Span ::styled (
" Frozen, press 'f' to unfreeze " ,
self . colours . currently_selected_text_style ,
) ) ,
Layout ::default ( )
. horizontal_margin ( 1 )
. constraints ( [ Constraint ::Length ( 1 ) ] )
. split ( draw_loc ) [ 0 ] ,
)
}
2020-02-29 23:47:30 +00:00
pub fn draw_data < B : Backend > (
2020-02-29 22:05:01 +00:00
& mut self , terminal : & mut Terminal < B > , app_state : & mut app ::App ,
) -> error ::Result < ( ) > {
2020-04-02 00:31:43 +00:00
use BottomWidgetType ::* ;
2020-09-18 16:35:32 +00:00
terminal . draw ( | mut f | {
2020-10-18 03:26:03 +00:00
let ( terminal_size , frozen_draw_loc ) = if app_state . is_frozen {
let split_loc = Layout ::default ( )
. constraints ( [ Constraint ::Min ( 0 ) , Constraint ::Length ( 1 ) ] )
. split ( f . size ( ) ) ;
( split_loc [ 0 ] , Some ( split_loc [ 1 ] ) )
} else {
( f . size ( ) , None )
} ;
2020-09-18 16:35:32 +00:00
let terminal_height = terminal_size . height ;
let terminal_width = terminal_size . width ;
if ( self . height = = 0 & & self . width = = 0 )
| | ( self . height ! = terminal_height | | self . width ! = terminal_width )
{
app_state . is_force_redraw = true ;
self . height = terminal_height ;
self . width = terminal_width ;
2020-08-29 22:54:18 +00:00
}
2020-09-11 08:20:14 +00:00
2020-09-18 16:35:32 +00:00
if app_state . should_get_widget_bounds ( ) {
// If we're force drawing, reset ALL mouse boundaries.
for widget in app_state . widget_map . values_mut ( ) {
widget . top_left_corner = None ;
widget . bottom_right_corner = None ;
}
2021-02-18 22:10:51 +00:00
// Reset dd_dialog...
2020-12-16 02:39:17 +00:00
app_state . delete_dialog_state . button_positions = vec! [ ] ;
2020-09-11 08:20:14 +00:00
2021-02-18 22:10:51 +00:00
// Reset battery dialog...
2020-09-18 16:35:32 +00:00
for battery_widget in app_state . battery_state . widget_states . values_mut ( ) {
battery_widget . tab_click_locs = None ;
}
2021-02-18 22:10:51 +00:00
// Reset column headers for sorting in process widget...
for proc_widget in app_state . proc_state . widget_states . values_mut ( ) {
proc_widget . columns . column_header_y_loc = None ;
proc_widget . columns . column_header_x_locs = None ;
}
2020-09-11 08:20:14 +00:00
}
2020-08-29 22:54:18 +00:00
2020-02-29 22:05:01 +00:00
if app_state . help_dialog_state . is_showing_help {
2020-03-06 04:54:39 +00:00
let gen_help_len = GENERAL_HELP_TEXT . len ( ) as u16 + 3 ;
2020-09-18 16:35:32 +00:00
let border_len = terminal_height . saturating_sub ( gen_help_len ) / 2 ;
2020-02-29 22:05:01 +00:00
let vertical_dialog_chunk = Layout ::default ( )
. direction ( Direction ::Vertical )
2020-10-17 22:35:21 +00:00
. constraints ( [
Constraint ::Length ( border_len ) ,
Constraint ::Length ( gen_help_len ) ,
Constraint ::Length ( border_len ) ,
] )
2020-09-18 16:35:32 +00:00
. split ( terminal_size ) ;
2020-02-29 22:05:01 +00:00
let middle_dialog_chunk = Layout ::default ( )
. direction ( Direction ::Horizontal )
2020-10-17 22:35:21 +00:00
. constraints ( if terminal_width < 100 {
// TODO: [REFACTOR] The point we start changing size at currently hard-coded in.
[
Constraint ::Percentage ( 0 ) ,
Constraint ::Percentage ( 100 ) ,
Constraint ::Percentage ( 0 ) ,
]
} else {
[
Constraint ::Percentage ( 20 ) ,
Constraint ::Percentage ( 60 ) ,
Constraint ::Percentage ( 20 ) ,
]
} )
2020-02-29 22:05:01 +00:00
. split ( vertical_dialog_chunk [ 1 ] ) ;
2020-03-08 17:56:18 +00:00
self . draw_help_dialog ( & mut f , app_state , middle_dialog_chunk [ 1 ] ) ;
2020-02-29 22:05:01 +00:00
} else if app_state . delete_dialog_state . is_showing_dd {
2020-08-12 04:27:02 +00:00
// 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 ) ;
2020-12-16 02:39:17 +00:00
let text_width = if terminal_width < 100 {
terminal_width * 90 / 100
} else {
terminal_width * 50 / 100
} ;
2021-02-16 03:23:22 +00:00
let text_height = if cfg! ( target_os = " windows " )
| | ! app_state . app_config_fields . is_advanced_kill
2020-12-16 02:39:17 +00:00
{
2021-02-16 03:23:22 +00:00
7
} else {
22
} ;
2020-08-16 08:25:59 +00:00
// let (text_width, text_height) = if let Some(dd_text) = &dd_text {
2020-09-18 16:35:32 +00:00
// let width = if current_width < 100 {
// current_width * 90 / 100
2020-08-16 08:25:59 +00:00
// } else {
2020-09-18 16:35:32 +00:00
// let min_possible_width = (current_width * 50 / 100) as usize;
2020-08-16 08:25:59 +00:00
// let mut width = dd_text.width();
2020-08-12 04:27:02 +00:00
2020-08-16 08:25:59 +00:00
// // This should theoretically never allow width to be 0... we can be safe and do an extra check though.
2020-09-18 16:35:32 +00:00
// while width > (current_width as usize) && width / 2 > min_possible_width {
2020-08-16 08:25:59 +00:00
// width /= 2;
// }
2020-08-12 04:27:02 +00:00
2020-08-16 08:25:59 +00:00
// std::cmp::max(width, min_possible_width) as u16
// };
2020-08-12 04:27:02 +00:00
2020-08-16 08:25:59 +00:00
// (
// width,
// (dd_text.height() + 2 + (dd_text.width() / width as usize)) as u16,
// )
// } else {
// // AFAIK this shouldn't happen, unless something went wrong...
// (
2020-09-18 16:35:32 +00:00
// if current_width < 100 {
// current_width * 90 / 100
2020-08-16 08:25:59 +00:00
// } else {
2020-09-18 16:35:32 +00:00
// current_width * 50 / 100
2020-08-16 08:25:59 +00:00
// },
// 7,
// )
// };
2020-08-12 04:27:02 +00:00
2020-09-18 16:35:32 +00:00
let vertical_bordering = terminal_height . saturating_sub ( text_height ) / 2 ;
2020-02-29 22:05:01 +00:00
let vertical_dialog_chunk = Layout ::default ( )
. direction ( Direction ::Vertical )
2020-10-17 22:35:21 +00:00
. constraints ( [
Constraint ::Length ( vertical_bordering ) ,
Constraint ::Length ( text_height ) ,
Constraint ::Length ( vertical_bordering ) ,
] )
2020-09-18 16:35:32 +00:00
. split ( terminal_size ) ;
2020-02-29 22:05:01 +00:00
2020-09-18 16:35:32 +00:00
let horizontal_bordering = terminal_width . saturating_sub ( text_width ) / 2 ;
2020-02-29 22:05:01 +00:00
let middle_dialog_chunk = Layout ::default ( )
. direction ( Direction ::Horizontal )
2020-10-17 22:35:21 +00:00
. constraints ( [
Constraint ::Length ( horizontal_bordering ) ,
Constraint ::Length ( text_width ) ,
Constraint ::Length ( horizontal_bordering ) ,
] )
2020-02-29 22:05:01 +00:00
. split ( vertical_dialog_chunk [ 1 ] ) ;
2020-08-12 04:27:02 +00:00
// 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 ] ) ;
2020-02-29 22:05:01 +00:00
} else if app_state . is_expanded {
2020-10-18 03:26:03 +00:00
if let Some ( frozen_draw_loc ) = frozen_draw_loc {
self . draw_frozen_indicator ( & mut f , frozen_draw_loc ) ;
}
2020-02-29 22:05:01 +00:00
let rect = Layout ::default ( )
2020-04-02 00:31:43 +00:00
. margin ( 0 )
2020-10-17 22:35:21 +00:00
. constraints ( [ Constraint ::Percentage ( 100 ) ] )
2020-09-18 16:35:32 +00:00
. split ( terminal_size ) ;
2020-04-02 00:31:43 +00:00
match & app_state . current_widget . widget_type {
Cpu = > self . draw_cpu (
& mut f ,
app_state ,
rect [ 0 ] ,
app_state . current_widget . widget_id ,
) ,
CpuLegend = > self . draw_cpu (
& mut f ,
app_state ,
rect [ 0 ] ,
app_state . current_widget . widget_id - 1 ,
) ,
Mem | BasicMem = > self . draw_memory_graph (
& mut f ,
app_state ,
rect [ 0 ] ,
app_state . current_widget . widget_id ,
) ,
Disk = > self . draw_disk_table (
& mut f ,
app_state ,
rect [ 0 ] ,
true ,
app_state . current_widget . widget_id ,
) ,
Temp = > self . draw_temp_table (
& mut f ,
app_state ,
rect [ 0 ] ,
true ,
app_state . current_widget . widget_id ,
) ,
Net = > self . draw_network_graph (
& mut f ,
app_state ,
rect [ 0 ] ,
app_state . current_widget . widget_id ,
2020-04-19 01:11:20 +00:00
false ,
2020-04-02 00:31:43 +00:00
) ,
2020-09-03 02:02:49 +00:00
Proc | ProcSearch | ProcSort = > {
2020-08-16 00:35:49 +00:00
let widget_id = app_state . current_widget . widget_id
2020-09-03 02:02:49 +00:00
- match & app_state . current_widget . widget_type {
2020-08-16 00:35:49 +00:00
ProcSearch = > 1 ,
ProcSort = > 2 ,
_ = > 0 ,
} ;
self . draw_process_features ( & mut f , app_state , rect [ 0 ] , true , widget_id ) ;
}
2020-04-17 00:06:50 +00:00
Battery = > self . draw_battery_display (
& mut f ,
app_state ,
rect [ 0 ] ,
2020-04-27 19:52:39 +00:00
true ,
2020-04-17 00:06:50 +00:00
app_state . current_widget . widget_id ,
) ,
2020-04-02 00:31:43 +00:00
_ = > { }
2020-02-29 22:05:01 +00:00
}
2020-09-22 22:12:36 +00:00
} else if app_state . is_config_open {
let rect = Layout ::default ( )
. margin ( 0 )
2020-10-17 22:35:21 +00:00
. constraints ( [ Constraint ::Percentage ( 100 ) ] )
2020-09-22 22:12:36 +00:00
. split ( f . size ( ) ) [ 0 ] ;
self . draw_config_screen ( & mut f , app_state , rect )
2020-02-29 23:47:30 +00:00
} else if app_state . app_config_fields . use_basic_mode {
// Basic mode. This basically removes all graphs but otherwise
// the same info.
2020-10-18 03:26:03 +00:00
if let Some ( frozen_draw_loc ) = frozen_draw_loc {
self . draw_frozen_indicator ( & mut f , frozen_draw_loc ) ;
}
2020-02-29 23:47:30 +00:00
2021-01-25 07:21:33 +00:00
let actual_cpu_data_len = app_state . canvas_data . cpu_data . len ( ) . saturating_sub ( 1 ) ;
let cpu_height = ( actual_cpu_data_len / 4 ) as u16
+ ( if actual_cpu_data_len % 4 = = 0 { 0 } else { 1 } ) ;
2020-03-01 22:16:08 +00:00
let vertical_chunks = Layout ::default ( )
2020-02-29 23:47:30 +00:00
. direction ( Direction ::Vertical )
2021-01-25 07:21:33 +00:00
. margin ( 0 )
2020-10-17 22:35:21 +00:00
. constraints ( [
2021-01-25 07:21:33 +00:00
Constraint ::Length ( cpu_height + if cpu_height < = 1 { 1 } else { 0 } ) , // This fixes #397, apparently if the height is 1, it can't render the CPU bars...
Constraint ::Length ( if cpu_height < = 1 { 0 } else { 1 } ) ,
2020-10-17 22:35:21 +00:00
Constraint ::Length ( 2 ) ,
Constraint ::Length ( 2 ) ,
Constraint ::Min ( 5 ) ,
] )
2020-09-18 16:35:32 +00:00
. split ( terminal_size ) ;
2020-02-29 23:47:30 +00:00
2020-03-05 07:09:29 +00:00
let middle_chunks = Layout ::default ( )
. direction ( Direction ::Horizontal )
2020-10-17 22:35:21 +00:00
. constraints ( [ Constraint ::Percentage ( 50 ) , Constraint ::Percentage ( 50 ) ] )
2020-03-05 07:09:29 +00:00
. split ( vertical_chunks [ 2 ] ) ;
2020-04-02 00:31:43 +00:00
self . draw_basic_cpu ( & mut f , app_state , vertical_chunks [ 0 ] , 1 ) ;
self . draw_basic_memory ( & mut f , app_state , middle_chunks [ 0 ] , 2 ) ;
self . draw_basic_network ( & mut f , app_state , middle_chunks [ 1 ] , 3 ) ;
2020-08-29 22:54:18 +00:00
let mut later_widget_id : Option < u64 > = None ;
2020-04-02 00:31:43 +00:00
if let Some ( basic_table_widget_state ) = & app_state . basic_table_widget_state {
let widget_id = basic_table_widget_state . currently_displayed_widget_id ;
2020-08-29 22:54:18 +00:00
later_widget_id = Some ( widget_id ) ;
2020-04-02 00:31:43 +00:00
match basic_table_widget_state . currently_displayed_widget_type {
Disk = > self . draw_disk_table (
& mut f ,
app_state ,
vertical_chunks [ 4 ] ,
false ,
widget_id ,
) ,
2020-08-16 00:35:49 +00:00
Proc | ProcSort = > {
let wid = widget_id
- match basic_table_widget_state . currently_displayed_widget_type {
2020-08-29 22:54:18 +00:00
ProcSearch = > 1 ,
2020-08-16 00:35:49 +00:00
ProcSort = > 2 ,
_ = > 0 ,
} ;
self . draw_process_features (
& mut f ,
app_state ,
vertical_chunks [ 4 ] ,
false ,
wid ,
) ;
}
2020-04-02 00:31:43 +00:00
Temp = > self . draw_temp_table (
& mut f ,
app_state ,
vertical_chunks [ 4 ] ,
false ,
widget_id ,
) ,
2020-04-27 19:52:39 +00:00
Battery = > self . draw_battery_display (
& mut f ,
app_state ,
vertical_chunks [ 4 ] ,
false ,
widget_id ,
) ,
2020-04-02 00:31:43 +00:00
_ = > { }
}
2020-03-02 04:53:49 +00:00
}
2020-08-29 22:54:18 +00:00
if let Some ( widget_id ) = later_widget_id {
self . draw_basic_table_arrows ( & mut f , app_state , vertical_chunks [ 3 ] , widget_id ) ;
}
2020-02-29 22:05:01 +00:00
} else {
2020-09-10 01:51:52 +00:00
// Draws using the passed in (or default) layout.
2020-10-18 03:26:03 +00:00
if let Some ( frozen_draw_loc ) = frozen_draw_loc {
self . draw_frozen_indicator ( & mut f , frozen_draw_loc ) ;
}
2020-04-24 23:17:58 +00:00
if self . derived_widget_draw_locs . is_empty ( ) | | app_state . is_force_redraw {
2020-12-09 03:34:21 +00:00
let draw_locs = Layout ::default ( )
2020-04-07 03:38:00 +00:00
. margin ( 0 )
. constraints ( self . row_constraints . as_ref ( ) )
. direction ( Direction ::Vertical )
2020-09-18 16:35:32 +00:00
. split ( terminal_size ) ;
2020-04-07 03:38:00 +00:00
2020-12-09 03:34:21 +00:00
self . derived_widget_draw_locs = izip! (
draw_locs ,
& self . col_constraints ,
& self . col_row_constraints ,
2020-04-07 03:38:00 +00:00
& self . layout_constraints ,
& self . widget_layout . rows
)
2020-12-09 03:34:21 +00:00
. map (
| (
draw_loc ,
col_constraint ,
col_row_constraint ,
row_constraint_vec ,
cols ,
) | {
izip! (
Layout ::default ( )
. constraints ( col_constraint . as_ref ( ) )
. direction ( Direction ::Horizontal )
. split ( draw_loc )
. into_iter ( ) ,
col_row_constraint ,
row_constraint_vec ,
& cols . children
)
. map ( | ( split_loc , constraint , col_constraint_vec , col_rows ) | {
izip! (
Layout ::default ( )
. constraints ( constraint . as_ref ( ) )
. direction ( Direction ::Vertical )
. split ( split_loc )
. into_iter ( ) ,
col_constraint_vec ,
& col_rows . children
)
. map ( | ( draw_loc , col_row_constraint_vec , widgets ) | {
// Note that col_row_constraint_vec CONTAINS the widget constraints
let widget_draw_locs = Layout ::default ( )
. constraints ( col_row_constraint_vec . as_ref ( ) )
. direction ( Direction ::Horizontal )
. split ( draw_loc ) ;
// Side effect, draw here.
self . draw_widgets_with_constraints (
& mut f ,
app_state ,
widgets ,
& widget_draw_locs ,
2020-04-07 03:38:00 +00:00
) ;
2020-12-09 03:34:21 +00:00
widget_draw_locs
} )
. collect ( )
} )
. collect ( )
} ,
)
. collect ( ) ;
2020-04-07 03:38:00 +00:00
} else {
self . widget_layout
. rows
. iter ( )
2020-12-09 03:34:21 +00:00
. map ( | row | & row . children )
. flatten ( )
. map ( | col | & col . children )
. flatten ( )
. zip ( self . derived_widget_draw_locs . iter ( ) . flatten ( ) . flatten ( ) )
. for_each ( | ( widgets , widget_draw_locs ) | {
self . draw_widgets_with_constraints (
& mut f ,
app_state ,
widgets ,
& widget_draw_locs ,
2020-04-07 03:04:04 +00:00
) ;
2020-04-07 03:38:00 +00:00
} ) ;
}
2020-02-29 22:05:01 +00:00
}
} ) ? ;
2020-04-24 23:17:58 +00:00
app_state . is_force_redraw = false ;
2020-08-29 22:54:18 +00:00
app_state . is_determining_widget_boundary = false ;
2020-02-29 22:05:01 +00:00
Ok ( ( ) )
}
2020-04-07 03:38:00 +00:00
fn draw_widgets_with_constraints < B : Backend > (
& self , f : & mut Frame < '_ , B > , app_state : & mut App , widgets : & BottomColRow ,
widget_draw_locs : & [ Rect ] ,
) {
use BottomWidgetType ::* ;
for ( widget , widget_draw_loc ) in widgets . children . iter ( ) . zip ( widget_draw_locs ) {
match & widget . widget_type {
Empty = > { }
Cpu = > self . draw_cpu ( f , app_state , * widget_draw_loc , widget . widget_id ) ,
Mem = > self . draw_memory_graph ( f , app_state , * widget_draw_loc , widget . widget_id ) ,
Net = > self . draw_network ( f , app_state , * widget_draw_loc , widget . widget_id ) ,
Temp = > {
self . draw_temp_table ( f , app_state , * widget_draw_loc , true , widget . widget_id )
}
Disk = > {
self . draw_disk_table ( f , app_state , * widget_draw_loc , true , widget . widget_id )
}
2020-08-16 00:35:49 +00:00
Proc = > self . draw_process_features (
2020-04-07 03:38:00 +00:00
f ,
app_state ,
* widget_draw_loc ,
true ,
widget . widget_id ,
) ,
2020-04-27 19:52:39 +00:00
Battery = > self . draw_battery_display (
f ,
app_state ,
* widget_draw_loc ,
true ,
widget . widget_id ,
) ,
2020-04-07 03:38:00 +00:00
_ = > { }
}
}
}
2019-12-28 03:39:25 +00:00
}