fully migrate over custom layout creation

This commit is contained in:
ClementTsang 2023-06-05 01:44:40 -04:00
parent a68a7346c3
commit 000ea7cce4
No known key found for this signature in database
GPG Key ID: DC3B7867D8D97095
5 changed files with 1006 additions and 968 deletions

View File

@ -5,7 +5,7 @@ use tui::layout::Direction;
use crate::canvas::LayoutConstraint;
use crate::constants::DEFAULT_WIDGET_ID;
use crate::error::{BottomError, Result};
use crate::options::layout_options::Row;
use crate::options::layout_options::{Row, RowChildren};
use crate::utils::error;
/// Represents a start and end coordinate in some dimension.
@ -15,29 +15,11 @@ 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>,
pub(crate) children: Vec<NodeId>,
/// How the container should be sized.
pub(crate) constraint: LayoutConstraint,
@ -47,7 +29,7 @@ pub(crate) struct Container {
}
impl Container {
pub(crate) fn row(children: Vec<usize>, sizing: LayoutConstraint) -> Self {
pub(crate) fn row(children: Vec<NodeId>, sizing: LayoutConstraint) -> Self {
Self {
children,
constraint: sizing,
@ -55,7 +37,7 @@ impl Container {
}
}
pub(crate) fn col(children: Vec<usize>, constraint: LayoutConstraint) -> Self {
pub(crate) fn col(children: Vec<NodeId>, constraint: LayoutConstraint) -> Self {
Self {
children,
constraint,
@ -88,42 +70,301 @@ impl From<ContainerDirection> for Direction {
}
}
/// An ID for a node in a [`BottomLayout`].
#[derive(Clone, Copy, Debug)]
pub enum NodeId {
/// The ID for a [`Container`].
Container(usize),
/// The ID for a [`BottomWidget`].
Widget(usize),
}
fn new_cpu(
layout: &mut BottomLayout, left_legend: bool, iter_id: &mut u64, width: u32, total: u32,
) -> NodeId {
let cpu_id = *iter_id;
*iter_id += 1;
let legend_id = *iter_id;
if left_legend {
let cpu_legend = layout.add_widget(
BottomWidget::new_handled(BottomWidgetType::CpuLegend, legend_id)
.parent_reflector(Some((WidgetDirection::Right, 1))),
);
let cpu = layout.add_widget(BottomWidget::new_handled(BottomWidgetType::Cpu, cpu_id));
layout.add_container(Container::row(
vec![cpu_legend, cpu],
LayoutConstraint::Ratio { a: width, b: total },
))
} else {
let cpu = layout.add_widget(BottomWidget::new_handled(BottomWidgetType::Cpu, cpu_id));
let cpu_legend = layout.add_widget(
BottomWidget::new_handled(BottomWidgetType::CpuLegend, legend_id)
.parent_reflector(Some((WidgetDirection::Left, 1))),
);
layout.add_container(Container::row(
vec![cpu, cpu_legend],
LayoutConstraint::Ratio { a: width, b: total },
))
}
}
fn new_proc(layout: &mut BottomLayout, iter_id: &mut u64, width: u32, total: u32) -> NodeId {
let main_id = *iter_id;
let search_id = *iter_id + 1;
*iter_id += 2;
let sort_id = *iter_id;
let main = layout.add_widget(BottomWidget::new_fill(BottomWidgetType::Proc, main_id));
let search = layout.add_widget(
BottomWidget::new_fill(BottomWidgetType::ProcSearch, search_id)
.parent_reflector(Some((WidgetDirection::Up, 1))),
);
let sort = layout.add_widget(
BottomWidget::new_handled(BottomWidgetType::ProcSort, sort_id)
.parent_reflector(Some((WidgetDirection::Right, 2))),
);
let top = layout.add_container(Container::row(
vec![sort, main],
LayoutConstraint::CanvasHandled,
));
layout.add_container(Container::col(
vec![top, search],
LayoutConstraint::Ratio { a: width, b: total },
))
}
fn new_widget(
layout: &mut BottomLayout, widget_type: BottomWidgetType, iter_id: &mut u64, width: u32,
total_ratio: u32, left_legend: bool,
) -> NodeId {
*iter_id += 1;
match widget_type {
BottomWidgetType::Cpu => new_cpu(layout, left_legend, iter_id, width, total_ratio),
BottomWidgetType::Proc => new_proc(layout, iter_id, width, total_ratio),
_ => layout.add_widget(BottomWidget::new(
widget_type,
*iter_id,
LayoutConstraint::Ratio {
a: width,
b: total_ratio,
},
)),
}
}
/// 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>,
containers: Vec<Container>,
widgets: Vec<BottomWidget>,
}
impl BottomLayout {
/// 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);
/// Add a container to the layout arena. The ID is returned.
pub fn add_container(&mut self, container: Container) -> NodeId {
let id = self.containers.len();
self.containers.push(container);
id
NodeId::Container(id)
}
/// Add a node to the layout arena. The ID is returned.
pub fn add_widget(&mut self, widget: BottomWidget) -> NodeId {
let id = self.widgets.len();
self.widgets.push(widget);
NodeId::Widget(id)
}
/// Get the node with the corresponding ID.
pub fn get_node(&self, id: usize) -> Option<&Node> {
self.arena.get(id)
pub fn get_container(&self, id: usize) -> Option<&Container> {
self.containers.get(id)
}
/// Returns the number of elements in the layout.
/// Get the node with the corresponding ID.
pub fn get_widget(&self, id: usize) -> Option<&BottomWidget> {
self.widgets.get(id)
}
/// Returns an iterator of all widgets.
pub fn widgets_iter(&self) -> impl Iterator<Item = &BottomWidget> {
self.widgets.iter()
}
/// Returns the root ID if there is one. If there are no nodes, it will return [`None`].
pub fn root_id(&self) -> Option<NodeId> {
if self.containers.is_empty() {
if self.widgets.is_empty() {
None
} else {
Some(NodeId::Widget(self.widgets.len() - 1))
}
} else {
Some(NodeId::Container(self.containers.len() - 1))
}
}
/// Returns the number of elements (widgets + containers) in the layout.
pub fn len(&self) -> usize {
self.arena.len()
self.widgets.len() + self.containers.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;
/// Returns the number of widgets in the layout.
pub fn widgets_len(&self) -> usize {
self.widgets.len()
}
// TODO: Create the thing; use num_widgets to count how many widgets were inserted.
/// Creates a new [`BottomLayout`] given a slice of [`Row`]s, as well as the default widget ID.
pub fn from_rows(
rows: &[Row], default_widget_type: Option<BottomWidgetType>, mut default_widget_count: u64,
left_legend: bool,
) -> error::Result<(Self, u64)> {
let mut layout = Self::default();
let mut default_widget_id = 1;
let mut iter_id = 0; // TODO: In the future, remove this in favour of using the layout's ID system.
if num_widgets > 0 {
todo!()
let outer_col_total_ratio = rows.iter().map(|row| row.ratio.unwrap_or(1)).sum();
let mut outer_col_children = Vec::with_capacity(rows.len());
for row in rows {
// This code is all ported from the old row-to-bottom_row code, and converted
// to work with our new system.
// TODO: In the future we want to also add percentages.
// But for MVP, we aren't going to bother.
let row_ratio = row.ratio.unwrap_or(1);
if let Some(children) = &row.child {
let mut row_children = Vec::with_capacity(children.len());
let rows_total_ratio = children
.iter()
.map(|c| match c {
RowChildren::Widget(w) => w.ratio.unwrap_or(1),
RowChildren::Col { ratio, .. } => ratio.unwrap_or(1),
})
.sum();
for child in children {
match child {
RowChildren::Widget(widget) => {
let width = widget.ratio.unwrap_or(1);
let widget_type = widget.widget_type.parse::<BottomWidgetType>()?;
if let Some(default_widget_type_val) = default_widget_type {
if default_widget_type_val == widget_type
&& default_widget_count > 0
{
default_widget_count -= 1;
if default_widget_count == 0 {
default_widget_id = iter_id;
}
}
} else {
// Check default flag
if let Some(default_widget_flag) = widget.default {
if default_widget_flag {
default_widget_id = iter_id;
}
}
}
let widget = new_widget(
&mut layout,
widget_type,
&mut iter_id,
width,
rows_total_ratio,
left_legend,
);
row_children.push(widget);
}
RowChildren::Col {
ratio,
child: children,
} => {
let col_ratio = ratio.unwrap_or(1);
let mut col_children = vec![];
let inner_col_total_ratio =
children.iter().map(|w| w.ratio.unwrap_or(1)).sum();
for widget in children {
let widget_type = widget.widget_type.parse::<BottomWidgetType>()?;
let height = widget.ratio.unwrap_or(1);
if let Some(default_widget_type_val) = default_widget_type {
if default_widget_type_val == widget_type
&& default_widget_count > 0
{
default_widget_count -= 1;
if default_widget_count == 0 {
default_widget_id = iter_id;
}
}
} else {
// Check default flag
if let Some(default_widget_flag) = widget.default {
if default_widget_flag {
default_widget_id = iter_id;
}
}
}
let widget = new_widget(
&mut layout,
widget_type,
&mut iter_id,
height,
inner_col_total_ratio,
left_legend,
);
col_children.push(widget);
}
row_children.push(layout.add_container(Container::col(
col_children,
LayoutConstraint::Ratio {
a: col_ratio,
b: rows_total_ratio,
},
)));
}
}
}
outer_col_children.push(layout.add_container(Container::row(
row_children,
LayoutConstraint::Ratio {
a: row_ratio,
b: outer_col_total_ratio,
},
)));
};
}
layout.add_container(Container::col(
outer_col_children,
LayoutConstraint::FlexGrow,
));
if layout.widgets_len() > 0 {
layout.get_movement_mappings();
Ok((layout, default_widget_id))
} else {
Err(error::BottomError::ConfigError(
"please have at least one widget under the '[[row]]' section.".to_string(),
@ -133,153 +374,162 @@ impl BottomLayout {
/// Creates a new [`BottomLayout`] following the basic layout.
pub fn new_basic(use_battery: bool) -> Self {
let mut layout = BottomLayout::default();
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)
let disk = layout.add_widget(
BottomWidget::new_handled(BottomWidgetType::Disk, 4)
.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)));
.left_neighbour(Some(8))
.right_neighbour(Some(DEFAULT_WIDGET_ID + 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 = {
let proc_sort = layout.add_widget(
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_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 main_proc = layout.add_widget(
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 temp = BottomWidget::new_handled(BottomWidgetType::Temp, 7)
.up_neighbour(Some(100))
.left_neighbour(Some(DEFAULT_WIDGET_ID))
.right_neighbour(Some(8));
let proc_search = layout.add_widget(
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 battery = BottomWidget::new_handled(BottomWidgetType::Battery, 8)
.up_neighbour(Some(100))
.left_neighbour(Some(7))
.right_neighbour(Some(4));
let top = layout.add_container(Container::row(
vec![proc_sort, main_proc],
LayoutConstraint::CanvasHandled,
));
layout.add_container(Container::col(
vec![top, proc_search],
LayoutConstraint::CanvasHandled,
))
};
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),
]
let temp = layout.add_widget(
BottomWidget::new_handled(BottomWidgetType::Temp, 7)
.up_neighbour(Some(100))
.left_neighbour(Some(DEFAULT_WIDGET_ID))
.right_neighbour(Some(8)),
);
let battery = layout.add_widget(
BottomWidget::new_handled(BottomWidgetType::Battery, 8)
.up_neighbour(Some(100))
.left_neighbour(Some(7))
.right_neighbour(Some(4)),
);
layout.add_container(Container::row(
vec![disk, proc, temp, battery],
LayoutConstraint::CanvasHandled,
))
} 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)
let disk = layout.add_widget(
BottomWidget::new_handled(BottomWidgetType::Disk, 4)
.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)));
.left_neighbour(Some(7))
.right_neighbour(Some(DEFAULT_WIDGET_ID + 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 = {
let proc_sort = layout.add_widget(
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_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 main_proc = layout.add_widget(
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 temp = BottomWidget::new_handled(BottomWidgetType::Temp, 7)
.up_neighbour(Some(100))
.left_neighbour(Some(DEFAULT_WIDGET_ID))
.right_neighbour(Some(4));
let proc_search = layout.add_widget(
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))),
);
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 top = layout.add_container(Container::row(
vec![proc_sort, main_proc],
LayoutConstraint::CanvasHandled,
));
layout.add_container(Container::col(
vec![top, proc_search],
LayoutConstraint::CanvasHandled,
))
};
let temp = layout.add_widget(
BottomWidget::new_handled(BottomWidgetType::Temp, 7)
.up_neighbour(Some(100))
.left_neighbour(Some(DEFAULT_WIDGET_ID))
.right_neighbour(Some(4)),
);
layout.add_container(Container::row(
vec![disk, proc, temp],
LayoutConstraint::CanvasHandled,
))
};
let cpu = BottomWidget::new_handled(BottomWidgetType::BasicCpu, 1).down_neighbour(Some(2));
let cpu = layout.add_widget(
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 mem = layout.add_widget(
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 net = layout.add_widget(
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 net = layout.add_widget(
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?
let middle_bars = layout.add_container(Container::row(
vec![mem, net],
LayoutConstraint::CanvasHandled,
));
// 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),
// ],
// }
let table = layout.add_widget(
BottomWidget::new_handled(BottomWidgetType::BasicTables, 100).up_neighbour(Some(2)),
);
layout.add_container(Container::col(
vec![cpu, middle_bars, table, table_widgets],
LayoutConstraint::CanvasHandled,
));
layout
}
@ -1000,7 +1250,7 @@ impl BottomWidget {
Self::new(
widget_type,
widget_id,
LayoutConstraint::Ratio { lhs: 1, rhs: 1 },
LayoutConstraint::Ratio { a: 1, b: 1 },
)
}
@ -1036,7 +1286,7 @@ impl BottomWidget {
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default)]
pub enum BottomWidgetType {
#[default]
Empty,

View File

@ -13,7 +13,7 @@ use tui::{
use crate::{
app::{
self,
layout_manager::{BottomColRow, BottomLayout, BottomWidget, BottomWidgetType, Node},
layout_manager::{BottomColRow, BottomLayout, BottomWidget, BottomWidgetType, NodeId},
App,
},
constants::*,
@ -72,7 +72,7 @@ pub struct Painter {
#[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 },
Ratio { a: u32, b: u32 },
/// Denotes that the canvas should let this element grow to take up whatever remaining space is left after
/// sizing the other sibling elements.
@ -94,7 +94,7 @@ impl Painter {
width: 0,
styled_help_text: Vec::default(),
widget_layout,
derived_widget_draw_locs: Vec::default(),
derived_widget_draw_locs: HashMap::default(),
};
painter.complete_painter_init();
@ -496,7 +496,7 @@ impl Painter {
constraints.zip(sizes.iter_mut()).enumerate()
{
match constraint {
LayoutConstraint::Ratio { lhs, rhs } => {
LayoutConstraint::Ratio { a: lhs, b: rhs } => {
match direction {
Direction::Horizontal => {
let amount = (((area.width as u32) * lhs) / rhs) as u16;
@ -612,45 +612,60 @@ impl Painter {
}
// 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
}
});
let rects =
get_rects(container.direction().into(), constraints, rect);
// If it's a container, push in reverse order to the stack.
for child in container
.children
.iter()
.cloned()
.zip(rects.into_iter())
.rev()
if let Some(root_id) = self.widget_layout.root_id() {
let mut queue = vec![(root_id, terminal_size)];
while let Some((current_id, rect)) = queue.pop() {
match current_id {
NodeId::Container(current_id) => {
if let Some(container) =
self.widget_layout.get_container(current_id)
{
queue.push(child);
let constraints = container.children.iter().map(|child| {
match child {
NodeId::Container(child) => self
.widget_layout
.get_container(*child)
.map(|c| c.constraint),
NodeId::Widget(child) => self
.widget_layout
.get_widget(*child)
.map(|w| w.constraint),
}
.unwrap_or(LayoutConstraint::FlexGrow)
});
let rects = get_rects(
container.direction().into(),
constraints,
rect,
);
// 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);
NodeId::Widget(current_id) => {
if let Some(widget) = self.widget_layout.get_widget(current_id)
{
// 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 {
for (id, rect) in &self.derived_widget_draw_locs {
match &self.widget_layout.get_node(*id) {
Some(Node::Widget(widget)) => {
match self.widget_layout.get_widget(*id) {
Some(widget) => {
self.draw_widget(f, app_state, widget, *rect);
}
_ => {

View File

@ -274,116 +274,110 @@ pub fn build_app(
is_command: is_default_command,
};
for row in &widget_layout.rows {
for col in &row.children {
for col_row in &col.children {
for widget in &col_row.children {
widget_map.insert(widget.widget_id, widget.clone());
if let Some(default_widget_type) = &default_widget_type_option {
if !is_custom_layout || use_basic_mode {
match widget.widget_type {
BasicCpu => {
if let Cpu = *default_widget_type {
initial_widget_id = widget.widget_id;
initial_widget_type = Cpu;
}
}
BasicMem => {
if let Mem = *default_widget_type {
initial_widget_id = widget.widget_id;
initial_widget_type = Cpu;
}
}
BasicNet => {
if let Net = *default_widget_type {
initial_widget_id = widget.widget_id;
initial_widget_type = Cpu;
}
}
_ => {
if *default_widget_type == widget.widget_type {
initial_widget_id = widget.widget_id;
initial_widget_type = widget.widget_type.clone();
}
}
}
// Determine the initial widget ID/type + initialize states.
for widget in widget_layout.widgets_iter() {
widget_map.insert(widget.widget_id, widget.clone());
if let Some(default_widget_type) = &default_widget_type_option {
if !is_custom_layout || use_basic_mode {
match widget.widget_type {
BasicCpu => {
if let Cpu = *default_widget_type {
initial_widget_id = widget.widget_id;
initial_widget_type = Cpu;
}
}
used_widget_set.insert(widget.widget_type.clone());
match widget.widget_type {
Cpu => {
cpu_state_map.insert(
widget.widget_id,
CpuWidgetState::new(
&app_config_fields,
default_time_value,
autohide_timer,
styling,
),
);
BasicMem => {
if let Mem = *default_widget_type {
initial_widget_id = widget.widget_id;
initial_widget_type = Cpu;
}
Mem => {
mem_state_map.insert(
widget.widget_id,
MemWidgetState::init(default_time_value, autohide_timer),
);
}
BasicNet => {
if let Net = *default_widget_type {
initial_widget_id = widget.widget_id;
initial_widget_type = Cpu;
}
Net => {
net_state_map.insert(
widget.widget_id,
NetWidgetState::init(default_time_value, autohide_timer),
);
}
_ => {
if *default_widget_type == widget.widget_type {
initial_widget_id = widget.widget_id;
initial_widget_type = widget.widget_type.clone();
}
Proc => {
let mode = if is_grouped {
ProcWidgetMode::Grouped
} else if is_default_tree {
ProcWidgetMode::Tree {
collapsed_pids: Default::default(),
}
} else {
ProcWidgetMode::Normal
};
proc_state_map.insert(
widget.widget_id,
ProcWidgetState::new(
&app_config_fields,
mode,
table_config,
styling,
&proc_columns,
),
);
}
Disk => {
disk_state_map.insert(
widget.widget_id,
DiskTableWidget::new(&app_config_fields, styling),
);
}
Temp => {
temp_state_map.insert(
widget.widget_id,
TempWidgetState::new(&app_config_fields, styling),
);
}
Battery => {
battery_state_map
.insert(widget.widget_id, BatteryWidgetState::default());
}
_ => {}
}
}
}
}
used_widget_set.insert(widget.widget_type.clone());
match widget.widget_type {
Cpu => {
cpu_state_map.insert(
widget.widget_id,
CpuWidgetState::new(
&app_config_fields,
default_time_value,
autohide_timer,
styling,
),
);
}
Mem => {
mem_state_map.insert(
widget.widget_id,
MemWidgetState::init(default_time_value, autohide_timer),
);
}
Net => {
net_state_map.insert(
widget.widget_id,
NetWidgetState::init(default_time_value, autohide_timer),
);
}
Proc => {
let mode = if is_grouped {
ProcWidgetMode::Grouped
} else if is_default_tree {
ProcWidgetMode::Tree {
collapsed_pids: Default::default(),
}
} else {
ProcWidgetMode::Normal
};
proc_state_map.insert(
widget.widget_id,
ProcWidgetState::new(
&app_config_fields,
mode,
table_config,
styling,
&proc_columns,
),
);
}
Disk => {
disk_state_map.insert(
widget.widget_id,
DiskTableWidget::new(&app_config_fields, styling),
);
}
Temp => {
temp_state_map.insert(
widget.widget_id,
TempWidgetState::new(&app_config_fields, styling),
);
}
Battery => {
battery_state_map.insert(widget.widget_id, BatteryWidgetState::default());
}
_ => {}
}
}
let basic_table_widget_state = if use_basic_mode {
Some(match initial_widget_type {
Proc | Disk | Temp => BasicTableWidgetState {
Proc | Disk | Temp | Battery => BasicTableWidgetState {
currently_displayed_widget_type: initial_widget_type,
currently_displayed_widget_id: initial_widget_id,
widget_id: 100,
@ -464,14 +458,15 @@ pub fn get_widget_layout(
) -> error::Result<(BottomLayout, u64, Option<BottomWidgetType>)> {
let left_legend = is_flag_enabled!(left_legend, matches, config);
let (default_widget_type, mut default_widget_count) =
let (default_widget_type, default_widget_count) =
get_default_widget_and_count(matches, config)?;
let mut default_widget_id = 1;
let bottom_layout = if is_flag_enabled!(basic, matches, config) {
default_widget_id = DEFAULT_WIDGET_ID;
BottomLayout::new_basic(get_use_battery(matches, config))
if is_flag_enabled!(basic, matches, config) {
Ok((
BottomLayout::new_basic(get_use_battery(matches, config)),
DEFAULT_WIDGET_ID,
default_widget_type,
))
} else {
let ref_row: Vec<Row>; // Required to handle reference
let rows = match &config.row {
@ -489,30 +484,11 @@ 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 (layout, default_widget_id) =
BottomLayout::from_rows(rows, default_widget_type, default_widget_count, left_legend)?;
// 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<_>>>()?,
// };
BottomLayout::from_rows(rows)?
};
Ok((bottom_layout, default_widget_id, default_widget_type))
Ok((layout, default_widget_id, default_widget_type))
}
}
fn get_update_rate_in_milliseconds(matches: &ArgMatches, config: &Config) -> error::Result<u64> {

View File

@ -1,9 +1,6 @@
use serde::{Deserialize, Serialize};
use crate::app::layout_manager::*;
use crate::error::Result;
/// Represents a row. This has a length of some sort (optional) and a vector
/// Represents a row. This has a length of some sort (optional) and a vector
/// of children.
#[derive(Clone, Deserialize, Debug, Serialize)]
#[serde(rename = "row")]
@ -12,209 +9,9 @@ pub struct Row {
pub child: Option<Vec<RowChildren>>,
}
fn new_cpu(left_legend: bool, iter_id: &mut u64) -> BottomColRow {
let cpu_id = *iter_id;
*iter_id += 1;
let legend_id = *iter_id;
if left_legend {
BottomColRow::new(vec![
BottomWidget::new_handled(BottomWidgetType::CpuLegend, legend_id)
.parent_reflector(Some((WidgetDirection::Right, 1))),
BottomWidget::new_handled(BottomWidgetType::Cpu, cpu_id),
])
} else {
BottomColRow::new(vec![
BottomWidget::new_handled(BottomWidgetType::Cpu, cpu_id),
BottomWidget::new_handled(BottomWidgetType::CpuLegend, legend_id)
.parent_reflector(Some((WidgetDirection::Left, 1))),
])
}
}
fn new_proc_sort(sort_id: u64) -> BottomWidget {
BottomWidget::new_handled(BottomWidgetType::ProcSort, sort_id)
.parent_reflector(Some((WidgetDirection::Right, 2)))
}
fn new_proc(proc_id: u64) -> BottomWidget {
BottomWidget::new_fill(BottomWidgetType::Proc, proc_id)
}
fn new_proc_search(search_id: u64) -> BottomWidget {
BottomWidget::new_fill(BottomWidgetType::ProcSearch, search_id)
.parent_reflector(Some((WidgetDirection::Up, 1)))
}
impl Row {
pub fn convert_row_to_bottom_row(
&self, iter_id: &mut u64, total_height_ratio: &mut u32, default_widget_id: &mut u64,
default_widget_type: &Option<BottomWidgetType>, default_widget_count: &mut u64,
left_legend: bool,
) -> Result<BottomRow> {
// TODO: In the future we want to also add percentages.
// But for MVP, we aren't going to bother.
let row_ratio = self.ratio.unwrap_or(1);
let mut children = Vec::new();
*total_height_ratio += row_ratio;
let mut total_col_ratio = 0;
if let Some(row_children) = &self.child {
for row_child in row_children {
match row_child {
RowChildren::Widget(widget) => {
*iter_id += 1;
let width_ratio = widget.ratio.unwrap_or(1);
total_col_ratio += width_ratio;
let widget_type = widget.widget_type.parse::<BottomWidgetType>()?;
if let Some(default_widget_type_val) = default_widget_type {
if *default_widget_type_val == widget_type && *default_widget_count > 0
{
*default_widget_count -= 1;
if *default_widget_count == 0 {
*default_widget_id = *iter_id;
}
}
} else {
// Check default flag
if let Some(default_widget_flag) = widget.default {
if default_widget_flag {
*default_widget_id = *iter_id;
}
}
}
children.push(match widget_type {
BottomWidgetType::Cpu => {
BottomCol::new(vec![new_cpu(left_legend, iter_id)])
.col_width_ratio(width_ratio)
}
BottomWidgetType::Proc => {
let proc_id = *iter_id;
let proc_search_id = *iter_id + 1;
*iter_id += 2;
BottomCol::new(vec![
BottomColRow::new(vec![
new_proc_sort(*iter_id),
new_proc(proc_id),
])
.total_widget_ratio(3)
.flex_grow(true),
BottomColRow::new(vec![new_proc_search(proc_search_id)])
.canvas_handle_height(true),
])
.total_col_row_ratio(2)
.col_width_ratio(width_ratio)
}
_ => BottomCol::new(vec![BottomColRow::new(vec![
BottomWidget::new_fill(widget_type, *iter_id),
])])
.col_width_ratio(width_ratio),
});
}
RowChildren::Col { ratio, child } => {
let col_width_ratio = ratio.unwrap_or(1);
total_col_ratio += col_width_ratio;
let mut total_col_row_ratio = 0;
let mut contains_proc = false;
let mut col_row_children: Vec<BottomColRow> = Vec::new();
for widget in child {
let widget_type = widget.widget_type.parse::<BottomWidgetType>()?;
*iter_id += 1;
let col_row_height_ratio = widget.ratio.unwrap_or(1);
total_col_row_ratio += col_row_height_ratio;
if let Some(default_widget_type_val) = default_widget_type {
if *default_widget_type_val == widget_type
&& *default_widget_count > 0
{
*default_widget_count -= 1;
if *default_widget_count == 0 {
*default_widget_id = *iter_id;
}
}
} else {
// Check default flag
if let Some(default_widget_flag) = widget.default {
if default_widget_flag {
*default_widget_id = *iter_id;
}
}
}
match widget_type {
BottomWidgetType::Cpu => {
col_row_children.push(
new_cpu(left_legend, iter_id)
.col_row_height_ratio(col_row_height_ratio),
);
}
BottomWidgetType::Proc => {
contains_proc = true;
let proc_id = *iter_id;
let proc_search_id = *iter_id + 1;
*iter_id += 2;
col_row_children.push(
BottomColRow::new(vec![
new_proc_sort(*iter_id),
new_proc(proc_id),
])
.col_row_height_ratio(col_row_height_ratio)
.total_widget_ratio(3),
);
col_row_children.push(
BottomColRow::new(vec![new_proc_search(proc_search_id)])
.canvas_handle_height(true)
.col_row_height_ratio(col_row_height_ratio),
);
}
_ => col_row_children.push(
BottomColRow::new(vec![BottomWidget::new_fill(
widget_type,
*iter_id,
)])
.col_row_height_ratio(col_row_height_ratio),
),
}
}
if contains_proc {
// Must adjust ratios to work with proc
total_col_row_ratio *= 2;
for child in &mut col_row_children {
// Multiply all non-proc or proc-search ratios by 2
if !child.children.is_empty() {
match child.children[0].widget_type {
BottomWidgetType::ProcSearch => {}
_ => child.col_row_height_ratio *= 2,
}
}
}
}
children.push(
BottomCol::new(col_row_children)
.total_col_row_ratio(total_col_row_ratio)
.col_width_ratio(col_width_ratio),
);
}
}
}
}
Ok(BottomRow::new(children)
.total_col_ratio(total_col_ratio)
.row_height_ratio(row_ratio))
}
}
/// Represents a child of a Row - either a Col (column) or a FinalWidget.
///
/// A Col can also have an optional length and children. We only allow columns
/// A Col can also have an optional length and children. We only allow columns
/// to have FinalWidgets as children, lest we get some amount of mutual
/// recursion between Row and Col.
#[derive(Clone, Deserialize, Debug, Serialize)]

View File

@ -1,469 +1,469 @@
//! Mocks layout management, so we can check if we broke anything.
// //! Mocks layout management, so we can check if we broke anything.
use bottom::app::layout_manager::{BottomLayout, BottomWidgetType};
#[cfg(feature = "battery")]
use bottom::constants::DEFAULT_BATTERY_LAYOUT;
use bottom::constants::{DEFAULT_LAYOUT, DEFAULT_WIDGET_ID};
use bottom::options::{layout_options::Row, Config};
use bottom::utils::error;
use toml_edit::de::from_str;
// use bottom::app::layout_manager::{BottomLayout, BottomWidgetType};
// #[cfg(feature = "battery")]
// use bottom::constants::DEFAULT_BATTERY_LAYOUT;
// use bottom::constants::{DEFAULT_LAYOUT, DEFAULT_WIDGET_ID};
// use bottom::options::{layout_options::Row, Config};
// use bottom::utils::error;
// use toml_edit::de::from_str;
// FIXME: Move these into the library!
// // FIXME: Move these tests into the library!
const PROC_LAYOUT: &str = r##"
[[row]]
[[row.child]]
type="proc"
[[row]]
[[row.child]]
type="proc"
[[row.child]]
type="proc"
[[row]]
[[row.child]]
type="proc"
[[row.child]]
type="proc"
"##;
// const PROC_LAYOUT: &str = r##"
// [[row]]
// [[row.child]]
// type="proc"
// [[row]]
// [[row.child]]
// type="proc"
// [[row.child]]
// type="proc"
// [[row]]
// [[row.child]]
// type="proc"
// [[row.child]]
// type="proc"
// "##;
fn test_create_layout(
rows: &[Row], default_widget_id: u64, default_widget_type: Option<BottomWidgetType>,
default_widget_count: u64, left_legend: bool,
) -> BottomLayout {
let mut iter_id = 0; // A lazy way of forcing unique IDs *shrugs*
let mut total_height_ratio = 0;
let mut default_widget_count = default_widget_count;
let mut default_widget_id = default_widget_id;
// fn test_create_layout(
// rows: &[Row], default_widget_id: u64, default_widget_type: Option<BottomWidgetType>,
// default_widget_count: u64, left_legend: bool,
// ) -> BottomLayout {
// let mut iter_id = 0; // A lazy way of forcing unique IDs *shrugs*
// let mut total_height_ratio = 0;
// let mut default_widget_count = default_widget_count;
// let mut default_widget_id = default_widget_id;
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<_>>>()
.unwrap(),
total_row_height_ratio: total_height_ratio,
};
ret_bottom_layout.get_movement_mappings();
// 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<_>>>()
// .unwrap(),
// total_row_height_ratio: total_height_ratio,
// };
// ret_bottom_layout.get_movement_mappings();
ret_bottom_layout
}
// ret_bottom_layout
// }
#[test]
/// Tests the default setup.
fn test_default_movement() {
let rows = from_str::<Config>(DEFAULT_LAYOUT).unwrap().row.unwrap();
let ret_bottom_layout = test_create_layout(&rows, DEFAULT_WIDGET_ID, None, 1, false);
// #[test]
// /// Tests the default setup.
// fn test_default_movement() {
// let rows = from_str::<Config>(DEFAULT_LAYOUT).unwrap().row.unwrap();
// let ret_bottom_layout = test_create_layout(&rows, DEFAULT_WIDGET_ID, None, 1, false);
// Simple tests for the top CPU widget
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].down_neighbour,
Some(3)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].right_neighbour,
Some(2)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].left_neighbour,
None
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].up_neighbour,
None
);
// // Simple tests for the top CPU widget
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].down_neighbour,
// Some(3)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].right_neighbour,
// Some(2)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].left_neighbour,
// None
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].up_neighbour,
// None
// );
// Test CPU legend
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].down_neighbour,
Some(4)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].right_neighbour,
None
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].left_neighbour,
Some(1)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].up_neighbour,
None
);
// // Test CPU legend
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].down_neighbour,
// Some(4)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].right_neighbour,
// None
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].left_neighbour,
// Some(1)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].up_neighbour,
// None
// );
// Test memory->temp, temp->disk, disk->memory mappings
assert_eq!(
ret_bottom_layout.rows[1].children[0].children[0].children[0].right_neighbour,
Some(4)
);
assert_eq!(
ret_bottom_layout.rows[1].children[1].children[0].children[0].down_neighbour,
Some(5)
);
assert_eq!(
ret_bottom_layout.rows[1].children[1].children[1].children[0].left_neighbour,
Some(3)
);
// // Test memory->temp, temp->disk, disk->memory mappings
// assert_eq!(
// ret_bottom_layout.rows[1].children[0].children[0].children[0].right_neighbour,
// Some(4)
// );
// assert_eq!(
// ret_bottom_layout.rows[1].children[1].children[0].children[0].down_neighbour,
// Some(5)
// );
// assert_eq!(
// ret_bottom_layout.rows[1].children[1].children[1].children[0].left_neighbour,
// Some(3)
// );
// Test disk -> processes, processes -> process sort, process sort -> network
assert_eq!(
ret_bottom_layout.rows[1].children[1].children[1].children[0].down_neighbour,
Some(7)
);
assert_eq!(
ret_bottom_layout.rows[2].children[1].children[0].children[1].left_neighbour,
Some(9)
);
assert_eq!(
ret_bottom_layout.rows[2].children[1].children[0].children[0].left_neighbour,
Some(6)
);
}
// // Test disk -> processes, processes -> process sort, process sort -> network
// assert_eq!(
// ret_bottom_layout.rows[1].children[1].children[1].children[0].down_neighbour,
// Some(7)
// );
// assert_eq!(
// ret_bottom_layout.rows[2].children[1].children[0].children[1].left_neighbour,
// Some(9)
// );
// assert_eq!(
// ret_bottom_layout.rows[2].children[1].children[0].children[0].left_neighbour,
// Some(6)
// );
// }
#[cfg(feature = "battery")]
#[test]
/// Tests battery movement in the default setup.
fn test_default_battery_movement() {
let rows = from_str::<Config>(DEFAULT_BATTERY_LAYOUT)
.unwrap()
.row
.unwrap();
let ret_bottom_layout = test_create_layout(&rows, DEFAULT_WIDGET_ID, None, 1, false);
// #[cfg(feature = "battery")]
// #[test]
// /// Tests battery movement in the default setup.
// fn test_default_battery_movement() {
// let rows = from_str::<Config>(DEFAULT_BATTERY_LAYOUT)
// .unwrap()
// .row
// .unwrap();
// let ret_bottom_layout = test_create_layout(&rows, DEFAULT_WIDGET_ID, None, 1, false);
// Simple tests for the top CPU widget
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].down_neighbour,
Some(4)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].right_neighbour,
Some(2)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].left_neighbour,
None
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].up_neighbour,
None
);
// // Simple tests for the top CPU widget
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].down_neighbour,
// Some(4)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].right_neighbour,
// Some(2)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].left_neighbour,
// None
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].up_neighbour,
// None
// );
// Test CPU legend
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].down_neighbour,
Some(5)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].right_neighbour,
Some(3)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].left_neighbour,
Some(1)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].up_neighbour,
None
);
}
// // Test CPU legend
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].down_neighbour,
// Some(5)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].right_neighbour,
// Some(3)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].left_neighbour,
// Some(1)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].up_neighbour,
// None
// );
// }
#[test]
/// Tests using left_legend.
fn test_left_legend() {
let rows = from_str::<Config>(DEFAULT_LAYOUT).unwrap().row.unwrap();
let ret_bottom_layout = test_create_layout(&rows, DEFAULT_WIDGET_ID, None, 1, true);
// #[test]
// /// Tests using left_legend.
// fn test_left_legend() {
// let rows = from_str::<Config>(DEFAULT_LAYOUT).unwrap().row.unwrap();
// let ret_bottom_layout = test_create_layout(&rows, DEFAULT_WIDGET_ID, None, 1, true);
// Legend
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].down_neighbour,
Some(3)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].right_neighbour,
Some(1)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].left_neighbour,
None
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].up_neighbour,
None
);
// // Legend
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].down_neighbour,
// Some(3)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].right_neighbour,
// Some(1)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].left_neighbour,
// None
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].up_neighbour,
// None
// );
// Widget
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].down_neighbour,
Some(3)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].right_neighbour,
None
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].left_neighbour,
Some(2)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].up_neighbour,
None
);
}
// // Widget
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].down_neighbour,
// Some(3)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].right_neighbour,
// None
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].left_neighbour,
// Some(2)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].up_neighbour,
// None
// );
// }
#[test]
/// Tests explicit default widget.
fn test_default_widget_in_layout() {
let proc_layout = r##"
[[row]]
[[row.child]]
type="proc"
[[row]]
[[row.child]]
type="proc"
[[row.child]]
type="proc"
[[row]]
[[row.child]]
type="proc"
default=true
[[row.child]]
type="proc"
"##;
let rows = from_str::<Config>(proc_layout).unwrap().row.unwrap();
let mut iter_id = 0; // A lazy way of forcing unique IDs *shrugs*
let mut total_height_ratio = 0;
let mut default_widget_count = 1;
let mut default_widget_id = DEFAULT_WIDGET_ID;
let default_widget_type = None;
let left_legend = false;
// #[test]
// /// Tests explicit default widget.
// fn test_default_widget_in_layout() {
// let proc_layout = r##"
// [[row]]
// [[row.child]]
// type="proc"
// [[row]]
// [[row.child]]
// type="proc"
// [[row.child]]
// type="proc"
// [[row]]
// [[row.child]]
// type="proc"
// default=true
// [[row.child]]
// type="proc"
// "##;
// let rows = from_str::<Config>(proc_layout).unwrap().row.unwrap();
// let mut iter_id = 0; // A lazy way of forcing unique IDs *shrugs*
// let mut total_height_ratio = 0;
// let mut default_widget_count = 1;
// let mut default_widget_id = DEFAULT_WIDGET_ID;
// let default_widget_type = None;
// let left_legend = false;
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<_>>>()
.unwrap(),
total_row_height_ratio: total_height_ratio,
};
ret_bottom_layout.get_movement_mappings();
// 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<_>>>()
// .unwrap(),
// total_row_height_ratio: total_height_ratio,
// };
// ret_bottom_layout.get_movement_mappings();
assert_eq!(default_widget_id, 10);
}
// assert_eq!(default_widget_id, 10);
// }
#[test]
/// Tests default widget by setting type and count.
fn test_default_widget_by_option() {
let rows = from_str::<Config>(PROC_LAYOUT).unwrap().row.unwrap();
let mut iter_id = 0; // A lazy way of forcing unique IDs *shrugs*
let mut total_height_ratio = 0;
let mut default_widget_count = 3;
let mut default_widget_id = DEFAULT_WIDGET_ID;
let default_widget_type = Some(BottomWidgetType::Proc);
let left_legend = false;
// #[test]
// /// Tests default widget by setting type and count.
// fn test_default_widget_by_option() {
// let rows = from_str::<Config>(PROC_LAYOUT).unwrap().row.unwrap();
// let mut iter_id = 0; // A lazy way of forcing unique IDs *shrugs*
// let mut total_height_ratio = 0;
// let mut default_widget_count = 3;
// let mut default_widget_id = DEFAULT_WIDGET_ID;
// let default_widget_type = Some(BottomWidgetType::Proc);
// let left_legend = false;
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<_>>>()
.unwrap(),
total_row_height_ratio: total_height_ratio,
};
ret_bottom_layout.get_movement_mappings();
// 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<_>>>()
// .unwrap(),
// total_row_height_ratio: total_height_ratio,
// };
// ret_bottom_layout.get_movement_mappings();
assert_eq!(default_widget_id, 7);
}
// assert_eq!(default_widget_id, 7);
// }
#[test]
fn test_proc_custom_layout() {
let rows = from_str::<Config>(PROC_LAYOUT).unwrap().row.unwrap();
let ret_bottom_layout = test_create_layout(&rows, DEFAULT_WIDGET_ID, None, 1, false);
// #[test]
// fn test_proc_custom_layout() {
// let rows = from_str::<Config>(PROC_LAYOUT).unwrap().row.unwrap();
// let ret_bottom_layout = test_create_layout(&rows, DEFAULT_WIDGET_ID, None, 1, false);
// First proc widget
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].down_neighbour,
Some(2)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].left_neighbour,
Some(3)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].right_neighbour,
None
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[1].up_neighbour,
None
);
// // First proc widget
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].down_neighbour,
// Some(2)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].left_neighbour,
// Some(3)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].right_neighbour,
// None
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[1].up_neighbour,
// None
// );
// Its search
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[1].children[0].down_neighbour,
Some(4)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[1].children[0].left_neighbour,
None
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[1].children[0].right_neighbour,
None
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[1].children[0].up_neighbour,
Some(1)
);
// // Its search
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[1].children[0].down_neighbour,
// Some(4)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[1].children[0].left_neighbour,
// None
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[1].children[0].right_neighbour,
// None
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[1].children[0].up_neighbour,
// Some(1)
// );
// Its sort
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].down_neighbour,
Some(2)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].left_neighbour,
None
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].right_neighbour,
Some(1)
);
assert_eq!(
ret_bottom_layout.rows[0].children[0].children[0].children[0].up_neighbour,
None
);
// // Its sort
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].down_neighbour,
// Some(2)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].left_neighbour,
// None
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].right_neighbour,
// Some(1)
// );
// assert_eq!(
// ret_bottom_layout.rows[0].children[0].children[0].children[0].up_neighbour,
// None
// );
// Let us now test the second row's first widget...
assert_eq!(
ret_bottom_layout.rows[1].children[0].children[0].children[1].down_neighbour,
Some(5)
);
assert_eq!(
ret_bottom_layout.rows[1].children[0].children[0].children[1].left_neighbour,
Some(6)
);
assert_eq!(
ret_bottom_layout.rows[1].children[0].children[0].children[1].right_neighbour,
Some(9)
);
assert_eq!(
ret_bottom_layout.rows[1].children[0].children[0].children[1].up_neighbour,
Some(2)
);
// // Let us now test the second row's first widget...
// assert_eq!(
// ret_bottom_layout.rows[1].children[0].children[0].children[1].down_neighbour,
// Some(5)
// );
// assert_eq!(
// ret_bottom_layout.rows[1].children[0].children[0].children[1].left_neighbour,
// Some(6)
// );
// assert_eq!(
// ret_bottom_layout.rows[1].children[0].children[0].children[1].right_neighbour,
// Some(9)
// );
// assert_eq!(
// ret_bottom_layout.rows[1].children[0].children[0].children[1].up_neighbour,
// Some(2)
// );
// Sort
assert_eq!(
ret_bottom_layout.rows[1].children[0].children[0].children[0].down_neighbour,
Some(5)
);
assert_eq!(
ret_bottom_layout.rows[1].children[0].children[0].children[0].left_neighbour,
None
);
assert_eq!(
ret_bottom_layout.rows[1].children[0].children[0].children[0].right_neighbour,
Some(4)
);
assert_eq!(
ret_bottom_layout.rows[1].children[0].children[0].children[0].up_neighbour,
Some(2)
);
// // Sort
// assert_eq!(
// ret_bottom_layout.rows[1].children[0].children[0].children[0].down_neighbour,
// Some(5)
// );
// assert_eq!(
// ret_bottom_layout.rows[1].children[0].children[0].children[0].left_neighbour,
// None
// );
// assert_eq!(
// ret_bottom_layout.rows[1].children[0].children[0].children[0].right_neighbour,
// Some(4)
// );
// assert_eq!(
// ret_bottom_layout.rows[1].children[0].children[0].children[0].up_neighbour,
// Some(2)
// );
// Search
assert_eq!(
ret_bottom_layout.rows[1].children[0].children[1].children[0].down_neighbour,
Some(10)
);
assert_eq!(
ret_bottom_layout.rows[1].children[0].children[1].children[0].left_neighbour,
None
);
assert_eq!(
ret_bottom_layout.rows[1].children[0].children[1].children[0].right_neighbour,
Some(8)
);
assert_eq!(
ret_bottom_layout.rows[1].children[0].children[1].children[0].up_neighbour,
Some(4)
);
// // Search
// assert_eq!(
// ret_bottom_layout.rows[1].children[0].children[1].children[0].down_neighbour,
// Some(10)
// );
// assert_eq!(
// ret_bottom_layout.rows[1].children[0].children[1].children[0].left_neighbour,
// None
// );
// assert_eq!(
// ret_bottom_layout.rows[1].children[0].children[1].children[0].right_neighbour,
// Some(8)
// );
// assert_eq!(
// ret_bottom_layout.rows[1].children[0].children[1].children[0].up_neighbour,
// Some(4)
// );
// Third row, second
assert_eq!(
ret_bottom_layout.rows[2].children[1].children[0].children[1].down_neighbour,
Some(14)
);
assert_eq!(
ret_bottom_layout.rows[2].children[1].children[0].children[1].left_neighbour,
Some(15)
);
assert_eq!(
ret_bottom_layout.rows[2].children[1].children[0].children[1].right_neighbour,
None
);
assert_eq!(
ret_bottom_layout.rows[2].children[1].children[0].children[1].up_neighbour,
Some(8)
);
// // Third row, second
// assert_eq!(
// ret_bottom_layout.rows[2].children[1].children[0].children[1].down_neighbour,
// Some(14)
// );
// assert_eq!(
// ret_bottom_layout.rows[2].children[1].children[0].children[1].left_neighbour,
// Some(15)
// );
// assert_eq!(
// ret_bottom_layout.rows[2].children[1].children[0].children[1].right_neighbour,
// None
// );
// assert_eq!(
// ret_bottom_layout.rows[2].children[1].children[0].children[1].up_neighbour,
// Some(8)
// );
// Sort
assert_eq!(
ret_bottom_layout.rows[2].children[1].children[0].children[0].down_neighbour,
Some(14)
);
assert_eq!(
ret_bottom_layout.rows[2].children[1].children[0].children[0].left_neighbour,
Some(10)
);
assert_eq!(
ret_bottom_layout.rows[2].children[1].children[0].children[0].right_neighbour,
Some(13)
);
assert_eq!(
ret_bottom_layout.rows[2].children[1].children[0].children[0].up_neighbour,
Some(8)
);
// // Sort
// assert_eq!(
// ret_bottom_layout.rows[2].children[1].children[0].children[0].down_neighbour,
// Some(14)
// );
// assert_eq!(
// ret_bottom_layout.rows[2].children[1].children[0].children[0].left_neighbour,
// Some(10)
// );
// assert_eq!(
// ret_bottom_layout.rows[2].children[1].children[0].children[0].right_neighbour,
// Some(13)
// );
// assert_eq!(
// ret_bottom_layout.rows[2].children[1].children[0].children[0].up_neighbour,
// Some(8)
// );
// Search
assert_eq!(
ret_bottom_layout.rows[2].children[1].children[1].children[0].down_neighbour,
None
);
assert_eq!(
ret_bottom_layout.rows[2].children[1].children[1].children[0].left_neighbour,
Some(11)
);
assert_eq!(
ret_bottom_layout.rows[2].children[1].children[1].children[0].right_neighbour,
None
);
assert_eq!(
ret_bottom_layout.rows[2].children[1].children[1].children[0].up_neighbour,
Some(13)
);
}
// // Search
// assert_eq!(
// ret_bottom_layout.rows[2].children[1].children[1].children[0].down_neighbour,
// None
// );
// assert_eq!(
// ret_bottom_layout.rows[2].children[1].children[1].children[0].left_neighbour,
// Some(11)
// );
// assert_eq!(
// ret_bottom_layout.rows[2].children[1].children[1].children[0].right_neighbour,
// None
// );
// assert_eq!(
// ret_bottom_layout.rows[2].children[1].children[1].children[0].up_neighbour,
// Some(13)
// );
// }