use core::marker::PhantomData;
use embedded_graphics::{fonts::Font, geometry::Point, primitives::Rectangle};
#[derive(Copy, Clone, Debug)]
pub struct Cursor<F: Font> {
_marker: PhantomData<F>,
pub position: Point,
left: i32,
right: i32,
bottom: i32,
}
impl<F: Font> Cursor<F> {
#[inline]
#[must_use]
pub fn new(bounds: Rectangle) -> Self {
Self {
_marker: PhantomData,
position: bounds.top_left,
bottom: bounds.bottom_right.y + 1,
left: bounds.top_left.x,
right: (bounds.bottom_right.x + 1).max(bounds.top_left.x),
}
}
#[inline]
pub fn line_width(&self) -> u32 {
(self.right - self.left) as u32
}
#[inline]
pub fn new_line(&mut self) {
self.position.y += F::CHARACTER_SIZE.height as i32;
}
#[inline]
pub fn carriage_return(&mut self) {
self.position.x = self.left;
}
#[inline]
pub fn in_display_area(&self) -> bool {
(self.position.y + F::CHARACTER_SIZE.height as i32) < self.bottom
}
#[inline]
pub fn fits_in_line(&self, width: u32) -> bool {
width as i32 <= self.right - self.position.x
}
#[inline]
pub fn advance(&mut self, by: u32) {
self.position.x += by as i32;
}
}
#[cfg(test)]
mod test {
use super::*;
use embedded_graphics::fonts::Font6x8;
#[test]
fn fits_in_line() {
let cursor: Cursor<Font6x8> = Cursor::new(Rectangle::new(Point::zero(), Point::new(5, 7)));
assert!(cursor.fits_in_line(6));
assert!(!cursor.fits_in_line(7));
}
#[test]
fn advance_moves_position() {
let mut cursor: Cursor<Font6x8> =
Cursor::new(Rectangle::new(Point::zero(), Point::new(5, 7)));
assert!(cursor.fits_in_line(1));
cursor.advance(6);
assert!(!cursor.fits_in_line(1));
}
}