diff --git a/src/app.rs b/src/app.rs index d397c027..52807a1f 100644 --- a/src/app.rs +++ b/src/app.rs @@ -30,14 +30,12 @@ use crate::{ canvas::Painter, constants, data_conversion::ConvertedData, - tuine::{Application, Element, Flex, Status, ViewContext}, + tuine::{Application, Element, Status, ViewContext}, units::data_units::DataUnit, Pid, }; use anyhow::Result; -use indextree::{Arena, NodeId}; -use rustc_hash::FxHashMap; // FIXME: Move this! #[derive(Debug, Clone)] @@ -86,10 +84,10 @@ impl UsedWidgets { } } -/// AppConfigFields is meant to cover basic fields that would normally be set +/// [`AppConfig`] is meant to cover basic fields that would normally be set /// by config files or launch options. #[derive(Debug)] -pub struct AppConfigFields { +pub struct AppConfig { pub update_rate_in_milliseconds: u64, pub temperature_type: temperature::TemperatureType, pub use_dot: bool, @@ -145,34 +143,32 @@ pub enum AppMessages { pub struct AppState { pub data_collection: DataCollection, - pub used_widgets: UsedWidgets, pub filters: DataFilters, - pub app_config_fields: AppConfigFields, + pub app_config: AppConfig, - // --- NEW STUFF --- frozen_state: FrozenState, current_screen: CurrentScreen, - painter: Painter, + pub painter: Painter, terminator: Arc, } impl AppState { /// Creates a new [`AppState`]. pub fn new( - app_config_fields: AppConfigFields, filters: DataFilters, - layout_tree_output: LayoutCreationOutput, painter: Painter, + app_config: AppConfig, filters: DataFilters, layout_tree_output: LayoutCreationOutput, + painter: Painter, ) -> Result { let LayoutCreationOutput { - layout_tree, - root: layout_tree_root, + layout_tree: _, + root: _, widget_lookup_map, - selected: selected_widget, + selected: _, used_widgets, } = layout_tree_output; Ok(Self { - app_config_fields, + app_config, filters, used_widgets, painter, @@ -250,48 +246,7 @@ impl Application for AppState { } fn view<'b>(&mut self, ctx: &mut ViewContext<'_>) -> Element { - use crate::tuine::FlexElement; - use crate::tuine::StatefulComponent; - use crate::tuine::{TempTable, TextTable, TextTableProps}; - - let data = match &self.frozen_state { - FrozenState::NotFrozen => &self.data_collection, - FrozenState::Frozen(frozen_data_collection) => &frozen_data_collection, - }; - - let mut converted_data = ConvertedData::default(); - - Flex::column() - .with_flex_child( - Flex::row_with_children(vec![ - FlexElement::new(TempTable::build( - ctx, - &self.painter, - converted_data.temp_table(data, self.app_config_fields.temperature_type), - )), - FlexElement::new(TextTable::build( - ctx, - TextTableProps::new(vec!["D", "E", "F"]), - )), - ]), - 1, - ) - .with_flex_child( - Flex::row_with_children(vec![ - FlexElement::new(TextTable::build( - ctx, - TextTableProps::new(vec!["G", "H", "I", "J"]), - )), - FlexElement::new(TextTable::build( - ctx, - TextTableProps::new(vec!["L", "EM", "NO", "PQ"]) - .rows(vec![vec![1, 2, 3, 4], vec![4, 3, 2, 1]]) - .default_sort(crate::tuine::SortType::Descending(0)), - )), - ]), - 2, - ) - .into() + todo!() } fn destructor(&mut self) { diff --git a/src/app/layout_manager.rs b/src/app/layout_manager.rs index f589ea14..6f3595d6 100644 --- a/src/app/layout_manager.rs +++ b/src/app/layout_manager.rs @@ -5,19 +5,20 @@ use crate::{ }, error::{BottomError, Result}, options::{ - layout_options::{LayoutRule, Row, RowChildren}, + layout_options::{LayoutRow, LayoutRowChild, LayoutRule}, ProcessDefaults, }, + tuine::{Element, Flex}, }; use indextree::{Arena, NodeId}; use rustc_hash::FxHashMap; -use std::cmp::min; +use std::str::FromStr; use tui::layout::Rect; use crate::app::widgets::Widget; use super::{ - event::SelectionAction, AppConfigFields, BottomWidget, CpuGraph, TimeGraph, UsedWidgets, + event::SelectionAction, AppConfig, AppState, CpuGraph, OldBottomWidget, TimeGraph, UsedWidgets, }; #[derive(Debug, Clone, Eq, PartialEq, Hash)] @@ -46,7 +47,7 @@ impl Default for BottomWidgetType { } } -impl std::str::FromStr for BottomWidgetType { +impl FromStr for BottomWidgetType { type Err = BottomError; fn from_str(s: &str) -> Result { @@ -169,22 +170,6 @@ pub enum LayoutNode { Widget(WidgetLayout), } -impl LayoutNode { - fn set_bound(&mut self, bound: Rect) { - match self { - LayoutNode::Row(row) => { - row.bound = bound; - } - LayoutNode::Col(col) => { - col.bound = bound; - } - LayoutNode::Widget(widget) => { - widget.bound = bound; - } - } - } -} - /// Relative movement direction from the currently selected widget. pub enum MovementDirection { Left, @@ -193,11 +178,40 @@ pub enum MovementDirection { Down, } +pub fn initialize_widget_layout( + layout_rows: &[LayoutRow], app: &AppState, +) -> anyhow::Result> { + let mut root = Flex::column(); + + for layout_row in layout_rows { + let mut row = Flex::row(); + if let Some(children) = &layout_row.child { + for child in children { + match child { + LayoutRowChild::Widget(widget) => {} + LayoutRowChild::Carousel { + carousel_children, + default, + } => {} + LayoutRowChild::LayoutCol { + ratio, + child: children, + } => for child in children {}, + } + } + } + + root = root.with_child(row); + } + + Ok(root.into()) +} + /// A wrapper struct to simplify the output of [`create_layout_tree`]. pub struct LayoutCreationOutput { pub layout_tree: Arena, pub root: NodeId, - pub widget_lookup_map: FxHashMap, + pub widget_lookup_map: FxHashMap, pub selected: NodeId, pub used_widgets: UsedWidgets, } @@ -207,11 +221,11 @@ pub struct LayoutCreationOutput { /// selected [`NodeId`]. // FIXME: [AFTER REFACTOR] This is currently jury-rigged "glue" just to work with the existing config system! We are NOT keeping it like this, it's too awful to keep like this! pub fn create_layout_tree( - rows: &[Row], process_defaults: ProcessDefaults, app_config_fields: &AppConfigFields, + rows: &[LayoutRow], process_defaults: ProcessDefaults, app_config_fields: &AppConfig, ) -> Result { fn add_widget_to_map( - widget_lookup_map: &mut FxHashMap, widget_type: BottomWidgetType, - widget_id: NodeId, process_defaults: &ProcessDefaults, app_config_fields: &AppConfigFields, + widget_lookup_map: &mut FxHashMap, widget_type: BottomWidgetType, + widget_id: NodeId, process_defaults: &ProcessDefaults, app_config_fields: &AppConfig, width: LayoutRule, height: LayoutRule, ) -> Result<()> { match widget_type { @@ -341,7 +355,7 @@ pub fn create_layout_tree( if let Some(children) = &row.child { for child in children { match child { - RowChildren::Widget(widget) => { + LayoutRowChild::Widget(widget) => { let widget_id = arena.new_node(LayoutNode::Widget(WidgetLayout::default())); row_id.append(widget_id, &mut arena); @@ -366,7 +380,7 @@ pub fn create_layout_tree( LayoutRule::default(), )?; } - RowChildren::Carousel { + LayoutRowChild::Carousel { carousel_children, default, } => { @@ -422,7 +436,7 @@ pub fn create_layout_tree( ); } } - RowChildren::Col { + LayoutRowChild::LayoutCol { ratio, child: col_child, } => { @@ -518,7 +532,7 @@ pub enum MoveWidgetResult { /// A more restricted movement, only within a single widget. pub fn move_expanded_widget_selection( - widget_lookup_map: &mut FxHashMap, current_widget_id: NodeId, + widget_lookup_map: &mut FxHashMap, current_widget_id: NodeId, direction: MovementDirection, ) -> MoveWidgetResult { if let Some(current_widget) = widget_lookup_map.get_mut(¤t_widget_id) { @@ -542,8 +556,9 @@ pub fn move_expanded_widget_selection( /// - Only [`LayoutNode::Widget`]s are leaves. /// - Only [`LayoutNode::Row`]s or [`LayoutNode::Col`]s are non-leaves. pub fn move_widget_selection( - layout_tree: &mut Arena, widget_lookup_map: &mut FxHashMap, - current_widget_id: NodeId, direction: MovementDirection, + layout_tree: &mut Arena, + widget_lookup_map: &mut FxHashMap, current_widget_id: NodeId, + direction: MovementDirection, ) -> MoveWidgetResult { // We first give our currently-selected widget a chance to react to the movement - it may handle it internally! let handled = { @@ -816,317 +831,3 @@ pub fn move_widget_selection( } } } - -/// Generates the bounds for each node in the `arena, taking into account per-leaf desires, -/// and finally storing the calculated bounds in the given `arena`. -/// -/// Stored bounds are given in *relative* coordinates - they are relative to their parents. -/// That is, you may have a child widget "start" at (0, 0), but its parent is actually at x = 5,s -/// so the absolute coordinate of the child widget is actually (5, 0). -/// -/// The algorithm is mostly based on the algorithm used by Flutter, adapted to work for -/// our use case. For more information, check out both: -/// -/// - [How the constraint system works in Flutter](https://flutter.dev/docs/development/ui/layout/constraints) -/// - [How Flutter does sublinear layout](https://flutter.dev/docs/resources/inside-flutter#sublinear-layout) -pub fn generate_layout( - root: NodeId, arena: &mut Arena, area: Rect, - lookup_map: &FxHashMap, -) { - // TODO: [Optimization, Layout] Add some caching/dirty mechanisms to reduce calls. - - /// A [`Size`] is a set of widths and heights that a node in our layout wants to be. - #[derive(Default, Clone, Copy, Debug)] - struct Size { - width: u16, - height: u16, - } - - /// A [`LayoutConstraint`] is just a set of maximal widths/heights. - #[derive(Clone, Copy, Debug)] - struct LayoutConstraints { - max_width: u16, - max_height: u16, - } - - impl LayoutConstraints { - fn new(max_width: u16, max_height: u16) -> Self { - Self { - max_width, - max_height, - } - } - - /// Shrinks the width of itself given another width. - fn shrink_width(&mut self, width: u16) { - self.max_width = self.max_width.saturating_sub(width); - } - - /// Shrinks the height of itself given another height. - fn shrink_height(&mut self, height: u16) { - self.max_height = self.max_height.saturating_sub(height); - } - - /// Returns a new [`LayoutConstraints`] with a new width given a ratio. - fn ratio_width(&self, numerator: u32, denominator: u32) -> Self { - Self { - max_width: (self.max_width as u32 * numerator / denominator) as u16, - max_height: self.max_height, - } - } - - /// Returns a new [`LayoutConstraints`] with a new height given a ratio. - fn ratio_height(&self, numerator: u32, denominator: u32) -> Self { - Self { - max_width: self.max_width, - max_height: (self.max_height as u32 * numerator / denominator) as u16, - } - } - } - - /// The internal recursive call to build a layout. Builds off of `arena` and stores bounds inside it. - fn layout( - node: NodeId, arena: &mut Arena, lookup_map: &FxHashMap, - mut constraints: LayoutConstraints, - ) -> Size { - if let Some(layout_node) = arena.get(node).map(|n| n.get()) { - match layout_node { - LayoutNode::Row(row) => { - let children = node.children(arena).collect::>(); - let mut row_bounds = vec![Size::default(); children.len()]; - - if let LayoutRule::Length { length } = row.parent_rule { - constraints.max_height = length; - } - - let (flexible_indices, inflexible_indices): (Vec<_>, Vec<_>) = children - .iter() - .enumerate() - .filter_map(|(itx, node)| { - if let Some(layout_node) = arena.get(*node).map(|n| n.get()) { - match layout_node { - LayoutNode::Row(RowLayout { parent_rule, .. }) - | LayoutNode::Col(ColLayout { parent_rule, .. }) => { - match parent_rule { - LayoutRule::Expand { ratio } => { - Some((itx, true, *ratio)) - } - LayoutRule::Child => Some((itx, false, 0)), - LayoutRule::Length { .. } => Some((itx, false, 0)), - } - } - LayoutNode::Widget(_) => { - if let Some(widget) = lookup_map.get(node) { - match widget.width() { - LayoutRule::Expand { ratio } => { - Some((itx, true, ratio)) - } - LayoutRule::Child => Some((itx, false, 0)), - LayoutRule::Length { .. } => Some((itx, false, 0)), - } - } else { - None - } - } - } - } else { - None - } - }) - .partition(|(_itx, is_flex, _ratio)| *is_flex); - - // First handle non-flexible children. - for (index, _, _) in inflexible_indices { - // The unchecked get is safe, since the index is obtained by iterating through the children - // vector in the first place. - let child = unsafe { children.get_unchecked(index) }; - let desired_size = layout(*child, arena, lookup_map, constraints); - - constraints.shrink_width(desired_size.width); - - // This won't panic, since the two vectors are the same length. - row_bounds[index] = desired_size; - } - - // Handle flexible children now. - let denominator: u32 = flexible_indices.iter().map(|(_, _, ratio)| ratio).sum(); - let original_constraints = constraints; - let mut split_constraints = flexible_indices - .iter() - .map(|(_, _, numerator)| { - let constraint = - original_constraints.ratio_width(*numerator, denominator); - constraints.shrink_width(constraint.max_width); - - constraint - }) - .collect::>(); - (0..constraints.max_width) - .zip(&mut split_constraints) - .for_each(|(_, split_constraint)| { - split_constraint.max_width += 1; - }); - - for ((index, _, _), constraint) in - flexible_indices.into_iter().zip(split_constraints) - { - // The unchecked get is safe, since the index is obtained by iterating through the children - // vector in the first place. - let child = unsafe { children.get_unchecked(index) }; - let desired_size = layout(*child, arena, lookup_map, constraint); - - // This won't panic, since the two vectors are the same length. - row_bounds[index] = desired_size; - } - - // Now let's turn each Size into a relative Rect! - let mut current_x = 0; - row_bounds.iter().zip(children).for_each(|(size, child)| { - let bound = Rect::new(current_x, 0, size.width, size.height); - current_x += size.width; - if let Some(node) = arena.get_mut(child) { - node.get_mut().set_bound(bound); - } - }); - - Size { - height: row_bounds.iter().map(|size| size.height).max().unwrap_or(0), - width: row_bounds.into_iter().map(|size| size.width).sum(), - } - } - LayoutNode::Col(col) => { - let children = node.children(arena).collect::>(); - let mut col_bounds = vec![Size::default(); children.len()]; - - if let LayoutRule::Length { length } = col.parent_rule { - constraints.max_width = length; - } - - let (flexible_indices, inflexible_indices): (Vec<_>, Vec<_>) = children - .iter() - .enumerate() - .filter_map(|(itx, node)| { - if let Some(layout_node) = arena.get(*node).map(|n| n.get()) { - match layout_node { - LayoutNode::Row(RowLayout { parent_rule, .. }) - | LayoutNode::Col(ColLayout { parent_rule, .. }) => { - match parent_rule { - LayoutRule::Expand { ratio } => { - Some((itx, true, *ratio)) - } - LayoutRule::Child => Some((itx, false, 0)), - LayoutRule::Length { .. } => Some((itx, false, 0)), - } - } - LayoutNode::Widget(_) => { - if let Some(widget) = lookup_map.get(node) { - match widget.height() { - LayoutRule::Expand { ratio } => { - Some((itx, true, ratio)) - } - LayoutRule::Child => Some((itx, false, 0)), - LayoutRule::Length { length: _ } => { - Some((itx, false, 0)) - } - } - } else { - None - } - } - } - } else { - None - } - }) - .partition(|(_itx, is_flex, _ratio)| *is_flex); - - for (index, _, _) in inflexible_indices { - // The unchecked get is safe, since the index is obtained by iterating through the children - // vector in the first place. - let child = unsafe { children.get_unchecked(index) }; - let desired_size = layout(*child, arena, lookup_map, constraints); - - constraints.shrink_height(desired_size.height); - - // This won't panic, since the two vectors are the same length. - col_bounds[index] = desired_size; - } - - let denominator: u32 = flexible_indices.iter().map(|(_, _, ratio)| ratio).sum(); - let original_constraints = constraints; - let mut split_constraints = flexible_indices - .iter() - .map(|(_, _, numerator)| { - let new_constraint = - original_constraints.ratio_height(*numerator, denominator); - constraints.shrink_height(new_constraint.max_height); - - new_constraint - }) - .collect::>(); - (0..constraints.max_height) - .zip(&mut split_constraints) - .for_each(|(_, split_constraint)| { - split_constraint.max_height += 1; - }); - - for ((index, _, _), constraint) in - flexible_indices.into_iter().zip(split_constraints) - { - // The unchecked get is safe, since the index is obtained by iterating through the children - // vector in the first place. - let child = unsafe { children.get_unchecked(index) }; - let desired_size = layout(*child, arena, lookup_map, constraint); - - // This won't panic, since the two vectors are the same length. - col_bounds[index] = desired_size; - } - - // Now let's turn each Size into a relative Rect! - let mut current_y = 0; - col_bounds.iter().zip(children).for_each(|(size, child)| { - let bound = Rect::new(0, current_y, size.width, size.height); - current_y += size.height; - if let Some(node) = arena.get_mut(child) { - node.get_mut().set_bound(bound); - } - }); - - Size { - width: col_bounds.iter().map(|size| size.width).max().unwrap_or(0), - height: col_bounds.into_iter().map(|size| size.height).sum(), - } - } - LayoutNode::Widget(_) => { - if let Some(widget) = lookup_map.get(&node) { - let width = match widget.width() { - LayoutRule::Expand { ratio: _ } => constraints.max_width, - LayoutRule::Length { length } => min(length, constraints.max_width), - LayoutRule::Child => constraints.max_width, - }; - - let height = match widget.height() { - LayoutRule::Expand { ratio: _ } => constraints.max_height, - LayoutRule::Length { length } => min(length, constraints.max_height), - LayoutRule::Child => constraints.max_height, - }; - - Size { width, height } - } else { - Size::default() - } - } - } - } else { - Size::default() - } - } - - // And this is all you need to call, the layout function will do it all~ - layout( - root, - arena, - lookup_map, - LayoutConstraints::new(area.width, area.height), - ); -} diff --git a/src/app/widgets.rs b/src/app/widgets.rs index a6e09781..2607a51a 100644 --- a/src/app/widgets.rs +++ b/src/app/widgets.rs @@ -156,7 +156,7 @@ pub enum SelectableType { /// The "main" widgets that are used by bottom to display information! #[allow(clippy::large_enum_variant)] #[enum_dispatch(Component, Widget)] -pub enum BottomWidget { +pub enum OldBottomWidget { MemGraph, TempTable, DiskTable, @@ -172,7 +172,7 @@ pub enum BottomWidget { Empty, } -impl Debug for BottomWidget { +impl Debug for OldBottomWidget { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::MemGraph(_) => write!(f, "MemGraph"), diff --git a/src/app/widgets/base/time_graph.rs b/src/app/widgets/base/time_graph.rs index cc2a8c69..7ab4da7c 100644 --- a/src/app/widgets/base/time_graph.rs +++ b/src/app/widgets/base/time_graph.rs @@ -20,7 +20,7 @@ use crate::{ custom_legend_chart::{Axis, Dataset}, TimeChart, }, - AppConfigFields, Component, + AppConfig, Component, }, canvas::Painter, constants::{ @@ -139,7 +139,7 @@ impl TimeGraph { } /// Creates a new [`TimeGraph`] given an [`AppConfigFields`]. - pub fn from_config(app_config_fields: &AppConfigFields) -> Self { + pub fn from_config(app_config_fields: &AppConfig) -> Self { Self::new( app_config_fields.default_time_value, if app_config_fields.hide_time { diff --git a/src/app/widgets/bottom_widgets/basic_cpu.rs b/src/app/widgets/bottom_widgets/basic_cpu.rs index f4aa4435..8d7a67f5 100644 --- a/src/app/widgets/bottom_widgets/basic_cpu.rs +++ b/src/app/widgets/bottom_widgets/basic_cpu.rs @@ -8,7 +8,7 @@ use tui::{ }; use crate::{ - app::{widgets::tui_stuff::PipeGauge, AppConfigFields, Component, DataCollection, Widget}, + app::{widgets::tui_stuff::PipeGauge, AppConfig, Component, DataCollection, Widget}, canvas::Painter, constants::SIDE_BORDERS, options::layout_options::LayoutRule, @@ -26,7 +26,7 @@ pub struct BasicCpu { impl BasicCpu { /// Creates a new [`BasicCpu`] given a [`AppConfigFields`]. - pub fn from_config(app_config_fields: &AppConfigFields) -> Self { + pub fn from_config(app_config_fields: &AppConfig) -> Self { Self { bounds: Default::default(), display_data: Default::default(), diff --git a/src/app/widgets/bottom_widgets/basic_net.rs b/src/app/widgets/bottom_widgets/basic_net.rs index a739fd25..2f243d5d 100644 --- a/src/app/widgets/bottom_widgets/basic_net.rs +++ b/src/app/widgets/bottom_widgets/basic_net.rs @@ -7,7 +7,7 @@ use tui::{ }; use crate::{ - app::{AppConfigFields, AxisScaling, Component, DataCollection, Widget}, + app::{AppConfig, AxisScaling, Component, DataCollection, Widget}, canvas::Painter, constants::SIDE_BORDERS, data_conversion::convert_network_data_points, @@ -31,7 +31,7 @@ pub struct BasicNet { impl BasicNet { /// Creates a new [`BasicNet`] given a [`AppConfigFields`]. - pub fn from_config(app_config_fields: &AppConfigFields) -> Self { + pub fn from_config(app_config_fields: &AppConfig) -> Self { Self { bounds: Default::default(), width: Default::default(), diff --git a/src/app/widgets/bottom_widgets/cpu.rs b/src/app/widgets/bottom_widgets/cpu.rs index 9d01cdf9..9f14a441 100644 --- a/src/app/widgets/bottom_widgets/cpu.rs +++ b/src/app/widgets/bottom_widgets/cpu.rs @@ -13,7 +13,7 @@ use crate::{ text_table::SimpleColumn, time_graph::TimeGraphData, widgets::tui_stuff::BlockBuilder, - AppConfigFields, Component, DataCollection, TextTable, TimeGraph, Widget, + AppConfig, Component, DataCollection, TextTable, TimeGraph, Widget, }, canvas::Painter, data_conversion::{convert_cpu_data_points, ConvertedCpuData}, @@ -51,7 +51,7 @@ pub struct CpuGraph { impl CpuGraph { /// Creates a new [`CpuGraph`] from a config. - pub fn from_config(app_config_fields: &AppConfigFields) -> Self { + pub fn from_config(app_config_fields: &AppConfig) -> Self { let graph = TimeGraph::from_config(app_config_fields); let legend = TextTable::new(vec![ SimpleColumn::new_flex("CPU".into(), 0.5), diff --git a/src/app/widgets/bottom_widgets/disk.rs b/src/app/widgets/bottom_widgets/disk.rs index e23b2f4b..ad77f8fe 100644 --- a/src/app/widgets/bottom_widgets/disk.rs +++ b/src/app/widgets/bottom_widgets/disk.rs @@ -4,7 +4,7 @@ use tui::{backend::Backend, layout::Rect, widgets::Borders, Frame}; use crate::{ app::{ data_farmer::DataCollection, event::ComponentEventResult, - sort_text_table::SimpleSortableColumn, text_table::TextTableData, AppConfigFields, + sort_text_table::SimpleSortableColumn, text_table::TextTableData, AppConfig, Component, TextTable, Widget, }, canvas::Painter, @@ -27,7 +27,7 @@ pub struct DiskTable { impl DiskTable { /// Creates a [`DiskTable`] from a config. - pub fn from_config(app_config_fields: &AppConfigFields) -> Self { + pub fn from_config(app_config_fields: &AppConfig) -> Self { let table = TextTable::new(vec![ SimpleSortableColumn::new_flex("Disk".into(), None, false, 0.2), SimpleSortableColumn::new_flex("Mount".into(), None, false, 0.2), diff --git a/src/app/widgets/bottom_widgets/net.rs b/src/app/widgets/bottom_widgets/net.rs index 1f13380d..0f72fad9 100644 --- a/src/app/widgets/bottom_widgets/net.rs +++ b/src/app/widgets/bottom_widgets/net.rs @@ -10,7 +10,7 @@ use tui::{ use crate::{ app::{ data_farmer::DataCollection, event::ComponentEventResult, text_table::SimpleColumn, - time_graph::TimeGraphData, widgets::tui_stuff::BlockBuilder, AppConfigFields, AxisScaling, + time_graph::TimeGraphData, widgets::tui_stuff::BlockBuilder, AppConfig, AxisScaling, Component, TextTable, TimeGraph, Widget, }, canvas::Painter, @@ -387,7 +387,7 @@ pub struct NetGraph { impl NetGraph { /// Creates a new [`NetGraph`] given a [`AppConfigFields`]. - pub fn from_config(app_config_fields: &AppConfigFields) -> Self { + pub fn from_config(app_config_fields: &AppConfig) -> Self { let graph = TimeGraph::from_config(app_config_fields); Self { @@ -590,7 +590,7 @@ pub struct OldNetGraph { impl OldNetGraph { /// Creates a new [`OldNetGraph`] from a [`AppConfigFields`]. - pub fn from_config(config: &AppConfigFields) -> Self { + pub fn from_config(config: &AppConfig) -> Self { Self { net_graph: NetGraph::from_config(config).hide_legend(), table: TextTable::new(vec![ diff --git a/src/app/widgets/bottom_widgets/process.rs b/src/app/widgets/bottom_widgets/process.rs index ed540d28..1cbeebb7 100644 --- a/src/app/widgets/bottom_widgets/process.rs +++ b/src/app/widgets/bottom_widgets/process.rs @@ -22,7 +22,7 @@ use crate::{ query::*, text_table::{DesiredColumnWidth, TextTableRow}, widgets::tui_stuff::BlockBuilder, - AppConfigFields, DataCollection, ProcessData, + AppConfig, DataCollection, ProcessData, }, canvas::Painter, data_conversion::{get_string_with_bytes, get_string_with_bytes_per_second}, @@ -278,7 +278,7 @@ pub struct ProcessManager { impl ProcessManager { /// Creates a new [`ProcessManager`]. - pub fn new(process_defaults: &ProcessDefaults, config: &AppConfigFields) -> Self { + pub fn new(process_defaults: &ProcessDefaults, config: &AppConfig) -> Self { let process_table_columns = vec![ ProcessSortColumn::new(ProcessSortType::Pid), ProcessSortColumn::new(ProcessSortType::Name), diff --git a/src/app/widgets/bottom_widgets/temp.rs b/src/app/widgets/bottom_widgets/temp.rs index c6dfcff7..44071ffe 100644 --- a/src/app/widgets/bottom_widgets/temp.rs +++ b/src/app/widgets/bottom_widgets/temp.rs @@ -5,7 +5,7 @@ use crate::{ app::{ data_farmer::DataCollection, data_harvester::temperature::TemperatureType, event::ComponentEventResult, sort_text_table::SimpleSortableColumn, - text_table::TextTableData, AppConfigFields, Component, TextTable, Widget, + text_table::TextTableData, AppConfig, Component, TextTable, Widget, }, canvas::Painter, data_conversion::convert_temp_row, @@ -26,7 +26,7 @@ pub struct TempTable { impl TempTable { /// Creates a [`TempTable`] from a config. - pub fn from_config(app_config_fields: &AppConfigFields) -> Self { + pub fn from_config(app_config_fields: &AppConfig) -> Self { let table = TextTable::new(vec![ SimpleSortableColumn::new_flex("Sensor".into(), None, false, 0.8), SimpleSortableColumn::new_hard("Temp".into(), None, false, Some(5)), diff --git a/src/bin/main.rs b/src/bin/main.rs index 4292487c..73ac1732 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -77,7 +77,7 @@ fn main() -> Result<()> { collection_thread_ctrl_receiver, thread_termination_lock.clone(), thread_termination_cvar.clone(), - &app.app_config_fields, + &app.app_config, app.filters.clone(), app.used_widgets.clone(), ); diff --git a/src/canvas.rs b/src/canvas.rs index cf112ab0..eb30d1f3 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -1,29 +1,8 @@ use std::str::FromStr; -use indextree::{Arena, NodeId}; -use rustc_hash::FxHashMap; -use tui::{ - backend::Backend, - layout::{Constraint, Layout, Rect}, - text::Span, - widgets::Paragraph, - Frame, Terminal, -}; - use canvas_colours::*; -use crate::{ - app::{ - self, - layout_manager::{generate_layout, ColLayout, LayoutNode, RowLayout}, - widgets::{Component, Widget}, - BottomWidget, - }, - constants::*, - options::Config, - utils::error, - utils::error::BottomError, -}; +use crate::{constants::*, options::Config, utils::error, utils::error::BottomError}; mod canvas_colours; diff --git a/src/data_conversion.rs b/src/data_conversion.rs index 74fe5892..509a0342 100644 --- a/src/data_conversion.rs +++ b/src/data_conversion.rs @@ -8,19 +8,24 @@ use crate::{app::AxisScaling, units::data_units::DataUnit}; use std::borrow::Cow; /// Stores converted data, and caches results. -#[derive(Default)] -pub struct ConvertedData { +pub struct ConvertedData<'a> { + data: &'a DataCollection, temp_table: Option>>>, } -impl ConvertedData { - pub fn temp_table( - &mut self, data: &DataCollection, temp_type: TemperatureType, - ) -> Vec>> { +impl<'a> ConvertedData<'a> { + pub fn new(data: &'a DataCollection) -> Self { + Self { + data, + temp_table: None, + } + } + + pub fn temp_table(&mut self, temp_type: TemperatureType) -> Vec>> { match &self.temp_table { Some(temp_table) => temp_table.clone(), None => { - let temp_table = if data.temp_harvest.is_empty() { + let temp_table = if self.data.temp_harvest.is_empty() { vec![vec!["No Sensors Found".into(), "".into()]] } else { let unit = match temp_type { @@ -29,7 +34,8 @@ impl ConvertedData { data_harvester::temperature::TemperatureType::Fahrenheit => "°F", }; - data.temp_harvest + self.data + .temp_harvest .iter() .map(|temp_harvest| { let val = temp_harvest.temperature.ceil().to_string(); diff --git a/src/lib.rs b/src/lib.rs index 2d87db49..cecb00e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,7 +60,7 @@ pub type Pid = libc::pid_t; #[derive(Debug)] pub enum ThreadControlEvent { Reset, - UpdateConfig(Box), + UpdateConfig(Box), UpdateUsedWidgets(Box), UpdateUpdateTime(u64), } @@ -247,7 +247,7 @@ pub fn create_collection_thread( sender: std::sync::mpsc::Sender>, control_receiver: std::sync::mpsc::Receiver, termination_ctrl_lock: Arc>, termination_ctrl_cvar: Arc, - app_config_fields: &app::AppConfigFields, filters: app::DataFilters, + app_config_fields: &app::AppConfig, filters: app::DataFilters, used_widget_set: UsedWidgets, ) -> std::thread::JoinHandle<()> { let temp_type = app_config_fields.temperature_type.clone(); diff --git a/src/options.rs b/src/options.rs index 57ff4aae..93cca743 100644 --- a/src/options.rs +++ b/src/options.rs @@ -20,7 +20,7 @@ use anyhow::{Context, Result}; pub struct Config { pub flags: Option, pub colors: Option, - pub row: Option>, + pub row: Option>, pub disk_filter: Option, pub mount_filter: Option, pub temp_filter: Option, @@ -191,7 +191,7 @@ pub fn build_app(matches: &clap::ArgMatches<'static>, config: &mut Config) -> Re let network_scale_type = get_network_scale_type(matches, config); let network_use_binary_prefix = get_network_use_binary_prefix(matches, config); - let app_config_fields = AppConfigFields { + let app_config_fields = AppConfig { update_rate_in_milliseconds: get_update_rate_in_milliseconds(matches, config) .context("Update 'rate' in your config file.")?, temperature_type: get_temperature(matches, config) @@ -218,28 +218,31 @@ pub fn build_app(matches: &clap::ArgMatches<'static>, config: &mut Config) -> Re network_use_binary_prefix, }; - let layout_tree_output = if let Some(row) = &config.row { - create_layout_tree(row, process_defaults, &app_config_fields)? + let rows: Vec; + let row_ref = if let Some(row) = &config.row { + row } else if get_use_basic_mode(matches, config) { if get_use_battery(matches, config) { - let rows = toml::from_str::(DEFAULT_BASIC_BATTERY_LAYOUT)? + rows = toml::from_str::(DEFAULT_BASIC_BATTERY_LAYOUT)? .row .unwrap(); - create_layout_tree(&rows, process_defaults, &app_config_fields)? + &rows } else { - let rows = toml::from_str::(DEFAULT_BASIC_LAYOUT)?.row.unwrap(); - create_layout_tree(&rows, process_defaults, &app_config_fields)? + rows = toml::from_str::(DEFAULT_BASIC_LAYOUT)?.row.unwrap(); + &rows } } else if get_use_battery(matches, config) { - let rows = toml::from_str::(DEFAULT_BATTERY_LAYOUT)? + rows = toml::from_str::(DEFAULT_BATTERY_LAYOUT)? .row .unwrap(); - create_layout_tree(&rows, process_defaults, &app_config_fields)? + &rows } else { - let rows = toml::from_str::(DEFAULT_LAYOUT)?.row.unwrap(); - create_layout_tree(&rows, process_defaults, &app_config_fields)? + rows = toml::from_str::(DEFAULT_LAYOUT)?.row.unwrap(); + &rows }; + let layout_tree_output = create_layout_tree(row_ref, process_defaults, &app_config_fields)?; + let disk_filter = get_ignore_list(&config.disk_filter).context("Update 'disk_filter' in your config file")?; let mount_filter = get_ignore_list(&config.mount_filter) diff --git a/src/options/layout_options.rs b/src/options/layout_options.rs index 23815819..30eb699e 100644 --- a/src/options/layout_options.rs +++ b/src/options/layout_options.rs @@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize}; /// of children. #[derive(Clone, Deserialize, Debug, Serialize)] #[serde(rename = "row")] -pub struct Row { - pub child: Option>, +pub struct LayoutRow { + pub child: Option>, pub ratio: Option, } @@ -16,14 +16,14 @@ pub struct Row { /// recursion between Row and Col. #[derive(Clone, Deserialize, Debug, Serialize)] #[serde(untagged)] -pub enum RowChildren { +pub enum LayoutRowChild { Widget(FinalWidget), /// The first one in the list is the "default" selected widget. Carousel { carousel_children: Vec, default: Option, }, - Col { + LayoutCol { ratio: Option, child: Vec, }, diff --git a/src/tuine/component/widget/battery_table.rs b/src/tuine/component/widget/battery_table.rs index e69de29b..c1bd7e50 100644 --- a/src/tuine/component/widget/battery_table.rs +++ b/src/tuine/component/widget/battery_table.rs @@ -0,0 +1,30 @@ +use tui::{text::Text, widgets::Paragraph, Frame}; + +use crate::tuine::{DrawContext, StateContext, TmpComponent}; + +/// A [`BatteryTable`] is a widget displaying battery stats. +pub struct BatteryTable {} + +impl super::AppWidget for BatteryTable { + fn build( + ctx: &mut crate::tuine::ViewContext<'_>, painter: &crate::canvas::Painter, + config: &crate::app::AppConfig, data: &mut crate::data_conversion::ConvertedData<'_>, + ) -> Self { + Self {} + } +} + +impl TmpComponent for BatteryTable { + fn draw( + &mut self, _state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, + frame: &mut Frame<'_, Backend>, + ) where + Backend: tui::backend::Backend, + { + let rect = draw_ctx.global_rect(); + frame.render_widget( + Paragraph::new(Text::raw("Battery Table")).block(tui::widgets::Block::default()), + rect, + ); + } +} diff --git a/src/tuine/component/widget/cpu_graph.rs b/src/tuine/component/widget/cpu_graph.rs index e69de29b..18e240b0 100644 --- a/src/tuine/component/widget/cpu_graph.rs +++ b/src/tuine/component/widget/cpu_graph.rs @@ -0,0 +1,31 @@ +use tui::{text::Text, widgets::Paragraph, Frame}; + +use crate::tuine::{DrawContext, StateContext, TmpComponent}; + +/// A [`CpuGraph`] is a widget displaying CPU data in a graph-like form, and with controls for showing only +/// specific plots. +pub struct CpuGraph {} + +impl super::AppWidget for CpuGraph { + fn build( + ctx: &mut crate::tuine::ViewContext<'_>, painter: &crate::canvas::Painter, + config: &crate::app::AppConfig, data: &mut crate::data_conversion::ConvertedData<'_>, + ) -> Self { + Self {} + } +} + +impl TmpComponent for CpuGraph { + fn draw( + &mut self, _state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, + frame: &mut Frame<'_, Backend>, + ) where + Backend: tui::backend::Backend, + { + let rect = draw_ctx.global_rect(); + frame.render_widget( + Paragraph::new(Text::raw("CPU Graph")).block(tui::widgets::Block::default()), + rect, + ); + } +} diff --git a/src/tuine/component/widget/cpu_simple.rs b/src/tuine/component/widget/cpu_simple.rs index e69de29b..e20208f7 100644 --- a/src/tuine/component/widget/cpu_simple.rs +++ b/src/tuine/component/widget/cpu_simple.rs @@ -0,0 +1,30 @@ +use tui::{text::Text, widgets::Paragraph, Frame}; + +use crate::tuine::{DrawContext, StateContext, TmpComponent}; + +/// A [`CpuSimple`] is a widget displaying simple CPU stats. +pub struct CpuSimple {} + +impl super::AppWidget for CpuSimple { + fn build( + ctx: &mut crate::tuine::ViewContext<'_>, painter: &crate::canvas::Painter, + config: &crate::app::AppConfig, data: &mut crate::data_conversion::ConvertedData<'_>, + ) -> Self { + Self {} + } +} + +impl TmpComponent for CpuSimple { + fn draw( + &mut self, _state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, + frame: &mut Frame<'_, Backend>, + ) where + Backend: tui::backend::Backend, + { + let rect = draw_ctx.global_rect(); + frame.render_widget( + Paragraph::new(Text::raw("CPU Simple")).block(tui::widgets::Block::default()), + rect, + ); + } +} diff --git a/src/tuine/component/widget/disk_table.rs b/src/tuine/component/widget/disk_table.rs index e69de29b..42927cb1 100644 --- a/src/tuine/component/widget/disk_table.rs +++ b/src/tuine/component/widget/disk_table.rs @@ -0,0 +1,30 @@ +use tui::{text::Text, widgets::Paragraph, Frame}; + +use crate::tuine::{DrawContext, StateContext, TmpComponent}; + +/// A [`DiskTable`] is a table displaying disk data. +pub struct DiskTable {} + +impl super::AppWidget for DiskTable { + fn build( + ctx: &mut crate::tuine::ViewContext<'_>, painter: &crate::canvas::Painter, + config: &crate::app::AppConfig, data: &mut crate::data_conversion::ConvertedData<'_>, + ) -> Self { + Self {} + } +} + +impl TmpComponent for DiskTable { + fn draw( + &mut self, _state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, + frame: &mut Frame<'_, Backend>, + ) where + Backend: tui::backend::Backend, + { + let rect = draw_ctx.global_rect(); + frame.render_widget( + Paragraph::new(Text::raw("Disk Table")).block(tui::widgets::Block::default()), + rect, + ); + } +} diff --git a/src/tuine/component/widget/mem_graph.rs b/src/tuine/component/widget/mem_graph.rs index e69de29b..e93ff46c 100644 --- a/src/tuine/component/widget/mem_graph.rs +++ b/src/tuine/component/widget/mem_graph.rs @@ -0,0 +1,30 @@ +use tui::{text::Text, widgets::Paragraph, Frame}; + +use crate::tuine::{DrawContext, StateContext, TmpComponent}; + +/// A [`MemGraph`] is a widget displaying RAM/SWAP data in a graph-like form. +pub struct MemGraph {} + +impl super::AppWidget for MemGraph { + fn build( + ctx: &mut crate::tuine::ViewContext<'_>, painter: &crate::canvas::Painter, + config: &crate::app::AppConfig, data: &mut crate::data_conversion::ConvertedData<'_>, + ) -> Self { + Self {} + } +} + +impl TmpComponent for MemGraph { + fn draw( + &mut self, _state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, + frame: &mut Frame<'_, Backend>, + ) where + Backend: tui::backend::Backend, + { + let rect = draw_ctx.global_rect(); + frame.render_widget( + Paragraph::new(Text::raw("Mem Graph")).block(tui::widgets::Block::default()), + rect, + ); + } +} diff --git a/src/tuine/component/widget/mem_simple.rs b/src/tuine/component/widget/mem_simple.rs index e69de29b..0b3a6fb1 100644 --- a/src/tuine/component/widget/mem_simple.rs +++ b/src/tuine/component/widget/mem_simple.rs @@ -0,0 +1,30 @@ +use tui::{text::Text, widgets::Paragraph, Frame}; + +use crate::tuine::{DrawContext, StateContext, TmpComponent}; + +/// A [`MemSimple`] is a widget displaying simple CPU stats. +pub struct MemSimple {} + +impl super::AppWidget for MemSimple { + fn build( + ctx: &mut crate::tuine::ViewContext<'_>, painter: &crate::canvas::Painter, + config: &crate::app::AppConfig, data: &mut crate::data_conversion::ConvertedData<'_>, + ) -> Self { + Self {} + } +} + +impl TmpComponent for MemSimple { + fn draw( + &mut self, _state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, + frame: &mut Frame<'_, Backend>, + ) where + Backend: tui::backend::Backend, + { + let rect = draw_ctx.global_rect(); + frame.render_widget( + Paragraph::new(Text::raw("Mem Simple")).block(tui::widgets::Block::default()), + rect, + ); + } +} diff --git a/src/tuine/component/widget/mod.rs b/src/tuine/component/widget/mod.rs index 57ee7577..ca788d12 100644 --- a/src/tuine/component/widget/mod.rs +++ b/src/tuine/component/widget/mod.rs @@ -1,3 +1,6 @@ +use anyhow::{anyhow, Result}; +use enum_dispatch::enum_dispatch; + pub mod simple_table; pub use simple_table::*; @@ -30,3 +33,12 @@ pub use mem_simple::*; pub mod net_simple; pub use net_simple::*; + +use crate::{app::AppConfig, canvas::Painter, data_conversion::ConvertedData, tuine::ViewContext}; + +pub trait AppWidget { + fn build( + ctx: &mut ViewContext<'_>, painter: &Painter, config: &AppConfig, + data: &mut ConvertedData<'_>, + ) -> Self; +} diff --git a/src/tuine/component/widget/net_graph.rs b/src/tuine/component/widget/net_graph.rs index e69de29b..e4abf549 100644 --- a/src/tuine/component/widget/net_graph.rs +++ b/src/tuine/component/widget/net_graph.rs @@ -0,0 +1,30 @@ +use tui::{text::Text, widgets::Paragraph, Frame}; + +use crate::tuine::{DrawContext, StateContext, TmpComponent}; + +/// A [`NetGraph`] is a widget displaying RAM/SWAP data in a graph-like form. +pub struct NetGraph {} + +impl super::AppWidget for NetGraph { + fn build( + ctx: &mut crate::tuine::ViewContext<'_>, painter: &crate::canvas::Painter, + config: &crate::app::AppConfig, data: &mut crate::data_conversion::ConvertedData<'_>, + ) -> Self { + Self {} + } +} + +impl TmpComponent for NetGraph { + fn draw( + &mut self, _state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, + frame: &mut Frame<'_, Backend>, + ) where + Backend: tui::backend::Backend, + { + let rect = draw_ctx.global_rect(); + frame.render_widget( + Paragraph::new(Text::raw("Net Graph")).block(tui::widgets::Block::default()), + rect, + ); + } +} diff --git a/src/tuine/component/widget/net_simple.rs b/src/tuine/component/widget/net_simple.rs index e69de29b..60e704ea 100644 --- a/src/tuine/component/widget/net_simple.rs +++ b/src/tuine/component/widget/net_simple.rs @@ -0,0 +1,30 @@ +use tui::{text::Text, widgets::Paragraph, Frame}; + +use crate::tuine::{DrawContext, StateContext, TmpComponent}; + +/// A [`NetSimple`] is a widget displaying simple CPU stats. +pub struct NetSimple {} + +impl super::AppWidget for NetSimple { + fn build( + ctx: &mut crate::tuine::ViewContext<'_>, painter: &crate::canvas::Painter, + config: &crate::app::AppConfig, data: &mut crate::data_conversion::ConvertedData<'_>, + ) -> Self { + Self {} + } +} + +impl TmpComponent for NetSimple { + fn draw( + &mut self, _state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, + frame: &mut Frame<'_, Backend>, + ) where + Backend: tui::backend::Backend, + { + let rect = draw_ctx.global_rect(); + frame.render_widget( + Paragraph::new(Text::raw("Net Simple")).block(tui::widgets::Block::default()), + rect, + ); + } +} diff --git a/src/tuine/component/widget/process_table.rs b/src/tuine/component/widget/process_table.rs index e69de29b..03f97f01 100644 --- a/src/tuine/component/widget/process_table.rs +++ b/src/tuine/component/widget/process_table.rs @@ -0,0 +1,30 @@ +use tui::{text::Text, widgets::Paragraph, Frame}; + +use crate::tuine::{DrawContext, StateContext, TmpComponent}; + +/// A [`ProcessTable`] is a widget displaying process data, and with controls for searching/filtering entries. +pub struct ProcessTable {} + +impl super::AppWidget for ProcessTable { + fn build( + ctx: &mut crate::tuine::ViewContext<'_>, painter: &crate::canvas::Painter, + config: &crate::app::AppConfig, data: &mut crate::data_conversion::ConvertedData<'_>, + ) -> Self { + Self {} + } +} + +impl TmpComponent for ProcessTable { + fn draw( + &mut self, _state_ctx: &mut StateContext<'_>, draw_ctx: &DrawContext<'_>, + frame: &mut Frame<'_, Backend>, + ) where + Backend: tui::backend::Backend, + { + let rect = draw_ctx.global_rect(); + frame.render_widget( + Paragraph::new(Text::raw("Process Table")).block(tui::widgets::Block::default()), + rect, + ); + } +} diff --git a/src/tuine/component/widget/temp_table.rs b/src/tuine/component/widget/temp_table.rs index 5985b6ed..3dbd1b95 100644 --- a/src/tuine/component/widget/temp_table.rs +++ b/src/tuine/component/widget/temp_table.rs @@ -1,12 +1,14 @@ use crate::{ + app::AppConfig, canvas::Painter, + data_conversion::ConvertedData, tuine::{ Bounds, DataRow, DrawContext, LayoutNode, SimpleTable, Size, StateContext, Status, TmpComponent, ViewContext, }, }; -use super::simple_table; +use super::{simple_table, AppWidget}; /// A [`TempTable`] is a table displaying temperature data. /// @@ -15,9 +17,12 @@ pub struct TempTable { inner: SimpleTable, } -impl TempTable { - pub fn build>( - ctx: &mut ViewContext<'_>, painter: &Painter, data: Vec, +impl TempTable {} + +impl AppWidget for TempTable { + fn build( + ctx: &mut ViewContext<'_>, painter: &Painter, config: &AppConfig, + data: &mut ConvertedData<'_>, ) -> Self { let style = simple_table::StyleSheet { text: painter.colours.text_style, @@ -25,9 +30,10 @@ impl TempTable { table_header: painter.colours.table_header_style, border: painter.colours.border_style, }; + let rows = data.temp_table(config.temperature_type); Self { - inner: SimpleTable::build(ctx, style, vec!["Sensor", "Temp"], data), + inner: SimpleTable::build(ctx, style, vec!["Sensor", "Temp"], rows), } } } diff --git a/src/tuine/element.rs b/src/tuine/element.rs index 50031aab..a24590f7 100644 --- a/src/tuine/element.rs +++ b/src/tuine/element.rs @@ -1,10 +1,7 @@ use enum_dispatch::enum_dispatch; use tui::Frame; -use super::{ - Block, Bounds, Carousel, Container, DrawContext, Empty, Event, Flex, LayoutNode, Shortcut, - SimpleTable, Size, StateContext, Status, TempTable, TextTable, TmpComponent, -}; +use super::*; /// An [`Element`] is an instantiated [`Component`]. #[enum_dispatch(TmpComponent)] @@ -19,6 +16,15 @@ where Shortcut(Shortcut), TextTable(TextTable), Empty, + BatteryTable(BatteryTable), + CpuGraph(CpuGraph), + CpuSimple(CpuSimple), + DiskTable(DiskTable), + MemGraph(MemGraph), + MemSimple(MemSimple), + NetGraph(NetGraph), + NetSimple(NetSimple), + ProcessTable(ProcessTable), SimpleTable(SimpleTable), TempTable(TempTable), }