summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClement Tsang <34804052+ClementTsang@users.noreply.github.com>2024-01-02 01:13:02 -0500
committerClement Tsang <34804052+ClementTsang@users.noreply.github.com>2024-01-02 01:13:02 -0500
commitc730048c7a0a5ab2eb657fee2649d7b22e73652d (patch)
treee75b7e0e03f64e797bcc5a85195a2ffe8728cdb7
parentdbadbb996cb8d55d842b9632126c031f39596453 (diff)
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--src/app/layout_manager.rs22
-rw-r--r--src/canvas.rs19
-rw-r--r--src/canvas/components/column.rs2
-rw-r--r--src/canvas/components/row.rs2
-rw-r--r--src/lib.rs1
-rw-r--r--src/tuine.rs33
-rw-r--r--src/tuine/constraints.rs154
-rw-r--r--src/tuine/container.rs27
-rw-r--r--src/tuine/element.rs16
-rw-r--r--src/tuine/widget.rs7
-rw-r--r--src/widgets.rs8
13 files changed, 252 insertions, 41 deletions
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<BottomLayoutNode>,
-// 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<Line<'static>>,
// 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<Rect> {
+ // 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<Element>,
+}
+
+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<Data> {
+ /// 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<Data> {
- /// How to actually draw the widget to the terminal.
- fn draw(&self, f: &mut Frame<'_>, draw_location: Rect, widget_id: u64);
-}