diff options
author | ClementTsang <cjhtsang@uwaterloo.ca> | 2021-08-24 22:34:25 -0400 |
---|---|---|
committer | ClementTsang <cjhtsang@uwaterloo.ca> | 2021-08-24 22:49:06 -0400 |
commit | dd7e183ec8a152d5fda84c49a7f79141171e1448 (patch) | |
tree | ca3d44f3878ebb9181adef1d2fc969e361009f3a | |
parent | 189be96622431ece680e4fbf98eda8d07c63e9fe (diff) |
refactor: rip out trait system for drawing widgets
This rips out this weird trait system I previously used for drawing
widgets, where I implemented a trait onto the Painter struct that did
the drawing. I have no idea what I was thinking back then.
-rw-r--r-- | src/app.rs | 4 | ||||
-rw-r--r-- | src/bin/main.rs | 6 | ||||
-rw-r--r-- | src/canvas.rs | 93 | ||||
-rw-r--r-- | src/canvas/widgets.rs | 22 | ||||
-rw-r--r-- | src/canvas/widgets/basic_table_arrows.rs | 264 | ||||
-rw-r--r-- | src/canvas/widgets/battery_display.rs | 354 | ||||
-rw-r--r-- | src/canvas/widgets/cpu_basic.rs | 335 | ||||
-rw-r--r-- | src/canvas/widgets/cpu_graph.rs | 856 | ||||
-rw-r--r-- | src/canvas/widgets/disk_table.rs | 414 | ||||
-rw-r--r-- | src/canvas/widgets/mem_basic.rs | 191 | ||||
-rw-r--r-- | src/canvas/widgets/mem_graph.rs | 403 | ||||
-rw-r--r-- | src/canvas/widgets/network_basic.rs | 105 | ||||
-rw-r--r-- | src/canvas/widgets/network_graph.rs | 1318 | ||||
-rw-r--r-- | src/canvas/widgets/process_table.rs | 1387 | ||||
-rw-r--r-- | src/canvas/widgets/temp_table.rs | 390 | ||||
-rw-r--r-- | src/lib.rs | 7 |
16 files changed, 2999 insertions, 3150 deletions
@@ -270,6 +270,10 @@ impl AppState { EventResult::NoRedraw } } + BottomEvent::Resize { + width: _, + height: _, + } => EventResult::Redraw, BottomEvent::Clean => { self.data_collection .clean_data(constants::STALE_MAX_MILLISECONDS); diff --git a/src/bin/main.rs b/src/bin/main.rs index 075ea051..37431389 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -233,6 +233,12 @@ fn main() -> Result<()> { try_drawing(&mut terminal, &mut app, &mut painter)?; } } + BottomEvent::Resize { + width: _, + height: _, + } => { + try_drawing(&mut terminal, &mut app, &mut painter)?; + } BottomEvent::Clean => { app.data_collection .clean_data(constants::STALE_MAX_MILLISECONDS); diff --git a/src/canvas.rs b/src/canvas.rs index 55bbe968..5d9fe89f 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -95,8 +95,6 @@ impl FromStr for ColourScheme { /// Handles the canvas' state. TODO: [OPT] implement this. pub struct Painter { pub colours: CanvasColours, - height: u16, - width: u16, styled_help_text: Vec<Spans<'static>>, is_mac_os: bool, // FIXME: This feels out of place... row_constraints: Vec<Constraint>, @@ -182,8 +180,6 @@ impl Painter { let mut painter = Painter { colours: CanvasColours::default(), - height: 0, - width: 0, styled_help_text: Vec::default(), is_mac_os: cfg!(target_os = "macos"), row_constraints, @@ -313,36 +309,6 @@ impl Painter { 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; - } - - 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; - } - - // Reset dd_dialog... - app_state.delete_dialog_state.button_positions = vec![]; - - // Reset battery dialog... - for battery_widget in app_state.battery_state.widget_states.values_mut() { - battery_widget.tab_click_locs = None; - } - - // 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; - } - } - if app_state.help_dialog_state.is_showing_help { let gen_help_len = GENERAL_HELP_TEXT.len() as u16 + 3; let border_len = terminal_height.saturating_sub(gen_help_len) / 2; @@ -461,39 +427,45 @@ impl Painter { .constraints([Constraint::Percentage(100)]) .split(terminal_size); match &app_state.current_widget.widget_type { - Cpu => self.draw_cpu( + Cpu => draw_cpu( + self, &mut f, app_state, rect[0], app_state.current_widget.widget_id, ), - CpuLegend => self.draw_cpu( + CpuLegend => draw_cpu( + self, &mut f, app_state, rect[0], app_state.current_widget.widget_id - 1, ), - Mem | BasicMem => self.draw_memory_graph( + Mem | BasicMem => draw_memory_graph( + self, &mut f, app_state, rect[0], app_state.current_widget.widget_id, ), - Disk => self.draw_disk_table( + Disk => draw_disk_table( + self, &mut f, app_state, rect[0], true, app_state.current_widget.widget_id, ), - Temp => self.draw_temp_table( + Temp => draw_temp_table( + self, &mut f, app_state, rect[0], true, app_state.current_widget.widget_id, ), - Net => self.draw_network_graph( + Net => draw_network_graph( + self, &mut f, app_state, rect[0], @@ -508,9 +480,10 @@ impl Painter { _ => 0, }; - self.draw_process_features(&mut f, app_state, rect[0], true, widget_id); + draw_process_features(self, &mut f, app_state, rect[0], true, widget_id); } - Battery => self.draw_battery_display( + Battery => draw_battery_display( + self, &mut f, app_state, rect[0], @@ -555,16 +528,17 @@ impl Painter { .direction(Direction::Horizontal) .constraints([Constraint::Percentage(50), Constraint::Percentage(50)]) .split(vertical_chunks[1]); - 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); + draw_basic_cpu(self, &mut f, app_state, vertical_chunks[0], 1); + draw_basic_memory(self, &mut f, app_state, middle_chunks[0], 2); + draw_basic_network(self, &mut f, app_state, middle_chunks[1], 3); let mut later_widget_id: Option<u64> = None; if let Some(basic_table_widget_state) = &app_state.basic_table_widget_state { let widget_id = basic_table_widget_state.currently_displayed_widget_id; later_widget_id = Some(widget_id); match basic_table_widget_state.currently_displayed_widget_type { - Disk => self.draw_disk_table( + Disk => draw_disk_table( + self, &mut f, app_state, vertical_chunks[3], @@ -578,7 +552,8 @@ impl Painter { ProcSort => 2, _ => 0, }; - self.draw_process_features( + draw_process_features( + self, &mut f, app_state, vertical_chunks[3], @@ -586,14 +561,16 @@ impl Painter { wid, ); } - Temp => self.draw_temp_table( + Temp => draw_temp_table( + self, &mut f, app_state, vertical_chunks[3], false, widget_id, ), - Battery => self.draw_battery_display( + Battery => draw_battery_display( + self, &mut f, app_state, vertical_chunks[3], @@ -605,7 +582,7 @@ impl Painter { } if let Some(widget_id) = later_widget_id { - self.draw_basic_table_arrows(&mut f, app_state, vertical_chunks[2], widget_id); + draw_basic_table_arrows(self, &mut f, app_state, vertical_chunks[2], widget_id); } } else { // Draws using the passed in (or default) layout. @@ -713,23 +690,25 @@ impl Painter { 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), + Cpu => draw_cpu(self, f, app_state, *widget_draw_loc, widget.widget_id), + Mem => draw_memory_graph(self, f, app_state, *widget_draw_loc, widget.widget_id), + Net => draw_network(self, f, app_state, *widget_draw_loc, widget.widget_id), Temp => { - self.draw_temp_table(f, app_state, *widget_draw_loc, true, widget.widget_id) + draw_temp_table(self, 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) + draw_disk_table(self, f, app_state, *widget_draw_loc, true, widget.widget_id) } - Proc => self.draw_process_features( + Proc => draw_process_features( + self, f, app_state, *widget_draw_loc, true, widget.widget_id, ), - Battery => self.draw_battery_display( + Battery => draw_battery_display( + self, f, app_state, *widget_draw_loc, diff --git a/src/canvas/widgets.rs b/src/canvas/widgets.rs index a76b4591..c2f5f91e 100644 --- a/src/canvas/widgets.rs +++ b/src/canvas/widgets.rs @@ -10,14 +10,14 @@ pub mod network_graph; pub mod process_table; pub mod temp_table; -pub use basic_table_arrows::BasicTableArrows; -pub use battery_display::BatteryDisplayWidget; -pub use cpu_basic::CpuBasicWidget; -pub use cpu_graph::CpuGraphWidget; -pub use disk_table::DiskTableWidget; -pub use mem_basic::MemBasicWidget; -pub use mem_graph::MemGraphWidget; -pub use network_basic::NetworkBasicWidget; -pub use network_graph::NetworkGraphWidget; -pub use process_table::ProcessTableWidget; -pub use temp_table::TempTableWidget; +pub use basic_table_arrows::*; +pub use battery_display::*; +pub use cpu_basic::*; +pub use cpu_graph::*; +pub use disk_table::*; +pub use mem_basic::*; +pub use mem_graph::*; +pub use network_basic::*; +pub use network_graph::*; +pub use process_table::*; +pub use temp_table::*; diff --git a/src/canvas/widgets/basic_table_arrows.rs b/src/canvas/widgets/basic_table_arrows.rs index 82c23245..8e1f476e 100644 --- a/src/canvas/widgets/basic_table_arrows.rs +++ b/src/canvas/widgets/basic_table_arrows.rs @@ -12,154 +12,142 @@ use tui::{ widgets::{Block, Paragraph}, }; -pub trait BasicTableArrows { - fn draw_basic_table_arrows<B: Backend>( - &self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64, - ); -} +pub fn draw_basic_table_arrows<B: Backend>( + painter: &Painter, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, + widget_id: u64, +) { + if let Some(current_table) = app_state.widget_map.get(&widget_id) { + let current_table = if let BottomWidgetType::ProcSort = current_table.widget_type { + current_table + .right_neighbour + .map(|id| app_state.widget_map.get(&id).unwrap()) + .unwrap() + } else { + current_table + }; -impl BasicTableArrows for Painter { - fn draw_basic_table_arrows<B: Backend>( - &self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64, - ) { - if let Some(current_table) = app_state.widget_map.get(&widget_id) { - let current_table = if let BottomWidgetType::ProcSort = current_table.widget_type { + let (left_table, right_table) = ( + { current_table - .right_neighbour - .map(|id| app_state.widget_map.get(&id).unwrap()) - .unwrap() - } else { + .left_neighbour + .map(|left_widget_id| { + app_state + .widget_map + .get(&left_widget_id) + .map(|left_widget| { + if left_widget.widget_type == BottomWidgetType::ProcSort { + left_widget + .left_neighbour + .map(|left_left_widget_id| { + app_state.widget_map.get(&left_left_widget_id).map( + |left_left_widget| &left_left_widget.widget_type, + ) + }) + .unwrap_or(Some(&BottomWidgetType::Temp)) + .unwrap_or(&BottomWidgetType::Temp) + } else { + &left_widget.widget_type + } + }) + .unwrap_or(&BottomWidgetType::Temp) + }) + .unwrap_or(&BottomWidgetType::Temp) + }, + { current_table - }; - - let (left_table, right_table) = ( - { - current_table - .left_neighbour - .map(|left_widget_id| { - app_state - .widget_map - .get(&left_widget_id) - .map(|left_widget| { - if left_widget.widget_type == BottomWidgetType::ProcSort { - left_widget - .left_neighbour - .map(|left_left_widget_id| { - app_state.widget_map.get(&left_left_widget_id).map( - |left_left_widget| { - &left_left_widget.widget_type - }, - ) - }) - .unwrap_or(Some(&BottomWidgetType::Temp)) - .unwrap_or(&BottomWidgetType::Temp) - } else { - &left_widget.widget_type - } - }) - .unwrap_or(&BottomWidgetType::Temp) - }) - .unwrap_or(&BottomWidgetType::Temp) - }, - { - current_table - .right_neighbour - .map(|right_widget_id| { - app_state - .widget_map - .get(&right_widget_id) - .map(|right_widget| { - if right_widget.widget_type == BottomWidgetType::ProcSort { - right_widget - .right_neighbour - .map(|right_right_widget_id| { - app_state - .widget_map - .get(&right_right_widget_id) - .map(|right_right_widget| { - &right_right_widget.widget_type - }) - }) - .unwrap_or(Some(&BottomWidgetType::Disk)) - .unwrap_or(&BottomWidgetType::Disk) - } else { - &right_widget.widget_type - } - }) - .unwrap_or(&BottomWidgetType::Disk) - }) - .unwrap_or(&BottomWidgetType::Disk) - }, - ); + .right_neighbour + .map(|right_widget_id| { + app_state + .widget_map + .get(&right_widget_id) + .map(|right_widget| { + if right_widget.widget_type == BottomWidgetType::ProcSort { + right_widget + .right_neighbour + .map(|right_right_widget_id| { + app_state.widget_map.get(&right_right_widget_id).map( + |right_right_widget| { + &right_right_widget.widget_type + }, + ) + }) + .unwrap_or(Some(&BottomWidgetType::Disk)) + .unwrap_or(&BottomWidgetType::Disk) + } else { + &right_widget.widget_type + } + }) + .unwrap_or(&BottomWidgetType::Disk) + }) + .unwrap_or(&BottomWidgetType::Disk) + }, + ); - let left_name = left_table.get_pretty_name(); - let right_name = right_table.get_pretty_name(); + let left_name = left_table.get_pretty_name(); + let right_name = right_table.get_pretty_name(); - let num_spaces = - usize::from(draw_loc.width).saturating_sub(6 + left_name.len() + right_name.len()); + let num_spaces = + usize::from(draw_loc.width).saturating_sub(6 + left_name.len() + right_name.len()); - let left_arrow_text = vec![ - Spans::default(), - Spans::from(Span::styled( - format!("◄ {}", left_name), - self.colours.text_style, - )), - ]; + let left_arrow_text = vec![ + Spans::default(), + Spans::from(Span::styled( + format!("◄ {}", left_name), + painter.colours.text_style, + )), + ]; - let right_arrow_text = vec![ - Spans::default(), - Spans::from(Span::styled( - format!("{} ►", right_name), - self.colours.text_style, - )), - ]; + let right_arrow_text = vec![ + Spans::default(), + Spans::from(Span::styled( + format!("{} ►", right_name), + painter.colours.text_style, + )), + ]; - let margined_draw_loc = Layout::default() - .direction(Direction::Horizontal) - .constraints([ - Constraint::Length(2 + left_name.len() as u16), - Constraint::Length(num_spaces as u16), - Constraint::Length(2 + right_name.len() as u16), - ]) - .horizontal_margin(1) - .split(draw_loc); + let margined_draw_loc = Layout::default() + .direction(Direction::Horizontal) + .constraints([ + Constraint::Length(2 + left_name.len() as u16), + Constraint::Length(num_spaces as u16), + Constraint::Length(2 + right_name.len() as u16), + ]) + .horizontal_margin(1) + .split(draw_loc); - f.render_widget( - Paragraph::new(left_arrow_text).block(Block::default()), - margined_draw_loc[0], - ); - f.render_widget( - Paragraph::new(right_arrow_text) - .block(Block::default()) - .alignment(Alignment::Right), - margined_draw_loc[2], - ); + f.render_widget( + Paragraph::new(left_arrow_text).block(Block::default()), + margined_draw_loc[0], + ); + f.render_widget( + Paragraph::new(right_arrow_text) + .block(Block::default()) + .alignment(Alignment::Right), + margined_draw_loc[2], + ); - if app_state.should_get_widget_bounds() { - // Some explanations for future readers: - // - The "height" as of writing of this entire widget is 2. If it's 1, it occasionally doesn't draw. - // - As such, the buttons are only on the lower part of this 2-high widget. - // - So, we want to only check at one location, the `draw_loc.y + 1`, and that's it. - // - But why is it "+2" then? Well, it's because I have a REALLY ugly hack - // for mouse button checking, since most button checks are of the form `(draw_loc.y + draw_loc.height)`, - // and the same for the x and width. Unfortunately, if you check using >= and <=, the outer bound is - // actually too large - so, we assume all of them are one too big and check via < (see - // https://github.com/ClementTsang/bottom/pull/459 for details). - // - So in other words, to make it simple, we keep this to a standard and overshoot by one here. - if let Some(basic_table) = &mut app_state.basic_table_widget_state { - basic_table.left_tlc = - Some((margined_draw_loc[0].x, margined_draw_loc[0].y + 1)); - basic_table.left_brc = Some(( - margined_draw_loc[0].x + margined_draw_loc[0].width, - margined_draw_loc[0].y + 2, - )); - basic_table.right_tlc = - Some((margined_draw_loc[2].x, margined_draw_loc[2].y + 1)); - basic_table.right_brc = Some(( - margined_draw_loc[2].x + margined_draw_loc[2].width, - margined_draw_loc[2].y + 2, - )); - } + if app_state.should_get_widget_bounds() { + // Some explanations for future readers: + // - The "height" as of writing of this entire widget is 2. If it's 1, it occasionally doesn't draw. + // - As such, the buttons are only on the lower part of this 2-high widget. + // - So, we want to only check at one location, the `draw_loc.y + 1`, and that's it. + // - But why is it "+2" then? Well, it's because I have a REALLY ugly hack + // for mouse button checking, since most button checks are of the form `(draw_loc.y + draw_loc.height)`, + // and the same for the x and width. Unfortunately, if you check using >= and <=, the outer bound is + // actually too large - so, we assume all of them are one too big and check via < (see + // https://github.com/ClementTsang/bottom/pull/459 for details). + // - So in other words, to make it simple, we keep this to a standard and overshoot by one here. + if let Some(basic_table) = &mut app_state.basic_table_widget_state { + basic_table.left_tlc = Some((margined_draw_loc[0].x, margined_draw_loc[0].y + 1)); + basic_table.left_brc = Some(( + margined_draw_loc[0].x + margined_draw_loc[0].width, + margined_draw_loc[0].y + 2, + )); + basic_table.right_tlc = Some((margined_draw_loc[2].x, margined_draw_loc[2].y + 1)); + basic_table.right_brc = Some(( + margined_draw_loc[2].x + margined_draw_loc[2].width, + margined_draw_loc[2].y + 2, + )); } } } diff --git a/src/canvas/widgets/battery_display.rs b/src/canvas/widgets/battery_display.rs index 34d9783c..2b9fe5f5 100644 --- a/src/canvas/widgets/battery_display.rs +++ b/src/canvas/widgets/battery_display.rs @@ -13,198 +13,184 @@ use tui::{ }; use unicode_segmentation::UnicodeSegmentation; -pub trait BatteryDisplayWidget { - fn draw_battery_display<B: Backend>( - &self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, draw_border: bool, - widget_id: u64, - ); -} - -impl BatteryDisplayWidget for Painter { - fn draw_battery_display<B: Backend>( - &self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, draw_border: bool, - widget_id: u64, - ) { - let should_get_widget_bounds = app_state.should_get_widget_bounds(); - if let Some(battery_widget_state) = - app_state.battery_state.widget_states.get_mut(&widget_id) - { - let is_on_widget = widget_id == app_state.current_widget.widget_id; - let border_style = if is_on_widget { - self.colours.highlighted_border_style - } else { - self.colours.border_style - }; - let table_gap = if draw_loc.height < TABLE_GAP_HEIGHT_LIMIT { - 0 - } else { - app_state.app_config_fields.table_gap - }; - - let title = if app_state.is_expanded { - const TITLE_BASE: &str = " Battery ── Esc to go back "; - Spans::from(vec![ - Span::styled(" Battery ".to_string(), self.colours.widget_title_style), - Span::styled( - format!( - "─{}─ Esc to go back ", - "─".repeat(usize::from(draw_loc.width).saturating_sub( - UnicodeSegmentation::graphemes(TITLE_BASE, true).count() + 2 - )) - ), - border_style, +pub fn draw_battery_display<B: Backend>( + painter: &Painter, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, + draw_border: bool, widget_id: u64, +) { + let should_get_widget_bounds = app_state.should_get_widget_bounds(); + if let Some(battery_widget_state) = app_state.battery_state.widget_states.get_mut(&widget_id) { + let is_on_widget = widget_id == app_state.current_widget.widget_id; + let border_style = if is_on_widget { + painter.colours.highlighted_border_style + } else { + painter.colours.border_style + }; + let table_gap = if draw_loc.height < TABLE_GAP_HEIGHT_LIMIT { + 0 + } else { + app_state.app_config_fields.table_gap + }; + + let title = if app_state.is_expanded { + const TITLE_BASE: &str = " Battery ── Esc to go back "; + Spans::from(vec![ + Span::styled(" Battery ".to_string(), painter.colours.widget_title_style), + Span::styled( + format!( + "─{}─ Esc to go back ", + "─".repeat(usize::from(draw_loc.width).saturating_sub( + UnicodeSegmentation::graphemes(TITLE_BASE, true).count() + 2 + )) ), - ]) - } else { - Spans::from(Span::styled( - " Battery ".to_string(), - self.colours.widget_title_style, - )) - }; - - let battery_block = if draw_border { - Block::default() - .title(title) - .borders(Borders::ALL) - .border_style(border_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 battery_names = app_state - .canvas_data - .battery_data - .iter() - .map(|battery| &battery.battery_name) - .collect::<Vec<_>>(); - - let tab_draw_loc = Layout::default() - .constraints([ - Constraint::Length(1), - Constraint::Length(2), - Constraint::Min(0), - ]) - .direction(Direction::Vertical) - .split(draw_loc)[1]; + border_style, + ), + ]) + } else { + Spans::from(Span::styled( + " Battery ".to_string(), + painter.colours.widget_title_style, + )) + }; + + let battery_block = if draw_border { + Block::default() + .title(title) + .borders(Borders::ALL) + .border_style(border_style) + } else if is_on_widget { + Block::default() + .borders(*SIDE_BORDERS) + .border_style(painter.colours.highlighted_border_style) + } else { + Block::default().borders(Borders::NONE) + }; + + let battery_names = app_state + .canvas_data + .battery_data + .iter() + .map(|battery| &battery.battery_name) + .collect::<Vec<_>>(); + + let tab_draw_loc = Layout::default() + .constraints([ + Constraint::Length(1), + Constraint::Length(2), + Constraint::Min(0), + ]) + .direction(Direction::Vertical) + .split(draw_loc)[1]; + + f.render_widget( + Tabs::new( + battery_names + .iter() + .map(|name| Spans::from((*name).clone())) + .collect::<Vec<_>>(), + ) + .block(Block::default()) + .divider(tui::symbols::line::VERTICAL) + .style(painter.colours.text_style) + .highlight_style(painter.colours.currently_selected_text_style) + .select(battery_widget_state.currently_selected_battery_index), + tab_draw_loc, + ); + + let margined_draw_loc = Layout::default() + .constraints([Constraint::Percentage(100)]) + .horizontal_margin(if is_on_widget || draw_border { 0 } else { 1 }) + .direction(Direction::Horizontal) + .split(draw_loc)[0]; + + if let Some(battery_details) = app_state + .canvas_data + .battery_data + .get(battery_widget_state.currently_selected_battery_index) + { + // Assuming a 50/50 split in width + let bar_length = usize::from((draw_loc.width.saturating_sub(2) / 2).saturating_sub(8)); + let charge_percentage = battery_details.charge_percentage; + let num_bars = calculate_basic_use_bars(charge_percentage, bar_length); + let bars = format!( + "[{}{}{:3.0}%]", + "|".repeat(num_bars), + " ".repeat(bar_length - num_bars), + charge_percentage, |