.
This commit is contained in:
FantasyPvP
2023-04-29 02:11:02 +01:00
parent ad8d971b8a
commit 45304c26d8
3 changed files with 249 additions and 216 deletions
+151 -153
View File
@@ -1,18 +1,17 @@
use volatile::Volatile;
use lazy_static::lazy_static;
use core::fmt; use core::fmt;
use lazy_static::lazy_static;
use spin::Mutex; use spin::Mutex;
use volatile::Volatile;
use alloc::vec::Vec;
use alloc::vec;
use alloc::borrow::ToOwned; use alloc::borrow::ToOwned;
use alloc::vec;
use alloc::vec::Vec;
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)] #[repr(u8)]
pub enum Color { pub enum Color {
Black = 0, Black = 0,
Blue = 1, Blue = 1,
Green = 2, Green = 2,
Cyan = 3, Cyan = 3,
@@ -35,16 +34,16 @@ pub enum Color {
pub struct ColorCode(u8); pub struct ColorCode(u8);
impl ColorCode { impl ColorCode {
pub fn new(foreground: Color, background: Color) -> ColorCode { pub fn new(foreground: Color, background: Color) -> ColorCode {
ColorCode((background as u8) << 5 | (foreground as u8)) ColorCode((background as u8) << 5 | (foreground as u8))
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)] #[repr(C)]
struct ScreenChar { struct ScreenChar {
character: u8, character: u8,
colour: ColorCode, colour: ColorCode,
} }
pub const BUFFER_HEIGHT: usize = 25; pub const BUFFER_HEIGHT: usize = 25;
@@ -52,34 +51,31 @@ pub const BUFFER_WIDTH: usize = 80;
#[repr(transparent)] #[repr(transparent)]
struct Buffer { struct Buffer {
chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT], chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
} }
struct BufferSwap { struct BufferSwap {
chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT], chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
} }
struct CharGrid { struct CharGrid {
chars: Vec<[ScreenChar; BUFFER_WIDTH]> chars: Vec<[ScreenChar; BUFFER_WIDTH]>,
} }
pub struct Renderer { pub struct Renderer {
col_pos: usize, col_pos: usize,
pub col_code: ColorCode, pub col_code: ColorCode,
buffer: &'static mut Buffer, buffer: &'static mut Buffer,
userspace: BufferSwap, userspace: BufferSwap,
upwards: CharGrid, upwards: CharGrid,
downwards: CharGrid, downwards: CharGrid,
pub sandbox: bool, pub sandbox: bool,
} }
lazy_static! { lazy_static! {
pub static ref RENDERER: Mutex<Renderer> = Mutex::new(Renderer { pub static ref RENDERER: Mutex<Renderer> = Mutex::new(Renderer {
col_pos: 0, col_pos: 0,
col_code: ColorCode::new(Color::White, Color::Black), col_code: ColorCode::new(Color::White, Color::Black),
buffer: unsafe { buffer: unsafe { &mut *(0xb8000 as *mut Buffer) },
&mut *(0xb8000 as *mut Buffer)
},
userspace: BufferSwap { userspace: BufferSwap {
chars: [[ScreenChar { chars: [[ScreenChar {
character: 179u8, character: 179u8,
@@ -103,31 +99,30 @@ lazy_static! {
] ]
}, },
sandbox: false, sandbox: false,
}); });
} }
impl Renderer { impl Renderer {
pub fn text_mode(&mut self) -> Result<(), ()> { pub fn text_mode(&mut self) -> Result<(), ()> {
if !self.sandbox { return Err(()) }; if !self.sandbox {
return Err(());
};
self.buffer_swap().unwrap(); self.buffer_swap().unwrap();
self.sandbox = false; self.sandbox = false;
Ok(()) Ok(())
} }
pub fn sandbox_mode(&mut self) -> Result<(), ()> { pub fn sandbox_mode(&mut self) -> Result<(), ()> {
if self.sandbox { return Err(()) }; if self.sandbox {
return Err(());
};
self.buffer_swap().unwrap(); self.buffer_swap().unwrap();
self.sandbox = true; self.sandbox = true;
Ok(()) Ok(())
} }
fn buffer_swap(&mut self) -> Result<(), ()> { fn buffer_swap(&mut self) -> Result<(), ()> {
for (i, _) in self.userspace.chars.clone().iter().enumerate() { for (i, _) in self.userspace.chars.clone().iter().enumerate() {
let tmp = self.buffer.chars[i].clone(); let tmp = self.buffer.chars[i].clone();
for (j, col) in self.userspace.chars[i].clone().iter().enumerate() { for (j, col) in self.userspace.chars[i].clone().iter().enumerate() {
@@ -142,121 +137,126 @@ impl Renderer {
Ok(()) Ok(())
} }
pub fn render_frame(&mut self, frame: [ [ char; BUFFER_WIDTH ]; BUFFER_HEIGHT]) { pub fn render_frame(&mut self, frame: [[char; BUFFER_WIDTH]; BUFFER_HEIGHT]) {
for (i, row) in frame.iter().enumerate() { for (i, row) in frame.iter().enumerate() {
for (j, col) in row.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) { pub fn write_string(&mut self, string: &str) {
self.buffer.chars[i][j].write(ScreenChar { character: c, colour: self.col_code}); for ch in string.chars() {
} else { if let Some(x) = self.fancy_char(ch) {
self.buffer.chars[i][j].write(ScreenChar { character: *col as u8, colour: self.col_code}); 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<u8> {
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) { pub fn backspace(&mut self) -> Result<(), ()> {
for ch in string.chars() { 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) { let blank = ScreenChar {
self.write_byte(x) character: b' ',
} else { colour: self.col_code,
match ch as u8 { };
0x20..=0xff | b'\n' => self.write_byte(ch as u8), self.buffer.chars[row][col].write(blank);
_ => self.write_byte(0xfe), Ok(())
} }
}
}
}
fn fancy_char(&self, ch: char) -> Option<u8> { pub fn write_byte(&mut self, byte: u8) {
let res: u8 = match ch { match byte {
'│' => 179, b'\n' => self.newline(),
'─' => 196, byte => {
'┴' => 193, if self.col_pos >= BUFFER_WIDTH {
'┤' => 180, self.newline();
'═' => 205, }
'║' => 186, let row = BUFFER_HEIGHT - 1;
'╗' => 187, let col = self.col_pos;
'╝' => 188, let col_code = self.col_code;
'╚' => 200, self.buffer.chars[row][col].write(ScreenChar {
'╔' => 201, character: byte,
'»' => 175, colour: col_code,
'┐' => 191, });
'└' => 192, self.col_pos += 1
'┘' => 217, }
'┌' => 218, }
'┼' => 197, }
'░' => 176, fn newline(&mut self) {
'▓' => 178, for row in 1..BUFFER_HEIGHT {
_ => { return None; } for col in 0..BUFFER_WIDTH {
}; let character = self.buffer.chars[row][col].read();
Some(res) self.buffer.chars[row - 1][col].write(character);
} }
}
self.clear_row(BUFFER_HEIGHT - 1);
self.col_pos = 0;
}
pub fn backspace(&mut self) -> Result<(), ()> { pub fn undonewline(&mut self) {
if self.col_pos == 0 { for row in (0..BUFFER_HEIGHT - 1).rev() {
self.undonewline(); for col in 0..BUFFER_WIDTH {
} let character = self.buffer.chars[row][col].read();
self.col_pos -= 1; self.buffer.chars[row + 1][col].write(character);
let row = BUFFER_HEIGHT -1; }
let col = self.col_pos; }
self.clear_row(0);
let blank = ScreenChar { self.col_pos = BUFFER_WIDTH;
character: b' ', }
colour: self.col_code, pub fn clear(&mut self) {
}; for row in (0..BUFFER_HEIGHT - 1).rev() {
self.buffer.chars[row][col].write(blank); self.clear_row(row);
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) { fn clear_row(&mut self, row: usize) {
let blank = ScreenChar { let blank = ScreenChar {
@@ -270,20 +270,18 @@ impl Renderer {
} }
impl fmt::Write for Renderer { impl fmt::Write for Renderer {
fn write_str(&mut self, string:&str) -> fmt::Result { fn write_str(&mut self, string: &str) -> fmt::Result {
self.write_string(string); self.write_string(string);
Ok(()) Ok(())
} }
} }
pub fn write(args: fmt::Arguments, cols: (Color, Color)) { pub fn write(args: fmt::Arguments, cols: (Color, Color)) {
use core::fmt::Write; use core::fmt::Write;
use x86_64::instructions::interrupts; use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| { interrupts::without_interrupts(|| {
let mut writer = RENDERER.lock(); let mut writer = RENDERER.lock();
writer.col_code = ColorCode::new(cols.0, cols.1); writer.col_code = ColorCode::new(cols.0, cols.1);
writer.write_fmt(args).unwrap() writer.write_fmt(args).unwrap()
}) })
} }
+48 -38
View File
@@ -25,19 +25,17 @@ impl Pos {
} }
} }
/// all interface elements must implement this trait in order to be /// all interface elements must implement this trait in order to be
/// rendered on the screen /// rendered on the screen
pub trait Element { pub trait Element {
// default behaviour for all elements // default behaviour for all elements
fn render(&self) -> (Vec<Vec<char>>, (usize, usize)) { fn render(&self) -> (Vec<Vec<char>>, Pos) {
// recursive method for rendering the // recursive method for rendering the
// specified frame to the screen // specified frame to the screen
// insert rendering code for specific frame here // insert rendering code for specific frame here
// this should also render all children of the element // this should also render all children of the element
(Vec::<Vec<char>>::new(), (0, 0)) (Vec::<Vec<char>>::new(), Pos::new(0, 0))
} }
} }
@@ -46,16 +44,16 @@ pub struct Container {
// other containers together // other containers together
frame: Vec<Vec<char>>, frame: Vec<Vec<char>>,
elements: Vec<Box<dyn Element>>, elements: Vec<Box<dyn Element>>,
position: (usize, usize), // x,y position: Pos, // x,y
// //
outlined: bool, outlined: bool,
dimensions: (usize, usize), // x,y dimensions: Pos, // x,y
} }
impl Container { impl Container {
fn new(position: (usize, usize), dimensions: (usize, usize), outlined: bool) -> Container { fn new(position: Pos, dimensions: Pos, outlined: bool) -> Container {
Self { 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(), elements: Vec::new(),
position, position,
outlined, outlined,
@@ -68,7 +66,7 @@ impl Container {
} }
impl Element for Container { impl Element for Container {
fn render(&self) -> (Vec<Vec<char>>, (usize, usize)) { fn render(&self) -> (Vec<Vec<char>>, Pos) {
// returns all elements as a single frame // returns all elements as a single frame
let mut charmap = Vec::<Vec<char>>::new(); let mut charmap = Vec::<Vec<char>>::new();
@@ -78,23 +76,7 @@ impl Element for Container {
let mut lastline: Vec<char>; let mut lastline: Vec<char>;
if self.outlined { if self.outlined {
frstline = vec!['┌']; charmap = gen_outline(self.dimensions);
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);
} }
// render child elements // render child elements
@@ -110,7 +92,7 @@ impl Element for Container {
for (j, chr) in row.iter().enumerate() { for (j, chr) in row.iter().enumerate() {
// r.0 is the rendered element // r.0 is the rendered element
// r.1.0 is the x offset // 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, length: usize,
filled: usize, filled: usize,
abs: usize, abs: usize,
position: (usize, usize), position: Pos,
text: Option<String>,
} }
impl IndicatorBar { impl IndicatorBar {
fn new(position: (usize, usize), length: usize) -> IndicatorBar { fn new(position: Pos, length: usize) -> IndicatorBar {
IndicatorBar { IndicatorBar {
position, position,
length, length,
abs: 0, abs: 0,
filled: 0, filled: 0,
text: None,
} }
} }
fn set_value(&mut self, value: usize) { fn set_value(&mut self, value: usize) {
// takes a value from 1-100% // takes a value from 1-100%
// and turns it into a corresponding length filled // 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 { impl Element for IndicatorBar {
fn render(&self) -> (Vec<Vec<char>>, (usize, usize)) { fn render(&self) -> (Vec<Vec<char>>, Pos) {
let numlen = (self.abs.to_string().as_str()).len(); 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 relfilled = (self.filled as f64 / 100.0 * ((self.length - numlen) as f64)) as usize;
let mut line = Vec::<char>::new(); let mut line = Vec::<char>::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 (self.abs.to_string().chars().collect()));
line.append(&mut vec!['▓'; relfilled]); line.append(&mut vec!['▓'; relfilled]);
line.append(&mut vec!['░'; self.length - numlen - relfilled]); line.append(&mut vec!['░'; self.length - numlen - relfilled]);
@@ -172,9 +164,9 @@ pub fn render_frame(elements: Vec<Container>) {
for (i, row) in f.0.iter().enumerate() { for (i, row) in f.0.iter().enumerate() {
for (j, chr) in row.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); 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]); //print!("{}", buffer[i+frame.position.1][j+frame.position.0]);
} }
@@ -226,10 +218,12 @@ pub fn gen_outline(dimensions: Pos) -> Vec<Vec<char>> {
// testing functions // testing functions
pub fn test_elements() { pub fn test_elements() {
println!("e"); use super::libgui_elements;
let mut containers = Vec::<Container>::new(); let mut containers = Vec::<Container>::new();
/*
//for _ in 0..10 { //for _ in 0..10 {
// containers.push(generate_box()); // 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(bar));
containers[1].elements.push(Box::new(bar2)); containers[1].elements.push(Box::new(bar2));
use super::libgui_elements;
let tbox = libgui_elements::TextBox::new( let tbox = libgui_elements::TextBox::new(
String::from("title"), String::from("panic attack simps"),
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("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(25, 10),
Pos::new(10, 9), Pos::new(10, 9),
true, true,
@@ -258,6 +251,23 @@ pub fn test_elements() {
containers[1].elements.push(Box::new(tbox)); 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); render_frame(containers);
return; return;
@@ -271,5 +281,5 @@ fn generate_box() -> Container {
let height = Random::int(5, 10); let height = Random::int(5, 10);
let xoffset = Random::int(5, 50); let xoffset = Random::int(5, 50);
let yoffset = Random::int(5, 10); let yoffset = Random::int(5, 10);
Container::new((width, height), (xoffset, yoffset), true) Container::new(Pos::new(width, height), Pos::new(xoffset, yoffset), true)
} }
+47 -22
View File
@@ -1,12 +1,13 @@
use super::libgui_core::{self, Pos}; use super::libgui_core::{self, Pos};
use crate::std::io::println;
use alloc::{ use alloc::{
string::{String, ToString}, string::{String, ToString},
vec::Vec, vec::Vec,
}; };
use crate::std::io::println;
// TEXT BOX // TEXT BOX
// a widget to display text in a box
// has a title and a body
pub struct TextBox { pub struct TextBox {
dimensions: Pos, dimensions: Pos,
position: Pos, position: Pos,
@@ -15,58 +16,61 @@ pub struct TextBox {
outlined: bool, outlined: bool,
} }
// implements all rendering for TextBox widget
impl libgui_core::Element for TextBox { impl libgui_core::Element for TextBox {
fn render(&self) -> (Vec<Vec<char>>, (usize, usize)) { fn render(&self) -> (Vec<Vec<char>>, Pos) {
let mut charmap = Vec::<Vec<char>>::new(); let mut charmap = Vec::<Vec<char>>::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 { if self.outlined {
charmap = libgui_core::gen_outline(self.dimensions); charmap = libgui_core::gen_outline(self.dimensions);
} }
let mut titlechars = self.title.chars().collect::<Vec<char>>();
// render title // render title
let mut titlechars = self.title.chars().collect::<Vec<char>>();
for (i, char) in titlechars.iter().enumerate() { for (i, char) in titlechars.iter().enumerate() {
if i < inner_dims.x { if i < inner_dims.x {
charmap[0][i + 1] = *char; charmap[0][i + 1] = *char;
} else { } else {
charmap[0][inner_dims.x - 0] = '.';
charmap[0][inner_dims.x - 1] = '.';
charmap[0][inner_dims.x - 2] = '.';
break; break;
} }
} }
let mut idx = 0;
// render text // render text
let mut pos = Pos::new(0, 0);
let mut pos = Pos::new(0,0);
for chr in self.content.chars().collect::<Vec<char>>() { for chr in self.content.chars().collect::<Vec<char>>() {
if pos.x < inner_dims.x { if pos.x < inner_dims.x {
charmap[pos.y + 1][pos.x + 1] = chr; if chr != '\n' {
pos.x += 1; charmap[pos.y + 1][pos.x + 1] = chr;
pos.x += 1;
} else {
pos.y += 1;
pos.x = 0;
}
} else { } else {
// next line
pos.y += 1; pos.y += 1;
pos.x = 1; pos.x = 1;
if pos.y < inner_dims.y { if pos.y < inner_dims.y {
charmap[pos.y + 1][1] = chr; charmap[pos.y + 1][1] = chr;
} else { } else {
charmap[inner_dims.y][inner_dims.x] = '.'; // handles overflow out of the end of the box
charmap[inner_dims.y][inner_dims.x -1] = '.'; charmap[inner_dims.y][inner_dims.x] = '»';
charmap[inner_dims.y][inner_dims.x -2] = '.'; 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; break;
} }
} }
} }
return (charmap, self.position);
return (charmap, (self.position.x, self.position.y));
} }
} }
@@ -87,3 +91,24 @@ impl TextBox {
} }
} }
} }
struct IndicatorBox {
pub bars: Vec<libgui_core::IndicatorBar>,
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<Vec<char>>, Pos) {
(Vec::<Vec<char>>::new(), Pos::new(0, 0))
}
}