From 45304c26d8102834657c705ab20d3602198edf76 Mon Sep 17 00:00:00 2001 From: FantasyPvP Date: Sat, 29 Apr 2023 02:11:02 +0100 Subject: [PATCH] . . --- src/system/kernel/render.rs | 310 ++++++++++++------------- src/user/lib/libgui/libgui_core.rs | 86 ++++--- src/user/lib/libgui/libgui_elements.rs | 69 ++++-- 3 files changed, 249 insertions(+), 216 deletions(-) diff --git a/src/system/kernel/render.rs b/src/system/kernel/render.rs index e9b56d0..6b928d5 100644 --- a/src/system/kernel/render.rs +++ b/src/system/kernel/render.rs @@ -1,18 +1,17 @@ - -use volatile::Volatile; -use lazy_static::lazy_static; use core::fmt; +use lazy_static::lazy_static; use spin::Mutex; +use volatile::Volatile; -use alloc::vec::Vec; -use alloc::vec; use alloc::borrow::ToOwned; +use alloc::vec; +use alloc::vec::Vec; #[allow(dead_code)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum Color { - Black = 0, + Black = 0, Blue = 1, Green = 2, Cyan = 3, @@ -35,16 +34,16 @@ pub enum Color { pub struct ColorCode(u8); impl ColorCode { - pub fn new(foreground: Color, background: Color) -> ColorCode { - ColorCode((background as u8) << 5 | (foreground as u8)) - } + pub fn new(foreground: Color, background: Color) -> ColorCode { + ColorCode((background as u8) << 5 | (foreground as u8)) + } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(C)] struct ScreenChar { - character: u8, - colour: ColorCode, + character: u8, + colour: ColorCode, } pub const BUFFER_HEIGHT: usize = 25; @@ -52,34 +51,31 @@ pub const BUFFER_WIDTH: usize = 80; #[repr(transparent)] struct Buffer { - chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], + chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], } struct BufferSwap { chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT], } struct CharGrid { - chars: Vec<[ScreenChar; BUFFER_WIDTH]> + chars: Vec<[ScreenChar; BUFFER_WIDTH]>, } pub struct Renderer { - col_pos: usize, - pub col_code: ColorCode, - buffer: &'static mut Buffer, + col_pos: usize, + pub col_code: ColorCode, + buffer: &'static mut Buffer, userspace: BufferSwap, upwards: CharGrid, downwards: CharGrid, pub sandbox: bool, } - lazy_static! { - pub static ref RENDERER: Mutex = Mutex::new(Renderer { - col_pos: 0, - col_code: ColorCode::new(Color::White, Color::Black), - buffer: unsafe { - &mut *(0xb8000 as *mut Buffer) - }, + pub static ref RENDERER: Mutex = Mutex::new(Renderer { + col_pos: 0, + col_code: ColorCode::new(Color::White, Color::Black), + buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }, userspace: BufferSwap { chars: [[ScreenChar { character: 179u8, @@ -93,7 +89,7 @@ lazy_static! { colour: ColorCode::new(Color::White, Color::Black), }; 80] ] - }, + }, downwards: CharGrid { chars: vec![ [ScreenChar { @@ -103,31 +99,30 @@ lazy_static! { ] }, sandbox: false, - }); + }); } - - impl Renderer { - - pub fn text_mode(&mut self) -> Result<(), ()> { - if !self.sandbox { return Err(()) }; + pub fn text_mode(&mut self) -> Result<(), ()> { + if !self.sandbox { + return Err(()); + }; self.buffer_swap().unwrap(); self.sandbox = false; Ok(()) } - pub fn sandbox_mode(&mut self) -> Result<(), ()> { - if self.sandbox { return Err(()) }; + pub fn sandbox_mode(&mut self) -> Result<(), ()> { + if self.sandbox { + return Err(()); + }; self.buffer_swap().unwrap(); self.sandbox = true; Ok(()) } fn buffer_swap(&mut self) -> Result<(), ()> { - for (i, _) in self.userspace.chars.clone().iter().enumerate() { - let tmp = self.buffer.chars[i].clone(); for (j, col) in self.userspace.chars[i].clone().iter().enumerate() { @@ -142,122 +137,127 @@ impl Renderer { Ok(()) } - pub fn render_frame(&mut self, frame: [ [ char; BUFFER_WIDTH ]; BUFFER_HEIGHT]) { - for (i, row) in frame.iter().enumerate() { - for (j, col) in row.iter().enumerate() { + pub fn render_frame(&mut self, frame: [[char; BUFFER_WIDTH]; BUFFER_HEIGHT]) { + for (i, row) in frame.iter().enumerate() { + for (j, col) in row.iter().enumerate() { + if let Some(c) = self.fancy_char(*col) { + self.buffer.chars[i][j].write(ScreenChar { + character: c, + colour: self.col_code, + }); + } else { + self.buffer.chars[i][j].write(ScreenChar { + character: *col as u8, + colour: self.col_code, + }); + } + } + } + } - if let Some(c) = self.fancy_char(*col) { - self.buffer.chars[i][j].write(ScreenChar { character: c, colour: self.col_code}); - } else { - self.buffer.chars[i][j].write(ScreenChar { character: *col as u8, colour: self.col_code}); - } - } - } - } + pub fn write_string(&mut self, string: &str) { + for ch in string.chars() { + if let Some(x) = self.fancy_char(ch) { + self.write_byte(x) + } else { + match ch as u8 { + 0x20..=0xff | b'\n' => self.write_byte(ch as u8), + _ => self.write_byte(0xfe), + } + } + } + } + fn fancy_char(&self, ch: char) -> Option { + let res: u8 = match ch { + '│' => 179, + '─' => 196, + '┴' => 193, + '┤' => 180, + '═' => 205, + '║' => 186, + '╗' => 187, + '╝' => 188, + '╚' => 200, + '╔' => 201, + '»' => 175, + '┐' => 191, + '└' => 192, + '┘' => 217, + '┌' => 218, + '┼' => 197, + '░' => 176, + '▓' => 178, + '«' => 174, + '»' => 175, + _ => { + return None; + } + }; + Some(res) + } - pub fn write_string(&mut self, string: &str) { - for ch in string.chars() { + pub fn backspace(&mut self) -> Result<(), ()> { + if self.col_pos == 0 { + self.undonewline(); + } + self.col_pos -= 1; + let row = BUFFER_HEIGHT - 1; + let col = self.col_pos; - if let Some(x) = self.fancy_char(ch) { - self.write_byte(x) - } else { - match ch as u8 { - 0x20..=0xff | b'\n' => self.write_byte(ch as u8), - _ => self.write_byte(0xfe), - } - } - } - } + let blank = ScreenChar { + character: b' ', + colour: self.col_code, + }; + self.buffer.chars[row][col].write(blank); + Ok(()) + } - fn fancy_char(&self, ch: char) -> Option { - let res: u8 = match ch { - '│' => 179, - '─' => 196, - '┴' => 193, - '┤' => 180, - '═' => 205, - '║' => 186, - '╗' => 187, - '╝' => 188, - '╚' => 200, - '╔' => 201, - '»' => 175, - '┐' => 191, - '└' => 192, - '┘' => 217, - '┌' => 218, - '┼' => 197, - '░' => 176, - '▓' => 178, - _ => { return None; } - }; - Some(res) - } + pub fn write_byte(&mut self, byte: u8) { + match byte { + b'\n' => self.newline(), + byte => { + if self.col_pos >= BUFFER_WIDTH { + self.newline(); + } + let row = BUFFER_HEIGHT - 1; + let col = self.col_pos; + let col_code = self.col_code; + self.buffer.chars[row][col].write(ScreenChar { + character: byte, + colour: col_code, + }); + self.col_pos += 1 + } + } + } + fn newline(&mut self) { + for row in 1..BUFFER_HEIGHT { + for col in 0..BUFFER_WIDTH { + let character = self.buffer.chars[row][col].read(); + self.buffer.chars[row - 1][col].write(character); + } + } + self.clear_row(BUFFER_HEIGHT - 1); + self.col_pos = 0; + } - pub fn backspace(&mut self) -> Result<(), ()> { - if self.col_pos == 0 { - self.undonewline(); - } - self.col_pos -= 1; - let row = BUFFER_HEIGHT -1; - let col = self.col_pos; + pub fn undonewline(&mut self) { + for row in (0..BUFFER_HEIGHT - 1).rev() { + for col in 0..BUFFER_WIDTH { + let character = self.buffer.chars[row][col].read(); + self.buffer.chars[row + 1][col].write(character); + } + } + self.clear_row(0); + self.col_pos = BUFFER_WIDTH; + } + pub fn clear(&mut self) { + for row in (0..BUFFER_HEIGHT - 1).rev() { + self.clear_row(row); + } + } - let blank = ScreenChar { - character: b' ', - colour: self.col_code, - }; - self.buffer.chars[row][col].write(blank); - Ok(()) - } - - pub fn write_byte(&mut self, byte: u8) { - match byte { - b'\n' => { - self.newline() - }, - byte => { - if self.col_pos >= BUFFER_WIDTH { - self.newline(); - } - let row = BUFFER_HEIGHT -1; - let col = self.col_pos; - let col_code = self.col_code; - self.buffer.chars[row][col].write(ScreenChar { - character: byte, - colour: col_code, - }); - self.col_pos += 1 - } - } - } - fn newline(&mut self) { - for row in 1..BUFFER_HEIGHT { - for col in 0..BUFFER_WIDTH { - let character = self.buffer.chars[row][col].read(); - self.buffer.chars[row - 1][col].write(character); - } - } - self.clear_row(BUFFER_HEIGHT -1); - self.col_pos = 0; - } - - pub fn undonewline(&mut self) { - for row in (0..BUFFER_HEIGHT-1).rev() { - for col in 0..BUFFER_WIDTH { - let character = self.buffer.chars[row][col].read(); - self.buffer.chars[row + 1][col].write(character); - } - } - self.clear_row(0); - self.col_pos = BUFFER_WIDTH; - } - pub fn clear(&mut self) { - for row in (0..BUFFER_HEIGHT-1).rev() { - self.clear_row(row); - } - } - fn clear_row(&mut self, row: usize) { let blank = ScreenChar { character: b' ', @@ -270,20 +270,18 @@ impl Renderer { } impl fmt::Write for Renderer { - fn write_str(&mut self, string:&str) -> fmt::Result { - self.write_string(string); - Ok(()) - } + fn write_str(&mut self, string: &str) -> fmt::Result { + self.write_string(string); + Ok(()) + } } pub fn write(args: fmt::Arguments, cols: (Color, Color)) { - use core::fmt::Write; - use x86_64::instructions::interrupts; - interrupts::without_interrupts(|| { - let mut writer = RENDERER.lock(); - writer.col_code = ColorCode::new(cols.0, cols.1); - writer.write_fmt(args).unwrap() - }) + use core::fmt::Write; + use x86_64::instructions::interrupts; + interrupts::without_interrupts(|| { + let mut writer = RENDERER.lock(); + writer.col_code = ColorCode::new(cols.0, cols.1); + writer.write_fmt(args).unwrap() + }) } - - diff --git a/src/user/lib/libgui/libgui_core.rs b/src/user/lib/libgui/libgui_core.rs index 89ecf17..023ecd5 100644 --- a/src/user/lib/libgui/libgui_core.rs +++ b/src/user/lib/libgui/libgui_core.rs @@ -25,19 +25,17 @@ impl Pos { } } - - /// all interface elements must implement this trait in order to be /// rendered on the screen pub trait Element { // default behaviour for all elements - fn render(&self) -> (Vec>, (usize, usize)) { + fn render(&self) -> (Vec>, Pos) { // recursive method for rendering the // specified frame to the screen // insert rendering code for specific frame here // this should also render all children of the element - (Vec::>::new(), (0, 0)) + (Vec::>::new(), Pos::new(0, 0)) } } @@ -46,16 +44,16 @@ pub struct Container { // other containers together frame: Vec>, elements: Vec>, - position: (usize, usize), // x,y + position: Pos, // x,y // outlined: bool, - dimensions: (usize, usize), // x,y + dimensions: Pos, // x,y } impl Container { - fn new(position: (usize, usize), dimensions: (usize, usize), outlined: bool) -> Container { + fn new(position: Pos, dimensions: Pos, outlined: bool) -> Container { Self { - frame: vec![vec![' '; dimensions.0 as usize]; dimensions.1 as usize], + frame: vec![vec![' '; dimensions.x as usize]; dimensions.y as usize], elements: Vec::new(), position, outlined, @@ -68,7 +66,7 @@ impl Container { } impl Element for Container { - fn render(&self) -> (Vec>, (usize, usize)) { + fn render(&self) -> (Vec>, Pos) { // returns all elements as a single frame let mut charmap = Vec::>::new(); @@ -78,23 +76,7 @@ impl Element for Container { let mut lastline: Vec; if self.outlined { - frstline = vec!['┌']; - midlines = vec!['│']; - lastline = vec!['└']; - - frstline.append(&mut vec!['─'; self.dimensions.0 - 2]); - midlines.append(&mut vec![' '; self.dimensions.0 - 2]); - lastline.append(&mut vec!['─'; self.dimensions.0 - 2]); - - frstline.append(&mut vec!['┐']); - midlines.append(&mut vec!['│']); - lastline.append(&mut vec!['┘']); - - charmap.push(frstline); - for _ in 0..self.dimensions.1 - 2 { - charmap.push(midlines.clone()); - } - charmap.push(lastline); + charmap = gen_outline(self.dimensions); } // render child elements @@ -110,7 +92,7 @@ impl Element for Container { for (j, chr) in row.iter().enumerate() { // r.0 is the rendered element // r.1.0 is the x offset - charmap[i + r.1 .1][j + r.1 .0] = *chr; // r.1.1 is the y offset + charmap[i + r.1.y][j + r.1.x] = *chr; // r.1.1 is the y offset } } } @@ -123,31 +105,41 @@ pub struct IndicatorBar { length: usize, filled: usize, abs: usize, - position: (usize, usize), + position: Pos, + text: Option, } impl IndicatorBar { - fn new(position: (usize, usize), length: usize) -> IndicatorBar { + fn new(position: Pos, length: usize) -> IndicatorBar { IndicatorBar { position, length, abs: 0, filled: 0, + text: None, } } fn set_value(&mut self, value: usize) { // takes a value from 1-100% // and turns it into a corresponding length filled - self.filled = value + self.filled = value; + } + fn set_text(&mut self, s: String) { + self.text = Some(s); } } impl Element for IndicatorBar { - fn render(&self) -> (Vec>, (usize, usize)) { + fn render(&self) -> (Vec>, Pos) { let numlen = (self.abs.to_string().as_str()).len(); let relfilled = (self.filled as f64 / 100.0 * ((self.length - numlen) as f64)) as usize; let mut line = Vec::::new(); + if let Some(t) = &self.text { + line.append(&mut t.chars().collect()); + line.push(':'); + line.push(' '); + } line.append(&mut (self.abs.to_string().chars().collect())); line.append(&mut vec!['▓'; relfilled]); line.append(&mut vec!['░'; self.length - numlen - relfilled]); @@ -172,9 +164,9 @@ pub fn render_frame(elements: Vec) { for (i, row) in f.0.iter().enumerate() { for (j, chr) in row.iter().enumerate() { - let mut current = &buffer[i + f.1 .1][j + f.1 .0]; + let mut current = &buffer[i + f.1.y][j + f.1.x]; let newchar = overlap_check(*current, *chr); - buffer[i + f.1 .1][j + f.1 .0] = newchar; + buffer[i + f.1.y][j + f.1.x] = newchar; //print!("{}", buffer[i+frame.position.1][j+frame.position.0]); } @@ -226,10 +218,12 @@ pub fn gen_outline(dimensions: Pos) -> Vec> { // testing functions pub fn test_elements() { - println!("e"); + use super::libgui_elements; let mut containers = Vec::::new(); + /* + //for _ in 0..10 { // containers.push(generate_box()); //} @@ -247,10 +241,9 @@ pub fn test_elements() { containers[1].elements.push(Box::new(bar)); containers[1].elements.push(Box::new(bar2)); - use super::libgui_elements; let tbox = libgui_elements::TextBox::new( - String::from("title"), - String::from("text boxes are working gg but how well will they work if they go over the end of the textbox, will it cause a crash, well ima have to keep testing to figure that out properly, this could take a while lmao, i hope it works"), + String::from("panic attack simps"), + String::from("i have finally obtained evidence of his simpiness against tari and crystal, however i cannot reveal this evidence for now, however, once the contract is over NO ONE CAN STOP ME MWHAHAHAHAHA"), Pos::new(25, 10), Pos::new(10, 9), true, @@ -258,6 +251,23 @@ pub fn test_elements() { containers[1].elements.push(Box::new(tbox)); + */ + + containers.push(Container::new(Pos::new(0, 1), Pos::new(80, 24), true)); + + containers[0] + .elements + .push(Box::new(libgui_elements::TextBox::new( + String::from("ANNOUNCEMENTS"), + String::from( + "CrystalRPG coming soon! XD +this is gonna be the best game ever", + ), + Pos::new(25, 10), + Pos::new(0, 0), + true, + ))); + render_frame(containers); return; @@ -271,5 +281,5 @@ fn generate_box() -> Container { let height = Random::int(5, 10); let xoffset = Random::int(5, 50); let yoffset = Random::int(5, 10); - Container::new((width, height), (xoffset, yoffset), true) + Container::new(Pos::new(width, height), Pos::new(xoffset, yoffset), true) } diff --git a/src/user/lib/libgui/libgui_elements.rs b/src/user/lib/libgui/libgui_elements.rs index 8f9f9c6..44c4e09 100644 --- a/src/user/lib/libgui/libgui_elements.rs +++ b/src/user/lib/libgui/libgui_elements.rs @@ -1,12 +1,13 @@ use super::libgui_core::{self, Pos}; +use crate::std::io::println; use alloc::{ string::{String, ToString}, vec::Vec, }; -use crate::std::io::println; // TEXT BOX - +// a widget to display text in a box +// has a title and a body pub struct TextBox { dimensions: Pos, position: Pos, @@ -15,58 +16,61 @@ pub struct TextBox { outlined: bool, } +// implements all rendering for TextBox widget impl libgui_core::Element for TextBox { - fn render(&self) -> (Vec>, (usize, usize)) { + fn render(&self) -> (Vec>, Pos) { let mut charmap = Vec::>::new(); + let mut inner_dims = Pos::new(self.dimensions.x - 2, self.dimensions.y - 2); - let mut inner_dims = Pos::new(self.dimensions.x -2, self.dimensions.y -2); - + // generate outline if required if self.outlined { charmap = libgui_core::gen_outline(self.dimensions); } - - let mut titlechars = self.title.chars().collect::>(); // render title - + let mut titlechars = self.title.chars().collect::>(); for (i, char) in titlechars.iter().enumerate() { if i < inner_dims.x { charmap[0][i + 1] = *char; } else { + charmap[0][inner_dims.x - 0] = '.'; + charmap[0][inner_dims.x - 1] = '.'; + charmap[0][inner_dims.x - 2] = '.'; break; } } - let mut idx = 0; - // render text - - let mut pos = Pos::new(0,0); + let mut pos = Pos::new(0, 0); for chr in self.content.chars().collect::>() { - if pos.x < inner_dims.x { - charmap[pos.y + 1][pos.x + 1] = chr; - pos.x += 1; + if chr != '\n' { + charmap[pos.y + 1][pos.x + 1] = chr; + pos.x += 1; + } else { + pos.y += 1; + pos.x = 0; + } } else { + // next line pos.y += 1; pos.x = 1; if pos.y < inner_dims.y { charmap[pos.y + 1][1] = chr; } else { - charmap[inner_dims.y][inner_dims.x] = '.'; - charmap[inner_dims.y][inner_dims.x -1] = '.'; - charmap[inner_dims.y][inner_dims.x -2] = '.'; + // handles overflow out of the end of the box + charmap[inner_dims.y][inner_dims.x] = '»'; + charmap[inner_dims.y + 1][inner_dims.x - 0] = '.'; + charmap[inner_dims.y + 1][inner_dims.x - 1] = '.'; + charmap[inner_dims.y + 1][inner_dims.x - 2] = '.'; break; } } } - - - - return (charmap, (self.position.x, self.position.y)); + return (charmap, self.position); } } @@ -87,3 +91,24 @@ impl TextBox { } } } + +struct IndicatorBox { + pub bars: Vec, + position: Pos, + dimensions: Pos, +} +impl IndicatorBox { + pub fn new(position: Pos, dimensions: Pos) -> IndicatorBox { + Self { + bars: Vec::new(), + position, + dimensions, + } + } + pub fn add_item(&mut self) {} +} +impl libgui_core::Element for IndicatorBox { + fn render(&self) -> (Vec>, Pos) { + (Vec::>::new(), Pos::new(0, 0)) + } +}