- added a new API for switching between terminal and application mode
- removed unneeded imports to reduce the dumb amount of warnings from the compiler - added a bounds check in frame.rs to avoid a panic when a frame tries to render a character out of bounds, instead returning an error
This commit is contained in:
@@ -7,12 +7,9 @@
|
||||
#![feature(alloc_error_handler)]
|
||||
#![feature(async_fn_in_trait)]
|
||||
#![feature(async_closure)]
|
||||
#![feature(global_asm)]
|
||||
#![feature(inherent_associated_types)]
|
||||
|
||||
|
||||
use alloc::string::String;
|
||||
use alloc::vec;
|
||||
use bootloader::{entry_point, BootInfo};
|
||||
use core::panic::PanicInfo;
|
||||
extern crate alloc;
|
||||
@@ -23,7 +20,6 @@ pub mod user;
|
||||
pub use system::std as std;
|
||||
pub use user::bin::*;
|
||||
use crate::calc::Calculator;
|
||||
use crate::std::application::Application;
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
||||
+1
-5
@@ -7,7 +7,7 @@
|
||||
use bootloader::{entry_point, BootInfo};
|
||||
use core::panic::PanicInfo;
|
||||
use CrystalOS::std::tasks::{Executor, Task};
|
||||
use CrystalOS::{print, print_log, printerr, println, println_log, std::syscall};
|
||||
use CrystalOS::{printerr, std::syscall};
|
||||
extern crate alloc;
|
||||
use CrystalOS::user::bin::shell;
|
||||
|
||||
@@ -40,9 +40,5 @@ fn main(boot_info: &'static BootInfo) -> ! {
|
||||
loop {
|
||||
executor.try_run();
|
||||
}
|
||||
|
||||
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||
use crate::{print, println};
|
||||
use crate::println;
|
||||
use super::gdt;
|
||||
use lazy_static::lazy_static;
|
||||
use spin;
|
||||
@@ -28,7 +28,7 @@ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFr
|
||||
|
||||
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||
|
||||
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
|
||||
use pc_keyboard::{layouts, HandleControl, Keyboard, ScancodeSet1};
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
@@ -38,7 +38,7 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStac
|
||||
};
|
||||
}
|
||||
|
||||
let mut keyboard = KEYBOARD.lock();
|
||||
let keyboard = KEYBOARD.lock();
|
||||
let mut port = Port::new(0x60);
|
||||
let scancode: u8 = unsafe { port.read() };
|
||||
|
||||
|
||||
@@ -3,12 +3,8 @@ use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
use volatile::Volatile;
|
||||
|
||||
use alloc::borrow::ToOwned;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use crate::system::kernel::render::RenderError::InvalidRenderMode;
|
||||
use crate::serial_println;
|
||||
use crate::std::io::Screen;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -137,24 +133,14 @@ impl Renderer {
|
||||
self.internal_render();
|
||||
}
|
||||
|
||||
pub fn application_mode(&mut self) -> Result<(), RenderError> {
|
||||
if self.application_mode {
|
||||
return Err(InvalidRenderMode);
|
||||
} else {
|
||||
self.application_mode = true;
|
||||
self.internal_render();
|
||||
Ok(())
|
||||
}
|
||||
pub fn application_mode(&mut self) {
|
||||
self.application_mode = true;
|
||||
self.internal_render();
|
||||
}
|
||||
|
||||
pub fn terminal_mode(&mut self) -> Result<(), RenderError> {
|
||||
if !self.application_mode {
|
||||
return Err(InvalidRenderMode);
|
||||
} else {
|
||||
self.application_mode = false;
|
||||
self.internal_render();
|
||||
Ok(())
|
||||
}
|
||||
pub fn terminal_mode(&mut self) {
|
||||
self.application_mode = false;
|
||||
self.internal_render();
|
||||
}
|
||||
|
||||
pub fn mode_is_app(&self) -> bool {
|
||||
@@ -210,10 +196,10 @@ impl Renderer {
|
||||
|
||||
pub fn cursor_position(&mut self, x: u8, y: u8) -> Result<(), RenderError> {
|
||||
// check that x and y are within bounds
|
||||
if x >= 80 || x < 0 || y >= 25 || y < 0 {
|
||||
if x >= 80 || y >= 25 {
|
||||
return Err(RenderError::OutOfBounds(
|
||||
x >= 80 || x < 0,
|
||||
y >= 25 || y < 0
|
||||
x >= 80,
|
||||
y >= 25
|
||||
))
|
||||
}
|
||||
self.internal_set_cursor_position(x, y);
|
||||
|
||||
@@ -25,7 +25,6 @@ pub fn _serial_print(args: core::fmt::Arguments) {
|
||||
|
||||
}
|
||||
pub fn serial_reply(chr: char) -> char {
|
||||
use core::fmt::Write;
|
||||
use x86_64::instructions::interrupts;
|
||||
|
||||
let mut chr_return: char = 'X';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use crate::println;
|
||||
pub fn init() -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
@@ -5,7 +5,7 @@ use x86_64::instructions::interrupts;
|
||||
|
||||
use conquer_once::spin::OnceCell;
|
||||
use crossbeam_queue::ArrayQueue;
|
||||
use crate::{println, serial_println};
|
||||
use crate::println;
|
||||
|
||||
use core::{pin::Pin, task::{Poll, Context}};
|
||||
use futures_util::stream::Stream;
|
||||
|
||||
@@ -2,7 +2,7 @@ use alloc::string::String;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use crate::system::kernel::render::{RENDERER, ScreenChar};
|
||||
use crate::std::io::{Color, Screen};
|
||||
use crate::std::io::Color;
|
||||
|
||||
/// TODO: get a working implementation for CLI apps
|
||||
/// elements can be created using their from_str() method
|
||||
@@ -135,8 +135,12 @@ impl Frame {
|
||||
pub fn dimensions(&self) -> Dimensions {
|
||||
self.dimensions
|
||||
}
|
||||
pub fn write(&mut self, position: Position, char: ColouredChar) {
|
||||
self.frame[position.y][position.x] = char
|
||||
pub fn write(&mut self, position: Position, char: ColouredChar) -> Result<(), RenderError> {
|
||||
if position.x >= self.dimensions.x || position.y >= self.dimensions.y {
|
||||
return Err(RenderError::OutOfBounds(true, true));
|
||||
}
|
||||
self.frame[position.y][position.x] = char;
|
||||
Ok(())
|
||||
}
|
||||
pub fn place_child_element(&mut self, other: &Frame) {
|
||||
for (i, row) in other.frame.iter().enumerate() {
|
||||
|
||||
+26
-4
@@ -48,13 +48,15 @@ pub enum Screen {
|
||||
Terminal,
|
||||
Application,
|
||||
}
|
||||
|
||||
/// DEPRECATED - STOP USING THIS SOON
|
||||
impl Screen {
|
||||
/// mode can be set for the kernel using this method
|
||||
pub fn set_mode(&self) -> Result<(), RenderError> {
|
||||
match self {
|
||||
Ok(match self {
|
||||
Screen::Terminal => RENDERER.lock().terminal_mode(),
|
||||
Screen::Application => RENDERER.lock().application_mode(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// returns the current display mode
|
||||
@@ -68,9 +70,9 @@ impl Screen {
|
||||
/// switches between modes
|
||||
pub fn switch(&self) {
|
||||
if RENDERER.lock().mode_is_app() == true {
|
||||
RENDERER.lock().terminal_mode().unwrap();
|
||||
RENDERER.lock().terminal_mode();
|
||||
} else {
|
||||
RENDERER.lock().application_mode().unwrap();
|
||||
RENDERER.lock().application_mode();
|
||||
}
|
||||
}
|
||||
pub fn clear() {
|
||||
@@ -78,6 +80,26 @@ impl Screen {
|
||||
}
|
||||
}
|
||||
|
||||
/// An interface that tells the kernel what rendering mode to use
|
||||
/// Creating an instance of this struct will enable application rendering mode
|
||||
/// Dropping the instance will return the display to focus on the terminal.
|
||||
pub struct Display;
|
||||
|
||||
impl Display {
|
||||
pub fn borrow() -> Display {
|
||||
RENDERER.lock().application_mode();
|
||||
Display
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Display {
|
||||
fn drop(&mut self) {
|
||||
RENDERER.lock().terminal_mode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! println_log {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use alloc::{string::{String, ToString}, vec::Vec};
|
||||
use core::ops::Index;
|
||||
use rand::{Rng, SeedableRng, rngs::SmallRng, RngCore};
|
||||
use rand::{SeedableRng, rngs::SmallRng, RngCore};
|
||||
use spin::Mutex;
|
||||
use lazy_static::lazy_static;
|
||||
use cmos_rtc::{ReadRTC, Time};
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
use core::time::Duration;
|
||||
use embedded_time::{Clock, Timer};
|
||||
use cmos_rtc::{ReadRTC, Time};
|
||||
use crate::println;
|
||||
use super::super::kernel::interrupts::GLOBALTIMER;
|
||||
use x86_64::instructions::interrupts;
|
||||
|
||||
@@ -293,12 +293,6 @@ impl GameTimer {
|
||||
self.time_since_move += 1;
|
||||
}
|
||||
|
||||
pub fn get_spawn_time(&self) -> u32 {
|
||||
self.time_since_spawn
|
||||
}
|
||||
pub fn reset_spawn_time(&mut self) {
|
||||
self.time_since_spawn = 0
|
||||
}
|
||||
pub fn get_move_time(&self) -> u32 {
|
||||
self.time_since_move
|
||||
}
|
||||
|
||||
@@ -5,15 +5,12 @@ use alloc::borrow::ToOwned;
|
||||
use crate::{println, print, mknode, std};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use lazy_static::lazy_static;
|
||||
use crate::std::application::{
|
||||
Application,
|
||||
Error as ShellError
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct Parser {
|
||||
tokens: Vec<Token>,
|
||||
idx: i32,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use alloc::format;
|
||||
use alloc::string::String;
|
||||
use crate::println;
|
||||
|
||||
const PI: f64 = 3.14159265358979323846264338327950288419716939937510;
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use async_trait::async_trait;
|
||||
use alloc::{boxed::Box, format, string::String, vec::Vec};
|
||||
use log::info;
|
||||
|
||||
use crate::{std::os::OS, std::io::{Color, write, Screen}, println, std::application::{
|
||||
Application,
|
||||
Error,
|
||||
}, std};
|
||||
use crate::std::{
|
||||
os::OS,
|
||||
io::{Color, write, Screen},
|
||||
application::{Application, Error},
|
||||
};
|
||||
use crate::println;
|
||||
|
||||
const CRYSTAL_LOGO: &str =
|
||||
"\n $$$$$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$\\
|
||||
|
||||
+146
-146
@@ -1,146 +1,146 @@
|
||||
use alloc::{boxed::Box, string::String, vec::Vec};
|
||||
use core::cmp::min;
|
||||
|
||||
struct Player {
|
||||
username: String,
|
||||
stats: EntityStats,
|
||||
|
||||
exp: u32,
|
||||
level: u32,
|
||||
skill_points: u32,
|
||||
skills: Vec<Box<dyn Skill>>,
|
||||
|
||||
helmet: Option<Helmet>,
|
||||
chestplate: Option<Chestplate>,
|
||||
boots: Option<Boots>,
|
||||
|
||||
inventory: Vec<Item>,
|
||||
}
|
||||
|
||||
struct EntityStats {
|
||||
health: i32,
|
||||
max_health: i32,
|
||||
mana: i32,
|
||||
max_mana: i32,
|
||||
defence: i32,
|
||||
}
|
||||
|
||||
impl Player {
|
||||
fn new(username: String) -> Self {
|
||||
Self {
|
||||
username,
|
||||
stats: EntityStats {
|
||||
health: 100,
|
||||
max_health: 100,
|
||||
mana: 100,
|
||||
max_mana: 100,
|
||||
defence: 0,
|
||||
},
|
||||
exp: 0,
|
||||
level: 0,
|
||||
skill_points: 0,
|
||||
skills: Vec::new(),
|
||||
|
||||
helmet: None,
|
||||
chestplate: None,
|
||||
boots: None,
|
||||
inventory: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn heal(&mut self, amount: i32) {
|
||||
let max_health = self.max_health();
|
||||
|
||||
self.stats.health = min(self.stats.health + amount, max_health);
|
||||
}
|
||||
|
||||
fn damage(&mut self, amount: i32) {
|
||||
let hp = self.health_points();
|
||||
}
|
||||
|
||||
fn inventory_contents_mut(&mut self) -> &mut Vec<Item> {
|
||||
&mut self.inventory
|
||||
}
|
||||
|
||||
fn max_health(&self) -> i32 {
|
||||
let mut max_health = self.stats.max_health;
|
||||
|
||||
if let Some(helmet) = &self.helmet {
|
||||
max_health += helmet.stats.health_bonus;
|
||||
}
|
||||
if let Some(chestplate) = &self.chestplate {
|
||||
max_health += chestplate.stats.health_bonus;
|
||||
}
|
||||
if let Some(boots) = &self.boots {
|
||||
max_health += boots.stats.health_bonus;
|
||||
}
|
||||
|
||||
max_health
|
||||
}
|
||||
|
||||
fn health_points(&self) -> i32 {
|
||||
let mut hp = self.stats.health;
|
||||
if let Some(helmet) = &self.helmet {
|
||||
hp += helmet.stats.health_bonus;
|
||||
}
|
||||
if let Some(chestplate) = &self.chestplate {
|
||||
hp += chestplate.stats.health_bonus;
|
||||
}
|
||||
if let Some(boots) = &self.boots {
|
||||
hp += boots.stats.health_bonus;
|
||||
}
|
||||
hp
|
||||
}
|
||||
}
|
||||
|
||||
enum Item {
|
||||
Helmet(Helmet),
|
||||
Chestplate(Chestplate),
|
||||
Boots(Boots),
|
||||
Sword,
|
||||
Potion,
|
||||
}
|
||||
|
||||
struct Helmet {
|
||||
name: &'static str,
|
||||
lore: &'static str,
|
||||
stats: ArmourStats,
|
||||
}
|
||||
|
||||
struct Chestplate {
|
||||
name: &'static str,
|
||||
lore: &'static str,
|
||||
stats: ArmourStats,
|
||||
}
|
||||
|
||||
struct Boots {
|
||||
name: &'static str,
|
||||
lore: &'static str,
|
||||
stats: ArmourStats,
|
||||
}
|
||||
|
||||
struct ArmourStats {
|
||||
durability: i32,
|
||||
max_durability: i32,
|
||||
defence: i32,
|
||||
health_bonus: i32,
|
||||
mana_bonus: i32,
|
||||
}
|
||||
|
||||
struct PlayerStats {}
|
||||
|
||||
trait Skill {
|
||||
fn skill_name(&self) -> &str; // returns the name of the skill
|
||||
fn skill_level(&self) -> &str; // returns the level of that skill
|
||||
fn description(&self) -> &str; // returns the status of that skill
|
||||
fn skillpoint_level_req(&self) -> i32;
|
||||
fn increase_level(&mut self, level: &u32, skill_points: &mut u32) -> Result<(), GameError>;
|
||||
fn decrease_level(&mut self, skill_points: &mut u32) -> Result<(), GameError>;
|
||||
fn modify_stats(&self, stats: EntityStats) -> EntityStats;
|
||||
}
|
||||
|
||||
enum GameError {
|
||||
SkillLevelMaxed,
|
||||
InsufficientSkillPoints,
|
||||
InsufficientLevel,
|
||||
}
|
||||
// use alloc::{boxed::Box, string::String, vec::Vec};
|
||||
// use core::cmp::min;
|
||||
//
|
||||
// struct Player {
|
||||
// username: String,
|
||||
// stats: EntityStats,
|
||||
//
|
||||
// exp: u32,
|
||||
// level: u32,
|
||||
// skill_points: u32,
|
||||
// skills: Vec<Box<dyn Skill>>,
|
||||
//
|
||||
// helmet: Option<Helmet>,
|
||||
// chestplate: Option<Chestplate>,
|
||||
// boots: Option<Boots>,
|
||||
//
|
||||
// inventory: Vec<Item>,
|
||||
// }
|
||||
//
|
||||
// struct EntityStats {
|
||||
// health: i32,
|
||||
// max_health: i32,
|
||||
// mana: i32,
|
||||
// max_mana: i32,
|
||||
// defence: i32,
|
||||
// }
|
||||
//
|
||||
// impl Player {
|
||||
// fn new(username: String) -> Self {
|
||||
// Self {
|
||||
// username,
|
||||
// stats: EntityStats {
|
||||
// health: 100,
|
||||
// max_health: 100,
|
||||
// mana: 100,
|
||||
// max_mana: 100,
|
||||
// defence: 0,
|
||||
// },
|
||||
// exp: 0,
|
||||
// level: 0,
|
||||
// skill_points: 0,
|
||||
// skills: Vec::new(),
|
||||
//
|
||||
// helmet: None,
|
||||
// chestplate: None,
|
||||
// boots: None,
|
||||
// inventory: Vec::new(),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fn heal(&mut self, amount: i32) {
|
||||
// let max_health = self.max_health();
|
||||
//
|
||||
// self.stats.health = min(self.stats.health + amount, max_health);
|
||||
// }
|
||||
//
|
||||
// fn damage(&mut self, amount: i32) {
|
||||
// let hp = self.health_points();
|
||||
// }
|
||||
//
|
||||
// fn inventory_contents_mut(&mut self) -> &mut Vec<Item> {
|
||||
// &mut self.inventory
|
||||
// }
|
||||
//
|
||||
// fn max_health(&self) -> i32 {
|
||||
// let mut max_health = self.stats.max_health;
|
||||
//
|
||||
// if let Some(helmet) = &self.helmet {
|
||||
// max_health += helmet.stats.health_bonus;
|
||||
// }
|
||||
// if let Some(chestplate) = &self.chestplate {
|
||||
// max_health += chestplate.stats.health_bonus;
|
||||
// }
|
||||
// if let Some(boots) = &self.boots {
|
||||
// max_health += boots.stats.health_bonus;
|
||||
// }
|
||||
//
|
||||
// max_health
|
||||
// }
|
||||
//
|
||||
// fn health_points(&self) -> i32 {
|
||||
// let mut hp = self.stats.health;
|
||||
// if let Some(helmet) = &self.helmet {
|
||||
// hp += helmet.stats.health_bonus;
|
||||
// }
|
||||
// if let Some(chestplate) = &self.chestplate {
|
||||
// hp += chestplate.stats.health_bonus;
|
||||
// }
|
||||
// if let Some(boots) = &self.boots {
|
||||
// hp += boots.stats.health_bonus;
|
||||
// }
|
||||
// hp
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// enum Item {
|
||||
// Helmet(Helmet),
|
||||
// Chestplate(Chestplate),
|
||||
// Boots(Boots),
|
||||
// Sword,
|
||||
// Potion,
|
||||
// }
|
||||
//
|
||||
// struct Helmet {
|
||||
// name: &'static str,
|
||||
// lore: &'static str,
|
||||
// stats: ArmourStats,
|
||||
// }
|
||||
//
|
||||
// struct Chestplate {
|
||||
// name: &'static str,
|
||||
// lore: &'static str,
|
||||
// stats: ArmourStats,
|
||||
// }
|
||||
//
|
||||
// struct Boots {
|
||||
// name: &'static str,
|
||||
// lore: &'static str,
|
||||
// stats: ArmourStats,
|
||||
// }
|
||||
//
|
||||
// struct ArmourStats {
|
||||
// durability: i32,
|
||||
// max_durability: i32,
|
||||
// defence: i32,
|
||||
// health_bonus: i32,
|
||||
// mana_bonus: i32,
|
||||
// }
|
||||
//
|
||||
// struct PlayerStats {}
|
||||
//
|
||||
// trait Skill {
|
||||
// fn skill_name(&self) -> &str; // returns the name of the skill
|
||||
// fn skill_level(&self) -> &str; // returns the level of that skill
|
||||
// fn description(&self) -> &str; // returns the status of that skill
|
||||
// fn skillpoint_level_req(&self) -> i32;
|
||||
// fn increase_level(&mut self, level: &u32, skill_points: &mut u32) -> Result<(), GameError>;
|
||||
// fn decrease_level(&mut self, skill_points: &mut u32) -> Result<(), GameError>;
|
||||
// fn modify_stats(&self, stats: EntityStats) -> EntityStats;
|
||||
// }
|
||||
//
|
||||
// enum GameError {
|
||||
// SkillLevelMaxed,
|
||||
// InsufficientSkillPoints,
|
||||
// InsufficientLevel,
|
||||
// }
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use alloc::borrow::ToOwned;
|
||||
use alloc::string::String;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
@@ -6,9 +5,8 @@ use alloc::boxed::Box;
|
||||
use crate::std::application::{Application, Error};
|
||||
use async_trait::async_trait;
|
||||
use crate::std::frame::{ColouredChar, Frame, Position, Dimensions, RenderError};
|
||||
use crate::std::io::{KeyStroke, Screen, Stdin, Color, ColorCode};
|
||||
use crate::std::io::{KeyStroke, Stdin, Color, ColorCode, Display};
|
||||
use crate::std::time::wait;
|
||||
use crate::user::bin::snake::Game;
|
||||
|
||||
pub struct GameOfLife {
|
||||
frame: Frame
|
||||
@@ -25,7 +23,7 @@ impl Application for GameOfLife {
|
||||
}
|
||||
async fn run(&mut self, args: Vec<String>) -> Result<(), Error> {
|
||||
// setup:
|
||||
Screen::Application.set_mode();
|
||||
let d = Display::borrow();
|
||||
|
||||
let xoffset = 38;
|
||||
let yoffset = 5;
|
||||
@@ -56,7 +54,6 @@ impl Application for GameOfLife {
|
||||
|
||||
self.mainloop()?;
|
||||
|
||||
Screen::Terminal.set_mode();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ use async_trait::async_trait;
|
||||
use alloc::{boxed::Box, string::String, vec::Vec};
|
||||
|
||||
use crate::{
|
||||
std::os::OS,
|
||||
std::io::{Color, write},
|
||||
println,
|
||||
std::application::{
|
||||
Application,
|
||||
|
||||
+4
-10
@@ -2,17 +2,11 @@ use alloc::string::{String, ToString};
|
||||
use alloc::{format, vec};
|
||||
use alloc::vec::Vec;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::fmt::format;
|
||||
use alloc::sync::Arc;
|
||||
use core::any::Any;
|
||||
use async_trait::async_trait;
|
||||
use spin::Mutex;
|
||||
use crate::{println, serial_println};
|
||||
use crate::std::io::{ColorCode};
|
||||
use crate::shell::command_handler;
|
||||
use crate::std::application::{Application, Error};
|
||||
use crate::std::frame::{self, Frame, Position, Dimensions, ColouredChar, RenderError};
|
||||
use crate::std::io::{Color, KeyStroke, Screen, Stdin};
|
||||
use crate::std::frame::{Frame, Position, Dimensions, ColouredChar, RenderError};
|
||||
use crate::std::io::{KeyStroke, Screen, Stdin};
|
||||
|
||||
use crate::user::lib::libgui::{
|
||||
cg_core::{CgComponent},
|
||||
@@ -100,7 +94,7 @@ impl Application for Grapher {
|
||||
|
||||
while let c = Stdin::keystroke().await {
|
||||
|
||||
let mut entry_widget = container.elements.get("entry_box").unwrap();
|
||||
let entry_widget = container.elements.get("entry_box").unwrap();
|
||||
let mut entry = entry_widget.fetch::<CgLineEdit>().unwrap();
|
||||
|
||||
rerender = true;
|
||||
@@ -196,7 +190,7 @@ impl Grapher {
|
||||
|
||||
let offset_x = point.x + OFFSET_X;
|
||||
let offset_y = point.y + OFFSET_Y;
|
||||
self.frame.write(Position::new(offset_x as usize, 21-offset_y as usize), ColouredChar::new('*'));
|
||||
self.frame.write(Position::new(offset_x as usize, 21-offset_y as usize), ColouredChar::new('*')).expect("Failed to write to frame - this function is broken.");
|
||||
}
|
||||
|
||||
fn reset_frame(&mut self) {
|
||||
|
||||
+56
-12
@@ -1,12 +1,15 @@
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use core::any::Any;
|
||||
use async_trait::async_trait;
|
||||
use core::fmt::Write;
|
||||
use crate::std::application::{Application, Error};
|
||||
use crate::std;
|
||||
use crate::std::frame::{ColouredChar, Dimensions, Frame, Position, RenderError};
|
||||
use crate::std::io::{Display, KeyStroke, Stdin};
|
||||
use crate::user::lib::libgui::cg_core::CgComponent;
|
||||
|
||||
struct Game {
|
||||
pub(crate) struct Game {
|
||||
ball: Ball,
|
||||
player1: Player,
|
||||
player2: Player,
|
||||
@@ -18,40 +21,81 @@ impl Application for Game {
|
||||
Game {
|
||||
ball: Ball::new(),
|
||||
player1: Player::new(1),
|
||||
player2: Player::new(2),
|
||||
player2: Player::new(78),
|
||||
}
|
||||
}
|
||||
|
||||
async fn run(&mut self, _: Vec<String>) -> Result<(), Error> {
|
||||
let d = Display::borrow();
|
||||
|
||||
loop {
|
||||
self.ball.update(&self.player1, &self.player2);
|
||||
std::time::wait(0.01);
|
||||
|
||||
if let Some(key) = Stdin::try_keystroke() {
|
||||
match key {
|
||||
KeyStroke::Char('w') => {
|
||||
self.player1.pos.y -= 1;
|
||||
},
|
||||
KeyStroke::Char('s') => {
|
||||
self.player1.pos.y += 1;
|
||||
},
|
||||
KeyStroke::Up => {
|
||||
self.player2.pos.y -= 1;
|
||||
},
|
||||
KeyStroke::Down => {
|
||||
self.player2.pos.y += 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if let Ok(frame) = self.render() {
|
||||
frame.write_to_screen().unwrap();
|
||||
}
|
||||
// self.ball.update(&self.player1, &self.player2);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl CgComponent for Game {
|
||||
fn render(&self) -> Result<Frame, RenderError> {
|
||||
let mut frame = Frame::new(Dimensions::new(0, 0), Dimensions::new(80, 25))?;
|
||||
|
||||
frame.write(self.player1.pos, ColouredChar::new('@')).unwrap();
|
||||
frame.write(self.player2.pos, ColouredChar::new('@')).unwrap();
|
||||
frame.write(self.ball.pos, ColouredChar::new('@')).unwrap();
|
||||
|
||||
Ok(frame)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
struct Player {
|
||||
x: i32,
|
||||
y: i32,
|
||||
pos: Position,
|
||||
score: i32,
|
||||
}
|
||||
|
||||
impl Player {
|
||||
fn new(y: i32) -> Self {
|
||||
Player { x: 0, y, score: 0 }
|
||||
fn new(x: usize) -> Self {
|
||||
Player { pos: Position::new(x, 12), score: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
struct Ball {
|
||||
x: i32,
|
||||
y: i32,
|
||||
pos: Position,
|
||||
vx: i32,
|
||||
vy: i32,
|
||||
}
|
||||
|
||||
impl Ball {
|
||||
fn new() -> Self {
|
||||
Ball { x: 0, y: 0 }
|
||||
Ball { pos: Position::new(40, 12), vx: 1, vy: 0 }
|
||||
}
|
||||
|
||||
fn update(&mut self, player1: &Player, player2: &Player) {
|
||||
self.x += 1;
|
||||
self.pos.x = (self.pos.x as i32 + self.vx) as usize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ const RICKROLL2: &str = "
|
||||
1a###w#*mObo*oatXkW*oo#*###p `--' `---' `----' `-----' | |-'
|
||||
`--'";
|
||||
|
||||
use crate::{println, serial_println};
|
||||
use crate::println;
|
||||
use alloc::{string::String, boxed::Box, vec::Vec};
|
||||
|
||||
|
||||
|
||||
+8
-13
@@ -1,33 +1,26 @@
|
||||
use async_trait::async_trait;
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
|
||||
use alloc::{boxed::Box, format, string::{String, ToString}, vec, vec::Vec};
|
||||
use futures_util::TryFutureExt;
|
||||
use vga::writers::{GraphicsWriter, PrimitiveDrawing};
|
||||
use vga::writers::{PrimitiveDrawing};
|
||||
|
||||
use crate::{
|
||||
print,
|
||||
printerr,
|
||||
println,
|
||||
serial_println,
|
||||
};
|
||||
|
||||
use crate::std::{
|
||||
application::{Application, Error, Exit},
|
||||
time::{timer, wait},
|
||||
random::Random,
|
||||
io::{
|
||||
Color, write, Screen, Stdin, Serial, KeyStroke
|
||||
},
|
||||
frame::{Dimensions, Position, ColorCode},
|
||||
};
|
||||
|
||||
use crate::user::{
|
||||
lib::libgui::{
|
||||
cg_core::{CgComponent, CgTextEdit, CgKeyboardCapture, CgTextInput, Widget},
|
||||
cg_widgets::{CgTextBox, CgContainer, CgLabel, CgStatusBar, CgDialog},
|
||||
cg_inputs::CgLineEdit,
|
||||
cg_core::{CgComponent, CgKeyboardCapture},
|
||||
cg_widgets::CgDialog,
|
||||
},
|
||||
bin::*,
|
||||
};
|
||||
@@ -140,6 +133,9 @@ async fn exec() -> Result<(), Error> {
|
||||
let mut asteroid_game = asteroids::Game::new();
|
||||
asteroid_game.run(args).await?;
|
||||
}
|
||||
"pong" => {
|
||||
pong::Game::new().run(args).await?;
|
||||
}
|
||||
"serial" => {
|
||||
let c = Serial::reply_char('e');
|
||||
println!("{}", c);
|
||||
@@ -149,8 +145,8 @@ async fn exec() -> Result<(), Error> {
|
||||
game.run(Vec::new()).await?;
|
||||
}
|
||||
"tetris" => {
|
||||
let mut game = tetris::TetrisEngine::new();
|
||||
game.run(Vec::new()).await?;
|
||||
// let mut game = tetris::TetrisEngine::new();
|
||||
// game.run(Vec::new()).await?;
|
||||
}
|
||||
|
||||
"gigachad?" => {
|
||||
@@ -192,7 +188,6 @@ async fn exec() -> Result<(), Error> {
|
||||
};
|
||||
}
|
||||
"time" => {
|
||||
use crate::std::time::timer;
|
||||
timer();
|
||||
}
|
||||
"test_features" => {
|
||||
|
||||
+6
-16
@@ -1,19 +1,13 @@
|
||||
use alloc::string::{String, ToString};
|
||||
use alloc::string::String;
|
||||
use alloc::{format, vec, vec::Vec, boxed::Box};
|
||||
use alloc::borrow::ToOwned;
|
||||
use core::arch::x86_64::_mm_test_all_ones;
|
||||
use core::cell::RefCell;
|
||||
use async_trait::async_trait;
|
||||
use crate::std::io::{Color, KeyStroke, Screen, Stdin};
|
||||
use crate::std::io::{Color, Display, KeyStroke, Stdin};
|
||||
use crate::std::time;
|
||||
use crossbeam_queue::SegQueue;
|
||||
use lazy_static::lazy_static;
|
||||
use crate::{println, serial_println};
|
||||
use crate::std::application::{Application, Error};
|
||||
use crate::std::frame::{ColouredChar, Dimensions, Frame, RenderError, ColorCode};
|
||||
use crate::std::random::Random;
|
||||
use crate::system::std::frame;
|
||||
use super::super::lib::coords::{Line, Position, Direction};
|
||||
use super::super::lib::coords::{Position, Direction};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum Gamemode {
|
||||
@@ -53,10 +47,10 @@ impl Application for Game {
|
||||
|
||||
async fn run(&mut self, args: Vec<String>) -> Result<(), Error> {
|
||||
|
||||
let mut settings = [0, 0, 0]; // ai_count, snake_len, poi_count
|
||||
let settings = [0, 0, 0]; // ai_count, snake_len, poi_count
|
||||
|
||||
if args.len() == 0 {
|
||||
self.gamemode == Gamemode::SinglePlayer;
|
||||
self.gamemode = Gamemode::SinglePlayer;
|
||||
} else {
|
||||
match args[0].as_str() {
|
||||
"easy" => {
|
||||
@@ -81,13 +75,11 @@ impl Application for Game {
|
||||
self.prepare();
|
||||
|
||||
// switch OS to application mode
|
||||
Screen::Application.set_mode();
|
||||
let d = Display::borrow();
|
||||
// render the initial state of the screen.
|
||||
self.render().map_err(|_| Error::ApplicationError(String::from("failed to render game screen")))?;
|
||||
// run the game
|
||||
self.gameloop().await?;
|
||||
// return to the terminal
|
||||
Screen::Terminal.set_mode();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -356,8 +348,6 @@ impl PathFinder {
|
||||
// serial_println!("{:?} {:?} {:?} {:?}", nearest_poi, rel_pos, head, optimal);
|
||||
return optimal;
|
||||
}
|
||||
|
||||
Direction::None
|
||||
}
|
||||
|
||||
fn optimal_move(head: &Position, rel_pos: &Position, moves: &Vec<Direction>) -> Direction {
|
||||
|
||||
@@ -3,12 +3,11 @@ use crate::std::application::{
|
||||
Application,
|
||||
Error
|
||||
};
|
||||
use crate::{print, println};
|
||||
use crate::println;
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
use async_trait::async_trait;
|
||||
use alloc::{
|
||||
string::ToString,
|
||||
borrow::ToOwned,
|
||||
};
|
||||
|
||||
@@ -101,13 +100,13 @@ println!("\n-------------------------------------");
|
||||
|
||||
impl Tasks {
|
||||
fn add_task(&mut self, content: String) {
|
||||
TASKS.lock().add(content);
|
||||
TASKS.lock().add(content).unwrap();
|
||||
}
|
||||
fn remove_task(&self, idx: usize) {
|
||||
TASKS.lock().remove(idx);
|
||||
TASKS.lock().remove(idx).unwrap();
|
||||
}
|
||||
fn select_task(&self, idx: i32) {
|
||||
TASKS.lock().select(idx);
|
||||
TASKS.lock().select(idx).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+112
-114
@@ -1,117 +1,115 @@
|
||||
use async_trait::async_trait;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use crate::std::frame::{ColouredChar};
|
||||
use crate::{serial_print, serial_println};
|
||||
use crate::std::application::{Application, Error};
|
||||
use crate::std::io::Screen;
|
||||
use crate::user::lib::coords::{Direction, Position, PositionReal};
|
||||
|
||||
|
||||
pub(crate) struct TetrisEngine {
|
||||
score: u32,
|
||||
next: TetrisPiece,
|
||||
completed_frame: [[ColouredChar; 80]; 25], // this frame does not contain falling blocks, only static ones
|
||||
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Application for TetrisEngine {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
score: 0,
|
||||
next: TetrisPiece::new(PieceType::OPiece),
|
||||
completed_frame: [[ColouredChar::null(); 80]; 25],
|
||||
}
|
||||
}
|
||||
async fn run(&mut self, args: Vec<String>) -> Result<(), Error> {
|
||||
// setup:
|
||||
Screen::Application.set_mode();
|
||||
|
||||
let piece_type = PieceType::OPiece;
|
||||
let mut piece = TetrisPiece::new(piece_type);
|
||||
|
||||
serial_println!("{:?}", piece.get_positions());
|
||||
piece.rotate_right();
|
||||
serial_println!("{:?}", piece.get_positions());
|
||||
|
||||
|
||||
Screen::Terminal.set_mode();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum PieceType {
|
||||
OPiece,
|
||||
IPiece,
|
||||
JPiece,
|
||||
LPiece,
|
||||
SPiece,
|
||||
ZPiece,
|
||||
}
|
||||
|
||||
struct TetrisPiece {
|
||||
type_: PieceType,
|
||||
pos: Position,
|
||||
rotation: Direction,
|
||||
}
|
||||
|
||||
impl TetrisPiece {
|
||||
fn new(type_: PieceType) -> Self {
|
||||
Self {
|
||||
type_,
|
||||
pos: Position { x: 40, y: 30 },
|
||||
rotation: Direction::Degrees0,
|
||||
}
|
||||
}
|
||||
fn rotate_right(&mut self) {
|
||||
self.rotation = match self.rotation {
|
||||
Direction::Degrees90 => Direction::Degrees180,
|
||||
Direction::Degrees180 => Direction::Degrees270,
|
||||
Direction::Degrees270 => Direction::Degrees0,
|
||||
Direction::Degrees0 => Direction::Degrees90,
|
||||
Direction::None => panic!("direction should never be none in this application"),
|
||||
};
|
||||
}
|
||||
|
||||
/// function that maps the coordinates of the object.
|
||||
fn get_positions(&self) -> Vec<Position> {
|
||||
match self.type_ {
|
||||
PieceType::OPiece => {
|
||||
let positions = vec![
|
||||
PositionReal { x: -0.5, y: -0.5 },
|
||||
PositionReal { x: 0.5, y: -0.5 },
|
||||
PositionReal { x: -0.5, y: 0.5 },
|
||||
PositionReal { x: 0.5, y: 0.5 },
|
||||
];
|
||||
positions.into_iter().map(|p|
|
||||
( p.rotate(self.rotation.clone()) + self.pos.clone().real() + PositionReal { x: -0.5, y: 0.5 } ).integer()
|
||||
).collect::<Vec<Position>>()
|
||||
}
|
||||
_ => unimplemented!("E"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// use async_trait::async_trait;
|
||||
// use alloc::boxed::Box;
|
||||
// use alloc::string::String;
|
||||
// use alloc::vec;
|
||||
// use alloc::vec::Vec;
|
||||
// use crate::std::frame::{ColouredChar};
|
||||
// use crate::{serial_print, serial_println};
|
||||
// use crate::std::application::{Application, Error};
|
||||
// use crate::std::io::{Display, Screen};
|
||||
// use crate::user::lib::coords::{Direction, Position, PositionReal};
|
||||
//
|
||||
//
|
||||
// pub(crate) struct TetrisEngine {
|
||||
// score: u32,
|
||||
// next: TetrisPiece,
|
||||
// completed_frame: [[ColouredChar; 80]; 25], // this frame does not contain falling blocks, only static ones
|
||||
//
|
||||
// }
|
||||
//
|
||||
// #[async_trait]
|
||||
// impl Application for TetrisEngine {
|
||||
// fn new() -> Self {
|
||||
// Self {
|
||||
// score: 0,
|
||||
// next: TetrisPiece::new(PieceType::OPiece),
|
||||
// completed_frame: [[ColouredChar::null(); 80]; 25],
|
||||
// }
|
||||
// }
|
||||
// async fn run(&mut self, args: Vec<String>) -> Result<(), Error> {
|
||||
// // setup:
|
||||
// let d = Display::borrow();
|
||||
//
|
||||
// let piece_type = PieceType::OPiece;
|
||||
// let mut piece = TetrisPiece::new(piece_type);
|
||||
//
|
||||
// serial_println!("{:?}", piece.get_positions());
|
||||
// piece.rotate_right();
|
||||
// serial_println!("{:?}", piece.get_positions());
|
||||
//
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// enum PieceType {
|
||||
// OPiece,
|
||||
// IPiece,
|
||||
// JPiece,
|
||||
// LPiece,
|
||||
// SPiece,
|
||||
// ZPiece,
|
||||
// }
|
||||
//
|
||||
// struct TetrisPiece {
|
||||
// type_: PieceType,
|
||||
// pos: Position,
|
||||
// rotation: Direction,
|
||||
// }
|
||||
//
|
||||
// impl TetrisPiece {
|
||||
// fn new(type_: PieceType) -> Self {
|
||||
// Self {
|
||||
// type_,
|
||||
// pos: Position { x: 40, y: 30 },
|
||||
// rotation: Direction::Degrees0,
|
||||
// }
|
||||
// }
|
||||
// fn rotate_right(&mut self) {
|
||||
// self.rotation = match self.rotation {
|
||||
// Direction::Degrees90 => Direction::Degrees180,
|
||||
// Direction::Degrees180 => Direction::Degrees270,
|
||||
// Direction::Degrees270 => Direction::Degrees0,
|
||||
// Direction::Degrees0 => Direction::Degrees90,
|
||||
// Direction::None => panic!("direction should never be none in this application"),
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// /// function that maps the coordinates of the object.
|
||||
// fn get_positions(&self) -> Vec<Position> {
|
||||
// match self.type_ {
|
||||
// PieceType::OPiece => {
|
||||
// let positions = vec![
|
||||
// PositionReal { x: -0.5, y: -0.5 },
|
||||
// PositionReal { x: 0.5, y: -0.5 },
|
||||
// PositionReal { x: -0.5, y: 0.5 },
|
||||
// PositionReal { x: 0.5, y: 0.5 },
|
||||
// ];
|
||||
// positions.into_iter().map(|p|
|
||||
// ( p.rotate(self.rotation.clone()) + self.pos.clone().real() + PositionReal { x: -0.5, y: 0.5 } ).integer()
|
||||
// ).collect::<Vec<Position>>()
|
||||
// }
|
||||
// _ => unimplemented!("E"),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
use hashbrown::HashMap;
|
||||
use spin::{Mutex, MutexGuard};
|
||||
use crate::{printerr, serial_println};
|
||||
use crate::std::frame::{ColouredChar, Dimensions, Position, special_char, Frame, RenderError, ColorCode};
|
||||
use spin::{Mutex};
|
||||
use crate::std::frame::{Frame, RenderError};
|
||||
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
sync::Arc,
|
||||
vec::Vec,
|
||||
vec,
|
||||
string::String,
|
||||
};
|
||||
use core::any::Any;
|
||||
|
||||
@@ -2,7 +2,6 @@ use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use alloc::boxed::Box;
|
||||
use core::any::Any;
|
||||
use core::task::ready;
|
||||
use async_trait::async_trait;
|
||||
use crate::std::application::Exit;
|
||||
use crate::std::frame::{ColouredChar, Dimensions, Frame, Position, RenderError};
|
||||
@@ -23,7 +22,7 @@ impl CgLineEdit {
|
||||
CgLineEdit {
|
||||
position,
|
||||
dimensions: Dimensions::new(width, 1),
|
||||
prompt: prompt,
|
||||
prompt,
|
||||
text: Vec::new(),
|
||||
ptr: 0
|
||||
}
|
||||
@@ -39,24 +38,24 @@ impl CgComponent for CgLineEdit {
|
||||
if idx >= self.dimensions.x {
|
||||
break;
|
||||
}
|
||||
frame.write(Position::new(idx, 0), ColouredChar::new(c));
|
||||
frame.write(Position::new(idx, 0), ColouredChar::new(c)).unwrap();
|
||||
idx += 1
|
||||
}
|
||||
|
||||
idx += 1; // create a space between the prompt and the text
|
||||
|
||||
if idx + self.text.len() > self.dimensions.x {
|
||||
frame.write(Position::new(idx, 0), ColouredChar::new('['));
|
||||
frame.write(Position::new(idx + 1, 0), ColouredChar::new('.'));
|
||||
frame.write(Position::new(idx + 2, 0), ColouredChar::new('.'));
|
||||
frame.write(Position::new(idx + 3, 0), ColouredChar::new('.'));
|
||||
frame.write(Position::new(idx + 4, 0), ColouredChar::new(']'));
|
||||
frame.write(Position::new(idx, 0), ColouredChar::new('[')).unwrap();
|
||||
frame.write(Position::new(idx + 1, 0), ColouredChar::new('.')).unwrap();
|
||||
frame.write(Position::new(idx + 2, 0), ColouredChar::new('.')).unwrap();
|
||||
frame.write(Position::new(idx + 3, 0), ColouredChar::new('.')).unwrap();
|
||||
frame.write(Position::new(idx + 4, 0), ColouredChar::new(']')).unwrap();
|
||||
idx += 5
|
||||
}
|
||||
|
||||
|
||||
self.text.iter().rev().take(self.dimensions.x - idx).rev().for_each(|c| {
|
||||
frame.write(Position::new(idx, 0), ColouredChar::new(*c));
|
||||
frame.write(Position::new(idx, 0), ColouredChar::new(*c)).unwrap();
|
||||
idx += 1
|
||||
});
|
||||
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
use crate::std::frame::{ColouredChar, Dimensions, Frame, Position};
|
||||
use crate::std::frame::{ColouredChar, Dimensions, Frame, Position, RenderError};
|
||||
|
||||
pub(crate) fn render_outline(frame: &mut Frame, dimensions: Dimensions) {
|
||||
pub(crate) fn render_outline(frame: &mut Frame, dimensions: Dimensions) -> Result<(), RenderError> {
|
||||
// draws the sides of the container
|
||||
for i in 0..frame.dimensions.x {
|
||||
frame.write(Position::new(i, 0), ColouredChar::new('─'));
|
||||
frame.write(Position::new(i, frame.dimensions.y - 1), ColouredChar::new('─'));
|
||||
frame.write(Position::new(i, 0), ColouredChar::new('─'))?;
|
||||
frame.write(Position::new(i, frame.dimensions.y - 1), ColouredChar::new('─'))?;
|
||||
}
|
||||
|
||||
// draws the top and bottom of the container
|
||||
for i in 0..frame.dimensions.y {
|
||||
frame.write(Position::new(0, i), ColouredChar::new('│'));
|
||||
frame.write(Position::new(frame.dimensions.x - 1, i), ColouredChar::new('│'));
|
||||
frame.write(Position::new(0, i), ColouredChar::new('│'))?;
|
||||
frame.write(Position::new(frame.dimensions.x - 1, i), ColouredChar::new('│'))?;
|
||||
}
|
||||
|
||||
// draws the corners of the container
|
||||
frame.write(Position::new(0, 0), ColouredChar::new('┌'));
|
||||
frame.write(Position::new(dimensions.x - 1, 0), ColouredChar::new('┐'));
|
||||
frame.write(Position::new(0, dimensions.y - 1), ColouredChar::new('└'));
|
||||
frame.write(Position::new(dimensions.x - 1, dimensions.y - 1), ColouredChar::new('┘'));
|
||||
frame.write(Position::new(0, 0), ColouredChar::new('┌'))?;
|
||||
frame.write(Position::new(dimensions.x - 1, 0), ColouredChar::new('┐'))?;
|
||||
frame.write(Position::new(0, dimensions.y - 1), ColouredChar::new('└'))?;
|
||||
frame.write(Position::new(dimensions.x - 1, dimensions.y - 1), ColouredChar::new('┘'))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
|
||||
use alloc::fmt::format;
|
||||
use alloc::{boxed::Box, format, string::String, vec::Vec};
|
||||
use alloc::string::ToString;
|
||||
use core::any::Any;
|
||||
use core::cmp::{max, min};
|
||||
use async_trait::async_trait;
|
||||
use hashbrown::HashMap;
|
||||
use crate::serial_println;
|
||||
use crate::std::application::Exit;
|
||||
use super::cg_core::{CgComponent, CgKeyboardCapture, CgOutline, Widget};
|
||||
use super::cg_core::{CgComponent, CgKeyboardCapture, Widget};
|
||||
use super::cg_utils::render_outline;
|
||||
use crate::std::frame::{ColouredChar, Dimensions, Position, Frame, RenderError, ColorCode, BUFFER_WIDTH, BUFFER_HEIGHT};
|
||||
use crate::std::io::{Color, KeyStroke, Stdin};
|
||||
@@ -48,7 +46,7 @@ impl CgComponent for CgContainer {
|
||||
}
|
||||
|
||||
if self.outlined {
|
||||
render_outline(&mut result, self.dimensions.clone());
|
||||
render_outline(&mut result, self.dimensions.clone())?;
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
@@ -73,17 +71,18 @@ impl CgTextBox {
|
||||
CgTextBox { title, content, position, dimensions, outlined, wrap_words: true }
|
||||
}
|
||||
|
||||
fn render_title(&self, frame: &mut Frame) {
|
||||
fn render_title(&self, frame: &mut Frame) -> Result<(), RenderError>{
|
||||
let title = self.title.chars();
|
||||
for (i, c) in title.enumerate() {
|
||||
if i + 2 == self.dimensions.x - 3 { // we don't want to write at the top of the text box
|
||||
frame.write(Position::new(i + 1, 0), ColouredChar::new('.'));
|
||||
frame.write(Position::new(i + 1, 0), ColouredChar::new('.'))?;
|
||||
} else if i + 2 >= self.dimensions.x - 2 {
|
||||
frame.write(Position::new(i + 1, 0), ColouredChar::new('.'));
|
||||
frame.write(Position::new(i + 1, 0), ColouredChar::new('.'))?;
|
||||
break;
|
||||
}
|
||||
frame.write(Position::new(i + 2, 0), ColouredChar::new(c));
|
||||
}
|
||||
frame.write(Position::new(i + 2, 0), ColouredChar::new(c))?;
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
pub fn wrap_words(&mut self, wrap: bool) {
|
||||
self.wrap_words = wrap;
|
||||
@@ -95,10 +94,10 @@ impl CgComponent for CgTextBox {
|
||||
let mut result = Frame::new(self.position, self.dimensions)?;
|
||||
|
||||
if self.outlined {
|
||||
render_outline(&mut result, self.dimensions.clone());
|
||||
render_outline(&mut result, self.dimensions.clone())?;
|
||||
}
|
||||
|
||||
self.render_title(&mut result);
|
||||
self.render_title(&mut result)?;
|
||||
|
||||
let (mut x, mut y) = (1, 1);
|
||||
|
||||
@@ -123,13 +122,13 @@ impl CgComponent for CgTextBox {
|
||||
if y == self.dimensions.y - 1 {
|
||||
if c != ' ' {
|
||||
(2..5).for_each(|z| {
|
||||
result.write(Position::new(self.dimensions.x - z, self.dimensions.y - 1), ColouredChar::new('.'));
|
||||
result.write(Position::new(self.dimensions.x - z, self.dimensions.y - 1), ColouredChar::new('.')).unwrap();
|
||||
})
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
result.write(Position::new(x, y), ColouredChar::new(c));
|
||||
result.write(Position::new(x, y), ColouredChar::new(c))?;
|
||||
x += 1;
|
||||
};
|
||||
}
|
||||
@@ -180,11 +179,11 @@ impl CgComponent for CgLabel {
|
||||
for (i, c) in shortened_string.chars().enumerate() {
|
||||
if i + left >= self.dimensions.x {
|
||||
(0..3).for_each(|z| {
|
||||
result.write(Position::new(self.dimensions.x - z + left, self.dimensions.y - 1), ColouredChar::new('.'));
|
||||
result.write(Position::new(self.dimensions.x - z + left, self.dimensions.y - 1), ColouredChar::new('.')).expect("failed to write");
|
||||
});
|
||||
break;
|
||||
}
|
||||
result.write(Position::new(i + left, 0), ColouredChar::new(c));
|
||||
result.write(Position::new(i + left, 0), ColouredChar::new(c))?;
|
||||
};
|
||||
Ok(result)
|
||||
}
|
||||
@@ -235,7 +234,7 @@ impl CgComponent for CgIndicatorWidget {
|
||||
|
||||
let shortened_string = self.content.chars().take(self.max_width).collect::<String>();
|
||||
for (i, c) in shortened_string.chars().enumerate() {
|
||||
result.write(Position::new(i, 0), ColouredChar::coloured(c, self.colour));
|
||||
result.write(Position::new(i, 0), ColouredChar::coloured(c, self.colour)).expect("failed to render indicator widget");
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
@@ -419,7 +418,9 @@ impl CgComponent for CgDialog {
|
||||
|
||||
// now that we know the X and Y offsets, we can start to draw the frame
|
||||
let mut frame = Frame::new(Position::new(x_offset, y_offset), Dimensions::new(width, height))?;
|
||||
render_outline(&mut frame, Dimensions::new(width, height));
|
||||
if let Err(e) = render_outline(&mut frame, Dimensions::new(width, height)) {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
|
||||
// render title
|
||||
@@ -449,7 +450,7 @@ impl CgComponent for CgDialog {
|
||||
break;
|
||||
}
|
||||
|
||||
frame.write(Position::new(x, y), ColouredChar::new(c));
|
||||
frame.write(Position::new(x, y), ColouredChar::new(c)).unwrap();
|
||||
x += 1;
|
||||
};
|
||||
}
|
||||
@@ -462,7 +463,7 @@ impl CgComponent for CgDialog {
|
||||
frame.write(Position::new(button_x_offset + i, height - 3), ColouredChar {
|
||||
character: c,
|
||||
colour: ColorCode::new(Color::Cyan, Color::Black),
|
||||
});
|
||||
}).expect("failed to write to frame, perhaps buttons were placed wrongly or width too great");
|
||||
})
|
||||
}
|
||||
CgDialogType::Confirmation => {
|
||||
@@ -483,7 +484,7 @@ impl CgComponent for CgDialog {
|
||||
|
||||
let button_x_offset = (width - button_fmt.len()) / 2;
|
||||
button_fmt.into_iter().enumerate().for_each(|(i, c)| {
|
||||
frame.write(Position::new(button_x_offset + i, height - 3), c);
|
||||
frame.write(Position::new(button_x_offset + i, height - 3), c).expect("failed to write to frame, perhaps buttons were placed wrongly or width too great");
|
||||
})
|
||||
},
|
||||
CgDialogType::Selection(options) => {
|
||||
@@ -504,7 +505,7 @@ impl CgComponent for CgDialog {
|
||||
|
||||
let button_x_offset = (width - button_fmt.len()) / 2;
|
||||
button_fmt.into_iter().enumerate().for_each(|(i, c)| {
|
||||
frame.write(Position::new(button_x_offset + i, height - 3), c);
|
||||
frame.write(Position::new(button_x_offset + i, height - 3), c).expect("failed to write to frame, perhaps buttons were placed wrongly or width too great");
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user