use crate::app::Application;
use crate::core::command::{CM_CANCEL, CM_NO, CM_OK, CM_YES, CommandId};
use crate::core::geometry::Rect;
use crate::views::View;
use crate::views::button::Button;
use crate::views::dialog::Dialog;
use crate::views::input_line::InputLine;
use crate::views::static_text::StaticText;
use std::cell::RefCell;
use std::rc::Rc;
pub const MF_WARNING: u16 = 0x0000;
pub const MF_ERROR: u16 = 0x0001;
pub const MF_INFORMATION: u16 = 0x0002;
pub const MF_CONFIRMATION: u16 = 0x0003;
pub const MF_ABOUT: u16 = 0x0004;
pub const MF_YES_BUTTON: u16 = 0x0100;
pub const MF_NO_BUTTON: u16 = 0x0200;
pub const MF_OK_BUTTON: u16 = 0x0400;
pub const MF_CANCEL_BUTTON: u16 = 0x0800;
pub const MF_YES_NO_CANCEL: u16 = MF_YES_BUTTON | MF_NO_BUTTON | MF_CANCEL_BUTTON;
pub const MF_OK_CANCEL: u16 = MF_OK_BUTTON | MF_CANCEL_BUTTON;
pub fn message_box(app: &mut Application, msg: &str, options: u16) -> CommandId {
let (width, height) = app.terminal.size();
let lines: Vec<&str> = msg.split('\n').collect();
let num_lines = lines.len() as i16;
let max_line_len = lines.iter().map(|l| l.len()).max().unwrap_or(0) as i16;
let dialog_width = (max_line_len + 4).clamp(40, 72);
let dialog_height = (1 + num_lines + 2 + 3).clamp(9, 20);
let dialog_x = (width - dialog_width) / 2;
let dialog_y = (height - dialog_height - 2) / 2;
let bounds = Rect::new(
dialog_x,
dialog_y,
dialog_x + dialog_width,
dialog_y + dialog_height,
);
message_box_rect(app, bounds, msg, options)
}
pub fn message_box_rect(app: &mut Application, bounds: Rect, msg: &str, options: u16) -> CommandId {
let title = match options & 0x0F {
MF_WARNING => "Warning ⚠️",
MF_ERROR => "Error 🛑",
MF_INFORMATION => "Information ℹ️",
MF_CONFIRMATION => "❔Confirm❔",
MF_ABOUT => "About ℹ️",
_ => "Message",
};
let mut dialog = Dialog::new(bounds, title);
let text_bounds = Rect::new(1, 1, bounds.width() - 2, bounds.height() - 3);
dialog.add(Box::new(StaticText::new(text_bounds, msg)));
let button_specs = [
(MF_YES_BUTTON, "~Y~es", CM_YES),
(MF_NO_BUTTON, "~N~o", CM_NO),
(MF_OK_BUTTON, "O~K~", CM_OK),
(MF_CANCEL_BUTTON, "Cancel", CM_CANCEL),
];
let mut buttons = Vec::new();
let mut total_width = -2i16;
for (flag, label, command) in button_specs.iter() {
if (options & flag) != 0 {
let button = Button::new(Rect::new(0, 0, 10, 2), label, *command, buttons.is_empty());
total_width += 10 + 2; buttons.push((button, *command));
}
}
let mut x = (bounds.width() - total_width) / 2;
let y = bounds.height() - 4;
for (mut button, _cmd) in buttons {
let button_bounds = Rect::new(x, y, x + 10, y + 2);
button.set_bounds(button_bounds);
dialog.add(Box::new(button));
x += 12; }
dialog.set_initial_focus();
dialog.execute(app)
}
pub fn input_box(
app: &mut Application,
title: &str,
label: &str,
default: &str,
limit: usize,
) -> (CommandId, String) {
let (width, height) = app.terminal.size();
let dialog_width = 60i16;
let dialog_height = 8i16;
let dialog_x = (width - dialog_width) / 2;
let dialog_y = (height - dialog_height - 2) / 2;
let bounds = Rect::new(
dialog_x,
dialog_y,
dialog_x + dialog_width,
dialog_y + dialog_height,
);
input_box_rect(app, bounds, title, label, default, limit)
}
pub fn input_box_rect(
app: &mut Application,
bounds: Rect,
title: &str,
label: &str,
default: &str,
limit: usize,
) -> (CommandId, String) {
let mut dialog = Dialog::new(bounds, title);
let input_data = Rc::new(RefCell::new(default.to_string()));
if !label.is_empty() {
let label_bounds = Rect::new(2, 2, 2 + label.len() as i16 + 1, 3);
dialog.add(Box::new(StaticText::new(label_bounds, label)));
}
let input_x = if !label.is_empty() {
4 + label.len() as i16
} else {
3
};
let input_bounds = Rect::new(input_x, 2, bounds.width() - 3, 3);
let input = InputLine::new(input_bounds, limit, Rc::clone(&input_data));
dialog.add(Box::new(input));
let ok_button = Button::new(
Rect::new(
bounds.width() / 2 - 12,
bounds.height() - 4,
bounds.width() / 2 - 2,
bounds.height() - 2,
),
"O~K~",
CM_OK,
true, );
dialog.add(Box::new(ok_button));
let cancel_button = Button::new(
Rect::new(
bounds.width() / 2 + 2,
bounds.height() - 4,
bounds.width() / 2 + 12,
bounds.height() - 2,
),
"Cancel",
CM_CANCEL,
false,
);
dialog.add(Box::new(cancel_button));
dialog.set_initial_focus();
let result = dialog.execute(app);
let text = input_data.borrow().clone();
(result, text)
}