lifeblood_os/src/dev/framebuffer/console.rs
2025-09-11 16:37:15 -07:00

95 lines
3.1 KiB
Rust

use crate::dev::framebuffer::{fb_clearscreen, fb_write_char_array};
use crate::spinlock::Spinlock;
use crate::trafficcontrol::TrafficControl;
pub struct FramebufferConsole {
pub buffer: [[char; 20]; 15], // our font is 16x16, 320x240 is the standard res, so 20x15
pub cursor: (usize, usize), // (x, y)
pub need_screen_clear: bool,
}
pub static FBCONSOLE: Spinlock<FramebufferConsole> = Spinlock::new(FramebufferConsole::empty());
impl FramebufferConsole {
pub const fn empty() -> Self {
Self {
buffer: [[' '; 20]; 15],
cursor: (0, 0),
need_screen_clear: true,
}
}
// does NOT send a framebuffer update! that's up to the caller
pub fn scroll_terminal(&mut self) {
for line_num in 0..(self.buffer.len() - 1) {
let copy_from = self.buffer[line_num + 1];
self.buffer[line_num] = copy_from;
}
self.buffer[self.buffer.len() - 1] = [' '; 20];
self.need_screen_clear = true;
}
// DOES send a framebuffer update!
pub fn clear_terminal(&mut self, tc: &mut TrafficControl) {
self.need_screen_clear = false;
self.buffer = [[' '; 20]; 15];
self.cursor = (0, 0);
self.render(tc);
}
// DOES send a framebuffer update!
pub fn printstr(&mut self, tc: &mut TrafficControl, str: &str) {
for c in str.chars() {
let mut was_special_char = false;
if c == '\n' || c == '\r' {
was_special_char = true;
self.cursor.0 = 0;
self.cursor.1 += 1;
}
if self.cursor.1 >= self.buffer.len() {
self.cursor.0 = 0;
self.cursor.1 = self.buffer.len() - 1;
self.scroll_terminal();
}
if c == '\x08' {
was_special_char = true;
// we don't clear the character, that's up to the terminal
self.need_screen_clear = true;
if self.cursor.0 > 0 {
self.cursor.0 -= 1;
} else {
self.cursor.0 = 0;
if self.cursor.1 > 0 {
self.cursor.1 -= 1;
self.cursor.0 = self.buffer[self.cursor.1].len() - 1;
}
}
}
if !was_special_char {
self.buffer[self.cursor.1][self.cursor.0] = c;
self.cursor.0 += 1;
if self.cursor.0 >= self.buffer[self.cursor.1].len() {
self.cursor.0 = 0;
self.cursor.1 += 1;
if self.cursor.1 >= self.buffer.len() {
self.cursor.1 = self.buffer.len() - 1;
self.scroll_terminal();
}
}
}
}
self.render(tc);
}
pub fn render(&mut self, tc: &mut TrafficControl) {
if self.need_screen_clear {
fb_clearscreen(tc);
self.need_screen_clear = false;
}
for (y, line) in self.buffer.iter().enumerate() {
fb_write_char_array(tc, 0, y * 16, line);
}
}
}