From c730048c7a0a5ab2eb657fee2649d7b22e73652d Mon Sep 17 00:00:00 2001 From: Clement Tsang <34804052+ClementTsang@users.noreply.github.com> Date: Tue, 2 Jan 2024 01:13:02 -0500 Subject: temp work --- Cargo.lock | 1 + Cargo.toml | 1 + src/app/layout_manager.rs | 22 ------ src/canvas.rs | 19 ++--- src/canvas/components/column.rs | 2 +- src/canvas/components/row.rs | 2 +- src/lib.rs | 1 + src/tuine.rs | 33 +++++++++ src/tuine/constraints.rs | 154 ++++++++++++++++++++++++++++++++++++++++ src/tuine/container.rs | 27 +++++++ src/tuine/element.rs | 16 +++++ src/tuine/widget.rs | 7 ++ src/widgets.rs | 8 --- 13 files changed, 252 insertions(+), 41 deletions(-) create mode 100644 src/tuine.rs create mode 100644 src/tuine/constraints.rs create mode 100644 src/tuine/container.rs create mode 100644 src/tuine/element.rs create mode 100644 src/tuine/widget.rs diff --git a/Cargo.lock b/Cargo.lock index 1dd09a57..eb110d55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,6 +174,7 @@ dependencies = [ "kstring", "libc", "log", + "lru", "mach2", "nvml-wrapper", "predicates", diff --git a/Cargo.toml b/Cargo.toml index 883a9fb3..a5e4e8fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,6 +93,7 @@ indexmap = "2.1.0" itertools = "0.12.0" kstring = { version = "2.0.0", features = ["arc"] } log = { version = "0.4.20", optional = true } +lru = "0.12.1" nvml-wrapper = { version = "0.9.0", optional = true, features = ["legacy-functions"] } regex = "1.10.2" serde = { version = "=1.0.193", features = ["derive"] } diff --git a/src/app/layout_manager.rs b/src/app/layout_manager.rs index ca353f52..866ed917 100644 --- a/src/app/layout_manager.rs +++ b/src/app/layout_manager.rs @@ -697,28 +697,6 @@ impl BottomLayout { } } -// pub enum BottomLayoutNode { -// Container(BottomContainer), -// Widget(BottomWidget), -// } - -// pub struct BottomContainer { -// children: Vec, -// root_ratio: u32, -// growth_type: BottomLayoutNodeSizing, -// } - -// pub enum BottomContainerType { -// Row, -// Col, -// } - -// pub enum BottomLayoutNodeSizing { -// Ratio(u32), -// CanvasHandles, -// FlexGrow, -// } - /// Represents a single row in the layout. #[derive(Clone, Debug)] pub struct BottomRow { diff --git a/src/canvas.rs b/src/canvas.rs index 38194f04..741b4400 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -55,11 +55,12 @@ impl FromStr for ColourScheme { } } -/// Handles the canvas' state. +/// Handles some state used while painting. pub struct Painter { pub colours: CanvasStyling, - height: u16, - width: u16, + + prev_height: u16, + prev_width: u16, styled_help_text: Vec>, // TODO: Redo this entire thing. @@ -153,8 +154,8 @@ impl Painter { let mut painter = Painter { colours: styling, - height: 0, - width: 0, + prev_height: 0, + prev_width: 0, styled_help_text: Vec::default(), row_constraints, col_constraints, @@ -244,12 +245,12 @@ impl Painter { let terminal_height = terminal_size.height; let terminal_width = terminal_size.width; - if (self.height == 0 && self.width == 0) - || (self.height != terminal_height || self.width != terminal_width) + if (self.prev_height == 0 && self.prev_width == 0) + || (self.prev_height != terminal_height || self.prev_width != terminal_width) { app_state.is_force_redraw = true; - self.height = terminal_height; - self.width = terminal_width; + self.prev_height = terminal_height; + self.prev_width = terminal_width; } if app_state.should_get_widget_bounds() { diff --git a/src/canvas/components/column.rs b/src/canvas/components/column.rs index 8b137891..381b902c 100644 --- a/src/canvas/components/column.rs +++ b/src/canvas/components/column.rs @@ -1 +1 @@ - +//! How to draw a container that has its children displayed vertically. diff --git a/src/canvas/components/row.rs b/src/canvas/components/row.rs index 8b137891..34316406 100644 --- a/src/canvas/components/row.rs +++ b/src/canvas/components/row.rs @@ -1 +1 @@ - +//! How to draw a container that has its children displayed horizontally. diff --git a/src/lib.rs b/src/lib.rs index 80b9af75..353331e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,7 @@ pub mod constants; pub mod data_collection; pub mod data_conversion; pub mod options; +pub mod tuine; pub mod widgets; use std::{ diff --git a/src/tuine.rs b/src/tuine.rs new file mode 100644 index 00000000..676da8af --- /dev/null +++ b/src/tuine.rs @@ -0,0 +1,33 @@ +//! tuine helps "tie" together ratatui/tui-rs and some layout/event logic to abstract away a bunch of the logic. + +mod constraints; +mod container; +mod element; +mod widget; + +pub use container::*; +pub use element::*; +pub use widget::*; + +use crate::app::layout_manager::BottomLayout; + +/// The overall widget tree. +/// +/// TODO: The current implementation is a bit WIP while I transition things over. +pub struct WidgetTree { + root: Element, +} + +impl WidgetTree { + /// Create a [`WidgetTree`]. + /// + /// TODO: The current implementation is a bit WIP while I transition things over. + pub fn new(layout: BottomLayout) -> Self { + + + Self { root: todo!() } + } + + /// Draw the widget tree. + pub fn draw(&mut self) {} +} diff --git a/src/tuine/constraints.rs b/src/tuine/constraints.rs new file mode 100644 index 00000000..a05462be --- /dev/null +++ b/src/tuine/constraints.rs @@ -0,0 +1,154 @@ +use tui::layout::{Direction, Rect}; + +use crate::canvas::LayoutConstraint; + +pub(super) fn get_constraints( + direction: Direction, constraints: &[LayoutConstraint], area: Rect, +) -> Vec { + // Order of operations: + // - Ratios first + canvas-handled (which is just zero) + // - Then any flex-grows to take up remaining space; divide amongst remaining + // hand out any remaining space + + #[derive(Debug, Default, Clone, Copy)] + struct Size { + width: u16, + height: u16, + } + + impl Size { + fn shrink_width(&mut self, amount: u16) { + self.width -= amount; + } + + fn shrink_height(&mut self, amount: u16) { + self.height -= amount; + } + } + + let mut bounds = Size { + width: area.width, + height: area.height, + }; + let mut sizes = vec![Size::default(); constraints.len()]; + let mut grow = vec![]; + let mut num_non_ch = 0; + + for (itx, (constraint, size)) in constraints.iter().zip(sizes.iter_mut()).enumerate() { + match constraint { + LayoutConstraint::Ratio(a, b) => { + match direction { + Direction::Horizontal => { + let amount = (((area.width as u32) * (*a)) / (*b)) 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; + bounds.shrink_height(amount); + size.width = area.width; + size.height = amount; + } + } + num_non_ch += 1; + } + LayoutConstraint::Grow => { + // Mark it as grow in the vector and handle in second pass. + grow.push(itx); + num_non_ch += 1; + } + LayoutConstraint::CanvasHandled => { + // Do nothing in this case. It's already 0. + } + } + } + + if !grow.is_empty() { + match direction { + Direction::Horizontal => { + let width = bounds.width / grow.len() as u16; + bounds.shrink_width(width * grow.len() as u16); + for g in grow { + sizes[g] = Size { + width, + height: area.height, + }; + } + } + Direction::Vertical => { + let height = bounds.height / grow.len() as u16; + bounds.shrink_height(height * grow.len() as u16); + for g in grow { + sizes[g] = Size { + width: area.width, + height, + }; + } + } + } + } + + if num_non_ch > 0 { + match direction { + Direction::Horizontal => { + let per_item = bounds.width / num_non_ch; + let mut remaining_width = bounds.width % num_non_ch; + for (size, constraint) in sizes.iter_mut().zip(constraints) { + match constraint { + LayoutConstraint::CanvasHandled => {} + LayoutConstraint::Grow | LayoutConstraint::Ratio(_, _) => { + if remaining_width > 0 { + size.width += per_item + 1; + remaining_width -= 1; + } else { + size.width += per_item; + } + } + } + } + } + Direction::Vertical => { + let per_item = bounds.height / num_non_ch; + let mut remaining_height = bounds.height % num_non_ch; + for (size, constraint) in sizes.iter_mut().zip(constraints) { + match constraint { + LayoutConstraint::CanvasHandled => {} + LayoutConstraint::Grow | LayoutConstraint::Ratio(_, _) => { + if remaining_height > 0 { + size.height += per_item + 1; + remaining_height -= 1; + } else { + size.height += per_item; + } + } + } + } + } + } + } + + let mut curr_x = area.x; + let mut curr_y = area.y; + sizes + .into_iter() + .map(|size| { + let rect = Rect::new(curr_x, curr_y, size.width, size.height); + match direction { + Direction::Horizontal => { + curr_x += size.width; + } + Direction::Vertical => { + curr_y += size.height; + } + } + + rect + }) + .collect() +} + +#[cfg(test)] +mod test { + // TODO: Add some tests. +} diff --git a/src/tuine/container.rs b/src/tuine/container.rs new file mode 100644 index 00000000..e26006dc --- /dev/null +++ b/src/tuine/container.rs @@ -0,0 +1,27 @@ +use crate::canvas::LayoutConstraint; + +use super::Element; + +/// A [`ContainerDirection`] determines the direction of the [`Container`]. +pub enum ContainerDirection { + Row, + Column, +} + +/// A [`Container`] holds either more containers or a [`BottomWidget`]. +/// +/// Basically, a non-leaf node in the [`Element`] tree. +pub struct Container { + direction: ContainerDirection, + constraint: LayoutConstraint, + pub(super) children: Vec, +} + +impl Container { + pub fn draw(&mut self) { + match self.direction { + ContainerDirection::Row => {} + ContainerDirection::Column => {} + } + } +} diff --git a/src/tuine/element.rs b/src/tuine/element.rs new file mode 100644 index 00000000..14172e22 --- /dev/null +++ b/src/tuine/element.rs @@ -0,0 +1,16 @@ +use super::Container; + +/// A widget within bottom. +/// +/// We use an enum to represent them to avoid dynamic dispatch. +pub enum BottomWidget {} + +impl BottomWidget {} + +/// An [`Element`] represents a node in the overall layout tree. +pub enum Element { + BottomWidget(BottomWidget), + Container(Container), +} + +impl Element {} diff --git a/src/tuine/widget.rs b/src/tuine/widget.rs new file mode 100644 index 00000000..ebe06dc6 --- /dev/null +++ b/src/tuine/widget.rs @@ -0,0 +1,7 @@ +use tui::{layout::Rect, Frame}; + +/// A [`Widget`] converts raw data into something that a user can see and interact with. +pub trait Widget { + /// How to actually draw the widget to the terminal. + fn draw(&self, f: &mut Frame<'_>, draw_location: Rect, widget_id: u64); +} diff --git a/src/widgets.rs b/src/widgets.rs index a477e1d2..21cf0479 100644 --- a/src/widgets.rs +++ b/src/widgets.rs @@ -13,11 +13,3 @@ pub use mem_graph::*; pub use net_graph::*; pub use process_table::*; pub use temperature_table::*; - -use tui::{layout::Rect, Frame}; - -/// A [`Widget`] converts raw data into something that a user can see and interact with. -pub trait Widget { - /// How to actually draw the widget to the terminal. - fn draw(&self, f: &mut Frame<'_>, draw_location: Rect, widget_id: u64); -} -- cgit v1.2.3