125 lines
2.7 KiB
Rust
125 lines
2.7 KiB
Rust
use crate::ui::utils::{background_block, centered_rect};
|
|
use ratatui::buffer::Buffer;
|
|
use ratatui::layout::{Constraint, Layout, Rect};
|
|
use ratatui::widgets::{Block, Clear, Widget};
|
|
|
|
#[cfg(test)]
|
|
#[path = "popup_tests.rs"]
|
|
mod popup_tests;
|
|
|
|
pub enum Size {
|
|
SmallPrompt,
|
|
MediumPrompt,
|
|
LargePrompt,
|
|
WideLargePrompt,
|
|
Message,
|
|
NarrowMessage,
|
|
LargeMessage,
|
|
InputBox,
|
|
Dropdown,
|
|
Small,
|
|
Medium,
|
|
Large,
|
|
XLarge,
|
|
XXLarge,
|
|
Long,
|
|
LongNarrowTable,
|
|
}
|
|
|
|
impl Size {
|
|
pub fn to_percent(&self) -> (u16, u16) {
|
|
match self {
|
|
Size::SmallPrompt => (20, 20),
|
|
Size::MediumPrompt => (37, 37),
|
|
Size::LargePrompt => (45, 45),
|
|
Size::WideLargePrompt => (70, 50),
|
|
Size::Message => (25, 8),
|
|
Size::NarrowMessage => (50, 20),
|
|
Size::LargeMessage => (25, 25),
|
|
Size::InputBox => (30, 13),
|
|
Size::Dropdown => (20, 30),
|
|
Size::Small => (40, 40),
|
|
Size::Medium => (60, 60),
|
|
Size::Large => (75, 75),
|
|
Size::XLarge => (83, 83),
|
|
Size::XXLarge => (90, 90),
|
|
Size::Long => (65, 75),
|
|
Size::LongNarrowTable => (55, 85),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Popup<'a, T: Widget> {
|
|
widget: T,
|
|
margin: u16,
|
|
percent_x: u16,
|
|
percent_y: u16,
|
|
block: Option<Block<'a>>,
|
|
}
|
|
|
|
impl<'a, T: Widget> Popup<'a, T> {
|
|
pub fn new(widget: T) -> Self {
|
|
Self {
|
|
widget,
|
|
percent_x: 0,
|
|
percent_y: 0,
|
|
margin: 0,
|
|
block: None,
|
|
}
|
|
}
|
|
|
|
pub fn size(mut self, size: Size) -> Self {
|
|
let (percent_x, percent_y) = size.to_percent();
|
|
self.percent_x = percent_x;
|
|
self.percent_y = percent_y;
|
|
self
|
|
}
|
|
|
|
pub fn dimensions(mut self, percent_x: u16, percent_y: u16) -> Self {
|
|
self.percent_x = percent_x;
|
|
self.percent_y = percent_y;
|
|
self
|
|
}
|
|
|
|
pub fn block(mut self, block: Block<'a>) -> Self {
|
|
self.block = Some(block);
|
|
self
|
|
}
|
|
|
|
pub fn margin(mut self, margin: u16) -> Self {
|
|
self.margin = margin;
|
|
self
|
|
}
|
|
|
|
fn render_popup(self, area: Rect, buf: &mut Buffer) {
|
|
let mut popup_area = centered_rect(self.percent_x, self.percent_y, area);
|
|
let height = if popup_area.height < 3 {
|
|
3
|
|
} else {
|
|
popup_area.height
|
|
};
|
|
popup_area = Rect {
|
|
height,
|
|
..popup_area
|
|
};
|
|
Clear.render(popup_area, buf);
|
|
background_block().render(popup_area, buf);
|
|
|
|
if let Some(block) = self.block {
|
|
block.render(popup_area, buf);
|
|
}
|
|
|
|
let [content_area, _] = Layout::vertical([Constraint::Fill(1), Constraint::Fill(0)])
|
|
.margin(self.margin)
|
|
.areas(popup_area);
|
|
|
|
self.widget.render(content_area, buf);
|
|
}
|
|
}
|
|
|
|
impl<T: Widget> Widget for Popup<'_, T> {
|
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
|
self.render_popup(area, buf);
|
|
}
|
|
}
|