remove code dedup

This commit is contained in:
ClementTsang 2023-06-04 14:48:16 -04:00
parent 6555d2d751
commit a68a7346c3
No known key found for this signature in database
GPG Key ID: DC3B7867D8D97095
5 changed files with 398 additions and 403 deletions

View File

@ -1,15 +1,12 @@
use std::collections::BTreeMap;
use tui::layout::Direction;
use crate::canvas::LayoutConstraint;
use crate::constants::DEFAULT_WIDGET_ID;
use crate::error::{BottomError, Result};
/// Represents a more usable representation of the layout, derived from the
/// config.
#[derive(Clone, Debug)]
pub struct BottomLayout {
pub rows: Vec<BottomRow>,
pub total_row_height_ratio: u32,
}
use crate::options::layout_options::Row;
use crate::utils::error;
/// Represents a start and end coordinate in some dimension.
type LineSegment = (u32, u32);
@ -18,8 +15,276 @@ type WidgetMappings = (u32, BTreeMap<LineSegment, u64>);
type ColumnRowMappings = (u32, BTreeMap<LineSegment, WidgetMappings>);
type ColumnMappings = (u32, BTreeMap<LineSegment, ColumnRowMappings>);
#[derive(Clone, Debug)]
pub enum Node {
/// A container type, containing more [`Node`] children.
Container(Container),
/// A leaf node, containing a [`BottomWidget`].
Widget(BottomWidget),
}
impl Node {
pub fn constraint(&self) -> LayoutConstraint {
match self {
Node::Container(c) => c.constraint,
Node::Widget(w) => w.constraint,
}
}
}
/// A "container" that contains more [`Node`]s.
#[derive(Debug, Clone)]
pub(crate) struct Container {
/// The children elements.
pub(crate) children: Vec<usize>,
/// How the container should be sized.
pub(crate) constraint: LayoutConstraint,
/// The direction.
direction: ContainerDirection,
}
impl Container {
pub(crate) fn row(children: Vec<usize>, sizing: LayoutConstraint) -> Self {
Self {
children,
constraint: sizing,
direction: ContainerDirection::Row,
}
}
pub(crate) fn col(children: Vec<usize>, constraint: LayoutConstraint) -> Self {
Self {
children,
constraint,
direction: ContainerDirection::Col,
}
}
/// Returns the direction of the container.
pub fn direction(&self) -> ContainerDirection {
self.direction
}
}
/// The direction in which children in a [`BottomContainer`] will be laid out.
#[derive(Debug, Clone, Copy)]
pub(crate) enum ContainerDirection {
/// Lay out all children horizontally.
Row,
/// Lay out all children vertically.
Col,
}
impl From<ContainerDirection> for Direction {
fn from(value: ContainerDirection) -> Self {
match value {
ContainerDirection::Row => Direction::Horizontal,
ContainerDirection::Col => Direction::Vertical,
}
}
}
/// Represents a more usable representation of the layout, derived from the
/// config.
///
/// Internally represented by an arena-backed tree.
#[derive(Clone, Debug, Default)]
pub struct BottomLayout {
arena: Vec<Node>,
}
impl BottomLayout {
pub fn get_movement_mappings(&mut self) {
/// Add a node to the layout arena. The ID is returned.
pub fn add_node(&mut self, node: Node) -> usize {
let id = self.arena.len();
self.arena.push(node);
id
}
/// Get the node with the corresponding ID.
pub fn get_node(&self, id: usize) -> Option<&Node> {
self.arena.get(id)
}
/// Returns the number of elements in the layout.
pub fn len(&self) -> usize {
self.arena.len()
}
/// Creates a new [`BottomLayout`] given a slice of [`Row`]s.
pub fn from_rows(rows: &[Row]) -> error::Result<Self> {
let mut num_widgets = 0;
// TODO: Create the thing; use num_widgets to count how many widgets were inserted.
if num_widgets > 0 {
todo!()
} else {
Err(error::BottomError::ConfigError(
"please have at least one widget under the '[[row]]' section.".to_string(),
))
}
}
/// Creates a new [`BottomLayout`] following the basic layout.
pub fn new_basic(use_battery: bool) -> Self {
let table_widgets = if use_battery {
let disk_widget = BottomWidget::new_handled(BottomWidgetType::Disk, 4)
.up_neighbour(Some(100))
.left_neighbour(Some(8))
.right_neighbour(Some(DEFAULT_WIDGET_ID + 2));
let proc_sort =
BottomWidget::new_handled(BottomWidgetType::ProcSort, DEFAULT_WIDGET_ID + 2)
.up_neighbour(Some(100))
.down_neighbour(Some(DEFAULT_WIDGET_ID + 1))
.left_neighbour(Some(4))
.right_neighbour(Some(DEFAULT_WIDGET_ID))
.parent_reflector(Some((WidgetDirection::Right, 2)));
let proc = BottomWidget::new_handled(BottomWidgetType::Proc, DEFAULT_WIDGET_ID)
.up_neighbour(Some(100))
.down_neighbour(Some(DEFAULT_WIDGET_ID + 1))
.left_neighbour(Some(DEFAULT_WIDGET_ID + 2))
.right_neighbour(Some(7));
let proc_search =
BottomWidget::new_handled(BottomWidgetType::ProcSearch, DEFAULT_WIDGET_ID + 1)
.up_neighbour(Some(DEFAULT_WIDGET_ID))
.left_neighbour(Some(4))
.right_neighbour(Some(7))
.parent_reflector(Some((WidgetDirection::Up, 1)));
let temp = BottomWidget::new_handled(BottomWidgetType::Temp, 7)
.up_neighbour(Some(100))
.left_neighbour(Some(DEFAULT_WIDGET_ID))
.right_neighbour(Some(8));
let battery = BottomWidget::new_handled(BottomWidgetType::Battery, 8)
.up_neighbour(Some(100))
.left_neighbour(Some(7))
.right_neighbour(Some(4));
vec![
BottomCol::new(vec![
BottomColRow::new(vec![disk_widget]).canvas_handle_height(true)
])
.canvas_handle_width(true),
BottomCol::new(vec![
BottomColRow::new(vec![proc_sort, proc])
.canvas_handle_height(true)
.total_widget_ratio(3),
BottomColRow::new(vec![proc_search]).canvas_handle_height(true),
])
.canvas_handle_width(true),
BottomCol::new(vec![
BottomColRow::new(vec![temp]).canvas_handle_height(true)
])
.canvas_handle_width(true),
BottomCol::new(vec![
BottomColRow::new(vec![battery]).canvas_handle_height(true)
])
.canvas_handle_width(true),
]
} else {
let disk = BottomWidget::new_handled(BottomWidgetType::Disk, 4)
.up_neighbour(Some(100))
.left_neighbour(Some(7))
.right_neighbour(Some(DEFAULT_WIDGET_ID + 2));
let proc_sort =
BottomWidget::new_handled(BottomWidgetType::ProcSort, DEFAULT_WIDGET_ID + 2)
.up_neighbour(Some(100))
.down_neighbour(Some(DEFAULT_WIDGET_ID + 1))
.left_neighbour(Some(4))
.right_neighbour(Some(DEFAULT_WIDGET_ID))
.parent_reflector(Some((WidgetDirection::Right, 2)));
let proc = BottomWidget::new_handled(BottomWidgetType::Proc, DEFAULT_WIDGET_ID)
.up_neighbour(Some(100))
.down_neighbour(Some(DEFAULT_WIDGET_ID + 1))
.left_neighbour(Some(DEFAULT_WIDGET_ID + 2))
.right_neighbour(Some(7));
let proc_search =
BottomWidget::new_handled(BottomWidgetType::ProcSearch, DEFAULT_WIDGET_ID + 1)
.up_neighbour(Some(DEFAULT_WIDGET_ID))
.left_neighbour(Some(4))
.right_neighbour(Some(7))
.parent_reflector(Some((WidgetDirection::Up, 1)));
let temp = BottomWidget::new_handled(BottomWidgetType::Temp, 7)
.up_neighbour(Some(100))
.left_neighbour(Some(DEFAULT_WIDGET_ID))
.right_neighbour(Some(4));
vec![
BottomCol::new(vec![
BottomColRow::new(vec![disk]).canvas_handle_height(true)
])
.canvas_handle_width(true),
BottomCol::new(vec![
BottomColRow::new(vec![proc_sort, proc]).canvas_handle_height(true),
BottomColRow::new(vec![proc_search]).canvas_handle_height(true),
])
.canvas_handle_width(true),
BottomCol::new(vec![
BottomColRow::new(vec![temp]).canvas_handle_height(true)
])
.canvas_handle_width(true),
]
};
let cpu = BottomWidget::new_handled(BottomWidgetType::BasicCpu, 1).down_neighbour(Some(2));
let mem = BottomWidget::new_handled(BottomWidgetType::BasicMem, 2)
.up_neighbour(Some(1))
.down_neighbour(Some(100))
.right_neighbour(Some(3));
let net = BottomWidget::new_handled(BottomWidgetType::BasicNet, 3)
.up_neighbour(Some(1))
.down_neighbour(Some(100))
.left_neighbour(Some(2));
let table =
BottomWidget::new_handled(BottomWidgetType::BasicTables, 100).up_neighbour(Some(2));
let mut layout = BottomLayout::default();
// TODO: Add nodes; should we instead back with a hashmap?
// BottomLayout {
// total_row_height_ratio: 3,
// rows: vec![
// BottomRow::new(vec![BottomCol::new(vec![
// BottomColRow::new(vec![cpu]).canvas_handle_height(true)
// ])
// .canvas_handle_width(true)])
// .canvas_handle_height(true),
// BottomRow::new(vec![BottomCol::new(vec![BottomColRow::new(vec![
// mem, net,
// ])
// .canvas_handle_height(true)])
// .canvas_handle_width(true)])
// .canvas_handle_height(true),
// BottomRow::new(vec![BottomCol::new(vec![
// BottomColRow::new(vec![table]).canvas_handle_height(true)
// ])
// .canvas_handle_width(true)])
// .canvas_handle_height(true),
// BottomRow::new(table_widgets).canvas_handle_height(true),
// ],
// }
layout
}
fn get_movement_mappings(&mut self) {
#[allow(clippy::suspicious_operation_groupings)] // Have to enable this, clippy really doesn't like me doing this with tuples...
fn is_intersecting(a: LineSegment, b: LineSegment) -> bool {
a.0 >= b.0 && a.1 <= b.1
@ -39,7 +304,7 @@ impl BottomLayout {
}
// Now we need to create the correct mapping for moving from a specific
// widget to another
// widget to another.
let mut layout_mapping: BTreeMap<LineSegment, ColumnMappings> = BTreeMap::new();
let mut total_height = 0;
for row in &self.rows {
@ -529,201 +794,6 @@ impl BottomLayout {
height_cursor += row.row_height_ratio;
}
}
pub fn init_basic_default(use_battery: bool) -> Self {
let table_widgets = if use_battery {
let disk_widget = BottomWidget::new_handled(BottomWidgetType::Disk, 4)
.up_neighbour(Some(100))
.left_neighbour(Some(8))
.right_neighbour(Some(DEFAULT_WIDGET_ID + 2));
let proc_sort =
BottomWidget::new_handled(BottomWidgetType::ProcSort, DEFAULT_WIDGET_ID + 2)
.up_neighbour(Some(100))
.down_neighbour(Some(DEFAULT_WIDGET_ID + 1))
.left_neighbour(Some(4))
.right_neighbour(Some(DEFAULT_WIDGET_ID))
.parent_reflector(Some((WidgetDirection::Right, 2)));
let proc = BottomWidget::new_handled(BottomWidgetType::Proc, DEFAULT_WIDGET_ID)
.up_neighbour(Some(100))
.down_neighbour(Some(DEFAULT_WIDGET_ID + 1))
.left_neighbour(Some(DEFAULT_WIDGET_ID + 2))
.right_neighbour(Some(7));
let proc_search =
BottomWidget::new_handled(BottomWidgetType::ProcSearch, DEFAULT_WIDGET_ID + 1)
.up_neighbour(Some(DEFAULT_WIDGET_ID))
.left_neighbour(Some(4))
.right_neighbour(Some(7))
.parent_reflector(Some((WidgetDirection::Up, 1)));
let temp = BottomWidget::new_handled(BottomWidgetType::Temp, 7)
.up_neighbour(Some(100))
.left_neighbour(Some(DEFAULT_WIDGET_ID))
.right_neighbour(Some(8));
let battery = BottomWidget::new_handled(BottomWidgetType::Battery, 8)
.up_neighbour(Some(100))
.left_neighbour(Some(7))
.right_neighbour(Some(4));
vec![
BottomCol::new(vec![
BottomColRow::new(vec![disk_widget]).canvas_handle_height(true)
])
.canvas_handle_width(true),
BottomCol::new(vec![
BottomColRow::new(vec![proc_sort, proc])
.canvas_handle_height(true)
.total_widget_ratio(3),
BottomColRow::new(vec![proc_search]).canvas_handle_height(true),
])
.canvas_handle_width(true),
BottomCol::new(vec![
BottomColRow::new(vec![temp]).canvas_handle_height(true)
])
.canvas_handle_width(true),
BottomCol::new(vec![
BottomColRow::new(vec![battery]).canvas_handle_height(true)
])
.canvas_handle_width(true),
]
} else {
let disk = BottomWidget::new_handled(BottomWidgetType::Disk, 4)
.up_neighbour(Some(100))
.left_neighbour(Some(7))
.right_neighbour(Some(DEFAULT_WIDGET_ID + 2));
let proc_sort =
BottomWidget::new_handled(BottomWidgetType::ProcSort, DEFAULT_WIDGET_ID + 2)
.up_neighbour(Some(100))
.down_neighbour(Some(DEFAULT_WIDGET_ID + 1))
.left_neighbour(Some(4))
.right_neighbour(Some(DEFAULT_WIDGET_ID))
.parent_reflector(Some((WidgetDirection::Right, 2)));
let proc = BottomWidget::new_handled(BottomWidgetType::Proc, DEFAULT_WIDGET_ID)
.up_neighbour(Some(100))
.down_neighbour(Some(DEFAULT_WIDGET_ID + 1))
.left_neighbour(Some(DEFAULT_WIDGET_ID + 2))
.right_neighbour(Some(7));
let proc_search =
BottomWidget::new_handled(BottomWidgetType::ProcSearch, DEFAULT_WIDGET_ID + 1)
.up_neighbour(Some(DEFAULT_WIDGET_ID))
.left_neighbour(Some(4))
.right_neighbour(Some(7))
.parent_reflector(Some((WidgetDirection::Up, 1)));
let temp = BottomWidget::new_handled(BottomWidgetType::Temp, 7)
.up_neighbour(Some(100))
.left_neighbour(Some(DEFAULT_WIDGET_ID))
.right_neighbour(Some(4));
vec![
BottomCol::new(vec![
BottomColRow::new(vec![disk]).canvas_handle_height(true)
])
.canvas_handle_width(true),
BottomCol::new(vec![
BottomColRow::new(vec![proc_sort, proc]).canvas_handle_height(true),
BottomColRow::new(vec![proc_search]).canvas_handle_height(true),
])
.canvas_handle_width(true),
BottomCol::new(vec![
BottomColRow::new(vec![temp]).canvas_handle_height(true)
])
.canvas_handle_width(true),
]
};
let cpu = BottomWidget::new_handled(BottomWidgetType::BasicCpu, 1).down_neighbour(Some(2));
let mem = BottomWidget::new_handled(BottomWidgetType::BasicMem, 2)
.up_neighbour(Some(1))
.down_neighbour(Some(100))
.right_neighbour(Some(3));
let net = BottomWidget::new_handled(BottomWidgetType::BasicNet, 3)
.up_neighbour(Some(1))
.down_neighbour(Some(100))
.left_neighbour(Some(2));
let table =
BottomWidget::new_handled(BottomWidgetType::BasicTables, 100).up_neighbour(Some(2));
BottomLayout {
total_row_height_ratio: 3,
rows: vec![
BottomRow::new(vec![BottomCol::new(vec![
BottomColRow::new(vec![cpu]).canvas_handle_height(true)
])
.canvas_handle_width(true)])
.canvas_handle_height(true),
BottomRow::new(vec![BottomCol::new(vec![BottomColRow::new(vec![
mem, net,
])
.canvas_handle_height(true)])
.canvas_handle_width(true)])
.canvas_handle_height(true),
BottomRow::new(vec![BottomCol::new(vec![
BottomColRow::new(vec![table]).canvas_handle_height(true)
])
.canvas_handle_width(true)])
.canvas_handle_height(true),
BottomRow::new(table_widgets).canvas_handle_height(true),
],
}
}
}
#[derive(Debug, Clone)]
pub(crate) enum BottomLayoutNode {
/// A container type, containing more [`BottomLayoutNode`] children.
Container(BottomContainer),
/// A leaf node, containing a [`BottomWidget`].
Widget(BottomWidget),
}
/// A "container" that contains more [`BottomLayoutNode`]s.
#[derive(Debug, Clone)]
pub(crate) struct BottomContainer {
/// The children elements.
pub(crate) children: Vec<BottomLayoutNode>,
/// How the container should be sized.
pub(crate) sizing: ElementSizing,
}
/// The direction in which children in a [`BottomContainer`] will be laid out.
#[derive(Debug, Clone, Copy)]
pub(crate) enum BottomContainerType {
/// Lay out all children horizontally.
Row,
/// Lay out all children vertically.
Col,
}
/// How the element sizing should be determined.
///
/// FIXME: This should honestly be matched tighter to the canvas system; we currently have two very similar ways of doing things!
#[derive(Debug, Clone, Copy)]
pub(crate) enum ElementSizing {
/// Denotes that the canvas should follow the given ratio of `lhs:rhs` to determine spacing for the element.
Ratio { lhs: u32, rhs: u32 },
/// Denotes that the canvas should let this element grow to take up whatever remaining space is left after
/// sizing the other sibling elements.
FlexGrow,
/// Denotes that the canvas can do whatever it likes to determine spacing for the element.
CanvasHandled,
/// Denotes that the element should take up 100% of the space.
Fill,
}
/// Represents a single row in the layout.
@ -884,7 +954,7 @@ pub struct BottomWidget {
pub widget_id: u64,
/// How the widget should be sized by the canvas.
pub sizing: ElementSizing,
pub constraint: LayoutConstraint,
/// The widget ID to go to when moving to the left.
pub left_neighbour: Option<u64>,
@ -910,12 +980,12 @@ pub struct BottomWidget {
impl BottomWidget {
pub(crate) fn new(
widget_type: BottomWidgetType, widget_id: u64, sizing: ElementSizing,
widget_type: BottomWidgetType, widget_id: u64, constraint: LayoutConstraint,
) -> Self {
Self {
widget_type,
widget_id,
sizing,
constraint,
left_neighbour: None,
right_neighbour: None,
up_neighbour: None,
@ -927,11 +997,15 @@ impl BottomWidget {
}
pub(crate) fn new_fill(widget_type: BottomWidgetType, widget_id: u64) -> Self {
Self::new(widget_type, widget_id, ElementSizing::Fill)
Self::new(
widget_type,
widget_id,
LayoutConstraint::Ratio { lhs: 1, rhs: 1 },
)
}
pub(crate) fn new_handled(widget_type: BottomWidgetType, widget_id: u64) -> Self {
Self::new(widget_type, widget_id, ElementSizing::CanvasHandled)
Self::new(widget_type, widget_id, LayoutConstraint::CanvasHandled)
}
pub(crate) fn left_neighbour(mut self, left_neighbour: Option<u64>) -> Self {

View File

@ -1,7 +1,7 @@
use std::str::FromStr;
use canvas_styling::*;
use itertools::izip;
use hashbrown::HashMap;
use tui::{
backend::Backend,
layout::{Constraint, Direction, Layout, Rect},
@ -13,7 +13,7 @@ use tui::{
use crate::{
app::{
self,
layout_manager::{BottomColRow, BottomLayout, BottomWidgetType, ElementSizing},
layout_manager::{BottomColRow, BottomLayout, BottomWidget, BottomWidgetType, Node},
App,
},
constants::*,
@ -63,22 +63,23 @@ pub struct Painter {
height: u16,
width: u16,
styled_help_text: Vec<Line<'static>>,
is_mac_os: bool, // TODO: This feels out of place...
// TODO: Redo this entire thing.
row_constraints: Vec<LayoutConstraint>,
col_constraints: Vec<Vec<LayoutConstraint>>,
col_row_constraints: Vec<Vec<Vec<LayoutConstraint>>>,
layout_constraints: Vec<Vec<Vec<Vec<LayoutConstraint>>>>,
derived_widget_draw_locs: Vec<Vec<Vec<Vec<Rect>>>>,
derived_widget_draw_locs: HashMap<usize, Rect>,
widget_layout: BottomLayout,
}
// Part of a temporary fix for https://github.com/ClementTsang/bottom/issues/896
enum LayoutConstraint {
#[derive(Debug, Clone, Copy)]
pub enum LayoutConstraint {
/// Denotes that the canvas should follow the given ratio of `lhs:rhs` to determine spacing for the element.
Ratio { lhs: u32, rhs: u32 },
/// Denotes that the canvas should let this element grow to take up whatever remaining space is left after
/// sizing the other sibling elements.
FlexGrow,
/// Denotes that the canvas can do whatever it likes to determine spacing for the element.
CanvasHandled,
Grow,
Ratio(u32, u32),
}
impl Painter {
@ -87,77 +88,11 @@ impl Painter {
// We want to do this ONCE and reuse; after this we can just construct
// based on the console size.
let mut row_constraints = Vec::new();
let mut col_constraints = Vec::new();
let mut col_row_constraints = Vec::new();
let mut layout_constraints = Vec::new();
widget_layout.rows.iter().for_each(|row| {
if row.canvas_handle_height {
row_constraints.push(LayoutConstraint::CanvasHandled);
} else {
row_constraints.push(LayoutConstraint::Ratio(
row.row_height_ratio,
widget_layout.total_row_height_ratio,
));
}
let mut new_col_constraints = Vec::new();
let mut new_widget_constraints = Vec::new();
let mut new_col_row_constraints = Vec::new();
row.children.iter().for_each(|col| {
if col.canvas_handle_width {
new_col_constraints.push(LayoutConstraint::CanvasHandled);
} else {
new_col_constraints.push(LayoutConstraint::Ratio(
col.col_width_ratio,
row.total_col_ratio,
));
}
let mut new_new_col_row_constraints = Vec::new();
let mut new_new_widget_constraints = Vec::new();
col.children.iter().for_each(|col_row| {
if col_row.canvas_handle_height {
new_new_col_row_constraints.push(LayoutConstraint::CanvasHandled);
} else if col_row.flex_grow {
new_new_col_row_constraints.push(LayoutConstraint::Grow);
} else {
new_new_col_row_constraints.push(LayoutConstraint::Ratio(
col_row.col_row_height_ratio,
col.total_col_row_ratio,
));
}
let mut new_new_new_widget_constraints = Vec::new();
col_row.children.iter().for_each(|widget| {
new_new_new_widget_constraints.push(match widget.sizing {
ElementSizing::Ratio { lhs, rhs } => LayoutConstraint::Ratio(lhs, rhs),
ElementSizing::FlexGrow => LayoutConstraint::Grow,
ElementSizing::CanvasHandled => LayoutConstraint::CanvasHandled,
ElementSizing::Fill => LayoutConstraint::Ratio(1, 1),
});
});
new_new_widget_constraints.push(new_new_new_widget_constraints);
});
new_col_row_constraints.push(new_new_col_row_constraints);
new_widget_constraints.push(new_new_widget_constraints);
});
col_row_constraints.push(new_col_row_constraints);
layout_constraints.push(new_widget_constraints);
col_constraints.push(new_col_constraints);
});
let mut painter = Painter {
colours: styling,
height: 0,
width: 0,
styled_help_text: Vec::default(),
is_mac_os: cfg!(target_os = "macos"),
row_constraints,
col_constraints,
col_row_constraints,
layout_constraints,
widget_layout,
derived_widget_draw_locs: Vec::default(),
};
@ -525,8 +460,8 @@ impl Painter {
}
if self.derived_widget_draw_locs.is_empty() || app_state.is_force_redraw {
fn get_constraints(
direction: Direction, constraints: &[LayoutConstraint], area: Rect,
fn get_rects<I: ExactSizeIterator<Item = LayoutConstraint>>(
direction: Direction, constraints: I, area: Rect,
) -> Vec<Rect> {
// Order of operations:
// - Ratios first + canvas-handled (which is just zero)
@ -558,21 +493,20 @@ impl Painter {
let mut num_non_ch = 0;
for (itx, (constraint, size)) in
constraints.iter().zip(sizes.iter_mut()).enumerate()
constraints.zip(sizes.iter_mut()).enumerate()
{
match constraint {
LayoutConstraint::Ratio(a, b) => {
LayoutConstraint::Ratio { lhs, rhs } => {
match direction {
Direction::Horizontal => {
let amount =
(((area.width as u32) * (*a)) / (*b)) as u16;
let amount = (((area.width as u32) * lhs) / rhs) as u16;
bounds.shrink_width(amount);
size.width = amount;
size.height = area.height;
}
Direction::Vertical => {
let amount =
(((area.height as u32) * (*a)) / (*b)) as u16;
(((area.height as u32) * lhs) / rhs) as u16;
bounds.shrink_height(amount);
size.width = area.width;
size.height = amount;
@ -580,7 +514,7 @@ impl Painter {
}
num_non_ch += 1;
}
LayoutConstraint::Grow => {
LayoutConstraint::FlexGrow => {
// Mark it as grow in the vector and handle in second pass.
grow.push(itx);
num_non_ch += 1;
@ -624,8 +558,8 @@ impl Painter {
for (size, constraint) in sizes.iter_mut().zip(constraints) {
match constraint {
LayoutConstraint::CanvasHandled => {}
LayoutConstraint::Grow
| LayoutConstraint::Ratio(_, _) => {
LayoutConstraint::FlexGrow
| LayoutConstraint::Ratio { .. } => {
if remaining_width > 0 {
size.width += per_item + 1;
remaining_width -= 1;
@ -642,8 +576,8 @@ impl Painter {
for (size, constraint) in sizes.iter_mut().zip(constraints) {
match constraint {
LayoutConstraint::CanvasHandled => {}
LayoutConstraint::Grow
| LayoutConstraint::Ratio(_, _) => {
LayoutConstraint::FlexGrow
| LayoutConstraint::Ratio { .. } => {
if remaining_height > 0 {
size.height += per_item + 1;
remaining_height -= 1;
@ -677,79 +611,53 @@ impl Painter {
.collect()
}
let draw_locs =
get_constraints(Direction::Vertical, &self.row_constraints, terminal_size);
// Do a preorder traversal through the tree in, and calculate the draw [`Rect`]s for each widget.
let root_id = self.widget_layout.len().saturating_sub(1);
let mut queue = vec![(root_id, terminal_size)];
while let Some((current_id, rect)) = queue.pop() {
if let Some(widget) = self.widget_layout.get_node(current_id) {
match widget {
Node::Container(container) => {
let constraints = container.children.iter().map(|child| {
if let Some(node) = self.widget_layout.get_node(*child) {
node.constraint()
} else {
LayoutConstraint::FlexGrow
}
});
self.derived_widget_draw_locs = izip!(
draw_locs,
&self.col_constraints,
&self.col_row_constraints,
&self.layout_constraints,
&self.widget_layout.rows
)
.map(
|(
draw_loc,
col_constraint,
col_row_constraint,
row_constraint_vec,
cols,
)| {
izip!(
get_constraints(Direction::Horizontal, col_constraint, draw_loc),
col_row_constraint,
row_constraint_vec,
&cols.children
)
.map(|(split_loc, constraint, col_constraint_vec, col_rows)| {
izip!(
get_constraints(
Direction::Vertical,
constraint.as_slice(),
split_loc
),
col_constraint_vec,
&col_rows.children
)
.map(|(draw_loc, col_row_constraint_vec, widgets)| {
// Note that col_row_constraint_vec CONTAINS the widget constraints
let widget_draw_locs = get_constraints(
Direction::Horizontal,
col_row_constraint_vec.as_slice(),
draw_loc,
);
let rects =
get_rects(container.direction().into(), constraints, rect);
// Side effect, draw here.
self.draw_widgets_with_constraints(
f,
app_state,
widgets,
&widget_draw_locs,
);
widget_draw_locs
})
.collect()
})
.collect()
},
)
.collect();
// If it's a container, push in reverse order to the stack.
for child in container
.children
.iter()
.cloned()
.zip(rects.into_iter())
.rev()
{
queue.push(child);
}
}
Node::Widget(widget) => {
// If we're instead on a widget, we can instead assign the rect to the widget.
self.derived_widget_draw_locs.insert(current_id, rect);
}
}
}
}
} else {
self.widget_layout
.rows
.iter()
.flat_map(|row| &row.children)
.flat_map(|col| &col.children)
.zip(self.derived_widget_draw_locs.iter().flatten().flatten())
.for_each(|(widgets, widget_draw_locs)| {
self.draw_widgets_with_constraints(
f,
app_state,
widgets,
widget_draw_locs,
);
});
for (id, rect) in &self.derived_widget_draw_locs {
match &self.widget_layout.get_node(*id) {
Some(Node::Widget(widget)) => {
self.draw_widget(f, app_state, widget, *rect);
}
_ => {
// This should never happen, but if it does, do nothing.
}
}
}
}
}
})?;
@ -800,4 +708,23 @@ impl Painter {
}
}
}
fn draw_widget<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, widget: &BottomWidget, rect: Rect,
) {
use BottomWidgetType::*;
if rect.width >= 2 && rect.height >= 2 {
match &widget.widget_type {
Empty => {}
Cpu => self.draw_cpu(f, app_state, rect, widget.widget_id),
Mem => self.draw_memory_graph(f, app_state, rect, widget.widget_id),
Net => self.draw_network(f, app_state, rect, widget.widget_id),
Temp => self.draw_temp_table(f, app_state, rect, widget.widget_id),
Disk => self.draw_disk_table(f, app_state, rect, widget.widget_id),
Proc => self.draw_process_widget(f, app_state, rect, true, widget.widget_id),
Battery => self.draw_battery_display(f, app_state, rect, true, widget.widget_id),
_ => {}
}
}
}
}

View File

@ -220,10 +220,14 @@ impl Painter {
// TODO: [MOUSE] Mouse support for these in search
// TODO: [MOVEMENT] Movement support for these in search
let (case, whole, regex) = if self.is_mac_os {
("Case(F1)", "Whole(F2)", "Regex(F3)")
} else {
("Case(Alt+C)", "Whole(Alt+W)", "Regex(Alt+R)")
let (case, whole, regex) = {
cfg_if::cfg_if! {
if #[cfg(target_os = "macos")] {
("Case(F1)", "Whole(F2)", "Regex(F3)")
} else {
("Case(Alt+C)", "Whole(Alt+W)", "Regex(Alt+R)")
}
}
};
let option_text = Line::from(vec![
Span::styled(case, case_style),

View File

@ -471,7 +471,7 @@ pub fn get_widget_layout(
let bottom_layout = if is_flag_enabled!(basic, matches, config) {
default_widget_id = DEFAULT_WIDGET_ID;
BottomLayout::init_basic_default(get_use_battery(matches, config))
BottomLayout::new_basic(get_use_battery(matches, config))
} else {
let ref_row: Vec<Row>; // Required to handle reference
let rows = match &config.row {
@ -492,34 +492,24 @@ pub fn get_widget_layout(
let mut iter_id = 0; // A lazy way of forcing unique IDs *shrugs*
let mut total_height_ratio = 0;
let mut ret_bottom_layout = BottomLayout {
rows: rows
.iter()
.map(|row| {
row.convert_row_to_bottom_row(
&mut iter_id,
&mut total_height_ratio,
&mut default_widget_id,
&default_widget_type,
&mut default_widget_count,
left_legend,
)
})
.collect::<error::Result<Vec<_>>>()?,
total_row_height_ratio: total_height_ratio,
};
// let mut ret_bottom_layout = BottomLayout {
// arena: todo!(),
// arena: rows
// .iter()
// .map(|row| {
// row.convert_row_to_bottom_row(
// &mut iter_id,
// &mut total_height_ratio,
// &mut default_widget_id,
// &default_widget_type,
// &mut default_widget_count,
// left_legend,
// )
// })
// .collect::<error::Result<Vec<_>>>()?,
// };
// Confirm that we have at least ONE widget left - if not, error out!
if iter_id > 0 {
ret_bottom_layout.get_movement_mappings();
// debug!("Bottom layout: {:#?}", ret_bottom_layout);
ret_bottom_layout
} else {
return Err(error::BottomError::ConfigError(
"please have at least one widget under the '[[row]]' section.".to_string(),
));
}
BottomLayout::from_rows(rows)?
};
Ok((bottom_layout, default_widget_id, default_widget_type))

View File

@ -8,7 +8,7 @@ use bottom::options::{layout_options::Row, Config};
use bottom::utils::error;
use toml_edit::de::from_str;
// TODO: Could move these into the library files rather than external tbh.
// FIXME: Move these into the library!
const PROC_LAYOUT: &str = r##"
[[row]]