Radish alpha
r
Radicle terminal user interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
lib: Make table headerless
Erik Kundt committed 2 years ago
commit 8a0a6ef0f1b427f326c11ab36a45f934615e2003
parent 2c513a2f25a8e479efef5f72179e54be65b38603
2 files changed +45 -53
modified src/ui/widget.rs
@@ -11,7 +11,7 @@ use tokio::sync::mpsc::UnboundedSender;
use termion::event::Key;

use ratatui::prelude::*;
-
use ratatui::widgets::{Block, BorderType, Borders, Cell, Row, TableState};
+
use ratatui::widgets::{Cell, Row, TableState};

use super::theme::style;
use super::{layout, span};
@@ -321,9 +321,8 @@ where

impl<'a, R> Properties for TableProps<'a, R> where R: ToRow {}

-
pub struct Table<'a, B, S, A, R>
+
pub struct Table<'a, S, A, R>
where
-
    B: Backend,
    R: ToRow,
{
    /// Internal table properties
@@ -336,20 +335,12 @@ where
    on_change: Option<EventCallback<A>>,
    /// Internal selection and offset state
    state: TableState,
-
    /// Table header widget
-
    header: Option<BoxedWidget<B, S, A>>,
}

-
impl<'a, B, S, A, R> Table<'a, B, S, A, R>
+
impl<'a, S, A, R> Table<'a, S, A, R>
where
-
    B: Backend,
    R: ToRow,
{
-
    pub fn header(mut self, header: BoxedWidget<B, S, A>) -> Self {
-
        self.header = Some(header);
-
        self
-
    }
-

    fn prev(&mut self) -> Option<usize> {
        let selected = self
            .state
@@ -401,9 +392,8 @@ where
    }
}

-
impl<'a: 'static, B, S, A, R> View<S, A> for Table<'a, B, S, A, R>
+
impl<'a: 'static, S, A, R> View<S, A> for Table<'a, S, A, R>
where
-
    B: Backend,
    R: ToRow + Clone + 'static,
{
    fn new(_state: &S, action_tx: UnboundedSender<A>) -> Self {
@@ -411,7 +401,6 @@ where
            action_tx: action_tx.clone(),
            props: TableProps::default(),
            state: TableState::default().with_selected(Some(0)),
-
            header: None,
            on_update: None,
            on_change: None,
        }
@@ -476,7 +465,7 @@ where
    }
}

-
impl<'a: 'static, B, S, A, R> Widget<B, S, A> for Table<'a, B, S, A, R>
+
impl<'a: 'static, B, S, A, R> Widget<B, S, A> for Table<'a, S, A, R>
where
    B: Backend,
    R: ToRow + Clone + Debug + 'static,
@@ -486,9 +475,6 @@ where
            .and_then(|props| props.downcast_ref::<TableProps<'_, R>>())
            .unwrap_or(&self.props);

-
        let header_height = if self.header.is_some() { 3 } else { 0 };
-
        let [header_area, table_area] =
-
            Layout::vertical([Constraint::Length(header_height), Constraint::Min(1)]).areas(area);
        let widths: Vec<Constraint> = self
            .props
            .columns
@@ -502,13 +488,6 @@ where
            widths.iter().collect::<Vec<_>>()
        };

-
        let borders = match (self.header.is_some(), props.has_footer) {
-
            (false, false) => Borders::ALL,
-
            (true, false) => Borders::BOTTOM | Borders::LEFT | Borders::RIGHT,
-
            (false, true) => Borders::TOP | Borders::LEFT | Borders::RIGHT,
-
            (true, true) => Borders::LEFT | Borders::RIGHT,
-
        };
-

        if !props.items.is_empty() {
            let rows = props
                .items
@@ -534,31 +513,11 @@ where
                .rows(rows)
                .widths(widths)
                .column_spacing(1)
-
                .block(
-
                    Block::default()
-
                        .border_style(style::border(props.focus))
-
                        .border_type(BorderType::Rounded)
-
                        .borders(borders),
-
                )
                .highlight_style(style::highlight());

-
            if let Some(header) = &self.header {
-
                header.render(frame, header_area, None);
-
            }
-

-
            frame.render_stateful_widget(rows, table_area, &mut self.state.clone());
+
            frame.render_stateful_widget(rows, area, &mut self.state.clone());
        } else {
-
            let block = Block::default()
-
                .border_style(style::border(props.focus))
-
                .border_type(BorderType::Rounded)
-
                .borders(borders);
-

-
            if let Some(header) = &self.header {
-
                header.render(frame, header_area, None);
-
            }
-
            frame.render_widget(block, table_area);
-

-
            let center = layout::centered_rect(table_area, 50, 10);
+
            let center = layout::centered_rect(area, 50, 10);
            let hint = Text::from(span::default("Nothing to show".to_string()))
                .centered()
                .light_magenta()
modified src/ui/widget/container.rs
@@ -6,7 +6,7 @@ use tokio::sync::mpsc::UnboundedSender;
use termion::event::Key;

use ratatui::prelude::*;
-
use ratatui::widgets::{BorderType, Borders, Row};
+
use ratatui::widgets::{Block, BorderType, Borders, Row};

use crate::ui::ext::{FooterBlock, FooterBlockType, HeaderBlock};
use crate::ui::theme::style;
@@ -346,7 +346,20 @@ where

#[derive(Clone, Default)]
pub struct ContainerProps {
-
    _focus: bool,
+
    focus: bool,
+
    hide_footer: bool,
+
}
+

+
impl ContainerProps {
+
    pub fn hide_footer(mut self, hide: bool) -> Self {
+
        self.hide_footer = hide;
+
        self
+
    }
+

+
    pub fn focus(mut self, focus: bool) -> Self {
+
        self.focus = focus;
+
        self
+
    }
}

impl Properties for ContainerProps {}
@@ -451,12 +464,16 @@ where
    B: Backend,
{
    fn render(&self, frame: &mut ratatui::Frame, area: Rect, props: Option<&dyn Any>) {
-
        let _props = props
+
        let props = props
            .and_then(|props| props.downcast_ref::<ContainerProps>())
            .unwrap_or(&self.props);

        let header_h = if self.header.is_some() { 3 } else { 0 };
-
        let footer_h = if self.footer.is_some() { 3 } else { 0 };
+
        let footer_h = if self.footer.is_some() && !props.hide_footer {
+
            3
+
        } else {
+
            0
+
        };

        let [header_area, content_area, footer_area] = Layout::vertical([
            Constraint::Length(header_h),
@@ -465,12 +482,28 @@ where
        ])
        .areas(area);

+
        let borders = match (
+
            self.header.is_some(),
+
            (self.footer.is_some() && !props.hide_footer),
+
        ) {
+
            (false, false) => Borders::ALL,
+
            (true, false) => Borders::BOTTOM | Borders::LEFT | Borders::RIGHT,
+
            (false, true) => Borders::TOP | Borders::LEFT | Borders::RIGHT,
+
            (true, true) => Borders::LEFT | Borders::RIGHT,
+
        };
+

+
        let block = Block::default()
+
            .border_style(style::border(props.focus))
+
            .border_type(BorderType::Rounded)
+
            .borders(borders);
+
        frame.render_widget(block.clone(), content_area);
+

        if let Some(header) = &self.header {
            header.render(frame, header_area, None);
        }

        if let Some(content) = &self.content {
-
            content.render(frame, content_area, None);
+
            content.render(frame, block.inner(content_area), None);
        }

        if let Some(footer) = &self.footer {