cargo-port 0.0.1

A TUI for inspecting and managing Rust projects
use ratatui::layout::Rect;

/// A bounded cursor for scrollable lists. Replaces raw `usize` index + manual
/// bounds checking with a single type that enforces invariants.
#[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); }

    /// Clamp position to `0..len`. Useful after the backing list shrinks.
    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, PartialEq, Eq, Clone, Copy)]
pub(super) enum FocusTarget {
    #[default]
    ProjectList,
    DetailFields,
    CiRuns,
    ScanLog,
}

/// Cached layout rectangles from the last render frame, used for mouse
/// hit-testing in the event handler.
#[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>,
    pub ci_panel:             Rect,
    pub ci_table_offset:      usize,
    pub targets_table_offset: usize,
    pub finder_results_area:  Option<Rect>,
    pub finder_table_offset:  usize,
    pub settings_area:        Option<Rect>,
}