use embedded_graphics::{geometry::Point, primitives::Rectangle, text::LineHeight};
use az::{SaturatingAs, SaturatingCast};
#[derive(Debug, Clone)]
pub struct LineCursor {
start: Point,
width: u32,
position: u32,
tab_width: u32,
}
impl LineCursor {
pub fn new(width: u32, tab_width: u32) -> Self {
Self {
start: Point::zero(),
width,
tab_width,
position: 0,
}
}
pub fn pos(&self) -> Point {
self.start + Point::new(self.position.saturating_as(), 0)
}
pub fn next_tab_width(&self) -> u32 {
let next_tab_pos = (self.position / self.tab_width + 1) * self.tab_width;
next_tab_pos - self.position
}
pub fn line_width(&self) -> u32 {
self.width
}
pub fn fits_in_line(&self, width: u32) -> bool {
width <= self.space()
}
pub fn space(&self) -> u32 {
self.width - self.position
}
pub fn move_cursor(&mut self, by: i32) -> Result<i32, i32> {
if by < 0 {
let abs = by.abs() as u32;
if abs <= self.position {
self.position -= abs;
Ok(by)
} else {
Err(-self.position.saturating_as::<i32>())
}
} else {
let space = self.space().saturating_cast();
if by <= space {
self.position += by as u32;
Ok(by)
} else {
Err(space)
}
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct Cursor {
pub y: i32,
bounds: Rectangle,
line_height: i32,
line_spacing: i32,
tab_width: u32,
}
impl Cursor {
#[inline]
#[must_use]
pub fn new(
bounds: Rectangle,
base_line_height: u32,
line_height: LineHeight,
tab_width: u32,
) -> Self {
Self {
y: bounds.top_left.y,
line_height: base_line_height.saturating_as(),
line_spacing: line_height.to_absolute(base_line_height).saturating_as(),
bounds,
tab_width,
}
}
#[must_use]
pub fn line(&self) -> LineCursor {
LineCursor {
start: Point::new(self.bounds.top_left.x, self.y),
width: self.bounds.size.width,
position: 0,
tab_width: self.tab_width,
}
}
#[inline]
pub fn bottom_right(&self) -> Point {
self.bounds.bottom_right().unwrap_or(self.bounds.top_left)
}
#[inline]
pub fn top_left(&self) -> Point {
self.bounds.top_left
}
#[inline]
pub fn line_width(&self) -> u32 {
self.bounds.size.width
}
#[inline]
pub fn line_height(&self) -> i32 {
self.line_height
}
#[inline]
pub fn new_line(&mut self) {
self.y += self.line_spacing;
}
#[inline]
#[must_use]
pub fn in_display_area(&self) -> bool {
self.bounds.top_left.y <= self.y && self.y <= self.bottom_right().y - self.line_height + 1
}
}