use std::ops::RangeInclusive;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub struct PanelState {
pub viewport_id: u64,
pub buffer_id: u64,
pub visible_start: u32,
pub visible_end: u32,
pub cursor_line: u32,
pub cursor_col: u32,
pub total_lines: u32,
}
impl PanelState {
#[must_use]
pub const fn new(viewport_id: u64, buffer_id: u64) -> Self {
Self {
viewport_id,
buffer_id,
visible_start: 0,
visible_end: 0,
cursor_line: 0,
cursor_col: 0,
total_lines: 0,
}
}
#[must_use]
pub const fn with_visible_range(mut self, start: u32, end: u32) -> Self {
self.visible_start = start;
self.visible_end = end;
self
}
#[must_use]
pub const fn with_cursor(mut self, line: u32, col: u32) -> Self {
self.cursor_line = line;
self.cursor_col = col;
self
}
#[must_use]
pub const fn with_total_lines(mut self, total: u32) -> Self {
self.total_lines = total;
self
}
#[must_use]
pub const fn visible_range(&self) -> (u32, u32) {
(self.visible_start, self.visible_end)
}
#[must_use]
pub const fn visible_range_inclusive(&self) -> RangeInclusive<u32> {
self.visible_start..=self.visible_end
}
#[must_use]
pub const fn is_line_visible(&self, line: u32) -> bool {
line >= self.visible_start && line <= self.visible_end
}
#[must_use]
pub const fn visible_line_count(&self) -> u32 {
if self.visible_end >= self.visible_start {
self.visible_end - self.visible_start + 1
} else {
0
}
}
#[must_use]
pub const fn is_cursor_visible(&self) -> bool {
self.is_line_visible(self.cursor_line)
}
#[must_use]
#[allow(clippy::cast_precision_loss)] pub fn scroll_percentage(&self) -> f32 {
if self.total_lines == 0 {
return 0.0;
}
let max_start = self.total_lines.saturating_sub(self.visible_line_count());
if max_start == 0 {
return 0.0;
}
self.visible_start as f32 / max_start as f32
}
#[must_use]
pub const fn is_at_top(&self) -> bool {
self.visible_start == 0
}
#[must_use]
pub const fn is_at_bottom(&self) -> bool {
self.visible_end >= self.total_lines.saturating_sub(1)
}
}
#[cfg(test)]
#[path = "panel_tests.rs"]
mod tests;