- got text boxes fully working

- this includes text wrapping not cutting words in half (can be disabled using a method on the text box)
- refactored frame.rs, cg_core.rs and cg_widgets.rs to avoid code reuse and duplication
- created a simplified unified interface for rendering frames to the screen using the Frame struct provided by frame.rs instead of Element, FrameGen, etc.
- moved all widgets from cg_core.rs to cg_widgets.rs
- the label widget now works
- also added CgIndicatorBar and CgIndicatorWidget widgets to eventually make a working status bar
- refactored all applications in the system to use the new api to render to the screen
This commit is contained in:
FantasyPvP
2023-11-23 00:29:04 +00:00
parent 0ac21cd0b1
commit 461c9d9c6a
11 changed files with 488 additions and 501 deletions
+15 -13
View File
@@ -6,6 +6,7 @@ use volatile::Volatile;
use alloc::borrow::ToOwned;
use alloc::vec;
use alloc::vec::Vec;
use crate::kernel::render::RenderError::InvalidRenderMode;
use crate::serial_println;
use crate::std::io::Screen;
@@ -48,6 +49,14 @@ pub struct ScreenChar {
pub colour: ColorCode,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RenderError {
OutOfBounds(bool, bool), // (bool, bool) refers to x and y respectively
InvalidCharacter,
InvalidColour,
InvalidRenderMode,
}
impl ScreenChar {
pub fn null() -> ScreenChar {
ScreenChar {
@@ -108,7 +117,6 @@ impl Renderer {
pub fn render_frame(&mut self, frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT]) { // renders the given frame to the app buffer
let mut processed_frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
for (i, row) in frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
processed_frame[i][j] = match special_char(col.character as char) {
@@ -128,9 +136,9 @@ impl Renderer {
self.internal_render();
}
pub fn application_mode(&mut self) -> Result<(), ()> {
pub fn application_mode(&mut self) -> Result<(), RenderError> {
if self.application_mode {
return Err(());
return Err(InvalidRenderMode);
} else {
self.application_mode = true;
self.internal_render();
@@ -138,9 +146,9 @@ impl Renderer {
}
}
pub fn terminal_mode(&mut self) -> Result<(), ()> {
pub fn terminal_mode(&mut self) -> Result<(), RenderError> {
if !self.application_mode {
return Err(());
return Err(InvalidRenderMode);
} else {
self.application_mode = false;
self.internal_render();
@@ -172,7 +180,7 @@ impl Renderer {
self.internal_render();
}
pub fn backspace(&mut self) -> Result<(), ()> {
pub fn backspace(&mut self) -> Result<(), RenderError> {
if self.application_mode { return Ok(()); };
loop {
@@ -218,7 +226,7 @@ impl Renderer {
}
}
fn internal_backspace(&mut self) -> Result<bool, ()> {
fn internal_backspace(&mut self) -> Result<bool, RenderError> {
let mut should_break = false;
if self.col_pos == 0 {
@@ -327,12 +335,6 @@ pub fn special_char(ch: char) -> Option<u8> {
}
impl fmt::Write for Renderer {
fn write_str(&mut self, string: &str) -> fmt::Result {
self.write_string(string, None);
+190 -121
View File
@@ -1,9 +1,11 @@
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
use lazy_static::lazy_static;
use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER, ScreenChar};
use crate::println;
use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, ColorCode, RENDERER, ScreenChar};
use crate::{println, serial_println};
use spin::Mutex;
use crate::std::io::{Color, Screen};
/// TODO: get a working implementation for CLI apps
/// elements can be created using their from_str() method
@@ -13,145 +15,212 @@ use spin::Mutex;
/// nothing will appear on the screen until the frame is actually rendered by
/// the render_frame method on the renderer
pub use crate::system::kernel::render::special_char;
pub use crate::system::kernel::render::{special_char, RenderError};
pub type Frame = [ [ ScreenChar; BUFFER_WIDTH ]; BUFFER_HEIGHT];
#[derive(Clone)]
pub struct Element {
frame: Vec<Vec<char>>,
dimensions: (u8, u8)
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ColouredChar {
pub character: char,
pub colour: ColorCode,
}
impl Element {
impl ColouredChar {
pub fn coloured(character: char, colour: ColorCode) -> ColouredChar {
ColouredChar { character, colour }
}
pub fn new(character: char) -> ColouredChar {
ColouredChar {
character,
colour: ColorCode::new(Color::White, Color::Black),
}
}
pub fn null() -> ColouredChar {
ColouredChar {
character: ' ',
colour: ColorCode::new(Color::White, Color::Black),
}
}
pub fn as_screen_char(&self) -> ScreenChar {
ScreenChar {
character: {
if let Some(c) = special_char(self.character) {
c
} else {
self.character as u8
}
},
colour: self.colour,
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct Position {
pub x: usize,
pub y: usize,
}
impl Position {
pub fn new(x: usize, y: usize) -> Position {
Position { x, y }
}
}
pub type Dimensions = Position;
#[derive(Clone, Debug)]
pub struct Frame {
pub position: Position,
pub dimensions: Dimensions,
pub frame: Vec<Vec<ColouredChar>>,
}
impl Frame {
pub fn new(position: Position, dimensions: Dimensions) -> Result<Frame, RenderError> {
Ok(Frame {
position,
dimensions,
frame: vec![vec![ColouredChar::null(); dimensions.x]; dimensions.y],
})
}
pub fn from_str(elemstr: String) -> Self {
let mut element = Element { frame: Vec::<Vec<char>>::new(), dimensions: (0, 0) };
let mut element = Frame { frame: Vec::<Vec<ColouredChar>>::new(), dimensions: Dimensions::new(0, 0), position: Position::new(0, 0) };
for line in elemstr.split("\n") {
let mut ln = Vec::<char>::new();
for col in line.chars() {
ln.push(col)
};
element.frame.push(ln);
element.frame.push(
line
.chars()
.map(|c| ColouredChar::new(c))
.collect::<Vec<ColouredChar>>()
);
}
for row in element.clone().frame {
let n = row.len();
if n > element.dimensions.0 as usize {
element.dimensions.0 = n as u8;
if n > element.dimensions.x as usize {
element.dimensions.x = n;
}
}
element
}
pub fn generate(frame: Vec::<Vec<char>>, dims: (u8, u8)) -> Self {
Element { frame, dimensions: dims }
pub fn render(&self) -> Vec<Vec<ColouredChar>> {
self.frame.clone()
}
pub fn render(&mut self, pos: (u8, u8)) { // x,y
for (i, row) in self.frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
//println!("{} {} {}", i, j, col);
FRAMEGEN.lock().frame[i + pos.1 as usize][j + pos.0 as usize] = ScreenChar::white(*col as u8);
};
}
FRAMEGEN.lock().render_frame();
}
}
#[derive(Clone)]
pub struct ColouredElement {
pub frame: Vec<Vec<ScreenChar>>,
pub dimensions: (u8, u8)
}
impl ColouredElement {
pub fn from_str(elemstr: String) -> Self {
let mut element = ColouredElement { frame: Vec::<Vec<ScreenChar>>::new(), dimensions: (0, 0) };
for line in elemstr.split("\n") {
let mut ln = Vec::<ScreenChar>::new();
for col in line.chars() {
ln.push(ScreenChar::white(col as u8))
};
element.frame.push(ln);
}
for row in element.clone().frame {
let n = row.len();
if n > element.dimensions.0 as usize {
element.dimensions.0 = n as u8;
}
}
element
}
pub fn generate(frame: Vec::<Vec<ScreenChar>>, dims: (u8, u8)) -> Self {
ColouredElement { frame, dimensions: dims }
}
pub fn render(&mut self, pos: (u8, u8)) -> Result<(), ()> { // x,y
// this block returns an error if any characters will be drawn out of the bounds of the screen
if self.dimensions.0 + pos.0 > BUFFER_WIDTH as u8 {
return Err(());
} else if self.dimensions.1 + pos.1 > BUFFER_HEIGHT as u8 {
return Err(());
} else if self.frame.len() != self.dimensions.1 as usize {
return Err(())
} else if self.frame.iter().map(|r| r.len()).max().ok_or_else(|| ())? > self.dimensions.0 as usize {
return Err(())
}
for (i, row) in self.frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
//println!("{} {} {}", i, j, col);
FRAMEGEN.lock().frame[i + pos.1 as usize][j + pos.0 as usize] = *col;
};
}
FRAMEGEN.lock().render_frame();
Ok(())
}
}
#[derive(Clone, Copy)]
pub struct FrameGen {
frame: Frame,
}
impl FrameGen {
pub fn render_frame(&self) {
RENDERER.lock().render_frame(self.frame)
}
fn new() -> Self {
pub fn render_to_screen(&self) -> Result<(), RenderError> {
let mut frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
Self { frame: Frame::from(frame) }
}
fn set_frame(&mut self, frame: Frame) {
self.frame = frame;
}
pub fn get_frame(&self) -> &[ [ ScreenChar; BUFFER_WIDTH ]; BUFFER_HEIGHT] {
&self.frame
}
}
lazy_static! {
pub static ref FRAMEGEN: Mutex<FrameGen> = Mutex::new(FrameGen::new() );
}
impl core::fmt::Display for FrameGen {
fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
println!(" ");
for row in &self.frame {
println!("{}", row.iter().map(|c| c.character as char ).collect::<String>());
};
for (i, row) in self.frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
//println!("{} {} {}", i, j, col);
frame[i + self.position.y as usize][j + self.position.x as usize] = col.as_screen_char();
};
}
RENDERER.lock().render_frame(frame);
Ok(())
}
pub fn position(&self) -> Position {
self.position
}
pub fn set_position(&mut self, position: Position) {
self.position = position
}
pub fn dimensions(&self) -> Dimensions {
self.dimensions
}
pub fn write_pos(&mut self, position: Position, char: ColouredChar) {
self.frame[position.y][position.x] = char
}
pub fn render_element(&mut self, other: &Frame) {
for (i, row) in other.frame.iter().enumerate() {
for (j, chr) in row.iter().enumerate() {
self.frame[i + other.position.y][j + other.position.x] = *chr
}
}
}
pub fn render_bounds_check(&self, element: &Frame, should_panic: bool) -> Result<(), RenderError> {
let (mut x, mut y) = (false, false);
if element.dimensions().x + element.position().x > self.dimensions.x {
if should_panic { panic!(
"Element is to large to be rendered {} {}",
element.dimensions().x + element.position().x,
self.dimensions.x
)} else {
x = true;
}
}
if element.dimensions().y + element.position().y > self.dimensions.y {
if should_panic { panic!(
"Element is to large to be rendered {} {}",
element.dimensions().y + element.position().y,
self.dimensions.y
)} else {
y = true;
}
}
if x || y {
Err(RenderError::OutOfBounds(x, y))
} else {
Ok(())
}
}
}
impl core::ops::Index<usize> for Frame {
type Output = Vec<ColouredChar>;
fn index(&self, index: usize) -> &Self::Output {
&self.frame[index]
}
}
impl core::ops::IndexMut<usize> for Frame {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.frame[index]
}
}