From 68a4a82165d765e72e48048e1e34fb888fe9ec81 Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Thu, 13 Jun 2024 12:36:20 +0200 Subject: [PATCH] lib: Rework render width-dependent table column display --- src/ui.rs | 5 +++ src/ui/widget/container.rs | 84 +++++++++++++++++++++++++++++++++----- src/ui/widget/list.rs | 26 ++++-------- 3 files changed, 87 insertions(+), 28 deletions(-) diff --git a/src/ui.rs b/src/ui.rs index 930589e8..d8f9ccc1 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -22,6 +22,11 @@ use super::terminal; const RENDERING_TICK_RATE: Duration = Duration::from_millis(250); const INLINE_HEIGHT: usize = 20; +pub const RENDER_WIDTH_XSMALL: usize = 50; +pub const RENDER_WIDTH_SMALL: usize = 70; +pub const RENDER_WIDTH_MEDIUM: usize = 150; +pub const RENDER_WIDTH_LARGE: usize = usize::MAX; + /// The `Frontend` runs an applications' view concurrently. It handles /// terminal events as well as state updates and renders the view accordingly. /// diff --git a/src/ui/widget/container.rs b/src/ui/widget/container.rs index a82544e4..a911ccaf 100644 --- a/src/ui/widget/container.rs +++ b/src/ui/widget/container.rs @@ -8,14 +8,58 @@ use ratatui::widgets::{Block, BorderType, Borders, Row}; use crate::ui::ext::{FooterBlock, FooterBlockType, HeaderBlock}; use crate::ui::theme::style; +use crate::ui::{RENDER_WIDTH_LARGE, RENDER_WIDTH_MEDIUM, RENDER_WIDTH_SMALL}; use super::{PredefinedLayout, RenderProps, View, ViewProps, Widget}; +#[derive(Clone, Debug)] +pub struct ColumnView { + small: bool, + medium: bool, + large: bool, +} + +impl ColumnView { + pub fn all() -> Self { + Self { + small: true, + medium: true, + large: true, + } + } + + pub fn small(mut self) -> Self { + self.small = true; + self + } + + pub fn medium(mut self) -> Self { + self.medium = true; + self + } + + pub fn large(mut self) -> Self { + self.large = true; + self + } +} + +impl Default for ColumnView { + fn default() -> Self { + Self { + small: false, + medium: false, + large: false, + } + } +} + #[derive(Clone, Debug)] pub struct Column<'a> { pub text: Text<'a>, pub width: Constraint, pub skip: bool, + pub view: ColumnView, } impl<'a> Column<'a> { @@ -24,6 +68,7 @@ impl<'a> Column<'a> { text: text.into(), width, skip: false, + view: ColumnView::all(), } } @@ -31,6 +76,28 @@ impl<'a> Column<'a> { self.skip = skip; self } + + pub fn hide_small(mut self) -> Self { + self.view = ColumnView::default().medium().large(); + self + } + + pub fn hide_medium(mut self) -> Self { + self.view = ColumnView::default().large(); + self + } + + pub fn displayed(&self, area_width: usize) -> bool { + if area_width < RENDER_WIDTH_SMALL { + self.view.small + } else if area_width < RENDER_WIDTH_MEDIUM { + self.view.medium + } else if area_width < RENDER_WIDTH_LARGE { + self.view.large + } else { + true + } + } } #[derive(Clone, Debug)] @@ -86,22 +153,25 @@ impl<'a: 'static, S, M> View for Header { .and_then(|props| props.inner_ref::()) .unwrap_or(&default); + let width = render.area.width.saturating_sub(2); + let widths: Vec = props .columns .iter() - .filter_map(|column| { - if !column.skip { - Some(column.width) + .filter_map(|c| { + if !c.skip && c.displayed(width as usize) { + Some(c.width) } else { None } }) .collect(); + let cells = props .columns .iter() .filter_map(|column| { - if !column.skip { + if !column.skip && column.displayed(width as usize) { Some(column.text.clone()) } else { None @@ -109,12 +179,6 @@ impl<'a: 'static, S, M> View for Header { }) .collect::>(); - let widths = if render.area.width < props.cutoff as u16 { - widths.iter().take(props.cutoff_after).collect::>() - } else { - widths.iter().collect::>() - }; - // Render header let block = HeaderBlock::default() .borders(Borders::ALL) diff --git a/src/ui/widget/list.rs b/src/ui/widget/list.rs index 9eb6b9d0..ebca9a35 100644 --- a/src/ui/widget/list.rs +++ b/src/ui/widget/list.rs @@ -30,8 +30,6 @@ where pub selected: Option, pub columns: Vec>, pub has_footer: bool, - pub cutoff: usize, - pub cutoff_after: usize, pub page_size: usize, } @@ -44,8 +42,6 @@ where items: vec![], columns: vec![], has_footer: false, - cutoff: usize::MAX, - cutoff_after: usize::MAX, page_size: 1, selected: Some(0), } @@ -76,12 +72,6 @@ where self } - pub fn cutoff(mut self, cutoff: usize, cutoff_after: usize) -> Self { - self.cutoff = cutoff; - self.cutoff_after = cutoff_after; - self - } - pub fn page_size(mut self, page_size: usize) -> Self { self.page_size = page_size; self @@ -225,15 +215,15 @@ where let widths: Vec = props .columns .iter() - .filter_map(|c| if !c.skip { Some(c.width) } else { None }) + .filter_map(|c| { + if !c.skip && c.displayed(render.area.width as usize) { + Some(c.width) + } else { + None + } + }) .collect(); - let widths = if render.area.width < props.cutoff as u16 { - widths.iter().take(props.cutoff_after).collect::>() - } else { - widths.iter().collect::>() - }; - if !props.items.is_empty() { let rows = props .items @@ -244,7 +234,7 @@ where for cell in item.to_row() { if let Some(col) = it.next() { - if !col.skip { + if !col.skip && col.displayed(render.area.width as usize) { cells.push(cell.clone()); } } else {