diff --git a/Cargo.lock b/Cargo.lock index fb76618..8ce034f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,7 @@ dependencies = [ "conquer-once", "crossbeam-queue", "futures-util", + "hashbrown", "lazy_static", "linked_list_allocator", "pc-keyboard", @@ -24,6 +25,17 @@ dependencies = [ "x86_64", ] +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", + "version_check", +] + [[package]] name = "ansi_rgb" version = "0.2.0" @@ -80,6 +92,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "conquer-once" version = "0.3.2" @@ -101,7 +119,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "crossbeam-utils", "maybe-uninit", ] @@ -113,7 +131,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 0.1.10", ] [[package]] @@ -140,6 +158,15 @@ dependencies = [ "pin-utils", ] +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -174,6 +201,12 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + [[package]] name = "pc-keyboard" version = "0.5.1" @@ -298,6 +331,12 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "volatile" version = "0.2.7" diff --git a/Cargo.toml b/Cargo.toml index e1243b2..4277f3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ async-trait = "0.1.62" ansi_rgb = "0.2.0" rgb = "0.8" rand = { version = "0.8.5", default-features = false, features = ["small_rng"]} +hashbrown = "0.13.2" [dependencies.lazy_static] version = "1.0" diff --git a/src/lib.rs b/src/lib.rs index f1e1303..81b2d56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ #![feature(global_asm)] use core::panic::PanicInfo; -use spin::Mutex; + pub mod system; pub mod user; diff --git a/src/main.rs b/src/main.rs index be9d0b0..e0c80db 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,6 @@ use CrystalOS::{println, print, println_log, print_log}; use CrystalOS::kernel::tasks::{Task, executor::Executor}; use bootloader::{BootInfo, entry_point}; extern crate alloc; -use alloc::{boxed::Box, vec, vec::Vec, rc::Rc, string, string::String}; use CrystalOS::user::bin::shell; #[cfg(not(test))] @@ -32,7 +31,7 @@ fn main(boot_info: &'static BootInfo) -> ! { use CrystalOS::kernel::allocator; use CrystalOS::kernel::memory; use CrystalOS::kernel::memory::BootInfoFrameAllocator; - use x86_64::{structures::paging::{Page, Translate}, VirtAddr}; + use x86_64::VirtAddr; CrystalOS::init(); diff --git a/src/system/kernel/interrupts.rs b/src/system/kernel/interrupts.rs index 9d5de70..cacbc1e 100644 --- a/src/system/kernel/interrupts.rs +++ b/src/system/kernel/interrupts.rs @@ -19,7 +19,7 @@ extern "x86-interrupt" fn double_fault_handler(stack_frame: InterruptStackFrame, panic!("EXCEPTION: double fault\n{:#?}", stack_frame) } -extern "x86-interrupt" fn timer_interrupt_handler(stack_frame: InterruptStackFrame) { +extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) { unsafe { GLOBALTIMER.lock().inc(); PICS.lock().notify_end_of_interrupt(InterruptIndex::Timer.as_u8()); diff --git a/src/system/kernel/render.rs b/src/system/kernel/render.rs index ddf2886..e9b56d0 100644 --- a/src/system/kernel/render.rs +++ b/src/system/kernel/render.rs @@ -186,7 +186,10 @@ impl Renderer { '┐' => 191, '└' => 192, '┘' => 217, - '┌' => 218, + '┌' => 218, + '┼' => 197, + '░' => 176, + '▓' => 178, _ => { return None; } }; Some(res) diff --git a/src/system/std/io.rs b/src/system/std/io.rs index 7cc2532..1e59adb 100644 --- a/src/system/std/io.rs +++ b/src/system/std/io.rs @@ -52,11 +52,14 @@ pub struct Element { frame: Vec>, dimensions: (u8, u8) } + /// elements can be created using their from_str() method /// you can then render the element to the current frame using the render() method /// the position of the element by passing a tuple (x,y) to render() /// -/// nothing will appear on the screen until the frame is actually +/// nothing will appear on the screen until the frame is actually rendered by +/// the render_frame method on the renderer + impl Element { pub fn from_str(elemstr: String) -> Self { let mut element = Element { frame: Vec::>::new(), dimensions: (0, 0) }; diff --git a/src/system/std/random.rs b/src/system/std/random.rs index 199a57c..d292e71 100644 --- a/src/system/std/random.rs +++ b/src/system/std/random.rs @@ -1,5 +1,5 @@ -use alloc::{boxed::Box, string::{String, ToString}, vec::Vec}; +use alloc::{string::{String, ToString}, vec::Vec}; use rand::{Rng, SeedableRng, rngs::SmallRng, RngCore}; use spin::Mutex; use lazy_static::lazy_static; diff --git a/src/user/bin/crystal_rpg/init.rs b/src/user/bin/crystal_rpg/init.rs index d390d4a..fa7ee05 100644 --- a/src/user/bin/crystal_rpg/init.rs +++ b/src/user/bin/crystal_rpg/init.rs @@ -109,7 +109,7 @@ impl Application for GameLoop { } fn random() -> u64 { - let mut r = random::Random::int(0, 125) as u64; + let r = random::Random::int(0, 125) as u64; r } diff --git a/src/user/bin/mod.rs b/src/user/bin/mod.rs index d643a6c..a99546d 100644 --- a/src/user/bin/mod.rs +++ b/src/user/bin/mod.rs @@ -3,5 +3,5 @@ pub mod crystal_rpg; pub mod crystalfetch; pub mod rickroll; pub mod shell; -pub mod shellrewrite; +//pub mod shellrewrite; pub mod tasks; diff --git a/src/user/bin/shell.rs b/src/user/bin/shell.rs index 9e1f8a4..d3258df 100644 --- a/src/user/bin/shell.rs +++ b/src/user/bin/shell.rs @@ -131,7 +131,10 @@ async fn exec() -> Result<(), Error> { use crate::std::io; io::mkfs(); } - + "test_features" => { + use crate::user::lib::libgui; + libgui::libgui_core::test_elements(); + } _ => { return Err(Error::UnknownCommand( "command not yet implemented".to_string(), diff --git a/src/user/bin/tasks.rs b/src/user/bin/tasks.rs index 4d9888a..db3c6df 100644 --- a/src/user/bin/tasks.rs +++ b/src/user/bin/tasks.rs @@ -131,14 +131,14 @@ impl TaskList { } pub fn add(&mut self, content: String) -> Result<(), Error> { let task = Task::new(self.next(), content); - let id = task.taskid.clone(); + let _id = task.taskid.clone(); self.tasks.push(task); Ok(()) } - pub fn remove(&mut self, id: usize) -> Result<(), Error> { + pub fn remove(&mut self, _id: usize) -> Result<(), Error> { for (i, task) in self.tasks.clone().iter().enumerate() { match task.taskid { - id => { self.tasks.remove(i); }, + _id => { self.tasks.remove(i); }, _ => { return Err(Error::CommandFailed(String::from("this task does not exist"))); }, } }; diff --git a/src/user/lib/libgui/libgui_core.rs b/src/user/lib/libgui/libgui_core.rs new file mode 100644 index 0000000..788142a --- /dev/null +++ b/src/user/lib/libgui/libgui_core.rs @@ -0,0 +1,274 @@ +use crate::std::io::Frame; +use alloc::{vec::Vec, vec, boxed::Box, string::ToString}; +use crate::kernel::render::{BUFFER_WIDTH, BUFFER_HEIGHT, RENDERER}; +use crate::{println, print}; +/* + +- this library will provide useful structures for creating simple + command line based interfaces using ascii + +*/ + + + +/// all interface elements must implement this trait in order to be +/// rendered on the screen +trait Element { // default behaviour for all elements + + fn render(&self) -> (Vec>, (usize, usize)) { // 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)) + } + +} + + + +pub struct Container { // a simple container objects for grouping + // other containers together + frame: Vec>, + elements: Vec>, + position: (usize, usize), // x,y + // + outlined: bool, + dimensions: (usize, usize), // x,y +} + +impl Container { + + fn new(position: (usize, usize), dimensions: (usize, usize), outlined: bool) -> Container { + Self { + frame: vec![vec![' '; dimensions.0 as usize]; dimensions.1 as usize], + elements: Vec::new(), + position, + outlined, + dimensions, + } + } + fn place(&self, element: Vec>) { + return // unimplemented + } + +} + +impl Element for Container { + + fn render(&self) -> (Vec>, (usize, usize)) { // returns all elements as a single frame + + let mut charmap = Vec::>::new(); + + let mut frstline: Vec; + let mut midlines: Vec; + 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); + + } + + // render child elements + + for element in &self.elements { + let r = (*element).render(); + + // rendering code for child elements goes here + + + // code to render the object at the position marked by offset within the container + + + for (i, row) in r.0.iter().enumerate() { + 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 + } + } + } + + return (charmap, self.position); + + } +} + + + +pub struct IndicatorBar { + length: usize, + filled: usize, + abs: usize, + position: (usize, usize), +} + +impl IndicatorBar { + fn new(position: (usize, usize), length: usize) -> IndicatorBar { + IndicatorBar { position, length, abs: 0, filled: 0 } + } + fn set_value(&mut self, value: usize) { // takes a value from 1-100% + // and turns it into a corresponding length filled + self.filled = value + } +} + +impl Element for IndicatorBar { + fn render(&self) -> (Vec>, (usize, usize)) { + 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(); + line.append(&mut (self.abs.to_string().chars().collect())); + line.append(&mut vec!['▓'; relfilled]); + line.append(&mut vec!['░'; self.length-numlen-relfilled]); + + + let mut rendered = Vec::new(); + rendered.push(line); + + + println!("RENDERED: {:?}", rendered); + + return (rendered, (self.position)) + } +} + + + + + + + +// functions that deal with the rendering and interaction between objects being +// rendered. + +pub fn render_frame(elements: Vec) { + let mut buffer: Frame = [[' '; BUFFER_WIDTH]; BUFFER_HEIGHT]; + + for frame in elements.iter() { + + let f = frame.render(); + + 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 newchar = overlap_check(*current, *chr); + buffer[i + f.1.1][j + f.1.0] = newchar; + + //print!("{}", buffer[i+frame.position.1][j+frame.position.0]); + } + } + + } + + //println!("{:?}", buffer); + + RENDERER.lock().render_frame(buffer) +} + +pub fn overlap_check(oldchar: char, newchar: char) -> char { + match (oldchar, newchar) { + //┌│└ ┐┘─ + ('│', '─')|('┌', '┘')|('└', '┐') => '┼', + ('┌', '└') => '├', + ('┐', '┐') => '┤', + + (_, _) => newchar + } +} + +// function to return a charmap of the outline of an object + +fn gen_outline(dimensions: (usize, usize)) -> Vec> { + let mut charmap = Vec::>::new(); + + let mut frstline = vec!['┌']; + let mut midlines = vec!['│']; + let mut lastline = vec!['└']; + + frstline.append(&mut vec!['─'; dimensions.0 -2]); + midlines.append(&mut vec![' '; dimensions.0 -2]); + lastline.append(&mut vec!['─'; dimensions.0 -2]); + + frstline.append(&mut vec!['┐']); + midlines.append(&mut vec!['│']); + lastline.append(&mut vec!['┘']); + + + charmap.push(frstline); + for _ in 0..dimensions.1 -2 { + charmap.push(midlines.clone()); + } + charmap.push(lastline); + + return charmap +} + + + + + + + + + + + + +// testing functions + +pub fn test_elements() { + println!("e"); + + let mut containers = Vec::::new(); + + //for _ in 0..10 { + // containers.push(generate_box()); + //} + + containers.push(Container::new((5, 5), (15, 5), true)); + containers.push(Container::new((10, 3), (50, 15), true)); + + let mut bar = IndicatorBar::new((10, 10), 12); + let mut bar2 = IndicatorBar::new((10, 11), 12); + + + bar.set_value(43); + bar.abs = 101; + bar2.set_value(14); + bar2.abs= 15; + containers[1].elements.push(Box::new(bar)); + containers[1].elements.push(Box::new(bar2)); + + + render_frame(containers); + return +} + +// function to generate a box in a random location on the screen. + +fn generate_box() -> Container { + use crate::std::random::Random; + let width = Random::int(5, 20); + 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) +} \ No newline at end of file diff --git a/src/user/lib/libgui/libgui_elements.rs b/src/user/lib/libgui/libgui_elements.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/user/lib/libgui/mod.rs b/src/user/lib/libgui/mod.rs new file mode 100644 index 0000000..6bbad83 --- /dev/null +++ b/src/user/lib/libgui/mod.rs @@ -0,0 +1,2 @@ +pub mod libgui_core; +pub mod libgui_elements; diff --git a/src/user/lib/mod.rs b/src/user/lib/mod.rs index e69de29..da1a9da 100644 --- a/src/user/lib/mod.rs +++ b/src/user/lib/mod.rs @@ -0,0 +1 @@ +pub mod libgui;