feat(display): DrawText with built-in Spleen 8x16 font (BSD-2)
This commit is contained in:
@@ -48,3 +48,78 @@ impl Dimension {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// `DrawText`, shared by the display server and `libkos::display`: up to
|
||||
/// `TEXT_BYTES` characters at a pixel position, each cell `fg` on `bg`.
|
||||
/// Words: `[TEXT | len << 8 | fg << 16, x | y << 16 | bg << 32, bytes 0..8, 8..16]`.
|
||||
pub mod text {
|
||||
use super::{Color, ScreenCoord};
|
||||
|
||||
pub const TEXT: usize = 4;
|
||||
pub const TEXT_BYTES: usize = 16;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Text {
|
||||
pub x: ScreenCoord,
|
||||
pub y: ScreenCoord,
|
||||
pub fg: Color,
|
||||
pub bg: Color,
|
||||
pub bytes: [u8; TEXT_BYTES],
|
||||
pub len: usize,
|
||||
}
|
||||
|
||||
impl Text {
|
||||
/// `s` past `TEXT_BYTES` is cut off.
|
||||
pub fn new(x: ScreenCoord, y: ScreenCoord, fg: Color, bg: Color, s: &[u8]) -> Self {
|
||||
let len = s.len().min(TEXT_BYTES);
|
||||
let mut bytes = [0u8; TEXT_BYTES];
|
||||
bytes[..len].copy_from_slice(&s[..len]);
|
||||
Self { x, y, fg, bg, bytes, len }
|
||||
}
|
||||
|
||||
pub fn chars(&self) -> &[u8] {
|
||||
&self.bytes[..self.len.min(TEXT_BYTES)]
|
||||
}
|
||||
|
||||
pub fn words(&self) -> [usize; 4] {
|
||||
let (lo, hi) = self.bytes.as_chunks::<8>().0.split_at(1);
|
||||
[
|
||||
TEXT | self.len << 8 | (self.fg.raw() as usize) << 16,
|
||||
self.x.raw() as usize | (self.y.raw() as usize) << 16 | (self.bg.raw() as usize) << 32,
|
||||
u64::from_le_bytes(lo[0]) as usize,
|
||||
u64::from_le_bytes(hi[0]) as usize,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn from_words(w: [usize; 4]) -> Option<Self> {
|
||||
let len = (w[0] >> 8) & 0xFF;
|
||||
if w[0] & 0xFF != TEXT || len > TEXT_BYTES {
|
||||
return None;
|
||||
}
|
||||
let mut bytes = [0u8; TEXT_BYTES];
|
||||
for (b, word) in bytes.as_chunks_mut::<8>().0.iter_mut().zip(&w[2..]) {
|
||||
*b = (*word as u64).to_le_bytes();
|
||||
}
|
||||
Some(Self {
|
||||
x: ScreenCoord::new((w[1] & 0xFFFF) as u16),
|
||||
y: ScreenCoord::new(((w[1] >> 16) & 0xFFFF) as u16),
|
||||
fg: Color::from_raw((w[0] >> 16) as u32),
|
||||
bg: Color::from_raw((w[1] >> 32) as u32),
|
||||
bytes,
|
||||
len,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn text_round_trips() {
|
||||
let t = Text::new(ScreenCoord::new(1272), ScreenCoord::new(784), Color::rgb(1, 2, 3), Color::rgb(4, 5, 6), b"$ ls -la /home/x");
|
||||
assert_eq!(Text::from_words(t.words()), Some(t));
|
||||
assert_eq!(Text::new(t.x, t.y, t.fg, t.bg, &[b'a'; 40]).len, TEXT_BYTES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user