use retroglyph_core::{Backend, Rect, Style, Terminal};
use super::{Panel, Widget};
use crate::layout::centered_rect;
use crate::{Align, Theme};
#[derive(Clone, Copy, Debug)]
pub struct Modal<'a> {
width: u16,
height: u16,
title: Option<&'a str>,
title_align: Align,
border_style: Style,
fill_style: Style,
}
impl<'a> Modal<'a> {
#[must_use]
pub fn new(width: u16, height: u16) -> Self {
Self {
width,
height,
title: None,
title_align: Align::Center,
border_style: Style::new(),
fill_style: Style::new(),
}
}
#[must_use]
pub const fn title(mut self, title: &'a str) -> Self {
self.title = Some(title);
self
}
#[must_use]
pub const fn title_align(mut self, align: Align) -> Self {
self.title_align = align;
self
}
#[must_use]
pub const fn border_style(mut self, style: Style) -> Self {
self.border_style = style;
self
}
#[must_use]
pub const fn fill_style(mut self, style: Style) -> Self {
self.fill_style = style;
self
}
#[must_use]
pub fn theme(mut self, theme: Theme) -> Self {
self.border_style = Style::new().fg(theme.border).bg(theme.title_bg);
self.fill_style = Style::new().bg(theme.panel_bg);
self
}
pub fn render<B: Backend>(self, screen: Rect, term: &mut Terminal<B>) -> Rect {
let rect = centered_rect(screen, self.width, self.height);
let mut panel = Panel::new()
.border_style(self.border_style)
.fill_style(self.fill_style)
.title_align(self.title_align);
if let Some(title) = self.title {
panel = panel.title(title);
}
panel.render(rect, term);
Rect::new(
rect.left() + 1,
rect.top() + 1,
rect.width().saturating_sub(2),
rect.height().saturating_sub(2),
)
}
}
#[cfg(test)]
mod tests {
use retroglyph_core::Headless;
use super::*;
#[test]
fn centers_the_box_and_returns_the_inner_content_rect() {
let screen = Rect::new(0, 0, 20, 10);
let mut term = Terminal::new(Headless::new(20, 10));
let inner = Modal::new(10, 4).render(screen, &mut term);
assert_eq!(inner, Rect::new(6, 4, 8, 2));
assert_eq!(term.grid().get(5, 3).glyph(), '┌');
assert_eq!(term.grid().get(14, 3).glyph(), '┐');
}
#[test]
fn draws_only_the_box_leaving_the_rest_of_the_screen_untouched() {
let screen = Rect::new(0, 0, 20, 10);
let mut term = Terminal::new(Headless::new(20, 10));
Modal::new(10, 4).render(screen, &mut term);
assert_eq!(term.grid().get(0, 0).glyph(), ' ');
}
#[test]
fn theme_maps_named_roles_onto_border_and_fill() {
let screen = Rect::new(0, 0, 20, 10);
let mut term = Terminal::new(Headless::new(20, 10));
Modal::new(10, 4)
.theme(Theme::DARK)
.render(screen, &mut term);
assert_eq!(
term.grid().get(5, 3).style().foreground(),
Theme::DARK.border
);
assert_eq!(
term.grid().get(5, 3).style().background(),
Theme::DARK.title_bg
);
assert_eq!(
term.grid().get(6, 4).style().background(),
Theme::DARK.panel_bg
);
}
}