Creare una TUI in Rust

Mattepuffo's logo
Creare una TUI in Rust

Creare una TUI in Rust

La costruzione di TUI (text user interface) non è per nulla facile neanche se usiamo librerie apposite.

In questo articolo vediamo come usare il modulo tui in Rust!

Ovviamente il mio è un esempio abbastanza banale, non come quello che vedete nella pagina di documentazione.

Ma può essere un inizio se avete bisogno di qualcosa del genere; prima di tutto aggiungiamo queste dipendenze al Cargo.toml:

[dependencies]
tui = "0.19"
crossterm = "0.25"

Qui sotto il mio codice di esempio:

use crossterm::{
    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use std::{error::Error, io};
use tui::{
    backend::{Backend, CrosstermBackend},
    layout::{Alignment, Constraint, Direction, Layout},
    style::{Color, Modifier, Style},
    text::Span,
    widgets::{Block, BorderType, Borders},
    Frame, Terminal,
};

fn main() -> Result<(), Box<dyn Error>> {
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    let res = start_app(&mut terminal);

    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        println!("{:?}", err)
    }

    Ok(())
}

fn start_app<B: Backend>(terminal: &mut Terminal<B>) -> io::Result<()> {
    loop {
        terminal.draw(my_ui)?;

        if let Event::Key(key) = event::read()? {
            if let KeyCode::Char('q') = key.code {
                return Ok(());
            }
        }
    }
}

fn my_ui<B: Backend>(f: &mut Frame<B>) {
    let size = f.size();

    let block = Block::default()
        .borders(Borders::ALL)
        .title("Blocco principale")
        .title_alignment(Alignment::Center)
        .border_type(BorderType::Rounded);
    f.render_widget(block, size);

    let chunks = Layout::default()
        .direction(Direction::Vertical)
        .margin(4)
        .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
        .split(f.size());

    let top_chunks = Layout::default()
        .direction(Direction::Horizontal)
        .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
        .split(chunks[0]);

    let block = Block::default()
        .title(vec![
            Span::styled("Scritta verde su sfondo rosso", Style::default().fg(Color::Green)),
        ])
        .style(Style::default().bg(Color::Red));
    f.render_widget(block, top_chunks[0]);

    let block = Block::default()
        .title(Span::styled(
            "Testo con stile",
            Style::default()
                .fg(Color::White)
                .bg(Color::Red)
                .add_modifier(Modifier::BOLD),
        ))
        .title_alignment(Alignment::Right);
    f.render_widget(block, top_chunks[1]);

    let bottom_chunks = Layout::default()
        .direction(Direction::Horizontal)
        .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
        .split(chunks[1]);

    let block = Block::default()
        .title("Sotto blocco con bordo blu")
        .borders(Borders::ALL)
        .border_style(Style::default().fg(Color::LightBlue));
    f.render_widget(block, bottom_chunks[0]);
}

Enjoy!


Condividi

Commentami!