mirror of
https://seed.radicle.dev/rad:z39mP9rQAaGmERfUMPULfPUi473tY.git
synced 2026-10-27 23:30:38 +08:00
lib: Rework render width-dependent table column display
This commit is contained in:
@@ -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.
|
||||
///
|
||||
|
||||
+74
-10
@@ -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<S, M> {
|
||||
.and_then(|props| props.inner_ref::<HeaderProps>())
|
||||
.unwrap_or(&default);
|
||||
|
||||
let width = render.area.width.saturating_sub(2);
|
||||
|
||||
let widths: Vec<Constraint> = 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<S, M> {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let widths = if render.area.width < props.cutoff as u16 {
|
||||
widths.iter().take(props.cutoff_after).collect::<Vec<_>>()
|
||||
} else {
|
||||
widths.iter().collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
// Render header
|
||||
let block = HeaderBlock::default()
|
||||
.borders(Borders::ALL)
|
||||
|
||||
+8
-18
@@ -30,8 +30,6 @@ where
|
||||
pub selected: Option<usize>,
|
||||
pub columns: Vec<Column<'a>>,
|
||||
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<Constraint> = 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::<Vec<_>>()
|
||||
} else {
|
||||
widths.iter().collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user