Skip to content

Commit

Permalink
Create components for easier UI creation
Browse files Browse the repository at this point in the history
  • Loading branch information
ClementTsang committed Oct 14, 2020
1 parent 9140798 commit 1647df6
Show file tree
Hide file tree
Showing 17 changed files with 360 additions and 68 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"cmdline",
"commandline",
"concat",
"coord",
"crossterm",
"curr",
"cvar",
Expand Down
8 changes: 6 additions & 2 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use layout_manager::*;
pub use states::*;

use crate::{
canvas, constants,
canvas,
components::ScrollDirection,
constants,
options::Config,
options::ConfigFlags,
options::WidgetIdEnabled,
Expand Down Expand Up @@ -126,6 +128,7 @@ pub struct App {
pub filters: DataFilters,
pub config: Config,
pub config_path: Option<PathBuf>,
pub config_page_settings: Vec<MainConfigState>,
}

impl App {
Expand Down Expand Up @@ -1236,7 +1239,7 @@ impl App {
}
}
'C' => {
// self.open_config(),
// self.open_config_screen();
}
'c' => {
if let BottomWidgetType::Proc = self.current_widget.widget_type {
Expand Down Expand Up @@ -2593,6 +2596,7 @@ impl App {
}

// Now handle click propagation down to widget.
// self.current_widget.on_click(MouseButton::Left, Coordinate {x, y});
if let Some((_tlc_x, tlc_y)) = &self.current_widget.top_left_corner {
match &self.current_widget.widget_type {
BottomWidgetType::Proc
Expand Down
1 change: 1 addition & 0 deletions src/app/process_killer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub fn kill_process_given_pid(pid: Pid) -> crate::utils::error::Result<()> {
if cfg!(target_family = "unix") {
#[cfg(any(target_family = "unix"))]
{
// FIXME: [KILL] Forbid negative PID killing in unix
let output = unsafe { libc::kill(pid as i32, libc::SIGTERM) };
if output != 0 {
// We had an error...
Expand Down
47 changes: 21 additions & 26 deletions src/app/states.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,12 @@ use tui::widgets::TableState;

use crate::{
app::{layout_manager::BottomWidgetType, query::*},
components::ScrollDirection,
constants,
data_harvester::processes::{self, ProcessSorting},
};
use ProcessSorting::*;

#[derive(Debug)]
pub enum ScrollDirection {
// UP means scrolling up --- this usually DECREMENTS
Up,
// DOWN means scrolling down --- this usually INCREMENTS
Down,
}

impl Default for ScrollDirection {
fn default() -> Self {
ScrollDirection::Down
}
}

#[derive(Debug)]
pub enum CursorDirection {
Left,
Expand All @@ -34,6 +21,8 @@ pub enum CursorDirection {
/// AppScrollWidgetState deals with fields for a scrollable app's current state.
#[derive(Default)]
pub struct AppScrollWidgetState {
pub column_headers: Vec<String>,
pub column_contents: Vec<Vec<String>>,
pub current_scroll_position: usize,
pub previous_scroll_position: usize,
pub scroll_direction: ScrollDirection,
Expand Down Expand Up @@ -802,24 +791,30 @@ impl BatteryState {
}
}

// FIXME: [REFACTOR] Unify scroll state tracking implementations under one struct.
#[derive(Default)]
pub struct ParagraphScrollState {
pub current_scroll_index: u16,
pub max_scroll_index: u16,
}

#[derive(Default)]
pub struct ConfigState {
pub current_category_index: usize,
pub category_list: Vec<ConfigCategory>,
}

#[derive(Default)]
pub struct ConfigCategory {
pub struct MainConfigState {
pub category_name: &'static str,
pub options_list: Vec<ConfigOption>,
}

pub struct ConfigOption {
pub set_function: Box<dyn Fn() -> anyhow::Result<()>>,
pub config_sub_options: Vec<ConfigSubOptions>,
}

pub struct ConfigSubOptions {
/// The option's name.
pub option_name: &'static str,
/// The option's description.
pub description: &'static str,
/// How it handles drawing in an additional Block. If this does is None,
/// then nothing additional will be drawn here.
pub draw_fn: Option<Box<dyn Fn()>>,
/// How it handles inputs. For example, scroll states, mouse inputs, keyboard inputs, etc.
/// must be handled by the option itself.
pub input_fn: Box<dyn Fn()>,
/// How it updates the config. Must be handled by the option itself.
pub update_fn: Box<dyn Fn()>,
}
7 changes: 4 additions & 3 deletions src/canvas/canvas_colours.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub struct CanvasColours {
pub text_style: Style,
pub widget_title_style: Style,
pub graph_style: Style,
// Full, Medium, Low
// Order is full, medium, and low
pub battery_bar_styles: Vec<Style>,
pub invalid_query_style: Style,
pub disabled_text_style: Style,
Expand Down Expand Up @@ -88,8 +88,9 @@ impl CanvasColours {

pub fn set_table_header_colour(&mut self, colour: &str) -> error::Result<()> {
self.table_header_style = get_style_from_config(colour)?;
// Disabled as it seems to be bugged when I go into full command mode...? It becomes huge lol
// self.table_header_style = get_style_from_config(colour)?.modifier(Modifier::BOLD);
// TODO: Make arrows not bolded, rest of text bolded (if enabled)
// self.table_header_style =
// get_style_from_config(colour)?.add_modifier(tui::style::Modifier::BOLD);
Ok(())
}

Expand Down
8 changes: 4 additions & 4 deletions src/canvas/drawing_utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::app;
use crate::{app, components::ScrollDirection};
use std::cmp::{max, min};

/// Return a (hard)-width vector for column widths.
Expand Down Expand Up @@ -145,15 +145,15 @@ pub fn get_search_start_position(
}

pub fn get_start_position(
num_rows: usize, scroll_direction: &app::ScrollDirection, scroll_position_bar: &mut usize,
num_rows: usize, scroll_direction: &ScrollDirection, scroll_position_bar: &mut usize,
currently_selected_position: usize, is_force_redraw: bool,
) -> usize {
if is_force_redraw {
*scroll_position_bar = 0;
}

match scroll_direction {
app::ScrollDirection::Down => {
ScrollDirection::Down => {
if currently_selected_position < *scroll_position_bar + num_rows {
// If, using previous_scrolled_position, we can see the element
// (so within that and + num_rows) just reuse the current previously scrolled position
Expand All @@ -168,7 +168,7 @@ pub fn get_start_position(
0
}
}
app::ScrollDirection::Up => {
ScrollDirection::Up => {
if currently_selected_position <= *scroll_position_bar {
// If it's past the first element, then show from that element downwards
*scroll_position_bar = currently_selected_position;
Expand Down
48 changes: 18 additions & 30 deletions src/canvas/screens/config_screen.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![allow(unused_variables)] //FIXME: Remove this
#![allow(unused_imports)] //FIXME: Remove this
#![allow(unused_variables)]
#![allow(unused_imports)]
use crate::{app::App, canvas::Painter, constants};
use tui::{
backend::Backend,
Expand All @@ -9,7 +9,8 @@ use tui::{
layout::{Alignment, Rect},
terminal::Frame,
text::Span,
widgets::{Block, Borders, Paragraph},
text::Spans,
widgets::{Block, Borders, Paragraph, Tabs},
};

pub trait ConfigScreen {
Expand All @@ -23,37 +24,24 @@ impl ConfigScreen for Painter {
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect,
) {
let config_block = Block::default()
.title(" Config ") // FIXME: [Config] missing title styling
.title(Span::styled(" Config ", self.colours.widget_title_style))
.style(self.colours.border_style)
.borders(Borders::ALL)
.border_style(self.colours.border_style);

f.render_widget(config_block, draw_loc);
let titles: Vec<Spans<'_>> = app_state
.config_page_settings
.iter()
.map(|category| Spans::from(category.category_name))
.collect();

// let margined_draw_locs = Layout::default()
// .margin(2)
// .direction(Direction::Horizontal)
// .constraints(
// [
// Constraint::Percentage(33),
// Constraint::Percentage(34),
// Constraint::Percentage(33),
// ]
// .as_ref(),
// )
// .split(draw_loc)
// .into_iter()
// .map(|loc| {
// // Required to properly margin in *between* the rectangles.
// Layout::default()
// .horizontal_margin(1)
// .constraints([Constraint::Percentage(100)].as_ref())
// .split(loc)[0]
// })
// .collect::<Vec<Rect>>();

// for dl in margined_draw_locs {
// f.render_widget(Block::default().borders(Borders::ALL), dl);
// }
f.render_widget(
Tabs::new(titles)
.block(config_block)
.divider(tui::symbols::line::VERTICAL)
.style(self.colours.text_style)
.highlight_style(self.colours.currently_selected_text_style),
draw_loc,
)
}
}
4 changes: 2 additions & 2 deletions src/clap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ inspired by htop's.\n\n",
);
let battery = Arg::with_name("battery")
.long("battery")
.help("Shows the battery widget.")
.help("Shows the battery widget in default/basic mode.")
.long_help(
"\
Shows the battery widget in default or basic mode. No effect on
Shows the battery widget in default/basic mode. No effect on
custom layouts.\n\n",
);
let case_sensitive = Arg::with_name("case_sensitive")
Expand Down
51 changes: 51 additions & 0 deletions src/components/base_traits/base_widget.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use crate::app::layout_manager::{BottomWidget, BottomWidgetType};

use super::{Drawable, HandleClick, HandleKeyInputs, HandleScroll};

#[derive(Default, Debug)]
pub struct Coordinate {
pub x: u16,
pub y: u16,
}

#[derive(Default, Debug)]
pub struct WidgetCorners {
pub top_left_corner: Coordinate,
pub bottom_right_corner: Coordinate,
}

pub trait BaseWidget: HandleClick + HandleScroll + HandleKeyInputs + Drawable {
/// Get the widget bounds - returns the top left corner (TLC) and the bottom
/// right corner (BRC).
fn get_widget_bounds(&self) -> Option<WidgetCorners>;

/// Get if a border is being drawn around this widget.
fn is_drawing_borders(&self) -> bool {
self.is_drawing_horizontal_borders() && self.is_drawing_vertical_borders()
}

/// Get if horizontal borders are being drawn around this widget.
fn is_drawing_horizontal_borders(&self) -> bool;

/// Get if vertical borders are being drawn around this widget.
fn is_drawing_vertical_borders(&self) -> bool;

/// Obtain the widget ID.
fn get_widget_id(&self) -> u64 {
self.get_bottom_widget_details().widget_id
}

/// Obtain the widget type.
fn get_widget_type(&self) -> &BottomWidgetType {
&self.get_bottom_widget_details().widget_type
}

/// Obtain the widget layout details.
fn get_bottom_widget_details(&self) -> &BottomWidget;
}

pub trait BaseTableWidget: BaseWidget {
fn get_table_gap(&self) -> u16;
}

pub trait BaseGraphWidget: BaseWidget {}
9 changes: 9 additions & 0 deletions src/components/base_traits/drawable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use tui::{backend::Backend, layout::Rect, Frame};

use crate::app::App;

pub trait Drawable {
fn draw<B: Backend>(
&mut self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, is_force_redraw: bool,
);
}
25 changes: 25 additions & 0 deletions src/components/base_traits/events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use crossterm::event::KeyEvent;

use super::Coordinate;

pub trait HandleKeyInputs {
/// How to handle a key input
fn on_char(&mut self, key_input: KeyEvent);
}

pub trait HandleScroll {
fn on_scroll_up(&mut self);

fn on_scroll_down(&mut self);
}

pub enum MouseButton {
Left,
Middle,
Right,
}

pub trait HandleClick {
/// How to handle a click.
fn on_click(&mut self, button: MouseButton, click_coord: Coordinate);
}
7 changes: 7 additions & 0 deletions src/components/base_traits/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub mod base_widget;
pub mod drawable;
pub mod events;

pub use base_widget::*;
pub use drawable::*;
pub use events::*;
5 changes: 5 additions & 0 deletions src/components/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod base_traits;
pub mod scrollable_table;

pub use base_traits::*;
pub use scrollable_table::*;
Loading

0 comments on commit 1647df6

Please sign in to comment.