use crate::tui::{AppState, style};
use ratatui::buffer::Buffer;
use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::style::Stylize as _;
use ratatui::text::Text;
use ratatui::widgets::{Block, Clear, Padding, Paragraph, StatefulWidget, Widget as _};
use std::time::Duration;
#[derive(Debug, Clone)]
pub enum PopupMode {
Timed(Duration),
#[allow(unused)]
User,
}
#[derive(Debug, Clone)]
pub struct PopupView {
pub content: String,
pub mode: PopupMode,
pub is_err: bool,
}
impl PopupView {
pub fn is_timed(&self) -> bool {
matches!(self.mode, PopupMode::Timed(_))
}
}
pub struct PopupOverlay;
impl StatefulWidget for PopupOverlay {
type State = AppState;
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
let Some(popup) = state.popup().cloned() else {
return;
};
let lines: Vec<&str> = popup.content.lines().collect();
let longest = lines.iter().map(|l| l.chars().count()).max().unwrap_or(0) as u16;
let inner_width = longest.clamp(20, area.width.saturating_sub(6)).saturating_add(2);
let inner_height = (lines.len() as u16).clamp(1, area.height.saturating_sub(6)).saturating_add(2);
let [_, mid_v, _] = Layout::default()
.direction(Direction::Vertical)
.constraints(vec![
Constraint::Fill(1),
Constraint::Length(inner_height.saturating_add(2)), Constraint::Fill(1),
])
.areas(area);
let [_, popup_a, _] = Layout::default()
.direction(Direction::Horizontal)
.constraints(vec![
Constraint::Fill(1),
Constraint::Length(inner_width.saturating_add(3)), Constraint::Fill(1),
])
.areas(mid_v);
Clear.render(popup_a, buf);
let (txt_style, border_style) = if popup.is_err {
(style::STL_SECTION_MARKER_ERR, style::CLR_TXT_RED)
} else {
(style::CLR_TXT_HOVER_TO_CLIP.into(), style::CLR_TXT_WHITE)
};
let para = Paragraph::new(Text::from(popup.content.clone()))
.style(txt_style)
.block(
Block::bordered()
.border_style(border_style)
.padding(Padding::new(2, 2, 1, 1))
.bg(style::CLR_BKG_BLACK),
)
.centered();
para.render(popup_a, buf);
if matches!(popup.mode, PopupMode::User) {
let x_area = Rect {
x: popup_a.x.saturating_add(popup_a.width.saturating_sub(2)),
y: popup_a.y,
width: 1,
height: 1,
};
Paragraph::new("x").render(x_area, buf);
if let Some(mouse_evt) = state.mouse_evt()
&& mouse_evt.is_up()
&& mouse_evt.is_over(x_area)
{
state.clear_popup();
state.trigger_redraw();
state.clear_mouse_evts();
}
}
}
}