use envision::prelude::*;
struct DialogApp;
#[derive(Clone)]
struct State {
dialog: DialogState,
last_result: Option<String>,
}
#[derive(Clone, Debug)]
enum Msg {
Dialog(DialogMessage),
ShowDialog,
Quit,
}
impl App for DialogApp {
type State = State;
type Message = Msg;
fn init() -> (State, Command<Msg>) {
let dialog = DialogState::new(
"Unsaved Changes",
"You have unsaved changes.\nWhat would you like to do?",
vec![
DialogButton::new("discard", "Discard"),
DialogButton::new("save", "Save"),
DialogButton::new("cancel", "Cancel"),
],
);
let state = State {
dialog,
last_result: None,
};
(state, Command::none())
}
fn update(state: &mut State, msg: Msg) -> Command<Msg> {
match msg {
Msg::Dialog(m) => {
if let Some(output) = Dialog::update(&mut state.dialog, m) {
match output {
DialogOutput::ButtonPressed(id) => {
state.last_result = Some(format!("Pressed: {}", id));
}
DialogOutput::Closed => {
state.last_result = Some("Dialog closed".into());
}
}
}
}
Msg::ShowDialog => {
Dialog::show(&mut state.dialog);
}
Msg::Quit => return Command::quit(),
}
Command::none()
}
fn view(state: &State, frame: &mut Frame) {
let theme = Theme::default();
let area = frame.area();
let chunks = Layout::vertical([Constraint::Min(0), Constraint::Length(1)]).split(area);
let result_text = state.last_result.as_deref().unwrap_or("No action yet");
let content = ratatui::widgets::Paragraph::new(format!(" Result: {}", result_text)).block(
ratatui::widgets::Block::default()
.borders(ratatui::widgets::Borders::ALL)
.title("Dialog Demo"),
);
frame.render_widget(content, chunks[0]);
if Dialog::is_visible(&state.dialog) {
Dialog::view(&state.dialog, &mut RenderContext::new(frame, area, &theme));
}
let status = " d: show dialog, q: quit";
frame.render_widget(
ratatui::widgets::Paragraph::new(status).style(Style::default().fg(Color::DarkGray)),
chunks[1],
);
}
fn handle_event_with_state(state: &State, event: &Event) -> Option<Msg> {
if Dialog::is_visible(&state.dialog) {
return Dialog::handle_event(&state.dialog, event, &EventContext::new().focused(true))
.map(Msg::Dialog);
}
if let Some(key) = event.as_key() {
match key.code {
Key::Char('q') | Key::Esc => Some(Msg::Quit),
Key::Char('d') => Some(Msg::ShowDialog),
_ => None,
}
} else {
None
}
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut vt = Runtime::<DialogApp, _>::virtual_builder(60, 14).build()?;
println!("=== Dialog Example ===\n");
vt.tick()?;
println!("Initial state (no dialog):");
println!("{}\n", vt.display());
vt.dispatch(Msg::ShowDialog);
vt.tick()?;
println!("After showing dialog:");
println!("{}\n", vt.display());
vt.dispatch(Msg::Dialog(DialogMessage::FocusNext));
vt.dispatch(Msg::Dialog(DialogMessage::Press));
vt.tick()?;
println!("After pressing Save:");
println!("{}\n", vt.display());
Ok(())
}