use crossterm::event::{KeyEvent, MouseButton, MouseEventKind};
use ratatui::{
layout::{Flex, Layout},
prelude::*,
style::{Color, Style},
widgets::*,
};
use crate::app::Action;
use crate::mouse_input::MouseInput;
#[derive(Debug, Clone, Copy)]
pub enum MessageKind {
Info,
Warning,
Error,
}
#[derive(Debug, Clone)]
pub struct Message {
pub should_render: bool,
pub handle_input: bool,
pub text: String,
pub rect: Rect,
pub kind: MessageKind,
}
impl Message {
pub fn new(text: &str) -> Self {
Self {
should_render: true,
handle_input: true,
text: text.to_string(),
rect: Rect::default(),
kind: MessageKind::Info,
}
}
pub fn new_disabled() -> Self {
Self {
should_render: false,
handle_input: false,
text: "".to_string(),
rect: Rect::default(),
kind: MessageKind::Info,
}
}
}
impl Message {
pub fn render(&mut self, f: &mut Frame, _area: &Rect) {
if !self.should_render {
return;
}
let color = match self.kind {
MessageKind::Info => Color::Blue,
MessageKind::Warning => Color::Yellow,
MessageKind::Error => Color::Red,
};
let title = match self.kind {
MessageKind::Info => "Info",
MessageKind::Warning => "Warning",
MessageKind::Error => "Error",
};
let paragraph = Paragraph::new(self.text.clone())
.style(Style::default().fg(color))
.wrap(Wrap { trim: true })
.block(
Block::default()
.borders(Borders::ALL)
.title(title)
.border_type(BorderType::Rounded)
.title_top(Line::from("<Esc> to close").alignment(Alignment::Right)),
);
let window_width = f.area().width;
let text_area_width = (0.8 * (window_width as f32)) as u16;
let text_lines = paragraph.line_count(text_area_width) as u16;
let horizontal = Layout::horizontal([text_area_width]).flex(Flex::Center);
let vertical = Layout::vertical([text_lines + 2]).flex(Flex::Center);
let [rect] = vertical.areas(f.area());
let [rect] = horizontal.areas(rect);
self.rect = rect;
f.render_widget(Clear, rect);
f.render_widget(paragraph, rect);
}
}
impl Message {
pub fn input(&mut self, _action: &mut Action, _key_event: KeyEvent) -> bool {
if !self.handle_input {
return false;
}
self.should_render = false;
self.handle_input = false;
true
}
}
impl Message {
pub fn mouse_input(&mut self, _action: &mut Action, mouse_input: &mut MouseInput) {
if !self.handle_input {
return;
}
if let Some(mouse_event_kind) = mouse_input.kind() {
match mouse_event_kind {
MouseEventKind::Down(MouseButton::Left) => {
if !self.rect.contains(mouse_input.get_position()) {
self.should_render = false;
self.handle_input = false;
}
}
_ => {}
}
mouse_input.click();
}
}
}