summaryrefslogtreecommitdiff
path: root/toolkit/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/src/lib.rs')
-rw-r--r--toolkit/src/lib.rs491
1 files changed, 165 insertions, 326 deletions
diff --git a/toolkit/src/lib.rs b/toolkit/src/lib.rs
index a282c37..e1f9c33 100644
--- a/toolkit/src/lib.rs
+++ b/toolkit/src/lib.rs
@@ -1,357 +1,196 @@
-#![no_std]
-
-extern crate alloc;
-
-use alloc::string::{String, ToString};
-use alloc::{format, vec};
-use alloc::collections::BTreeMap;
-use alloc::vec::Vec;
-use uefi::{Char16, CStr16};
-use uefi::prelude::*;
-use uefi::fs::{Path, UefiDirectoryIter};
-use uefi::proto::console::text::{Color, Key, ScanCode};
-use uefi::fs::FileSystem;
-use uefi::table::runtime::ResetType;
-use crate::error::{display_error, Error};
-
-pub mod error;
-
-pub static mut CPU_ARCHITECTURE: &str = "unknown";
-
-pub struct ToolkitWorkingPath {
- name: String
-}
-
-pub struct ToolkitVersionInfo {
- pub version: &'static str,
- pub timestamp: &'static str,
- pub compiler: &'static str,
- pub profile: &'static str
-}
-
-pub struct Toolkit {
- system_table: SystemTable<Boot>,
- pub current_directory: ToolkitWorkingPath,
- pub version: ToolkitVersionInfo,
- pub globals: BTreeMap<String, String>
+use std::time::Duration;
+use embedded_graphics_framebuffer::FrameBufferDisplay;
+use embedded_graphics::{
+ pixelcolor::{Rgb888, RgbColor},
+ prelude::*,
+};
+use framebuffer::{Framebuffer, KdMode};
+use embedded_graphics::mono_font::ascii::FONT_10X20;
+use embedded_graphics::mono_font::MonoTextStyle;
+use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle};
+use embedded_graphics::text::Text;
+use chrono::Local;
+use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers, poll, read};
+
+pub struct GraphicalApp {
+ list_enabled: bool,
+ list_items: Vec<MenuItem>,
+ list_max_length: u32,
+ list_focused_item: u32,
+ list_name: String,
+ app_name: String,
+ display: FrameBufferDisplay
}
-impl Toolkit {
- pub fn new(system_table: SystemTable<Boot>, version: ToolkitVersionInfo) -> Self {
- unsafe {
- CPU_ARCHITECTURE = "unknown";
-
- #[cfg(target_arch = "x86_64")] {
- CPU_ARCHITECTURE = "x86_64";
- }
-
- #[cfg(target_arch = "aarch64")] {
- CPU_ARCHITECTURE = "aarch64";
+impl GraphicalApp {
+ pub fn new(app_name: &str) -> GraphicalApp {
+ let display = FrameBufferDisplay::new();
+
+ GraphicalApp {
+ list_enabled: false,
+ list_items: vec![],
+ list_max_length: 0,
+ list_name: String::new(),
+ list_focused_item: 0,
+ app_name: String::from(app_name),
+ display
+ }
+ }
+
+ fn update_display(&mut self) {
+ let mut display: &mut FrameBufferDisplay = &mut self.display;
+ display.clear(RgbColor::WHITE).expect("Failed to clear the screen");
+
+ Rectangle::new(Point::new(-1, -1), Size::new(display.size().width + 2, 26))
+ .into_styled(PrimitiveStyleBuilder::new()
+ .fill_color(Rgb888::CSS_DARK_GRAY)
+ .stroke_width(1)
+ .stroke_color(Rgb888::BLACK)
+ .build())
+ .draw(display).expect("Failed to draw");
+
+ let date = Local::now();
+ let string = date.format("%h %e %H:%M").to_string();
+ let text = string.as_str();
+ Text::new(text, Point::new((display.size().width - text.len() as u32 * 10u32 - 20) as i32, 18), MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK)).draw(display)
+ .expect("Failed to draw");
+
+ Text::new(&self.app_name, Point::new(20, 18), MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK)).draw(display)
+ .expect("Failed to draw");
+
+ if self.list_enabled {
+ Text::new(&self.list_name, Point::new(50, 70), MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK)).draw(display)
+ .expect("Failed to draw");
+
+ for (i, item) in (&self.list_items).iter().enumerate() {
+ if i == self.list_focused_item as usize {
+ Rectangle::new(Point::new(40, (90 + (i * 20)) as i32), Size::new(self.list_max_length * 10 + 20, 20))
+ .into_styled(PrimitiveStyleBuilder::new()
+ .fill_color(Rgb888::CSS_NAVY)
+ .build())
+ .draw(display).expect("Failed to draw");
+
+ item.show(&mut display, i, Rgb888::WHITE);
+ } else {
+ item.show(&mut display, i, Rgb888::new(90, 90, 90));
+ }
}
}
- Self {
- system_table,
- current_directory: ToolkitWorkingPath {
- name: String::from("")
- },
- version,
- globals: BTreeMap::new()
- }
- }
-}
-
-impl Toolkit {
- fn get_fs(&self) -> FileSystem {
- let handle = self.system_table.boot_services().image_handle();
- let fs = self.system_table.boot_services().get_image_file_system(handle).expect("Failed to start up filesystem");
- FileSystem::new(fs)
- }
-
- pub fn color(&mut self, fg: Color, bg: Color) {
- self.system_table.stdout().set_color(fg, bg).expect("Failed to set screen color");
+ display.flush().unwrap();
}
- pub fn prompt(&mut self) -> String {
- let mut out: String = String::from("");
- let mut chars: u32 = 0;
-
- loop {
- let mut events = [self.system_table.stdin().wait_for_key_event().unwrap()];
- self.system_table.boot_services()
- .wait_for_event(&mut events)
- .discard_errdata().expect("Failed to discard errors");
+ pub fn initialize_graphics<F: FnOnce(&mut GraphicalApp)>(&mut self, after_init: F) {
+ Framebuffer::set_kd_mode(KdMode::Graphics).unwrap();
+ crossterm::terminal::enable_raw_mode().expect("Failed to configure keyboard");
- let ret = Char16::try_from('\r').unwrap();
- let bks = Char16::try_from('\x08').unwrap();
- let ctc = Char16::try_from('\u{3}').unwrap();
- let ctl = Char16::try_from('\u{c}').unwrap();
- match self.system_table.stdin().read_key().expect("Failed to read key") {
- Some(Key::Printable(key)) if key == ret => {
- self.print("\r\n");
- return out;
- }
+ let mut first_updated = false;
+ let date = Local::now();
+ let mut time = date.format("%h %e %H:%M").to_string();
- Some(Key::Printable(key)) if key == bks => {
- if chars > 0 {
- chars -= 1;
- out = String::from(&out[..out.len() - 1]);
- self.print("\x08");
- }
- }
+ after_init(self);
- Some(Key::Printable(key)) if key == ctc => {
- self.print("\r\n");
- return String::from("");
- }
+ 'main_loop: loop {
+ let mut update = false || !first_updated;
- Some(Key::Printable(key)) if key == ctl => {
- self.print("\r\n");
- self.clear();
- return String::from("");
- }
+ let date = Local::now();
+ let new_time = date.format("%h %e %H:%M").to_string();
- Some(Key::Printable(key)) => {
- chars += 1;
- out += &key.to_string();
- self.print(&key.to_string());
- }
+ if time != new_time {
+ update = true;
+ let date = Local::now();
+ time = date.format("%h %e %H:%M").to_string();
+ }
- Some(Key::Special(ScanCode::ESCAPE)) => {
- panic!("Pressed Escape")
+ if poll(Duration::from_millis(100)).unwrap() {
+ match read().unwrap() {
+ Event::Key(event) => {
+ match event {
+ KeyEvent {
+ code: KeyCode::Char('c'),
+ modifiers: KeyModifiers::CONTROL,
+ ..
+ } => {
+ Framebuffer::set_kd_mode(KdMode::Text).unwrap();
+ crossterm::terminal::disable_raw_mode().expect("Failed to unconfigure keyboard");
+ break 'main_loop;
+ },
+ KeyEvent {
+ code: KeyCode::Up,
+ ..
+ } => {
+ if self.list_enabled {
+ if self.list_focused_item > 0 {
+ self.list_focused_item -= 1
+ } else {
+ self.list_focused_item = (self.list_items.len() - 1) as u32;
+ }
+ }
+
+ update = true;
+ },
+ KeyEvent {
+ code: KeyCode::Down,
+ ..
+ } => {
+ if self.list_enabled {
+ if self.list_focused_item + 1 < self.list_items.len() as u32 {
+ self.list_focused_item += 1
+ } else {
+ self.list_focused_item = 0;
+ }
+ }
+
+ update = true;
+ },
+ _ => {
+ update = true;
+ }
+ }
+ },
+ _ => {
+ update = true;
+ }
}
-
- _ => {}
}
- }
- }
-
- pub fn clear(&mut self) {
- let stdout = self.system_table.stdout();
- stdout.reset(false).expect("Failed to clear screen buffer");
- }
-
- pub fn get_cwd(&self) -> &str {
- &self.current_directory.name
- }
-
- pub fn chdir(&mut self, dir: &str) {
- if dir == "." {
- return;
- }
-
- if !self.file_exists(dir) {
- panic!("Attempted to change the working directory to a non-existent directory");
- }
-
- self.current_directory.name = format!("/{}", dir).replace('\\', "/");
- }
-
- pub fn uefi_version(&mut self) -> String {
- self.system_table.uefi_revision().to_string()
- }
-
- pub fn uefi_vendor(&mut self) -> String {
- self.system_table.firmware_vendor().to_string()
- }
-
- pub fn uefi_revision(&mut self) -> u32 {
- self.system_table.firmware_revision()
- }
-
- pub fn uefi_arch(&mut self) -> String {
- unsafe {
- CPU_ARCHITECTURE.to_string()
- }
- }
-
- pub fn set_cursor(&mut self, state: bool) {
- let stdout = self.system_table.stdout();
- stdout.enable_cursor(state).expect("Failed to change cursor state");
- }
-
- pub fn poweroff(&mut self, reboot: bool) {
- self.system_table.runtime_services().reset(if reboot {
- ResetType::COLD
- } else {
- ResetType::SHUTDOWN
- }, Status::SUCCESS, None);
- }
-
- pub fn disable_watchdog(&self) {
- self.system_table.boot_services().set_watchdog_timer(0, 65536, None).expect("Failed to disable the watchdog");
- }
-
- pub fn file_exists(&self, path: &str) -> bool {
- if path.is_empty() {
- return true;
- }
- let mut filesystem = self.get_fs();
- let mut buf: Vec<u16> = vec![0; path.len() + 1];
- return filesystem.try_exists(Path::new(&CStr16::from_str_with_buf(path, &mut buf).unwrap())).unwrap_or(false);
- }
-
- pub fn rename(&mut self, old: &str, new: &str) {
- let mut filesystem = self.get_fs();
- let mut buf: Vec<u16> = vec![0; old.len() + 1];
- let mut buf2: Vec<u16> = vec![0; new.len() + 1];
- filesystem.rename(Path::new(&CStr16::from_str_with_buf(old, &mut buf).unwrap()), Path::new(&CStr16::from_str_with_buf(new, &mut buf2).unwrap())).expect("Failed to move");
- }
-
- pub fn copy_file(&mut self, old: &str, new: &str) {
- let mut filesystem = self.get_fs();
- let mut buf: Vec<u16> = vec![0; old.len() + 1];
- let mut buf2: Vec<u16> = vec![0; new.len() + 1];
- filesystem.copy(Path::new(&CStr16::from_str_with_buf(old, &mut buf).unwrap()), Path::new(&CStr16::from_str_with_buf(new, &mut buf2).unwrap())).expect("Failed to move");
- }
-
- pub fn is_dir(&self, path: &str) -> bool {
- if path.is_empty() {
- return true;
- }
- let mut filesystem = self.get_fs();
- let mut buf: Vec<u16> = vec![0; path.len() + 1];
- return match filesystem.metadata(Path::new(&CStr16::from_str_with_buf(path, &mut buf).unwrap())) {
- Ok(b) => b.is_directory(),
- Err(_) => false
- };
- }
-
- pub fn is_file(&self, path: &str) -> bool {
- if path.is_empty() {
- return true;
- }
- let mut filesystem = self.get_fs();
- let mut buf: Vec<u16> = vec![0; path.len() + 1];
- return match filesystem.metadata(Path::new(&CStr16::from_str_with_buf(path, &mut buf).unwrap())) {
- Ok(b) => b.is_regular_file(),
- Err(_) => false
- };
- }
-
- pub fn read_file(&self, path: &str) -> Option<String> {
- if path.is_empty() {
- return None;
- }
- let mut filesystem = self.get_fs();
- let mut buf: Vec<u16> = vec![0; path.len() + 1];
- return match filesystem.read_to_string(Path::new(&CStr16::from_str_with_buf(path, &mut buf).unwrap())) {
- Ok(b) => Some(b),
- Err(_) => None
- };
- }
- pub fn write_file(&self, path: &str, text: &str) {
- if path.is_empty() {
- return;
- }
- let mut filesystem = self.get_fs();
- let mut buf: Vec<u16> = vec![0; path.len() + 1];
- filesystem.write(Path::new(&CStr16::from_str_with_buf(path, &mut buf).unwrap()), text.as_bytes()).unwrap();
- }
-
- pub fn scandir(&self, path: &str) -> UefiDirectoryIter {
- let mut filesystem = self.get_fs();
- let mut buf: Vec<u16> = vec![0; path.len() + 1];
- return match filesystem.read_dir(Path::new(&CStr16::from_str_with_buf(path, &mut buf).unwrap())) {
- Ok(b) => b,
- Err(_) => panic!("Failed to scan directory {}", path)
- };
- }
-
- pub fn execute_file(&mut self, path: &str) {
- if path.ends_with(".co") {
- match self.read_file(&path) {
- None => {
- display_error(self, Error::E13);
- }
- Some(data) => {
- self.println(&data.replace("\\r", "\\n").replace("\\n", "\\r\\n"));
- }
+ if update {
+ first_updated = true;
+ self.update_display();
}
- } else {
- display_error(self, Error::E14);
}
}
- pub fn resolve_path(&self, orig_og_path: &str) -> String {
- let og_path = orig_og_path.replace('\\', "/");
- let mut final_path = self.get_cwd().to_string().replace('/', "\\");
- let path = &og_path.replace('/', "\\");
- let mut buf = vec![0; path.len() + 1];
- let cstr = CStr16::from_str_with_buf(path, &mut buf).unwrap();
- let path = Path::new(cstr);
-
- if og_path.starts_with('/') {
- final_path = String::from("");
- }
-
- for i in path.components() {
- if i.to_string() == ".." {
- let parts = final_path.split('\\').collect::<Vec<&str>>();
- let len = parts.len() - 1;
+ pub fn menu(&mut self, items: Vec<MenuItem>, name: &str) {
+ self.list_items = items;
+ self.list_enabled = true;
+ self.list_max_length = 0;
+ self.list_focused_item = 0;
+ self.list_name = name.parse().unwrap();
- final_path = parts[..len].join("\\");
- } else if i.to_string() != "." {
- final_path = format!("{}\\{}", final_path, i).replace('/', "\\");
+ for item in &self.list_items {
+ if item.text.len() as u32 > self.list_max_length {
+ self.list_max_length = item.text.len() as u32;
}
}
- if !final_path.is_empty() {
- final_path[1..].to_string().replace("\\\\", "\\")
- } else {
- final_path.to_string().replace("\\\\", "\\")
- }
+ self.update_display();
}
+}
- pub fn make_readable(&self, _size: u64) -> String {
- let size = _size as f64;
+pub struct MenuItem {
+ text: String
+}
- if size > 1099511627776.0 {
- format!("{:.1}T", size / 1099511627776.0)
- } else if size > 1073741824.0 {
- format!("{:.1}G", size / 1073741824.0)
- } else if size > 1048576.0 {
- format!("{:.1}M", size / 1048576.0)
- } else if size > 1024.0 {
- format!("{:.1}K", size / 1024.0)
- } else {
- format!("{}B", size)
+impl MenuItem {
+ pub fn new(text: &str) -> Self {
+ MenuItem {
+ text: String::from(text)
}
}
- pub fn mkdir(&self, path: &str) {
- let mut filesystem = self.get_fs();
- let mut buf: Vec<u16> = vec![0; path.len() + 1];
- filesystem.create_dir_all(Path::new(&CStr16::from_str_with_buf(path, &mut buf).unwrap())).unwrap();
- }
-
- pub fn rmdir(&mut self, path: &str) {
- let mut filesystem = self.get_fs();
- let mut buf: Vec<u16> = vec![0; path.len() + 1];
- filesystem.remove_dir(Path::new(&CStr16::from_str_with_buf(path, &mut buf).unwrap())).unwrap();
- }
-
- pub fn unlink(&mut self, path: &str) {
- let mut filesystem = self.get_fs();
- let mut buf: Vec<u16> = vec![0; path.len() + 1];
- filesystem.remove_file(Path::new(&CStr16::from_str_with_buf(path, &mut buf).unwrap())).unwrap();
- }
-
- pub fn recursive_rmdir(&mut self, path: &str) {
- let mut filesystem = self.get_fs();
- let mut buf: Vec<u16> = vec![0; path.len() + 1];
- filesystem.remove_dir_all(Path::new(&CStr16::from_str_with_buf(path, &mut buf).unwrap())).unwrap();
- }
-
- pub fn print(&mut self, str: &str) {
- let stdout = self.system_table.stdout();
- let mut buf = vec![0; str.len() + 1];
- stdout.output_string(CStr16::from_str_with_buf(str, &mut buf).expect("Failed to format text")).expect("Failed to print");
+ pub fn show(&self, display: &mut FrameBufferDisplay, offset: usize, color: Rgb888) {
+ Text::new(&self.text, Point::new(50, (105 + (offset * 20)) as i32), MonoTextStyle::new(&FONT_10X20, color)).draw(display)
+ .expect("Failed to draw");
}
-
- pub fn println(&mut self, str: &str) {
- self.print(str);
- self.print("\r\n");
- }
-}
+} \ No newline at end of file