use crossterm::event::{KeyCode, KeyEvent}; use ratatui::{ layout::{Constraint, Direction, Layout, Rect}, Frame, }; pub trait FloatContent { fn draw(&mut self, frame: &mut Frame, area: Rect); fn handle_key_event(&mut self, key: &KeyEvent) -> bool; fn is_finished(&self) -> bool; } pub struct Float { content: Option, width_percent: u16, height_percent: u16, } impl Float { pub fn new(width_percent: u16, height_percent: u16) -> Self { Self { content: None, width_percent, height_percent, } } fn floating_window(&self, size: Rect) -> Rect { let hor_float = Layout::default() .constraints([ Constraint::Percentage((100 - self.width_percent) / 2), Constraint::Percentage(self.width_percent), Constraint::Percentage((100 - self.width_percent) / 2), ]) .direction(Direction::Horizontal) .split(size)[1]; Layout::default() .constraints([ Constraint::Percentage((100 - self.height_percent) / 2), Constraint::Percentage(self.height_percent), Constraint::Percentage((100 - self.height_percent) / 2), ]) .direction(Direction::Vertical) .split(hor_float)[1] } pub fn draw(&mut self, frame: &mut Frame, parent_area: Rect) { let popup_area = self.floating_window(parent_area); if let Some(content) = &mut self.content { let content_area = Rect { x: popup_area.x, y: popup_area.y, width: popup_area.width, height: popup_area.height, }; content.draw(frame, content_area); } } // Returns true if the key was processed by this Float. pub fn handle_key_event(&mut self, key: &KeyEvent) -> bool { if let Some(content) = &mut self.content { match key.code { KeyCode::Enter | KeyCode::Char('p') | KeyCode::Esc | KeyCode::Char('q') => { if content.is_finished() { self.content = None; } else { content.handle_key_event(key); } } _ => { content.handle_key_event(key); } } true } else { false } } pub fn get_content(&self) -> &Option { &self.content } pub fn set_content(&mut self, content: Option) { self.content = content; } }