refactor: use a builder for block building

This commit is contained in:
ClementTsang 2021-09-07 21:37:11 -04:00
parent 9ef38cbf1a
commit d8a6a2344e
15 changed files with 116 additions and 50 deletions

View File

@ -3,13 +3,7 @@ use std::time::Instant;
use crossterm::event::{KeyEvent, MouseEvent};
use enum_dispatch::enum_dispatch;
use indextree::NodeId;
use tui::{
backend::Backend,
layout::Rect,
text::Span,
widgets::{Block, Borders, TableState},
Frame,
};
use tui::{backend::Backend, layout::Rect, widgets::TableState, Frame};
use crate::{
app::{
@ -21,7 +15,7 @@ use crate::{
options::layout_options::LayoutRule,
};
mod tui_widgets;
mod tui_stuff;
pub mod base;
pub use base::*;
@ -29,6 +23,8 @@ pub use base::*;
pub mod bottom_widgets;
pub use bottom_widgets::*;
use self::tui_stuff::BlockBuilder;
use super::data_farmer::DataCollection;
/// A trait for things that are drawn with state.
@ -121,28 +117,10 @@ pub trait Widget {
/// Returns a [`Widget`]'s "pretty" display name.
fn get_pretty_name(&self) -> &'static str;
/// Returns a new [`Block`]. The default implementation returns
/// a basic [`Block`] with different border colours based on selected state.
fn block<'a>(&self, painter: &'a Painter, is_selected: bool, borders: Borders) -> Block<'a> {
let has_top_bottom_border =
borders.contains(Borders::TOP) || borders.contains(Borders::BOTTOM);
let block = Block::default()
.border_style(if is_selected {
painter.colours.highlighted_border_style
} else {
painter.colours.border_style
})
.borders(borders);
if has_top_bottom_border {
block.title(Span::styled(
format!(" {} ", self.get_pretty_name()),
painter.colours.widget_title_style,
))
} else {
block
}
/// Returns a new [`BlockBuilder`], which can become a [`Block`] if [`BlockBuilder::build`] is called.
/// The default implementation builds a [`Block`] that has all 4 borders with no selection or expansion.
fn block(&self) -> BlockBuilder {
BlockBuilder::new(self.get_pretty_name())
}
/// Draws a [`Widget`]. The default implementation draws nothing.

View File

@ -16,7 +16,7 @@ use tui::{
use crate::{
app::{
event::WidgetEventResult,
widgets::tui_widgets::{
widgets::tui_stuff::{
custom_legend_chart::{Axis, Dataset},
TimeChart,
},

View File

@ -8,7 +8,7 @@ use tui::{
};
use crate::{
app::{widgets::tui_widgets::PipeGauge, AppConfigFields, Component, DataCollection, Widget},
app::{widgets::tui_stuff::PipeGauge, AppConfigFields, Component, DataCollection, Widget},
canvas::Painter,
constants::SIDE_BORDERS,
options::layout_options::LayoutRule,

View File

@ -8,7 +8,7 @@ use tui::{
use crate::{
app::{
event::WidgetEventResult, widgets::tui_widgets::PipeGauge, Component, DataCollection,
event::WidgetEventResult, widgets::tui_stuff::PipeGauge, Component, DataCollection,
Widget,
},
canvas::Painter,

View File

@ -15,7 +15,7 @@ use tui::{
use crate::{
app::{
data_farmer::DataCollection, does_bound_intersect_coordinate, event::WidgetEventResult,
widgets::tui_widgets::PipeGauge, Component, Widget,
widgets::tui_stuff::PipeGauge, Component, Widget,
},
canvas::Painter,
constants::TABLE_GAP_HEIGHT_LIMIT,
@ -178,7 +178,11 @@ impl Widget for BatteryTable {
fn draw<B: Backend>(
&mut self, painter: &Painter, f: &mut Frame<'_, B>, area: Rect, selected: bool,
) {
let block = self.block(painter, selected, self.block_border);
let block = self
.block()
.selected(selected)
.borders(self.block_border)
.build(painter);
let inner_area = block.inner(area);
const CONSTRAINTS: [Constraint; 2] = [Constraint::Length(1), Constraint::Min(0)];

View File

@ -227,11 +227,10 @@ impl Widget for CpuGraph {
})
.collect::<Vec<_>>();
let graph_block = self.block(
painter,
selected && matches!(&self.selected, CpuGraphSelection::Graph),
Borders::ALL,
);
let graph_block = self
.block()
.selected(selected && matches!(&self.selected, CpuGraphSelection::Graph))
.build(painter);
self.graph.draw_tui_chart(
painter,

View File

@ -122,7 +122,11 @@ impl Widget for DiskTable {
fn draw<B: Backend>(
&mut self, painter: &Painter, f: &mut Frame<'_, B>, area: Rect, selected: bool,
) {
let block = self.block(painter, selected, self.block_border);
let block = self
.block()
.selected(selected)
.borders(self.block_border)
.build(painter);
self.table
.draw_tui_table(painter, f, &self.display_data, block, area, selected);

View File

@ -1,7 +1,7 @@
use std::{borrow::Cow, collections::HashMap, time::Instant};
use crossterm::event::{KeyEvent, MouseEvent};
use tui::{backend::Backend, layout::Rect, widgets::Borders};
use tui::{backend::Backend, layout::Rect};
use crate::{
app::{event::WidgetEventResult, time_graph::TimeGraphData, DataCollection},
@ -89,7 +89,7 @@ impl Widget for MemGraph {
&mut self, painter: &crate::canvas::Painter, f: &mut tui::Frame<'_, B>, area: Rect,
selected: bool,
) {
let block = self.block(painter, selected, Borders::ALL);
let block = self.block().selected(selected).build(painter);
let mut chart_data = Vec::with_capacity(2);
if let Some((label_percent, label_frac)) = &self.mem_labels {

View File

@ -518,7 +518,7 @@ impl Widget for NetGraph {
fn draw<B: Backend>(
&mut self, painter: &Painter, f: &mut Frame<'_, B>, area: Rect, selected: bool,
) {
let block = self.block(painter, selected, Borders::ALL);
let block = self.block().selected(selected).build(painter);
self.set_draw_cache();

View File

@ -1233,11 +1233,11 @@ impl Widget for ProcessManager {
area
};
let process_block = self.block(
painter,
selected && matches!(self.selected, ProcessManagerSelection::Processes),
self.block_border,
);
let process_block = self
.block()
.selected(selected && matches!(self.selected, ProcessManagerSelection::Processes))
.borders(self.block_border)
.build(painter);
self.process_table.draw_tui_table(
painter,

View File

@ -133,7 +133,11 @@ impl Widget for TempTable {
fn draw<B: Backend>(
&mut self, painter: &Painter, f: &mut Frame<'_, B>, area: Rect, selected: bool,
) {
let block = self.block(painter, selected, self.block_border);
let block = self
.block()
.selected(selected)
.borders(self.block_border)
.build(painter);
self.table
.draw_tui_table(painter, f, &self.display_data, block, area, selected);

View File

@ -3,3 +3,6 @@ pub use custom_legend_chart::TimeChart;
pub mod pipe_gauge;
pub use pipe_gauge::PipeGauge;
pub mod block_builder;
pub use block_builder::BlockBuilder;

View File

@ -0,0 +1,74 @@
use tui::{
text::Span,
widgets::{Block, Borders},
};
use crate::canvas::Painter;
/// A factory pattern builder for a tui [`Block`].
pub struct BlockBuilder {
borders: Borders,
selected: bool,
expanded: bool,
name: &'static str,
extra_text: Option<String>,
}
impl BlockBuilder {
/// Creates a new [`BlockBuilder`] with the name of block.
pub fn new(name: &'static str) -> Self {
Self {
borders: Borders::ALL,
selected: false,
expanded: false,
name,
extra_text: None,
}
}
/// Indicates that this block is currently selected, and should be drawn as such.
pub fn selected(mut self, selected: bool) -> Self {
self.selected = selected;
self
}
/// Indicates that this block is currently expanded, and should be drawn as such.
pub fn expanded(mut self, expanded: bool) -> Self {
self.expanded = expanded;
self
}
/// Indicates that this block has some extra text beyond the name.
pub fn extra_text(mut self, extra_text: String) -> Self {
self.extra_text = Some(extra_text);
self
}
/// Determines the borders of the built [`Block`].
pub fn borders(mut self, borders: Borders) -> Self {
self.borders = borders;
self
}
pub fn build<'a>(self, painter: &'a Painter) -> Block<'a> {
let has_top_bottom_border =
self.borders.contains(Borders::TOP) || self.borders.contains(Borders::BOTTOM);
let block = Block::default()
.border_style(if self.selected {
painter.colours.highlighted_border_style
} else {
painter.colours.border_style
})
.borders(self.borders);
if has_top_bottom_border {
block.title(Span::styled(
format!(" {} ", self.name),
painter.colours.widget_title_style,
))
} else {
block
}
}
}