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