use crossterm::terminal::WindowSize; use ratatui::layout::Rect; use super::{Offset, Origin}; #[derive(Clone, Copy, Debug, Default)] pub struct Position { pub origin: Origin, pub offset: Offset, } impl Position { pub const fn new(origin: Origin, offset: Offset) -> Self { Self { origin, offset } } pub fn rect(&self, WindowSize { columns, rows, .. }: WindowSize) -> Rect { use Origin::*; let Offset { x, y, width, height } = self.offset; let max_x = columns.saturating_sub(width); let new_x = match self.origin { TopLeft | BottomLeft => x.clamp(0, max_x as i16) as u16, TopCenter | BottomCenter | Center => { (columns / 2).saturating_sub(width / 2).saturating_add_signed(x).clamp(0, max_x) } TopRight | BottomRight => max_x.saturating_add_signed(x).clamp(0, max_x), Hovered => unreachable!(), }; let max_y = rows.saturating_sub(height); let new_y = match self.origin { TopLeft | TopCenter | TopRight => y.clamp(0, max_y as i16) as u16, Center => (rows / 2).saturating_sub(height / 2).saturating_add_signed(y).clamp(0, max_y), BottomLeft | BottomCenter | BottomRight => max_y.saturating_add_signed(y).clamp(0, max_y), Hovered => unreachable!(), }; Rect { x: new_x, y: new_y, width: width.min(columns.saturating_sub(new_x)), height: height.min(rows.saturating_sub(new_y)), } } pub fn sticky(WindowSize { columns, rows, .. }: WindowSize, base: Rect, offset: Offset) -> Rect { let Offset { x, y, width, height } = offset; let above = base.y.saturating_add(base.height).saturating_add(height).saturating_add_signed(y) > rows; let new_x = base.x.saturating_add_signed(x).clamp(0, columns.saturating_sub(width)); let new_y = if above { base.y.saturating_sub(height.saturating_sub(y.unsigned_abs())) } else { base.y.saturating_add(base.height).saturating_add_signed(y) }; Rect { x: new_x, y: new_y, width: width.min(columns.saturating_sub(new_x)), height: height.min(rows.saturating_sub(new_y)), } } }