Radish alpha
r
Radicle terminal user interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
lib: Add footer block container
Erik Kundt committed 2 years ago
commit 995ea2775120af7727b37ae3a4aaaf1d2e0d98ab
parent 70208c35db09df969f2f7288c39c80ab33f6d797
2 files changed +89 -29
modified src/flux/ui/ext.rs
@@ -113,6 +113,14 @@ impl Widget for HeaderBlock {
    }
}

+
#[derive(Clone)]
+
pub enum FooterBlockType {
+
    Single,
+
    Begin,
+
    End,
+
    Repeat,
+
}
+

pub struct FooterBlock {
    /// Visible borders
    borders: Borders,
@@ -121,6 +129,8 @@ pub struct FooterBlock {
    /// Type of the border. The default is plain lines but one can choose to have rounded corners
    /// or doubled lines instead.
    border_type: BorderType,
+
    ///
+
    block_type: FooterBlockType,
    /// Widget style
    style: Style,
}
@@ -128,7 +138,8 @@ pub struct FooterBlock {
impl Default for FooterBlock {
    fn default() -> Self {
        Self {
-
            borders: Borders::NONE,
+
            block_type: FooterBlockType::Single,
+
            borders: Self::borders(FooterBlockType::Single),
            border_style: Default::default(),
            border_type: BorderType::Rounded,
            style: Default::default(),
@@ -137,25 +148,35 @@ impl Default for FooterBlock {
}

impl FooterBlock {
-
    pub fn border_style(mut self, style: Style) -> FooterBlock {
+
    pub fn border_style(mut self, style: Style) -> Self {
        self.border_style = style;
        self
    }

-
    pub fn style(mut self, style: Style) -> FooterBlock {
+
    pub fn style(mut self, style: Style) -> Self {
        self.style = style;
        self
    }

-
    pub fn borders(mut self, flag: Borders) -> FooterBlock {
-
        self.borders = flag;
+
    pub fn block_type(mut self, block_type: FooterBlockType) -> Self {
+
        self.block_type = block_type.clone();
+
        self.borders = Self::borders(block_type);
        self
    }

-
    pub fn border_type(mut self, border_type: BorderType) -> FooterBlock {
+
    pub fn border_type(mut self, border_type: BorderType) -> Self {
        self.border_type = border_type;
        self
    }
+

+
    fn borders(block_type: FooterBlockType) -> Borders {
+
        match block_type {
+
            FooterBlockType::Single | FooterBlockType::Begin => Borders::ALL,
+
            FooterBlockType::End | FooterBlockType::Repeat => {
+
                Borders::TOP | Borders::RIGHT | Borders::BOTTOM
+
            }
+
        }
+
    }
}

impl Widget for FooterBlock {
@@ -200,13 +221,21 @@ impl Widget for FooterBlock {

        // Corners
        if self.borders.contains(Borders::RIGHT | Borders::BOTTOM) {
+
            let symbol = match self.block_type {
+
                FooterBlockType::Begin | FooterBlockType::Repeat => symbols::line::HORIZONTAL_UP,
+
                _ => symbols.bottom_right,
+
            };
            buf.get_mut(area.right() - 1, area.bottom() - 1)
-
                .set_symbol(symbols.bottom_right)
+
                .set_symbol(symbol)
                .set_style(self.border_style);
        }
        if self.borders.contains(Borders::RIGHT | Borders::TOP) {
+
            let symbol = match self.block_type {
+
                FooterBlockType::Begin | FooterBlockType::Repeat => symbols::line::HORIZONTAL_DOWN,
+
                _ => symbols::line::VERTICAL_LEFT,
+
            };
            buf.get_mut(area.right() - 1, area.top())
-
                .set_symbol(symbols::line::VERTICAL_LEFT)
+
                .set_symbol(symbol)
                .set_style(self.border_style);
        }
        if self.borders.contains(Borders::LEFT | Borders::BOTTOM) {
modified src/flux/ui/widget/container.rs
@@ -7,7 +7,7 @@ use termion::event::Key;
use ratatui::prelude::*;
use ratatui::widgets::{BorderType, Borders, Row};

-
use crate::flux::ui::ext::{FooterBlock, HeaderBlock};
+
use crate::flux::ui::ext::{FooterBlock, FooterBlockType, HeaderBlock};
use crate::flux::ui::theme::style;

use super::{Render, Widget};
@@ -51,20 +51,15 @@ impl<S, A> Widget<S, A> for Footer<A> {
    fn handle_key_event(&mut self, _key: Key) {}
}

-
impl<'a, A, const W: usize> Render<FooterProps<'a, W>> for Footer<A> {
-
    fn render<B: Backend>(&self, frame: &mut ratatui::Frame, area: Rect, props: FooterProps<W>) {
-
        let widths = props.widths.to_vec();
-
        let widths = if area.width < props.cutoff as u16 {
-
            widths.iter().take(props.cutoff_after).collect::<Vec<_>>()
-
        } else {
-
            widths.iter().collect::<Vec<_>>()
-
        };
-

-
        let footer_block = FooterBlock::default()
-
            .borders(Borders::ALL)
-
            .border_style(style::border(props.focus))
-
            .border_type(BorderType::Rounded);
-

+
impl<A> Footer<A> {
+
    fn render_cell<'a>(
+
        &self,
+
        frame: &mut ratatui::Frame,
+
        area: Rect,
+
        block_type: FooterBlockType,
+
        text: impl Into<Text<'a>>,
+
        focus: bool,
+
    ) {
        let footer_layout = Layout::default()
            .direction(Direction::Vertical)
            .constraints(vec![Constraint::Min(1)])
@@ -72,13 +67,49 @@ impl<'a, A, const W: usize> Render<FooterProps<'a, W>> for Footer<A> {
            .horizontal_margin(1)
            .split(area);

-
        let footer = ratatui::widgets::Table::default()
-
            .column_spacing(1)
-
            .header(Row::new(props.cells))
-
            .widths(widths);
-

+
        let footer_block = FooterBlock::default()
+
            .border_style(style::border(focus))
+
            .block_type(block_type);
        frame.render_widget(footer_block, area);
-
        frame.render_widget(footer, footer_layout[0]);
+
        frame.render_widget(text.into(), footer_layout[0]);
+
    }
+
}
+

+
impl<'a, A, const W: usize> Render<FooterProps<'a, W>> for Footer<A> {
+
    fn render<B: Backend>(&self, frame: &mut ratatui::Frame, area: Rect, props: FooterProps<W>) {
+
        let widths = props.widths.to_vec();
+
        let widths = if area.width < props.cutoff as u16 {
+
            widths
+
                .into_iter()
+
                .take(props.cutoff_after)
+
                .collect::<Vec<_>>()
+
        } else {
+
            widths.into_iter().collect::<Vec<_>>()
+
        };
+
        let widths = widths
+
            .into_iter()
+
            .map(|c| match c {
+
                Constraint::Min(min) => Constraint::Length(min.saturating_add(3)),
+
                _ => c,
+
            })
+
            .collect::<Vec<_>>();
+

+
        let layout = Layout::horizontal(widths).split(area);
+
        let cells = props.cells.iter().zip(layout.iter()).collect::<Vec<_>>();
+

+
        let last = cells.len().saturating_sub(1);
+
        let len = cells.len();
+

+
        for (i, (cell, area)) in cells.into_iter().enumerate() {
+
            // let last = cells.len().saturating_sub(1);
+
            let block_type = match i {
+
                0 if len == 1 => FooterBlockType::Single,
+
                0 => FooterBlockType::Begin,
+
                _ if i == last => FooterBlockType::End,
+
                _ => FooterBlockType::Repeat,
+
            };
+
            self.render_cell(frame, *area, block_type, cell.clone(), props.focus);
+
        }
    }
}