# Tuviv Tuviv is a library for building terminal user interfaces (TUIs) with rust with a heavy focus on layout. Tuviv does not come with as many widgets as, say, [tui-rs](https://crates.io/crates/tui), but rather contains many more widgets based on layout: specifically a [`Flexbox`](https://docs.rs/tuviv/latest/widgets/struct.Flexbox.html), and a [`Grid`](https://docs.rs/tuviv/latest/widgets/struct.Flexbox.html), along with others. The purpose of this library is to significantly ease creating layouts, which is mildly clunky with tui-rs: such as the fact that you cannot center text vertically ([#396](https://github.com/fdehau/tui-rs/issues/396)) - but also wider-scale things - such as the lack of a flexbox or a grid. ## Features - `crossterm` - backend. `crossterm` is enabled by default and is recommended. - `textwrap` - allows for the [`Paragraph`](crate::widgets::Paragraph) widget. Is enabled by default. (please note if you don't include this you will have to reimplement something to render text) ## Examples ### Create a Buffer And Render a Widget ```rust // Imports use std::io; use std::time::Duration; use tuviv::{ le::Orientation, prelude::*, widgets::{Filler, Flexbox}, }; fn main() -> io::Result<()> { // Create a flexbox // With coloured squares let flexbox = Flexbox::new(Orientation::Horizontal, false) .child( Filler::new(" ".styled().bg_red()) .fixed_size(16, 8) .centered() .to_flex_child() .expand(1), ) .child( Flexbox::new(Orientation::Vertical, false) .child( Filler::new(" ".styled().bg_yellow()) .fixed_size(16, 8) .centered() .to_flex_child() .expand(1), ) .child( Filler::new(" ".styled().bg_green()) .fixed_size(16, 8) .centered() .to_flex_child() .expand(1), ) .to_flex_child() .expand(1), ); // Render a single frame. // // Look at `tuviv::run_app` for a better way of doing this // for real applications tuviv::render_frame(&*flexbox, Duration::from_secs(2))?; Ok(()) } ``` ### Create More Complicated Widget Trees Tuviv uses a builder pattern so complicated widgets can be created easily: ```rust use tuviv::prelude::*; // Create a grid with progressbars: // // ╭───────────────╮ // │CPU █▌────────│ // │MEM ███▌──────│ // │GPU ─────CO o │ // ╰───────────────╯ let grid = Grid::new() .template_rows(vec![Sizing::Auto; 3]) .template_columns(vec![Sizing::Auto, Sizing::AutoFixed(10)]) .column_gap(2) .auto_child(Paragraph::new("CPU".styled())) .auto_child( ProgressBar::new() .total(100.0) .value(10.0) .align_y(Alignment::Center), ) .auto_child(Paragraph::new("MEM".styled())) .auto_child( ProgressBar::new() .total(8.0) .value(2.4) .align_y(Alignment::Center), ) .auto_child(Paragraph::new("GPU".styled())) .auto_child( ProgressBar::new() .total(15.0) .value(8.0) .fg(vec!["─".styled().bold()]) .edge("C".styled().yellow().bold()) .bg(vec!["O o ".styled()]) .align_y(Alignment::Center), ) .to_box_sizing() .border(Border::ROUNDED) .centered(); ```