use ratatui::layout::Position;
use ratatui::layout::Rect;
#[derive(Default, Clone)]
pub(super) struct ScrollState {
pos: usize,
}
impl ScrollState {
pub const fn pos(&self) -> usize { self.pos }
pub const fn set(&mut self, pos: usize) { self.pos = pos; }
pub const fn up(&mut self) {
if self.pos > 0 {
self.pos -= 1;
}
}
pub const fn down(&mut self, len: usize) {
if len > 0 && self.pos < len - 1 {
self.pos += 1;
}
}
pub const fn jump_home(&mut self) { self.pos = 0; }
pub const fn jump_end(&mut self, len: usize) { self.pos = len.saturating_sub(1); }
pub const fn clamp(&mut self, len: usize) {
if len == 0 {
self.pos = 0;
} else if self.pos >= len {
self.pos = len - 1;
}
}
}
#[derive(Default, Clone)]
pub(super) struct Pane {
cursor: ScrollState,
len: usize,
content_area: Rect,
scroll_offset: usize,
}
impl Pane {
pub const fn new() -> Self {
Self {
cursor: ScrollState { pos: 0 },
len: 0,
content_area: Rect::new(0, 0, 0, 0),
scroll_offset: 0,
}
}
pub const fn up(&mut self) { self.cursor.up(); }
pub const fn down(&mut self) { self.cursor.down(self.len); }
pub const fn home(&mut self) { self.cursor.jump_home(); }
pub const fn end(&mut self) { self.cursor.jump_end(self.len); }
pub const fn pos(&self) -> usize { self.cursor.pos() }
pub const fn set_pos(&mut self, pos: usize) { self.cursor.set(pos); }
pub const fn set_len(&mut self, len: usize) {
self.len = len;
self.cursor.clamp(len);
}
pub const fn set_content_area(&mut self, area: Rect) { self.content_area = area; }
pub const fn set_scroll_offset(&mut self, offset: usize) { self.scroll_offset = offset; }
pub const fn clicked_row(&self, pos: Position) -> Option<usize> {
if !self.content_area.contains(pos) {
return None;
}
let inner_y = (pos.y - self.content_area.y) as usize;
let row = self.scroll_offset + inner_y;
if row < self.len { Some(row) } else { None }
}
}
#[derive(Default, PartialEq, Eq, Clone, Copy)]
pub(super) enum FocusTarget {
#[default]
ProjectList,
DetailFields,
CiRuns,
ScanLog,
}
#[derive(Default)]
pub(super) struct LayoutCache {
pub project_list: Rect,
pub scan_log: Option<Rect>,
pub detail_columns: Vec<Rect>,
pub detail_targets_col: Option<usize>,
}