mirror of
https://github.com/ClementTsang/bottom.git
synced 2025-07-27 07:34:27 +02:00
refactor: another pass on sorting and columns
This commit is contained in:
parent
64d47d54d3
commit
74293aa243
@ -52,34 +52,80 @@ fn get_shortcut_name(e: &KeyEvent) -> String {
|
|||||||
format!("({}{})", modifier, key).into()
|
format!("({}{})", modifier, key).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
enum SortStatus {
|
pub enum SortStatus {
|
||||||
NotSorting,
|
NotSorting,
|
||||||
SortAscending,
|
SortAscending,
|
||||||
SortDescending,
|
SortDescending,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`SortableColumn`] represents some column in a [`SortableTextTable`].
|
/// A trait for sortable columns.
|
||||||
|
pub trait SortableColumn {
|
||||||
|
/// Returns the shortcut for the column, if it exists.
|
||||||
|
fn shortcut(&self) -> &Option<(KeyEvent, String)>;
|
||||||
|
|
||||||
|
/// Returns whether the column defaults to sorting in descending order or not.
|
||||||
|
fn default_descending(&self) -> bool;
|
||||||
|
|
||||||
|
/// Returns whether the column is currently selected for sorting, and if so,
|
||||||
|
/// what direction.
|
||||||
|
fn sorting_status(&self) -> SortStatus;
|
||||||
|
|
||||||
|
/// Sets the sorting status.
|
||||||
|
fn set_sorting_status(&mut self, sorting_status: SortStatus);
|
||||||
|
|
||||||
|
fn display_name(&self) -> Cow<'static, str>;
|
||||||
|
|
||||||
|
fn get_desired_width(&self) -> &DesiredColumnWidth;
|
||||||
|
|
||||||
|
fn get_x_bounds(&self) -> Option<(u16, u16)>;
|
||||||
|
|
||||||
|
fn set_x_bounds(&mut self, x_bounds: Option<(u16, u16)>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> TableColumn for T
|
||||||
|
where
|
||||||
|
T: SortableColumn,
|
||||||
|
{
|
||||||
|
fn display_name(&self) -> Cow<'static, str> {
|
||||||
|
self.display_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_desired_width(&self) -> &DesiredColumnWidth {
|
||||||
|
self.get_desired_width()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_x_bounds(&self) -> Option<(u16, u16)> {
|
||||||
|
self.get_x_bounds()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_x_bounds(&mut self, x_bounds: Option<(u16, u16)>) {
|
||||||
|
self.set_x_bounds(x_bounds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [`SimpleSortableColumn`] represents some column in a [`SortableTextTable`].
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SortableColumn {
|
pub struct SimpleSortableColumn {
|
||||||
pub shortcut: Option<(KeyEvent, String)>,
|
pub shortcut: Option<(KeyEvent, String)>,
|
||||||
pub default_descending: bool,
|
pub default_descending: bool,
|
||||||
pub internal: SimpleColumn,
|
pub internal: SimpleColumn,
|
||||||
sorting: SortStatus,
|
|
||||||
|
/// Whether this column is currently selected for sorting, and which direction.
|
||||||
|
sorting_status: SortStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SortableColumn {
|
impl SimpleSortableColumn {
|
||||||
/// Creates a new [`SortableColumn`].
|
/// Creates a new [`SimpleSortableColumn`].
|
||||||
fn new(
|
fn new(
|
||||||
shortcut_name: Cow<'static, str>, shortcut: Option<KeyEvent>, default_descending: bool,
|
full_name: Cow<'static, str>, shortcut: Option<(KeyEvent, String)>,
|
||||||
desired_width: DesiredColumnWidth,
|
default_descending: bool, desired_width: DesiredColumnWidth,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let shortcut = shortcut.map(|e| (e, get_shortcut_name(&e)));
|
|
||||||
Self {
|
Self {
|
||||||
shortcut,
|
shortcut,
|
||||||
default_descending,
|
default_descending,
|
||||||
internal: SimpleColumn::new(shortcut_name, desired_width),
|
internal: SimpleColumn::new(full_name, desired_width),
|
||||||
sorting: SortStatus::NotSorting,
|
sorting_status: SortStatus::NotSorting,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,18 +135,22 @@ impl SortableColumn {
|
|||||||
name: Cow<'static, str>, shortcut: Option<KeyEvent>, default_descending: bool,
|
name: Cow<'static, str>, shortcut: Option<KeyEvent>, default_descending: bool,
|
||||||
hard_length: Option<u16>,
|
hard_length: Option<u16>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let shortcut_name = if let Some(shortcut) = shortcut {
|
let (full_name, shortcut) = if let Some(shortcut) = shortcut {
|
||||||
get_shortcut_name(&shortcut).into()
|
let shortcut_name = get_shortcut_name(&shortcut);
|
||||||
|
(
|
||||||
|
format!("{}{}", name, shortcut_name).into(),
|
||||||
|
Some((shortcut, shortcut_name)),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
name
|
(name, None)
|
||||||
};
|
};
|
||||||
let shortcut_name_len = shortcut_name.len();
|
let full_name_len = full_name.len();
|
||||||
|
|
||||||
SortableColumn::new(
|
SimpleSortableColumn::new(
|
||||||
shortcut_name,
|
full_name,
|
||||||
shortcut,
|
shortcut,
|
||||||
default_descending,
|
default_descending,
|
||||||
DesiredColumnWidth::Hard(hard_length.unwrap_or(shortcut_name_len as u16 + 1)),
|
DesiredColumnWidth::Hard(hard_length.unwrap_or(full_name_len as u16 + 1)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,33 +159,53 @@ impl SortableColumn {
|
|||||||
name: Cow<'static, str>, shortcut: Option<KeyEvent>, default_descending: bool,
|
name: Cow<'static, str>, shortcut: Option<KeyEvent>, default_descending: bool,
|
||||||
max_percentage: f64,
|
max_percentage: f64,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let shortcut_name = if let Some(shortcut) = shortcut {
|
let (full_name, shortcut) = if let Some(shortcut) = shortcut {
|
||||||
get_shortcut_name(&shortcut).into()
|
let shortcut_name = get_shortcut_name(&shortcut);
|
||||||
|
(
|
||||||
|
format!("{}{}", name, shortcut_name).into(),
|
||||||
|
Some((shortcut, shortcut_name)),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
name
|
(name, None)
|
||||||
};
|
};
|
||||||
let shortcut_name_len = shortcut_name.len();
|
let full_name_len = full_name.len();
|
||||||
|
|
||||||
SortableColumn::new(
|
SimpleSortableColumn::new(
|
||||||
shortcut_name,
|
full_name,
|
||||||
shortcut,
|
shortcut,
|
||||||
default_descending,
|
default_descending,
|
||||||
DesiredColumnWidth::Flex {
|
DesiredColumnWidth::Flex {
|
||||||
desired: shortcut_name_len as u16,
|
desired: full_name_len as u16,
|
||||||
max_percentage,
|
max_percentage,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableColumn for SortableColumn {
|
impl SortableColumn for SimpleSortableColumn {
|
||||||
|
fn shortcut(&self) -> &Option<(KeyEvent, String)> {
|
||||||
|
&self.shortcut
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_descending(&self) -> bool {
|
||||||
|
self.default_descending
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sorting_status(&self) -> SortStatus {
|
||||||
|
self.sorting_status
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_sorting_status(&mut self, sorting_status: SortStatus) {
|
||||||
|
self.sorting_status = sorting_status;
|
||||||
|
}
|
||||||
|
|
||||||
fn display_name(&self) -> Cow<'static, str> {
|
fn display_name(&self) -> Cow<'static, str> {
|
||||||
const UP_ARROW: &str = "▲";
|
const UP_ARROW: &str = "▲";
|
||||||
const DOWN_ARROW: &str = "▼";
|
const DOWN_ARROW: &str = "▼";
|
||||||
format!(
|
format!(
|
||||||
"{}{}",
|
"{}{}",
|
||||||
self.internal.display_name(),
|
self.internal.display_name(),
|
||||||
match &self.sorting {
|
match &self.sorting_status {
|
||||||
SortStatus::NotSorting => "",
|
SortStatus::NotSorting => "",
|
||||||
SortStatus::SortAscending => UP_ARROW,
|
SortStatus::SortAscending => UP_ARROW,
|
||||||
SortStatus::SortDescending => DOWN_ARROW,
|
SortStatus::SortDescending => DOWN_ARROW,
|
||||||
@ -158,16 +228,22 @@ impl TableColumn for SortableColumn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A sortable, scrollable table with columns.
|
/// A sortable, scrollable table with columns.
|
||||||
pub struct SortableTextTable {
|
pub struct SortableTextTable<S = SimpleSortableColumn>
|
||||||
|
where
|
||||||
|
S: SortableColumn,
|
||||||
|
{
|
||||||
/// Which index we're sorting by.
|
/// Which index we're sorting by.
|
||||||
sort_index: usize,
|
sort_index: usize,
|
||||||
|
|
||||||
/// The underlying [`TextTable`].
|
/// The underlying [`TextTable`].
|
||||||
pub table: TextTable<SortableColumn>,
|
pub table: TextTable<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SortableTextTable {
|
impl<S> SortableTextTable<S>
|
||||||
pub fn new(columns: Vec<SortableColumn>) -> Self {
|
where
|
||||||
|
S: SortableColumn,
|
||||||
|
{
|
||||||
|
pub fn new(columns: Vec<S>) -> Self {
|
||||||
let mut st = Self {
|
let mut st = Self {
|
||||||
sort_index: 0,
|
sort_index: 0,
|
||||||
table: TextTable::new(columns),
|
table: TextTable::new(columns),
|
||||||
@ -193,32 +269,32 @@ impl SortableTextTable {
|
|||||||
fn set_sort_index(&mut self, new_index: usize) {
|
fn set_sort_index(&mut self, new_index: usize) {
|
||||||
if new_index == self.sort_index {
|
if new_index == self.sort_index {
|
||||||
if let Some(column) = self.table.columns.get_mut(self.sort_index) {
|
if let Some(column) = self.table.columns.get_mut(self.sort_index) {
|
||||||
match column.sorting {
|
match column.sorting_status() {
|
||||||
SortStatus::NotSorting => {
|
SortStatus::NotSorting => {
|
||||||
if column.default_descending {
|
if column.default_descending() {
|
||||||
column.sorting = SortStatus::SortDescending;
|
column.set_sorting_status(SortStatus::SortDescending);
|
||||||
} else {
|
} else {
|
||||||
column.sorting = SortStatus::SortAscending;
|
column.set_sorting_status(SortStatus::SortAscending);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SortStatus::SortAscending => {
|
SortStatus::SortAscending => {
|
||||||
column.sorting = SortStatus::SortDescending;
|
column.set_sorting_status(SortStatus::SortDescending);
|
||||||
}
|
}
|
||||||
SortStatus::SortDescending => {
|
SortStatus::SortDescending => {
|
||||||
column.sorting = SortStatus::SortAscending;
|
column.set_sorting_status(SortStatus::SortAscending);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Some(column) = self.table.columns.get_mut(self.sort_index) {
|
if let Some(column) = self.table.columns.get_mut(self.sort_index) {
|
||||||
column.sorting = SortStatus::NotSorting;
|
column.set_sorting_status(SortStatus::NotSorting);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(column) = self.table.columns.get_mut(new_index) {
|
if let Some(column) = self.table.columns.get_mut(new_index) {
|
||||||
if column.default_descending {
|
if column.default_descending() {
|
||||||
column.sorting = SortStatus::SortDescending;
|
column.set_sorting_status(SortStatus::SortDescending);
|
||||||
} else {
|
} else {
|
||||||
column.sorting = SortStatus::SortAscending;
|
column.set_sorting_status(SortStatus::SortAscending);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,10 +320,13 @@ impl SortableTextTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for SortableTextTable {
|
impl<S> Component for SortableTextTable<S>
|
||||||
|
where
|
||||||
|
S: SortableColumn,
|
||||||
|
{
|
||||||
fn handle_key_event(&mut self, event: KeyEvent) -> EventResult {
|
fn handle_key_event(&mut self, event: KeyEvent) -> EventResult {
|
||||||
for (index, column) in self.table.columns.iter().enumerate() {
|
for (index, column) in self.table.columns.iter().enumerate() {
|
||||||
if let Some((shortcut, _)) = column.shortcut {
|
if let &Some((shortcut, _)) = column.shortcut() {
|
||||||
if shortcut == event {
|
if shortcut == event {
|
||||||
self.set_sort_index(index);
|
self.set_sort_index(index);
|
||||||
return EventResult::Redraw;
|
return EventResult::Redraw;
|
||||||
@ -270,7 +349,7 @@ impl Component for SortableTextTable {
|
|||||||
|
|
||||||
if y == 0 {
|
if y == 0 {
|
||||||
for (index, column) in self.table.columns.iter().enumerate() {
|
for (index, column) in self.table.columns.iter().enumerate() {
|
||||||
if let Some((start, end)) = column.internal.get_x_bounds() {
|
if let Some((start, end)) = column.get_x_bounds() {
|
||||||
if x >= start && x <= end {
|
if x >= start && x <= end {
|
||||||
self.set_sort_index(index);
|
self.set_sort_index(index);
|
||||||
return EventResult::Redraw;
|
return EventResult::Redraw;
|
||||||
|
@ -9,7 +9,7 @@ use tui::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::{
|
app::{
|
||||||
event::EventResult, sort_text_table::SortableColumn, time_graph::TimeGraphData,
|
event::EventResult, sort_text_table::SimpleSortableColumn, time_graph::TimeGraphData,
|
||||||
AppConfigFields, DataCollection,
|
AppConfigFields, DataCollection,
|
||||||
},
|
},
|
||||||
canvas::Painter,
|
canvas::Painter,
|
||||||
@ -96,8 +96,8 @@ impl CpuGraph {
|
|||||||
pub fn from_config(app_config_fields: &AppConfigFields) -> Self {
|
pub fn from_config(app_config_fields: &AppConfigFields) -> Self {
|
||||||
let graph = TimeGraph::from_config(app_config_fields);
|
let graph = TimeGraph::from_config(app_config_fields);
|
||||||
let legend = SortableTextTable::new(vec![
|
let legend = SortableTextTable::new(vec![
|
||||||
SortableColumn::new_flex("CPU".into(), None, false, 0.5),
|
SimpleSortableColumn::new_flex("CPU".into(), None, false, 0.5),
|
||||||
SortableColumn::new_flex("Use%".into(), None, false, 0.5),
|
SimpleSortableColumn::new_flex("Use%".into(), None, false, 0.5),
|
||||||
]);
|
]);
|
||||||
let legend_position = if app_config_fields.left_legend {
|
let legend_position = if app_config_fields.left_legend {
|
||||||
CpuGraphLegendPosition::Left
|
CpuGraphLegendPosition::Left
|
||||||
|
@ -9,7 +9,7 @@ use tui::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::{data_farmer::DataCollection, event::EventResult, sort_text_table::SortableColumn},
|
app::{data_farmer::DataCollection, event::EventResult, sort_text_table::SimpleSortableColumn},
|
||||||
canvas::Painter,
|
canvas::Painter,
|
||||||
data_conversion::convert_disk_row,
|
data_conversion::convert_disk_row,
|
||||||
};
|
};
|
||||||
@ -63,13 +63,13 @@ pub struct DiskTable {
|
|||||||
impl Default for DiskTable {
|
impl Default for DiskTable {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let table = SortableTextTable::new(vec![
|
let table = SortableTextTable::new(vec![
|
||||||
SortableColumn::new_flex("Disk".into(), None, false, 0.2),
|
SimpleSortableColumn::new_flex("Disk".into(), None, false, 0.2),
|
||||||
SortableColumn::new_flex("Mount".into(), None, false, 0.2),
|
SimpleSortableColumn::new_flex("Mount".into(), None, false, 0.2),
|
||||||
SortableColumn::new_hard("Used".into(), None, false, Some(5)),
|
SimpleSortableColumn::new_hard("Used".into(), None, false, Some(5)),
|
||||||
SortableColumn::new_hard("Free".into(), None, false, Some(6)),
|
SimpleSortableColumn::new_hard("Free".into(), None, false, Some(6)),
|
||||||
SortableColumn::new_hard("Total".into(), None, false, Some(6)),
|
SimpleSortableColumn::new_hard("Total".into(), None, false, Some(6)),
|
||||||
SortableColumn::new_hard("R/s".into(), None, false, Some(7)),
|
SimpleSortableColumn::new_hard("R/s".into(), None, false, Some(7)),
|
||||||
SortableColumn::new_hard("W/s".into(), None, false, Some(7)),
|
SimpleSortableColumn::new_hard("W/s".into(), None, false, Some(7)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
@ -476,8 +476,6 @@ impl NetGraph {
|
|||||||
|
|
||||||
match &mut self.draw_cache {
|
match &mut self.draw_cache {
|
||||||
NetGraphCacheState::Uncached => {
|
NetGraphCacheState::Uncached => {
|
||||||
debug!("No cache!");
|
|
||||||
|
|
||||||
let (cached_upper_bound, labels) = adjust_network_data_point(
|
let (cached_upper_bound, labels) = adjust_network_data_point(
|
||||||
current_max_value,
|
current_max_value,
|
||||||
&self.scale_type,
|
&self.scale_type,
|
||||||
|
@ -23,8 +23,10 @@ use crate::{
|
|||||||
use ProcessSorting::*;
|
use ProcessSorting::*;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
text_table::TextTableData, AppScrollWidgetState, CanvasTableWidthState, Component,
|
sort_text_table::{SimpleSortableColumn, SortableColumn},
|
||||||
CursorDirection, ScrollDirection, SortableTextTable, TextInput, TextTable, Widget,
|
text_table::TextTableData,
|
||||||
|
AppScrollWidgetState, CanvasTableWidthState, Component, CursorDirection, ScrollDirection,
|
||||||
|
SortableTextTable, TextInput, TextTable, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// AppSearchState deals with generic searching (I might do this in the future).
|
/// AppSearchState deals with generic searching (I might do this in the future).
|
||||||
@ -638,10 +640,198 @@ struct SearchModifiers {
|
|||||||
enable_regex: bool,
|
enable_regex: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum FlexColumn {
|
||||||
|
Flex(f64),
|
||||||
|
Hard(Option<u16>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ProcessSortType {
|
||||||
|
Pid,
|
||||||
|
Count,
|
||||||
|
Name,
|
||||||
|
Command,
|
||||||
|
Cpu,
|
||||||
|
Mem,
|
||||||
|
MemPercent,
|
||||||
|
Rps,
|
||||||
|
Wps,
|
||||||
|
TotalRead,
|
||||||
|
TotalWrite,
|
||||||
|
User,
|
||||||
|
State,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProcessSortType {
|
||||||
|
fn to_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
ProcessSortType::Pid => "PID",
|
||||||
|
ProcessSortType::Count => "Count",
|
||||||
|
ProcessSortType::Name => "Name",
|
||||||
|
ProcessSortType::Command => "Command",
|
||||||
|
ProcessSortType::Cpu => "Cpu",
|
||||||
|
ProcessSortType::Mem => "Mem",
|
||||||
|
ProcessSortType::MemPercent => "Mem%",
|
||||||
|
ProcessSortType::Rps => "R/s",
|
||||||
|
ProcessSortType::Wps => "W/s",
|
||||||
|
ProcessSortType::TotalRead => "T.Read",
|
||||||
|
ProcessSortType::TotalWrite => "T.Write",
|
||||||
|
ProcessSortType::User => "User",
|
||||||
|
ProcessSortType::State => "State",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shortcut(&self) -> Option<KeyEvent> {
|
||||||
|
match self {
|
||||||
|
ProcessSortType::Pid => Some(KeyEvent::new(KeyCode::Char('p'), KeyModifiers::NONE)),
|
||||||
|
ProcessSortType::Count => None,
|
||||||
|
ProcessSortType::Name => Some(KeyEvent::new(KeyCode::Char('n'), KeyModifiers::NONE)),
|
||||||
|
ProcessSortType::Command => None,
|
||||||
|
ProcessSortType::Cpu => Some(KeyEvent::new(KeyCode::Char('c'), KeyModifiers::NONE)),
|
||||||
|
ProcessSortType::Mem => Some(KeyEvent::new(KeyCode::Char('m'), KeyModifiers::NONE)),
|
||||||
|
ProcessSortType::MemPercent => {
|
||||||
|
Some(KeyEvent::new(KeyCode::Char('m'), KeyModifiers::NONE))
|
||||||
|
}
|
||||||
|
ProcessSortType::Rps => None,
|
||||||
|
ProcessSortType::Wps => None,
|
||||||
|
ProcessSortType::TotalRead => None,
|
||||||
|
ProcessSortType::TotalWrite => None,
|
||||||
|
ProcessSortType::User => None,
|
||||||
|
ProcessSortType::State => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn column_type(&self) -> FlexColumn {
|
||||||
|
use FlexColumn::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
ProcessSortType::Pid => Hard(Some(7)),
|
||||||
|
ProcessSortType::Count => Hard(Some(8)),
|
||||||
|
ProcessSortType::Name => Flex(0.3),
|
||||||
|
ProcessSortType::Command => Flex(0.7),
|
||||||
|
ProcessSortType::Cpu => Hard(Some(8)),
|
||||||
|
ProcessSortType::Mem => Hard(Some(8)),
|
||||||
|
ProcessSortType::MemPercent => Hard(Some(8)),
|
||||||
|
ProcessSortType::Rps => Hard(Some(8)),
|
||||||
|
ProcessSortType::Wps => Hard(Some(8)),
|
||||||
|
ProcessSortType::TotalRead => Hard(Some(7)),
|
||||||
|
ProcessSortType::TotalWrite => Hard(Some(8)),
|
||||||
|
ProcessSortType::User => Flex(0.1),
|
||||||
|
ProcessSortType::State => Flex(0.2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_descending(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
ProcessSortType::Pid => false,
|
||||||
|
ProcessSortType::Count => true,
|
||||||
|
ProcessSortType::Name => false,
|
||||||
|
ProcessSortType::Command => false,
|
||||||
|
ProcessSortType::Cpu => true,
|
||||||
|
ProcessSortType::Mem => true,
|
||||||
|
ProcessSortType::MemPercent => true,
|
||||||
|
ProcessSortType::Rps => true,
|
||||||
|
ProcessSortType::Wps => true,
|
||||||
|
ProcessSortType::TotalRead => true,
|
||||||
|
ProcessSortType::TotalWrite => true,
|
||||||
|
ProcessSortType::User => false,
|
||||||
|
ProcessSortType::State => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A thin wrapper around a [`SortableColumn`] to help keep track of
|
||||||
|
/// how to sort given a chosen column.
|
||||||
|
pub struct ProcessSortColumn {
|
||||||
|
/// The underlying column.
|
||||||
|
sortable_column: SimpleSortableColumn,
|
||||||
|
|
||||||
|
/// The *type* of column. Useful for determining how to sort.
|
||||||
|
sort_type: ProcessSortType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProcessSortColumn {
|
||||||
|
pub fn new(sort_type: ProcessSortType) -> Self {
|
||||||
|
let sortable_column = {
|
||||||
|
let name = sort_type.to_str().into();
|
||||||
|
let shortcut = sort_type.shortcut();
|
||||||
|
let default_descending = sort_type.default_descending();
|
||||||
|
|
||||||
|
match sort_type.column_type() {
|
||||||
|
FlexColumn::Flex(max_percentage) => SimpleSortableColumn::new_flex(
|
||||||
|
name,
|
||||||
|
shortcut,
|
||||||
|
default_descending,
|
||||||
|
max_percentage,
|
||||||
|
),
|
||||||
|
FlexColumn::Hard(hard_length) => {
|
||||||
|
SimpleSortableColumn::new_hard(name, shortcut, default_descending, hard_length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
sortable_column,
|
||||||
|
sort_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sort_process(&self) {
|
||||||
|
match &self.sort_type {
|
||||||
|
ProcessSortType::Pid => {}
|
||||||
|
ProcessSortType::Count => {}
|
||||||
|
ProcessSortType::Name => {}
|
||||||
|
ProcessSortType::Command => {}
|
||||||
|
ProcessSortType::Cpu => {}
|
||||||
|
ProcessSortType::Mem => {}
|
||||||
|
ProcessSortType::MemPercent => {}
|
||||||
|
ProcessSortType::Rps => {}
|
||||||
|
ProcessSortType::Wps => {}
|
||||||
|
ProcessSortType::TotalRead => {}
|
||||||
|
ProcessSortType::TotalWrite => {}
|
||||||
|
ProcessSortType::User => {}
|
||||||
|
ProcessSortType::State => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SortableColumn for ProcessSortColumn {
|
||||||
|
fn shortcut(&self) -> &Option<(KeyEvent, String)> {
|
||||||
|
self.sortable_column.shortcut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_descending(&self) -> bool {
|
||||||
|
self.sortable_column.default_descending()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sorting_status(&self) -> super::sort_text_table::SortStatus {
|
||||||
|
self.sortable_column.sorting_status()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_sorting_status(&mut self, sorting_status: super::sort_text_table::SortStatus) {
|
||||||
|
self.sortable_column.set_sorting_status(sorting_status)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_name(&self) -> std::borrow::Cow<'static, str> {
|
||||||
|
self.sortable_column.display_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_desired_width(&self) -> &super::text_table::DesiredColumnWidth {
|
||||||
|
self.sortable_column.get_desired_width()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_x_bounds(&self) -> Option<(u16, u16)> {
|
||||||
|
self.sortable_column.get_x_bounds()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_x_bounds(&mut self, x_bounds: Option<(u16, u16)>) {
|
||||||
|
self.sortable_column.set_x_bounds(x_bounds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A searchable, sortable table to manage processes.
|
/// A searchable, sortable table to manage processes.
|
||||||
pub struct ProcessManager {
|
pub struct ProcessManager {
|
||||||
bounds: Rect,
|
bounds: Rect,
|
||||||
process_table: SortableTextTable,
|
process_table: SortableTextTable<ProcessSortColumn>,
|
||||||
sort_table: TextTable,
|
sort_table: TextTable,
|
||||||
search_input: TextInput,
|
search_input: TextInput,
|
||||||
|
|
||||||
@ -661,11 +851,25 @@ pub struct ProcessManager {
|
|||||||
impl ProcessManager {
|
impl ProcessManager {
|
||||||
/// Creates a new [`ProcessManager`].
|
/// Creates a new [`ProcessManager`].
|
||||||
pub fn new(process_defaults: &ProcessDefaults) -> Self {
|
pub fn new(process_defaults: &ProcessDefaults) -> Self {
|
||||||
let process_table_columns = vec![];
|
let process_table_columns = vec![
|
||||||
|
ProcessSortColumn::new(ProcessSortType::Pid),
|
||||||
|
ProcessSortColumn::new(ProcessSortType::Name),
|
||||||
|
ProcessSortColumn::new(ProcessSortType::Cpu),
|
||||||
|
ProcessSortColumn::new(ProcessSortType::MemPercent),
|
||||||
|
ProcessSortColumn::new(ProcessSortType::Rps),
|
||||||
|
ProcessSortColumn::new(ProcessSortType::Wps),
|
||||||
|
ProcessSortColumn::new(ProcessSortType::TotalRead),
|
||||||
|
ProcessSortColumn::new(ProcessSortType::TotalWrite),
|
||||||
|
#[cfg(target_family = "unix")]
|
||||||
|
ProcessSortColumn::new(ProcessSortType::User),
|
||||||
|
ProcessSortColumn::new(ProcessSortType::State),
|
||||||
|
];
|
||||||
|
|
||||||
|
let process_table = SortableTextTable::new(process_table_columns).default_sort_index(2);
|
||||||
|
|
||||||
let mut manager = Self {
|
let mut manager = Self {
|
||||||
bounds: Rect::default(),
|
bounds: Rect::default(),
|
||||||
process_table: SortableTextTable::new(process_table_columns), // TODO: Do this
|
process_table,
|
||||||
sort_table: TextTable::new(vec![]), // TODO: Do this too
|
sort_table: TextTable::new(vec![]), // TODO: Do this too
|
||||||
search_input: TextInput::new(),
|
search_input: TextInput::new(),
|
||||||
dd_multi: MultiKey::register(vec!['d', 'd']), // TODO: Maybe use something static...
|
dd_multi: MultiKey::register(vec!['d', 'd']), // TODO: Maybe use something static...
|
||||||
@ -870,14 +1074,8 @@ impl Widget for ProcessManager {
|
|||||||
})
|
})
|
||||||
.borders(Borders::ALL);
|
.borders(Borders::ALL);
|
||||||
|
|
||||||
self.process_table.table.draw_tui_table(
|
self.process_table
|
||||||
painter,
|
.draw_tui_table(painter, f, &self.display_data, block, area, selected);
|
||||||
f,
|
|
||||||
&self.display_data, // TODO: Fix this
|
|
||||||
block,
|
|
||||||
area,
|
|
||||||
selected,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_data(&mut self, data_collection: &DataCollection) {}
|
fn update_data(&mut self, data_collection: &DataCollection) {}
|
||||||
|
@ -11,7 +11,7 @@ use tui::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::{
|
app::{
|
||||||
data_farmer::DataCollection, data_harvester::temperature::TemperatureType,
|
data_farmer::DataCollection, data_harvester::temperature::TemperatureType,
|
||||||
event::EventResult, sort_text_table::SortableColumn,
|
event::EventResult, sort_text_table::SimpleSortableColumn,
|
||||||
},
|
},
|
||||||
canvas::Painter,
|
canvas::Painter,
|
||||||
data_conversion::convert_temp_row,
|
data_conversion::convert_temp_row,
|
||||||
@ -66,8 +66,8 @@ pub struct TempTable {
|
|||||||
impl Default for TempTable {
|
impl Default for TempTable {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let table = SortableTextTable::new(vec![
|
let table = SortableTextTable::new(vec![
|
||||||
SortableColumn::new_flex("Sensor".into(), None, false, 0.8),
|
SimpleSortableColumn::new_flex("Sensor".into(), None, false, 0.8),
|
||||||
SortableColumn::new_hard("Temp".into(), None, false, Some(5)),
|
SimpleSortableColumn::new_hard("Temp".into(), None, false, Some(5)),
|
||||||
])
|
])
|
||||||
.default_ltr(false);
|
.default_ltr(false);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user