use std::io::{Stdout, stdout};
use crossterm::{
event::{self, Event, KeyCode, KeyEventKind},
execute,
terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
};
use ratatui::{
Frame, Terminal,
backend::CrosstermBackend,
layout::{Constraint, Layout},
prelude::Stylize,
symbols::border,
text::Line,
widgets::{Borders, Paragraph, block::*},
};
use tui_dialog::{Dialog, centered_rect};
pub const SIDEBAR_SIZE: u16 = 40;
pub struct App {
pub dialog: Dialog,
pub text: String,
pub exit: bool,
}
fn main() {
let mut app = App {
dialog: Dialog::default(),
text: "Hello world!".to_string(),
exit: false,
};
let mut terminal = match Terminal::new(CrosstermBackend::new(stdout())) {
Ok(v) => v,
Err(e) => {
eprintln!("Error creating new terminal interface: {e}");
return;
}
};
if let Err(e) = execute!(terminal.backend_mut(), EnterAlternateScreen) {
eprintln!("Errow switching to alternate screen: {e}");
return;
}
if let Err(e) = enable_raw_mode() {
eprintln!("Error entering raw mode: {e}");
return;
}
if let Err(e) = run(&mut app, &mut terminal) {
eprintln!("Error running app: {e}");
return;
}
if let Err(e) = disable_raw_mode() {
eprintln!("Error disabling raw mode: {e}");
return;
}
if let Err(e) = execute!(terminal.backend_mut(), LeaveAlternateScreen) {
eprintln!("Error leaving alternate screen: {e}");
}
}
fn run(
app: &mut App,
terminal: &mut Terminal<CrosstermBackend<Stdout>>,
) -> Result<(), std::io::Error> {
while !app.exit {
terminal.draw(|frame| render(frame, app))?;
match event::read()? {
Event::Key(key_event) if key_event.kind == KeyEventKind::Press => {
if app.dialog.open {
app.dialog.key_action(&key_event.code);
if app.dialog.submitted {
app.text = app.dialog.submitted_input.clone();
}
} else {
match key_event.code {
KeyCode::Char('q') => app.exit = true,
KeyCode::Char('d') => app.dialog.open = true,
_ => (),
}
}
}
_ => (),
};
}
Ok(())
}
fn render(frame: &mut Frame, app: &mut App) {
let horizontal = Layout::horizontal([Constraint::Fill(1), Constraint::Length(SIDEBAR_SIZE)]);
let [left, right] = horizontal.areas(frame.area());
let main_block = Block::default()
.title_top(Line::from(" tui-dialog example ").bold().centered())
.borders(Borders::ALL)
.border_set(border::THICK)
.padding(Padding::horizontal(1));
let controls_block = Block::default()
.title_top(Line::from(" Controls").centered().bold())
.borders(Borders::ALL)
.border_set(border::THICK);
let controls_content: Vec<Line<'_>> = vec![
vec!["d".blue(), " Show dialog".into()].into(),
vec!["q".blue(), " Quit".into()].into(),
];
let controls = Paragraph::new(controls_content).block(controls_block);
frame.render_widget(controls, right);
frame.render_widget(Paragraph::new(app.text.clone()).block(main_block), left);
let dialog_area = centered_rect(frame.area(), 45, 5, -(SIDEBAR_SIZE as i16), 0);
frame.render_widget(app.dialog.title_top("Enter text:"), dialog_area);
}