Skip to content

Commit

Permalink
refactor: port over graph widgets
Browse files Browse the repository at this point in the history
Things working as of now:
- Actually drawing
- Interpolation
- Styling
  • Loading branch information
ClementTsang committed Aug 29, 2021
1 parent b72e76a commit 2bff04d
Show file tree
Hide file tree
Showing 21 changed files with 2,163 additions and 322 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ clap = "2.33"
cfg-if = "1.0"
dirs = "3.0.2"
enum_dispatch = "0.3.7"
float-ord = "0.3.2"
futures = "0.3.14"
futures-timer = "3.0.2"
fxhash = "0.2.1"
Expand Down
92 changes: 5 additions & 87 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use indextree::{Arena, NodeId};
use unicode_segmentation::GraphemeCursor;
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};

use data_farmer::*;
pub use data_farmer::*;
use data_harvester::{processes, temperature};
pub use filter::*;
use layout_manager::*;
Expand All @@ -28,9 +28,7 @@ pub use widgets::*;
use crate::{
canvas,
constants::{self, MAX_SIGNAL},
data_conversion::*,
units::data_units::DataUnit,
update_final_process_list,
utils::error::{BottomError, Result},
BottomEvent, Pid,
};
Expand Down Expand Up @@ -367,7 +365,10 @@ impl AppState {
self.data_collection.eat_data(new_data);

if !self.is_frozen {
self.convert_data();
let data_collection = &self.data_collection;
self.widget_lookup_map
.iter_mut()
.for_each(|(_id, widget)| widget.update_data(data_collection));

EventResult::Redraw
} else {
Expand Down Expand Up @@ -395,89 +396,6 @@ impl AppState {
}
}

fn convert_data(&mut self) {
// TODO: Probably refactor this.

// Network
if self.used_widgets.use_net {
let network_data = convert_network_data_points(
&self.data_collection,
false,
self.app_config_fields.use_basic_mode
|| self.app_config_fields.use_old_network_legend,
&self.app_config_fields.network_scale_type,
&self.app_config_fields.network_unit_type,
self.app_config_fields.network_use_binary_prefix,
);
self.canvas_data.network_data_rx = network_data.rx;
self.canvas_data.network_data_tx = network_data.tx;
self.canvas_data.rx_display = network_data.rx_display;
self.canvas_data.tx_display = network_data.tx_display;
if let Some(total_rx_display) = network_data.total_rx_display {
self.canvas_data.total_rx_display = total_rx_display;
}
if let Some(total_tx_display) = network_data.total_tx_display {
self.canvas_data.total_tx_display = total_tx_display;
}
}

// Disk
if self.used_widgets.use_disk {
self.canvas_data.disk_data = convert_disk_row(&self.data_collection);
}

// Temperatures
if self.used_widgets.use_temp {
self.canvas_data.temp_sensor_data = convert_temp_row(&self);
}

// Memory
if self.used_widgets.use_mem {
self.canvas_data.mem_data = convert_mem_data_points(&self.data_collection, false);
self.canvas_data.swap_data = convert_swap_data_points(&self.data_collection, false);
let (memory_labels, swap_labels) = convert_mem_labels(&self.data_collection);

self.canvas_data.mem_labels = memory_labels;
self.canvas_data.swap_labels = swap_labels;
}

if self.used_widgets.use_cpu {
// CPU
convert_cpu_data_points(&self.data_collection, &mut self.canvas_data.cpu_data, false);
self.canvas_data.load_avg_data = self.data_collection.load_avg_harvest;
}

// Processes
if self.used_widgets.use_proc {
self.update_all_process_lists();
}

// Battery
if self.used_widgets.use_battery {
self.canvas_data.battery_data = convert_battery_harvest(&self.data_collection);
}
}

#[allow(clippy::needless_collect)]
fn update_all_process_lists(&mut self) {
// TODO: Probably refactor this.

// According to clippy, I can avoid a collect... but if I follow it,
// I end up conflicting with the borrow checker since app is used within the closure... hm.
if !self.is_frozen {
let widget_ids = self
.proc_state
.widget_states
.keys()
.cloned()
.collect::<Vec<_>>();

widget_ids.into_iter().for_each(|widget_id| {
update_final_process_list(self, widget_id);
});
}
}

pub fn on_esc(&mut self) {
self.reset_multi_tap_keys();
if self.is_in_dialog() {
Expand Down
40 changes: 18 additions & 22 deletions src/app/layout_manager.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use crate::{
app::{
sort_text_table::SortableColumn, DiskTable, MemGraph, NetGraph, OldNetGraph,
ProcessManager, TempTable,
},
app::{DiskTable, MemGraph, NetGraph, OldNetGraph, ProcessManager, TempTable},
error::{BottomError, Result},
options::layout_options::{Row, RowChildren},
};
Expand All @@ -16,7 +13,7 @@ use crate::app::widgets::Widget;
use crate::constants::DEFAULT_WIDGET_ID;

use super::{
event::SelectionAction, CpuGraph, SortableTextTable, TimeGraph, TmpBottomWidget, UsedWidgets,
event::SelectionAction, AppConfigFields, CpuGraph, TimeGraph, TmpBottomWidget, UsedWidgets,
};

/// Represents a more usable representation of the layout, derived from the
Expand Down Expand Up @@ -1051,44 +1048,43 @@ pub struct LayoutCreationOutput {
// FIXME: 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: crate::options::ProcessDefaults,
app_config_fields: &super::AppConfigFields,
app_config_fields: &AppConfigFields,
) -> Result<LayoutCreationOutput> {
fn add_widget_to_map(
widget_lookup_map: &mut FxHashMap<NodeId, TmpBottomWidget>, widget_type: BottomWidgetType,
widget_id: NodeId, process_defaults: &crate::options::ProcessDefaults,
app_config_fields: &super::AppConfigFields,
app_config_fields: &AppConfigFields,
) -> Result<()> {
match widget_type {
BottomWidgetType::Cpu => {
let graph = TimeGraph::from_config(app_config_fields);
let legend = SortableTextTable::new(vec![
SortableColumn::new_flex("CPU".into(), None, false, 0.5),
SortableColumn::new_flex("Use%".into(), None, false, 0.5),
]);
let legend_position = super::CpuGraphLegendPosition::Right;

widget_lookup_map.insert(
widget_id,
CpuGraph::new(graph, legend, legend_position).into(),
);
widget_lookup_map
.insert(widget_id, CpuGraph::from_config(app_config_fields).into());
}
BottomWidgetType::Mem => {
let graph = TimeGraph::from_config(app_config_fields);
widget_lookup_map.insert(widget_id, MemGraph::new(graph).into());
}
BottomWidgetType::Net => {
let graph = TimeGraph::from_config(app_config_fields);
if app_config_fields.use_old_network_legend {
widget_lookup_map.insert(widget_id, OldNetGraph::new(graph).into());
widget_lookup_map.insert(
widget_id,
OldNetGraph::from_config(app_config_fields).into(),
);
} else {
widget_lookup_map.insert(widget_id, NetGraph::new(graph).into());
widget_lookup_map
.insert(widget_id, NetGraph::from_config(app_config_fields).into());
}
}
BottomWidgetType::Proc => {
widget_lookup_map.insert(widget_id, ProcessManager::new(process_defaults).into());
}
BottomWidgetType::Temp => {
widget_lookup_map.insert(widget_id, TempTable::default().into());
widget_lookup_map.insert(
widget_id,
TempTable::default()
.set_temp_type(app_config_fields.temperature_type.clone())
.into(),
);
}
BottomWidgetType::Disk => {
widget_lookup_map.insert(widget_id, DiskTable::default().into());
Expand Down
16 changes: 9 additions & 7 deletions src/app/widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ use crate::{
event::{EventResult, SelectionAction},
layout_manager::BottomWidgetType,
},
canvas::{DisplayableData, Painter},
canvas::Painter,
constants,
};

mod tui_widgets;

pub mod base;
pub use base::*;

Expand All @@ -37,6 +39,8 @@ pub use self::battery::*;
pub mod temp;
pub use temp::*;

use super::data_farmer::DataCollection;

/// A trait for things that are drawn with state.
#[enum_dispatch]
#[allow(unused_variables)]
Expand Down Expand Up @@ -75,9 +79,6 @@ pub trait Component {
#[enum_dispatch]
#[allow(unused_variables)]
pub trait Widget {
/// Updates a [`Widget`] given some data. Defaults to doing nothing.
fn update(&mut self) {}

/// Handles what to do when trying to respond to a widget selection movement to the left.
/// Defaults to just moving to the next-possible widget in that direction.
fn handle_widget_selection_left(&mut self) -> SelectionAction {
Expand Down Expand Up @@ -107,12 +108,13 @@ pub trait Widget {

/// Draws a [`Widget`]. Defaults to doing nothing.
fn draw<B: Backend>(
&mut self, painter: &Painter, f: &mut Frame<'_, B>, area: Rect, data: &DisplayableData,
selected: bool,
&mut self, painter: &Painter, f: &mut Frame<'_, B>, area: Rect, selected: bool,
) {
// TODO: Remove the default implementation in the future!
// TODO: Do another pass on ALL of the draw code - currently it's just glue, it should eventually be done properly!
}

/// How a [`Widget`] updates its internal displayed data. Defaults to doing nothing.
fn update_data(&mut self, data_collection: &DataCollection) {}
}

/// The "main" widgets that are used by bottom to display information!
Expand Down
6 changes: 3 additions & 3 deletions src/app/widgets/base/scrollable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl Scrollable {
}

/// Returns the currently selected index of the [`Scrollable`].
pub fn index(&self) -> usize {
pub fn current_index(&self) -> usize {
self.current_index
}

Expand Down Expand Up @@ -195,8 +195,8 @@ impl Scrollable {
self.num_items
}

pub fn tui_state(&self) -> TableState {
self.tui_state.clone()
pub fn tui_state(&mut self) -> &mut TableState {
&mut self.tui_state
}
}

Expand Down
26 changes: 23 additions & 3 deletions src/app/widgets/base/sort_text_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ use std::borrow::Cow;

use crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseEventKind};
use tui::{
backend::Backend,
layout::Rect,
widgets::{Table, TableState},
widgets::{Block, Table, TableState},
};

use crate::app::{event::EventResult, Component, TextTable};
use crate::{
app::{event::EventResult, Component, TextTable},
canvas::Painter,
};

use super::text_table::{DesiredColumnWidth, SimpleColumn, TableColumn};
use super::text_table::{DesiredColumnWidth, SimpleColumn, TableColumn, TextTableData};

fn get_shortcut_name(e: &KeyEvent) -> String {
let modifier = if e.modifiers.is_empty() {
Expand Down Expand Up @@ -182,6 +186,10 @@ impl SortableTextTable {
self
}

pub fn current_index(&self) -> usize {
self.table.current_index()
}

fn set_sort_index(&mut self, new_index: usize) {
if new_index == self.sort_index {
if let Some(column) = self.table.columns.get_mut(self.sort_index) {
Expand Down Expand Up @@ -218,6 +226,18 @@ impl SortableTextTable {
}
}

/// Draws a [`Table`] given the [`TextTable`] and the given data.
///
/// Note if the number of columns don't match in the [`TextTable`] and data,
/// it will only create as many columns as it can grab data from both sources from.
pub fn draw_tui_table<B: Backend>(
&mut self, painter: &Painter, f: &mut tui::Frame<'_, B>, data: &TextTableData,
block: Block<'_>, block_area: Rect, show_selected_entry: bool,
) {
self.table
.draw_tui_table(painter, f, data, block, block_area, show_selected_entry);
}

/// Creates a [`Table`] representing the sort list.
pub fn create_sort_list(&mut self) -> (Table<'_>, TableState) {
todo!()
Expand Down
Loading

0 comments on commit 2bff04d

Please sign in to comment.