- got text boxes fully working
- this includes text wrapping not cutting words in half (can be disabled using a method on the text box) - refactored frame.rs, cg_core.rs and cg_widgets.rs to avoid code reuse and duplication - created a simplified unified interface for rendering frames to the screen using the Frame struct provided by frame.rs instead of Element, FrameGen, etc. - moved all widgets from cg_core.rs to cg_widgets.rs - the label widget now works - also added CgIndicatorBar and CgIndicatorWidget widgets to eventually make a working status bar - refactored all applications in the system to use the new api to render to the screen
This commit is contained in:
+15
-13
@@ -6,6 +6,7 @@ use volatile::Volatile;
|
||||
use alloc::borrow::ToOwned;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use crate::kernel::render::RenderError::InvalidRenderMode;
|
||||
use crate::serial_println;
|
||||
use crate::std::io::Screen;
|
||||
|
||||
@@ -48,6 +49,14 @@ pub struct ScreenChar {
|
||||
pub colour: ColorCode,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum RenderError {
|
||||
OutOfBounds(bool, bool), // (bool, bool) refers to x and y respectively
|
||||
InvalidCharacter,
|
||||
InvalidColour,
|
||||
InvalidRenderMode,
|
||||
}
|
||||
|
||||
impl ScreenChar {
|
||||
pub fn null() -> ScreenChar {
|
||||
ScreenChar {
|
||||
@@ -108,7 +117,6 @@ impl Renderer {
|
||||
pub fn render_frame(&mut self, frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT]) { // renders the given frame to the app buffer
|
||||
let mut processed_frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
|
||||
|
||||
|
||||
for (i, row) in frame.iter().enumerate() {
|
||||
for (j, col) in row.iter().enumerate() {
|
||||
processed_frame[i][j] = match special_char(col.character as char) {
|
||||
@@ -128,9 +136,9 @@ impl Renderer {
|
||||
self.internal_render();
|
||||
}
|
||||
|
||||
pub fn application_mode(&mut self) -> Result<(), ()> {
|
||||
pub fn application_mode(&mut self) -> Result<(), RenderError> {
|
||||
if self.application_mode {
|
||||
return Err(());
|
||||
return Err(InvalidRenderMode);
|
||||
} else {
|
||||
self.application_mode = true;
|
||||
self.internal_render();
|
||||
@@ -138,9 +146,9 @@ impl Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn terminal_mode(&mut self) -> Result<(), ()> {
|
||||
pub fn terminal_mode(&mut self) -> Result<(), RenderError> {
|
||||
if !self.application_mode {
|
||||
return Err(());
|
||||
return Err(InvalidRenderMode);
|
||||
} else {
|
||||
self.application_mode = false;
|
||||
self.internal_render();
|
||||
@@ -172,7 +180,7 @@ impl Renderer {
|
||||
self.internal_render();
|
||||
}
|
||||
|
||||
pub fn backspace(&mut self) -> Result<(), ()> {
|
||||
pub fn backspace(&mut self) -> Result<(), RenderError> {
|
||||
if self.application_mode { return Ok(()); };
|
||||
|
||||
loop {
|
||||
@@ -218,7 +226,7 @@ impl Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
fn internal_backspace(&mut self) -> Result<bool, ()> {
|
||||
fn internal_backspace(&mut self) -> Result<bool, RenderError> {
|
||||
let mut should_break = false;
|
||||
|
||||
if self.col_pos == 0 {
|
||||
@@ -327,12 +335,6 @@ pub fn special_char(ch: char) -> Option<u8> {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
impl fmt::Write for Renderer {
|
||||
fn write_str(&mut self, string: &str) -> fmt::Result {
|
||||
self.write_string(string, None);
|
||||
|
||||
+190
-121
@@ -1,9 +1,11 @@
|
||||
use alloc::string::String;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use lazy_static::lazy_static;
|
||||
use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER, ScreenChar};
|
||||
use crate::println;
|
||||
use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, ColorCode, RENDERER, ScreenChar};
|
||||
use crate::{println, serial_println};
|
||||
use spin::Mutex;
|
||||
use crate::std::io::{Color, Screen};
|
||||
|
||||
/// TODO: get a working implementation for CLI apps
|
||||
/// elements can be created using their from_str() method
|
||||
@@ -13,145 +15,212 @@ use spin::Mutex;
|
||||
/// nothing will appear on the screen until the frame is actually rendered by
|
||||
/// the render_frame method on the renderer
|
||||
|
||||
pub use crate::system::kernel::render::special_char;
|
||||
pub use crate::system::kernel::render::{special_char, RenderError};
|
||||
|
||||
|
||||
pub type Frame = [ [ ScreenChar; BUFFER_WIDTH ]; BUFFER_HEIGHT];
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Element {
|
||||
frame: Vec<Vec<char>>,
|
||||
dimensions: (u8, u8)
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct ColouredChar {
|
||||
pub character: char,
|
||||
pub colour: ColorCode,
|
||||
}
|
||||
|
||||
impl Element {
|
||||
impl ColouredChar {
|
||||
pub fn coloured(character: char, colour: ColorCode) -> ColouredChar {
|
||||
ColouredChar { character, colour }
|
||||
}
|
||||
pub fn new(character: char) -> ColouredChar {
|
||||
ColouredChar {
|
||||
character,
|
||||
colour: ColorCode::new(Color::White, Color::Black),
|
||||
}
|
||||
}
|
||||
pub fn null() -> ColouredChar {
|
||||
ColouredChar {
|
||||
character: ' ',
|
||||
colour: ColorCode::new(Color::White, Color::Black),
|
||||
}
|
||||
}
|
||||
pub fn as_screen_char(&self) -> ScreenChar {
|
||||
ScreenChar {
|
||||
character: {
|
||||
if let Some(c) = special_char(self.character) {
|
||||
c
|
||||
} else {
|
||||
self.character as u8
|
||||
}
|
||||
},
|
||||
colour: self.colour,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Position {
|
||||
pub x: usize,
|
||||
pub y: usize,
|
||||
}
|
||||
|
||||
impl Position {
|
||||
pub fn new(x: usize, y: usize) -> Position {
|
||||
Position { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
pub type Dimensions = Position;
|
||||
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Frame {
|
||||
pub position: Position,
|
||||
pub dimensions: Dimensions,
|
||||
pub frame: Vec<Vec<ColouredChar>>,
|
||||
}
|
||||
|
||||
|
||||
impl Frame {
|
||||
pub fn new(position: Position, dimensions: Dimensions) -> Result<Frame, RenderError> {
|
||||
Ok(Frame {
|
||||
position,
|
||||
dimensions,
|
||||
frame: vec![vec![ColouredChar::null(); dimensions.x]; dimensions.y],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_str(elemstr: String) -> Self {
|
||||
let mut element = Element { frame: Vec::<Vec<char>>::new(), dimensions: (0, 0) };
|
||||
let mut element = Frame { frame: Vec::<Vec<ColouredChar>>::new(), dimensions: Dimensions::new(0, 0), position: Position::new(0, 0) };
|
||||
|
||||
for line in elemstr.split("\n") {
|
||||
let mut ln = Vec::<char>::new();
|
||||
for col in line.chars() {
|
||||
ln.push(col)
|
||||
};
|
||||
element.frame.push(ln);
|
||||
element.frame.push(
|
||||
line
|
||||
.chars()
|
||||
.map(|c| ColouredChar::new(c))
|
||||
.collect::<Vec<ColouredChar>>()
|
||||
);
|
||||
}
|
||||
|
||||
for row in element.clone().frame {
|
||||
let n = row.len();
|
||||
if n > element.dimensions.0 as usize {
|
||||
element.dimensions.0 = n as u8;
|
||||
if n > element.dimensions.x as usize {
|
||||
element.dimensions.x = n;
|
||||
}
|
||||
}
|
||||
element
|
||||
}
|
||||
|
||||
pub fn generate(frame: Vec::<Vec<char>>, dims: (u8, u8)) -> Self {
|
||||
Element { frame, dimensions: dims }
|
||||
pub fn render(&self) -> Vec<Vec<ColouredChar>> {
|
||||
self.frame.clone()
|
||||
}
|
||||
|
||||
pub fn render(&mut self, pos: (u8, u8)) { // x,y
|
||||
for (i, row) in self.frame.iter().enumerate() {
|
||||
for (j, col) in row.iter().enumerate() {
|
||||
//println!("{} {} {}", i, j, col);
|
||||
FRAMEGEN.lock().frame[i + pos.1 as usize][j + pos.0 as usize] = ScreenChar::white(*col as u8);
|
||||
};
|
||||
}
|
||||
FRAMEGEN.lock().render_frame();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ColouredElement {
|
||||
pub frame: Vec<Vec<ScreenChar>>,
|
||||
pub dimensions: (u8, u8)
|
||||
}
|
||||
|
||||
impl ColouredElement {
|
||||
pub fn from_str(elemstr: String) -> Self {
|
||||
let mut element = ColouredElement { frame: Vec::<Vec<ScreenChar>>::new(), dimensions: (0, 0) };
|
||||
|
||||
for line in elemstr.split("\n") {
|
||||
let mut ln = Vec::<ScreenChar>::new();
|
||||
for col in line.chars() {
|
||||
ln.push(ScreenChar::white(col as u8))
|
||||
};
|
||||
element.frame.push(ln);
|
||||
}
|
||||
|
||||
for row in element.clone().frame {
|
||||
let n = row.len();
|
||||
if n > element.dimensions.0 as usize {
|
||||
element.dimensions.0 = n as u8;
|
||||
}
|
||||
}
|
||||
element
|
||||
}
|
||||
|
||||
pub fn generate(frame: Vec::<Vec<ScreenChar>>, dims: (u8, u8)) -> Self {
|
||||
ColouredElement { frame, dimensions: dims }
|
||||
}
|
||||
|
||||
pub fn render(&mut self, pos: (u8, u8)) -> Result<(), ()> { // x,y
|
||||
|
||||
// this block returns an error if any characters will be drawn out of the bounds of the screen
|
||||
if self.dimensions.0 + pos.0 > BUFFER_WIDTH as u8 {
|
||||
return Err(());
|
||||
} else if self.dimensions.1 + pos.1 > BUFFER_HEIGHT as u8 {
|
||||
return Err(());
|
||||
} else if self.frame.len() != self.dimensions.1 as usize {
|
||||
return Err(())
|
||||
} else if self.frame.iter().map(|r| r.len()).max().ok_or_else(|| ())? > self.dimensions.0 as usize {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
for (i, row) in self.frame.iter().enumerate() {
|
||||
for (j, col) in row.iter().enumerate() {
|
||||
//println!("{} {} {}", i, j, col);
|
||||
FRAMEGEN.lock().frame[i + pos.1 as usize][j + pos.0 as usize] = *col;
|
||||
};
|
||||
}
|
||||
FRAMEGEN.lock().render_frame();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FrameGen {
|
||||
frame: Frame,
|
||||
}
|
||||
|
||||
|
||||
impl FrameGen {
|
||||
pub fn render_frame(&self) {
|
||||
RENDERER.lock().render_frame(self.frame)
|
||||
}
|
||||
|
||||
fn new() -> Self {
|
||||
pub fn render_to_screen(&self) -> Result<(), RenderError> {
|
||||
let mut frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
|
||||
Self { frame: Frame::from(frame) }
|
||||
}
|
||||
|
||||
fn set_frame(&mut self, frame: Frame) {
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
pub fn get_frame(&self) -> &[ [ ScreenChar; BUFFER_WIDTH ]; BUFFER_HEIGHT] {
|
||||
&self.frame
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref FRAMEGEN: Mutex<FrameGen> = Mutex::new(FrameGen::new() );
|
||||
}
|
||||
|
||||
|
||||
impl core::fmt::Display for FrameGen {
|
||||
fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
println!(" ");
|
||||
for row in &self.frame {
|
||||
println!("{}", row.iter().map(|c| c.character as char ).collect::<String>());
|
||||
};
|
||||
for (i, row) in self.frame.iter().enumerate() {
|
||||
for (j, col) in row.iter().enumerate() {
|
||||
//println!("{} {} {}", i, j, col);
|
||||
frame[i + self.position.y as usize][j + self.position.x as usize] = col.as_screen_char();
|
||||
};
|
||||
}
|
||||
RENDERER.lock().render_frame(frame);
|
||||
Ok(())
|
||||
}
|
||||
pub fn position(&self) -> Position {
|
||||
self.position
|
||||
}
|
||||
|
||||
pub fn set_position(&mut self, position: Position) {
|
||||
self.position = position
|
||||
}
|
||||
pub fn dimensions(&self) -> Dimensions {
|
||||
self.dimensions
|
||||
}
|
||||
pub fn write_pos(&mut self, position: Position, char: ColouredChar) {
|
||||
self.frame[position.y][position.x] = char
|
||||
}
|
||||
pub fn render_element(&mut self, other: &Frame) {
|
||||
for (i, row) in other.frame.iter().enumerate() {
|
||||
for (j, chr) in row.iter().enumerate() {
|
||||
self.frame[i + other.position.y][j + other.position.x] = *chr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_bounds_check(&self, element: &Frame, should_panic: bool) -> Result<(), RenderError> {
|
||||
|
||||
let (mut x, mut y) = (false, false);
|
||||
|
||||
if element.dimensions().x + element.position().x > self.dimensions.x {
|
||||
if should_panic { panic!(
|
||||
"Element is to large to be rendered {} {}",
|
||||
element.dimensions().x + element.position().x,
|
||||
self.dimensions.x
|
||||
)} else {
|
||||
x = true;
|
||||
}
|
||||
}
|
||||
|
||||
if element.dimensions().y + element.position().y > self.dimensions.y {
|
||||
if should_panic { panic!(
|
||||
"Element is to large to be rendered {} {}",
|
||||
element.dimensions().y + element.position().y,
|
||||
self.dimensions.y
|
||||
)} else {
|
||||
y = true;
|
||||
}
|
||||
}
|
||||
|
||||
if x || y {
|
||||
Err(RenderError::OutOfBounds(x, y))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Index<usize> for Frame {
|
||||
type Output = Vec<ColouredChar>;
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
&self.frame[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::IndexMut<usize> for Frame {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
&mut self.frame[index]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ use alloc::{borrow::ToOwned, format, string::{String, ToString}, vec::Vec, boxed
|
||||
use crate::{
|
||||
std::{
|
||||
io::{self, println, serial_println},
|
||||
frame::FRAMEGEN,
|
||||
random,
|
||||
},
|
||||
std::application::{
|
||||
@@ -18,8 +17,6 @@ use crate::{
|
||||
Error,
|
||||
},
|
||||
};
|
||||
use crate::system::std::frame::Element;
|
||||
|
||||
|
||||
pub struct GameLoop;
|
||||
|
||||
@@ -61,7 +58,7 @@ impl Application for GameLoop {
|
||||
println!("[{}\n[{}", player, enemy);
|
||||
}
|
||||
|
||||
FRAMEGEN.lock().render_frame();
|
||||
// FRAMEGEN.lock().render_frame();
|
||||
|
||||
|
||||
let string = String::from(format!(
|
||||
@@ -70,34 +67,34 @@ impl Application for GameLoop {
|
||||
│ {} / {}
|
||||
└────────────────────────────┘"
|
||||
, player.username, player.health_points, player.max_health_points));
|
||||
let mut healthbar = Element::from_str(string);
|
||||
healthbar.render((1, 1));
|
||||
|
||||
let new2 = String::from("[an element]");
|
||||
let mut new = Element::from_str(new2);
|
||||
|
||||
|
||||
new.render((10, 10));
|
||||
new.render((10, 15));
|
||||
new.render((5, 20));
|
||||
new.render((34, 16));
|
||||
|
||||
|
||||
FRAMEGEN.lock().render_frame();
|
||||
|
||||
let fr = FRAMEGEN.lock().get_frame().to_owned();
|
||||
serial_println!("{}", {
|
||||
let mut string = String::new();
|
||||
for row in fr {
|
||||
let mut r = String::new();
|
||||
for col in row {
|
||||
r.push(col.character as char);
|
||||
}
|
||||
string.push_str(&r);
|
||||
string.push('\n')
|
||||
};
|
||||
string
|
||||
});
|
||||
// let mut healthbar = Element::from_str(string);
|
||||
// healthbar.render((1, 1));
|
||||
//
|
||||
// let new2 = String::from("[an element]");
|
||||
// let mut new = Element::from_str(new2);
|
||||
//
|
||||
//
|
||||
// new.render((10, 10));
|
||||
// new.render((10, 15));
|
||||
// new.render((5, 20));
|
||||
// new.render((34, 16));
|
||||
//
|
||||
//
|
||||
// FRAMEGEN.lock().render_frame();
|
||||
//
|
||||
// let fr = FRAMEGEN.lock().get_frame().to_owned();
|
||||
// serial_println!("{}", {
|
||||
// let mut string = String::new();
|
||||
// for row in fr {
|
||||
// let mut r = String::new();
|
||||
// for col in row {
|
||||
// r.push(col.character as char);
|
||||
// }
|
||||
// string.push_str(&r);
|
||||
// string.push('\n')
|
||||
// };
|
||||
// string
|
||||
// });
|
||||
|
||||
|
||||
loop {
|
||||
|
||||
+33
-21
@@ -5,15 +5,15 @@ use alloc::vec::Vec;
|
||||
use alloc::boxed::Box;
|
||||
use crate::std::application::{Application, Error};
|
||||
use async_trait::async_trait;
|
||||
use crate::kernel::render::{Color, ColorCode, ScreenChar};
|
||||
use crate::kernel::render::{Color, ColorCode};
|
||||
use crate::{println, serial_println};
|
||||
use crate::std::frame::ColouredElement;
|
||||
use crate::std::frame::{ColouredChar, Frame, Position, Dimensions, RenderError};
|
||||
use crate::std::io::{Screen, Stdin};
|
||||
use crate::std::time::wait;
|
||||
use crate::user::bin::snake::Game;
|
||||
|
||||
pub struct GameOfLife {
|
||||
frame: [[ScreenChar; 80]; 25],
|
||||
frame: Frame
|
||||
}
|
||||
|
||||
const LOOP_SPEED: f64 = 0.1;
|
||||
@@ -22,7 +22,7 @@ const LOOP_SPEED: f64 = 0.1;
|
||||
impl Application for GameOfLife {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
frame: [[ScreenChar::null(); 80]; 25],
|
||||
frame: Frame::new(Position::new(0, 0), Dimensions::new(80, 25)).unwrap()
|
||||
}
|
||||
}
|
||||
async fn run(&mut self, args: Vec<String>) -> Result<(), Error> {
|
||||
@@ -65,7 +65,7 @@ impl Application for GameOfLife {
|
||||
|
||||
impl GameOfLife {
|
||||
fn activate(&mut self, x: u8, y: u8) {
|
||||
self.frame[24 - y as usize][x as usize] = ScreenChar::new('#' as u8, ColorCode::new(Color::Green, Color::Black));
|
||||
self.frame[24 - y as usize][x as usize] = ColouredChar::coloured('#', ColorCode::new(Color::Green, Color::Black));
|
||||
}
|
||||
fn mainloop(&mut self) -> Result<(), Error> {
|
||||
'mainloop: loop {
|
||||
@@ -81,43 +81,55 @@ impl GameOfLife {
|
||||
|
||||
// TODO: Logic goes here
|
||||
|
||||
let mut new_frame = [[ScreenChar::null(); 80]; 25];
|
||||
let mut frame = Frame::new(Position::new(0, 0), Dimensions::new(80, 25)).unwrap();
|
||||
|
||||
self.frame.iter().enumerate().for_each(|(y, row)| row.iter().enumerate().for_each(|(x, chr)| {
|
||||
new_frame[y][x] = self.get_new_value(x as u8, y as u8);
|
||||
self.frame.frame.iter().enumerate().for_each(|(y, row)| row.iter().enumerate().for_each(|(x, chr)| {
|
||||
frame[y][x] = self.get_new_value(x as u8, y as u8);
|
||||
}));
|
||||
|
||||
self.frame = new_frame;
|
||||
self.frame = frame;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_new_value(&self, x: u8, y: u8) -> ScreenChar {
|
||||
fn get_new_value(&self, x: u8, y: u8) -> ColouredChar {
|
||||
let adjacent = vec![(0i32, 1i32), (0, -1), (1, 0), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)].into_iter().map(|(relx, rely)| {
|
||||
(x as i32 + relx, y as i32 + rely)
|
||||
}).filter(|(absx, absy)| {
|
||||
0 <= *absx && *absx < 80 && 0 <= *absy && *absy < 25
|
||||
}).collect::<Vec<(i32, i32)>>();
|
||||
|
||||
let alive = adjacent.iter().filter(|(x, y)| self.frame[*y as usize][*x as usize] == ScreenChar::new('#' as u8, ColorCode::new(Color::Green, Color::Black))).count();
|
||||
let alive = adjacent.iter().filter(|(x, y)| self.frame[*y as usize][*x as usize] == ColouredChar::coloured('#', ColorCode::new(Color::Green, Color::Black))).count();
|
||||
|
||||
if alive == 2 {
|
||||
if self.frame[y as usize][x as usize] == ScreenChar::new('#' as u8, ColorCode::new(Color::Green, Color::Black)) {
|
||||
return ScreenChar::new('#' as u8, ColorCode::new(Color::Green, Color::Black));
|
||||
if self.frame[y as usize][x as usize] == ColouredChar::coloured('#', ColorCode::new(Color::Green, Color::Black)) {
|
||||
return ColouredChar::coloured('#', ColorCode::new(Color::Green, Color::Black));
|
||||
} else {
|
||||
return ScreenChar::null();
|
||||
return ColouredChar::null();
|
||||
}
|
||||
} else if alive == 3 {
|
||||
ScreenChar::new('#' as u8, ColorCode::new(Color::Green, Color::Black))
|
||||
ColouredChar::coloured('#', ColorCode::new(Color::Green, Color::Black))
|
||||
} else {
|
||||
ScreenChar::null()
|
||||
ColouredChar::null()
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&self) -> Result<(), ()> {
|
||||
let cloned_frame = self.frame.iter().map(|r| r.iter().map(|c| c.clone()).collect::<Vec<ScreenChar>>()).collect::<Vec<Vec<ScreenChar>>>();
|
||||
let mut elem = ColouredElement::generate(cloned_frame, (80, 25));
|
||||
elem.render((0,0));
|
||||
fn render(&self) -> Result<(), RenderError> {
|
||||
self.frame.render_to_screen()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@ use alloc::{format, vec};
|
||||
use alloc::vec::Vec;
|
||||
use alloc::boxed::Box;
|
||||
use async_trait::async_trait;
|
||||
use crate::println;
|
||||
use crate::{println, serial_println};
|
||||
use crate::shell::command_handler;
|
||||
use crate::std::application::{Application, Error};
|
||||
use crate::std::frame::Element;
|
||||
use crate::std::frame::{self, Frame, Position, Dimensions, ColouredChar};
|
||||
use crate::std::io::{Screen, Stdin};
|
||||
|
||||
const OFFSET_X: i64 = 40;
|
||||
@@ -14,7 +14,7 @@ const OFFSET_Y: i64 = 12;
|
||||
|
||||
pub struct Grapher {
|
||||
points: Vec<PointF64>,
|
||||
frame: Vec<Vec<char>>,
|
||||
frame: Frame,
|
||||
}
|
||||
|
||||
struct PointF64 {
|
||||
@@ -32,7 +32,7 @@ impl Application for Grapher {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
points: Vec::new(),
|
||||
frame: vec![vec![' '; 80]; 25],
|
||||
frame: Frame::new(Position::new(0, 0), Dimensions::new(80, 25)).unwrap()
|
||||
}
|
||||
}
|
||||
async fn run(&mut self, args: Vec<String>) -> Result<(), Error> {
|
||||
@@ -89,12 +89,13 @@ impl Grapher {
|
||||
let offset_x = point.x + OFFSET_X;
|
||||
let offset_y = point.y + OFFSET_Y;
|
||||
|
||||
self.frame[24-offset_y as usize][offset_x as usize] = '*';
|
||||
// serial_println!("{} {}", 24-offset_y as usize, offset_x as usize);
|
||||
|
||||
self.frame.write_pos(Position::new(offset_x as usize, 24-offset_y as usize), ColouredChar::new('*'));
|
||||
}
|
||||
|
||||
|
||||
fn display(&mut self) {
|
||||
let mut elem = Element::generate(self.frame.clone(), (80, 25));
|
||||
elem.render((0, 0));
|
||||
self.frame.render_to_screen().unwrap();
|
||||
}
|
||||
}
|
||||
+27
-33
@@ -1,24 +1,22 @@
|
||||
use async_trait::async_trait;
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::interrupts;
|
||||
|
||||
use alloc::{boxed::Box, string::{String, ToString}, vec, vec::Vec};
|
||||
use vga::writers::{GraphicsWriter, PrimitiveDrawing};
|
||||
|
||||
use crate::{print, printerr, println, serial_println, std, std::application::{Application, Error}, user::bin::*};
|
||||
use crate::kernel::render::ScreenChar;
|
||||
use crate::std::frame::ColouredElement;
|
||||
use crate::kernel::render::ColorCode;
|
||||
use crate::std::frame::{Dimensions, Position};
|
||||
use crate::std::io::{Color, write, Screen, Stdin, Serial};
|
||||
use crate::std::random::Random;
|
||||
use crate::user::bin::gigachad_detector::GigachadDetector;
|
||||
use crate::user::bin::grapher::Grapher;
|
||||
use crate::user::lib::libgui;
|
||||
use crate::user::lib::libgui::{
|
||||
cg_core::{Frame, Position, Dimensions, CgComponent},
|
||||
cg_core::{CgComponent},
|
||||
cg_widgets::{CgTextBox, CgContainer},
|
||||
};
|
||||
use crate::user::lib::libgui::cg_widgets::CgLabel;
|
||||
use crate::user::lib::libgui::cg_widgets::{CgIndicatorBar, CgIndicatorWidget, CgLabel};
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CMD: Mutex<CommandHandler> = Mutex::new(CommandHandler::new());
|
||||
@@ -44,7 +42,7 @@ pub async fn eventloop() {
|
||||
CMD.lock().prompt();
|
||||
|
||||
loop {
|
||||
let string = crate::std::io::Stdin::readline().await;
|
||||
let string = Stdin::readline().await;
|
||||
CMD.lock().current.push_str(&string);
|
||||
match exec().await {
|
||||
Ok(_) => {
|
||||
@@ -187,53 +185,49 @@ async fn exec() -> Result<(), Error> {
|
||||
"test_features" => {
|
||||
std::io::Screen::application_mode();
|
||||
|
||||
serial_println!("OK");
|
||||
|
||||
let textbox = CgTextBox::new(
|
||||
String::from("i'd just like to interject for a moment"),
|
||||
String::from("I'd just like to interject for a moment. What you're refering to as Linux, is in fact, GNU/Linux, or as I've recently taken to calling it, GNU plus Linux. Linux is not an operating system unto itself, but rather another free component of a fully functioning GNU system made useful by the GNU corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX. Many computer users run a modified version of the GNU system every day, without realizing it. Through a peculiar turn of events, the version of GNU which is widely used today is often called Linux, and many of its users are not aware that it is basically the GNU system, developed by the GNU Project. There really is a Linux, and these people are using it, but it is just a part of the system they use. Linux is the kernel: the program in the system that allocates the machine's resources to the other programs that you run. The kernel is an essential part of an operating system, but useless by itself; it can only function in the context of a complete operating system. Linux is normally used in combination with the GNU operating system: the whole system is basically GNU with Linux added, or GNU/Linux. All the so-called Linux distributions are really distributions of GNU/Linux!"),
|
||||
Position::new(2, 2),
|
||||
Position::new(2, 5),
|
||||
Dimensions::new(40, 12),
|
||||
true,
|
||||
);
|
||||
|
||||
let textbox2 = CgTextBox::new(
|
||||
String::from("i'd just like to interject for a moment"),
|
||||
String::from("I'd just like to interject for a moment. What you're refering to as Linux, is in fact, GNU/Linux, or as I've recently taken to calling it, GNU plus Linux. Linux is not an operating system unto itself, but rather another free component of a fully functioning GNU system made useful by the GNU corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX. Many computer users run a modified version of the GNU system every day, without realizing it. Through a peculiar turn of events, the version of GNU which is widely used today is often called Linux, and many of its users are not aware that it is basically the GNU system, developed by the GNU Project. There really is a Linux, and these people are using it, but it is just a part of the system they use. Linux is the kernel: the program in the system that allocates the machine's resources to the other programs that you run. The kernel is an essential part of an operating system, but useless by itself; it can only function in the context of a complete operating system. Linux is normally used in combination with the GNU operating system: the whole system is basically GNU with Linux added, or GNU/Linux. All the so-called Linux distributions are really distributions of GNU/Linux!"),
|
||||
Position::new(10, 5),
|
||||
Dimensions::new(40, 12),
|
||||
true,
|
||||
let mut indicatorbar = CgIndicatorBar::new(
|
||||
Position::new(0, 0),
|
||||
80
|
||||
);
|
||||
|
||||
|
||||
let mut label = CgLabel::new(
|
||||
String::from("i'd just like to interject for a moment"),
|
||||
Position::new(5, 16),
|
||||
15,
|
||||
let mut w1 = CgIndicatorWidget::new(
|
||||
String::from("test"),
|
||||
5
|
||||
);
|
||||
|
||||
let mut w2 = CgIndicatorWidget::new(
|
||||
String::from("widget 2"),
|
||||
20
|
||||
);
|
||||
w2.set_colour(ColorCode::new(Color::Cyan, Color::Black));
|
||||
|
||||
indicatorbar.fields.push(w1);
|
||||
indicatorbar.fields.push(w2);
|
||||
|
||||
let mut container = CgContainer::new(
|
||||
Position::new(2, 2),
|
||||
Dimensions::new(65, 20),
|
||||
true,
|
||||
Position::new(0, 0),
|
||||
Dimensions::new(80, 25),
|
||||
false,
|
||||
);
|
||||
|
||||
container.elements.push(Box::new(textbox));
|
||||
container.elements.push(Box::new(textbox2));
|
||||
container.elements.push(Box::new(label));
|
||||
container.elements.push(Box::new(indicatorbar));
|
||||
|
||||
let res = if let Ok(frame) = container.render() {
|
||||
frame
|
||||
if let Ok(frame) = container.render() {
|
||||
frame.render_to_screen().unwrap();
|
||||
} else {
|
||||
return Err(Error::CommandFailed("failed to render frame".to_string()))
|
||||
};
|
||||
|
||||
let mut elem = ColouredElement::generate(
|
||||
res.render_screen_char(),
|
||||
(res.dimensions().x as u8, res.dimensions().y as u8),
|
||||
);
|
||||
|
||||
elem.render((0, 0)).unwrap();
|
||||
|
||||
//std::io::Screen::terminal_mode();
|
||||
|
||||
|
||||
+19
-19
@@ -12,8 +12,9 @@ use lazy_static::lazy_static;
|
||||
use crate::kernel::render::{ColorCode, ScreenChar};
|
||||
use crate::{println, serial_println};
|
||||
use crate::std::application::{Application, Error};
|
||||
use crate::std::frame::{ColouredChar, Dimensions, Frame, RenderError};
|
||||
use crate::std::random::Random;
|
||||
use crate::system::std::frame::ColouredElement;
|
||||
use crate::system::std::frame;
|
||||
use super::super::lib::coords::{Line, Position, Direction};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
@@ -171,35 +172,34 @@ impl Game {
|
||||
self.new_poi();
|
||||
}
|
||||
|
||||
fn render(&mut self) -> Result<(), ()> {
|
||||
let mut frame = vec![vec![ScreenChar::null(); 80]; 25];
|
||||
fn render(&mut self) -> Result<(), RenderError> {
|
||||
|
||||
let mut frame = Frame::new(frame::Position::new(0, 0), Dimensions::new(80, 25))?;
|
||||
let mut curr_colour = ColorCode::new(Color::LightBlue, Color::Black);
|
||||
|
||||
for s in self.snakes.clone() {
|
||||
curr_colour = if s.ai_controlled {
|
||||
ColorCode::new(Color::Cyan, Color::Black)
|
||||
} else {
|
||||
ColorCode::new(Color::LightGreen, Color::Black)
|
||||
curr_colour = match s.ai_controlled {
|
||||
true => ColorCode::new(Color::Cyan, Color::Black),
|
||||
false => ColorCode::new(Color::LightGreen, Color::Black),
|
||||
};
|
||||
for point in s.tail.iter() {
|
||||
frame[24 - point.y as usize][point.x as usize] = ScreenChar::new('@' as u8, curr_colour);
|
||||
frame[24 - point.y as usize][point.x as usize] = ColouredChar::coloured('@', curr_colour);
|
||||
}
|
||||
}
|
||||
|
||||
self.pois.iter().for_each(|poi| {
|
||||
frame[24 - poi.y as usize][poi.x as usize] = ScreenChar::new('o' as u8, ColorCode::new(Color::Red, Color::Black));
|
||||
frame[24 - poi.y as usize][poi.x as usize] = ColouredChar::coloured('o', ColorCode::new(Color::Red, Color::Black));
|
||||
});
|
||||
|
||||
let literal = format!("snake go brr score: {}", self.score);
|
||||
let msg = Game::centre_text(80, literal);
|
||||
msg.chars().enumerate().for_each(|(i, c)| {
|
||||
if c != ' ' {
|
||||
frame[1][i] = ScreenChar::new(c as u8, ColorCode::new(Color::LightGreen, Color::Black))
|
||||
frame[1][i] = ColouredChar::coloured(c, ColorCode::new(Color::LightGreen, Color::Black))
|
||||
}
|
||||
});
|
||||
|
||||
let mut elem = ColouredElement::generate(frame, (80, 25));
|
||||
elem.render((0,0));
|
||||
frame.render_to_screen()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -214,15 +214,15 @@ impl Game {
|
||||
msg
|
||||
}
|
||||
|
||||
fn render_end_screen(&mut self) -> Result<(), ()> {
|
||||
let mut frame = vec![vec![ScreenChar::null(); 80]; 25];
|
||||
fn render_end_screen(&mut self) -> Result<(), RenderError> {
|
||||
let mut frame = Frame::new(frame::Position::new(0, 0), Dimensions::new(80, 25))?;
|
||||
|
||||
frame[10] = Game::centre_text(80, String::from("u lost")).chars().map(|c| ScreenChar::new(c as u8, ColorCode::new(Color::Red, Color::Black))).collect();
|
||||
frame[12] = Game::centre_text(80, String::from(format!("ur score was {}", self.score))).chars().map(|c| ScreenChar::new(c as u8, ColorCode::new(Color::LightGreen, Color::Black))).collect();
|
||||
frame[14] = Game::centre_text(80, String::from("L bozo")).chars().map(|c| ScreenChar::new(c as u8, ColorCode::new(Color::Red, Color::Black))).collect();
|
||||
frame[10] = Game::centre_text(80, String::from("u lost")).chars().map(|c| ColouredChar::coloured(c, ColorCode::new(Color::Red, Color::Black))).collect();
|
||||
frame[12] = Game::centre_text(80, String::from(format!("ur score was {}", self.score))).chars().map(|c| ColouredChar::coloured(c, ColorCode::new(Color::LightGreen, Color::Black))).collect();
|
||||
frame[14] = Game::centre_text(80, String::from("L bozo")).chars().map(|c| ColouredChar::coloured(c, ColorCode::new(Color::Red, Color::Black))).collect();
|
||||
|
||||
let mut elem = ColouredElement::generate(frame, (80, 25));
|
||||
elem.render((0,0))
|
||||
frame.render_to_screen()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ 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};
|
||||
use crate::user::lib::libgui_old_archive::libgui_core::Pos;
|
||||
|
||||
|
||||
pub(crate) struct TetrisEngine {
|
||||
|
||||
@@ -3,201 +3,18 @@ use alloc::string::String;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::slice::from_mut;
|
||||
use crate::kernel::render::{ColorCode, ScreenChar};
|
||||
use crate::kernel::render::{ColorCode, RenderError, ScreenChar};
|
||||
use crate::{printerr, serial_println};
|
||||
use crate::std::frame::special_char;
|
||||
use crate::std::io::Color;
|
||||
use crate::user::lib::libgui::cg_core::XorY::Both;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Position {
|
||||
pub x: usize,
|
||||
pub y: usize,
|
||||
}
|
||||
|
||||
impl Position {
|
||||
pub fn new(x: usize, y: usize) -> Position {
|
||||
Position { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum XorY {
|
||||
X,
|
||||
Y,
|
||||
Both,
|
||||
None,
|
||||
}
|
||||
use crate::std::frame::{ColouredChar, Dimensions, Position, special_char, Frame};
|
||||
|
||||
|
||||
impl XorY {
|
||||
pub fn setx(&mut self) {
|
||||
if self == &XorY::None {
|
||||
*self = XorY::X;
|
||||
} else if self == &XorY::Y {
|
||||
*self = XorY::Both;
|
||||
}
|
||||
}
|
||||
pub fn sety(&mut self) {
|
||||
if self == &XorY::None {
|
||||
*self = XorY::Y;
|
||||
} else if self == &XorY::X {
|
||||
*self = XorY::Both;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GuiError {
|
||||
OutOfBounds(XorY)
|
||||
}
|
||||
|
||||
pub type Dimensions = Position;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ColouredChar {
|
||||
pub character: char,
|
||||
pub colour: ColorCode,
|
||||
}
|
||||
|
||||
impl ColouredChar {
|
||||
pub fn new(character: char, colour: ColorCode) -> ColouredChar {
|
||||
ColouredChar {
|
||||
character,
|
||||
colour,
|
||||
}
|
||||
}
|
||||
pub fn white(character: char) -> ColouredChar {
|
||||
ColouredChar {
|
||||
character,
|
||||
colour: ColorCode::new(Color::White, Color::Black),
|
||||
}
|
||||
}
|
||||
pub fn null() -> ColouredChar {
|
||||
ColouredChar {
|
||||
character: ' ',
|
||||
colour: ColorCode::new(Color::White, Color::Black),
|
||||
}
|
||||
}
|
||||
pub fn as_screen_char(&self) -> ScreenChar {
|
||||
ScreenChar {
|
||||
character: {
|
||||
if let Some(c) = special_char(self.character) {
|
||||
c
|
||||
} else {
|
||||
self.character as u8
|
||||
}
|
||||
},
|
||||
colour: self.colour,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Frame {
|
||||
pub position: Position,
|
||||
pub dimensions: Dimensions,
|
||||
frame: Vec<Vec<ColouredChar>>,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn new(position: Position, dimensions: Dimensions) -> Result<Frame, GuiError> {
|
||||
Ok(Frame {
|
||||
position,
|
||||
dimensions,
|
||||
frame: vec![vec![ColouredChar::null(); dimensions.x]; dimensions.y],
|
||||
})
|
||||
}
|
||||
pub fn render(&self) -> Vec<Vec<ColouredChar>> {
|
||||
self.frame.clone()
|
||||
}
|
||||
|
||||
pub fn render_screen_char(&self) -> Vec<Vec<ScreenChar>> {
|
||||
self.frame.clone().into_iter().map(|row| {
|
||||
row.into_iter().map(|char| {
|
||||
char.as_screen_char()
|
||||
}).collect::<Vec<ScreenChar>>()
|
||||
}).collect::<Vec<Vec<ScreenChar>>>()
|
||||
}
|
||||
pub fn position(&self) -> Position {
|
||||
self.position
|
||||
}
|
||||
pub fn dimensions(&self) -> Dimensions {
|
||||
self.dimensions
|
||||
}
|
||||
pub fn set_pos(&mut self, position: Position, char: ColouredChar) {
|
||||
self.frame[position.y][position.x] = char
|
||||
}
|
||||
pub fn render_element(&mut self, other: &Frame) {
|
||||
serial_println!("frame:\n{}",
|
||||
other.frame.iter().map(|x| {
|
||||
x.iter().map(|y| {
|
||||
y.character
|
||||
}).collect::<String>()
|
||||
}).collect::<Vec<String>>().join("\n")
|
||||
);
|
||||
|
||||
for (i, row) in other.frame.iter().enumerate() {
|
||||
for (j, chr) in row.iter().enumerate() {
|
||||
self.frame[i + other.position.y][j + other.position.x] = *chr
|
||||
}
|
||||
}
|
||||
|
||||
serial_println!("self:\n{}",
|
||||
self.frame.iter().map(|x| {
|
||||
x.iter().map(|y| {
|
||||
y.character
|
||||
}).collect::<String>()
|
||||
}).collect::<Vec<String>>().join("\n")
|
||||
);
|
||||
}
|
||||
|
||||
pub fn render_bounds_check(&self, element: &Frame, should_panic: bool) -> Result<(), XorY> {
|
||||
use XorY::{X, Y};
|
||||
|
||||
let mut res = XorY::None;
|
||||
|
||||
if element.dimensions().x + element.position().x > self.dimensions.x {
|
||||
if should_panic {
|
||||
panic!(
|
||||
"Element is to large to be rendered {} {}",
|
||||
element.dimensions().x + element.position().x,
|
||||
self.dimensions.x
|
||||
)
|
||||
} else {
|
||||
res.setx();
|
||||
}
|
||||
}
|
||||
|
||||
if element.dimensions().y + element.position().y > self.dimensions.y {
|
||||
if should_panic {
|
||||
panic!(
|
||||
"Element is to large to be rendered {} {}",
|
||||
element.dimensions().y + element.position().y,
|
||||
self.dimensions.y
|
||||
)
|
||||
} else {
|
||||
res.sety();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if res != XorY::None {
|
||||
Err(res)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CgOutline {
|
||||
fn render_outline(&self, frame: &mut Frame);
|
||||
}
|
||||
|
||||
|
||||
pub trait CgComponent {
|
||||
fn render(&self) -> Result<Frame, GuiError>;
|
||||
fn render(&self) -> Result<Frame, RenderError>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
string::String,
|
||||
vec,
|
||||
vec::Vec,
|
||||
};
|
||||
use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
|
||||
use alloc::fmt::format;
|
||||
use crate::kernel::render::{ColorCode, RenderError};
|
||||
use crate::serial_println;
|
||||
use super::cg_core::{
|
||||
Position, Dimensions, ColouredChar, CgComponent, CgOutline, Frame, GuiError,
|
||||
CgComponent, CgOutline
|
||||
};
|
||||
|
||||
|
||||
use crate::std::frame::{ColouredChar, Dimensions, Position, Frame};
|
||||
use crate::std::io::Color;
|
||||
|
||||
|
||||
pub struct CgContainer {
|
||||
@@ -34,33 +31,33 @@ impl CgOutline for CgContainer {
|
||||
fn render_outline(&self, frame: &mut Frame) {
|
||||
// draws the sides of the container
|
||||
for i in 0..frame.dimensions.x {
|
||||
frame.set_pos(Position::new(i, 0), ColouredChar::white('─'));
|
||||
frame.set_pos(Position::new(i, frame.dimensions.y - 1), ColouredChar::white('─'));
|
||||
frame.write_pos(Position::new(i, 0), ColouredChar::new('─'));
|
||||
frame.write_pos(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.set_pos(Position::new(0, i), ColouredChar::white('│'));
|
||||
frame.set_pos(Position::new(frame.dimensions.x - 1, i), ColouredChar::white('│'));
|
||||
frame.write_pos(Position::new(0, i), ColouredChar::new('│'));
|
||||
frame.write_pos(Position::new(frame.dimensions.x - 1, i), ColouredChar::new('│'));
|
||||
}
|
||||
|
||||
// draws the corners of the container
|
||||
frame.set_pos(Position::new(0, 0), ColouredChar::white('┌'));
|
||||
frame.set_pos(Position::new(self.dimensions.x - 1, 0), ColouredChar::white('┐'));
|
||||
frame.set_pos(Position::new(0, self.dimensions.y - 1), ColouredChar::white('└'));
|
||||
frame.set_pos(Position::new(self.dimensions.x - 1, self.dimensions.y - 1), ColouredChar::white('┘'));
|
||||
frame.write_pos(Position::new(0, 0), ColouredChar::new('┌'));
|
||||
frame.write_pos(Position::new(self.dimensions.x - 1, 0), ColouredChar::new('┐'));
|
||||
frame.write_pos(Position::new(0, self.dimensions.y - 1), ColouredChar::new('└'));
|
||||
frame.write_pos(Position::new(self.dimensions.x - 1, self.dimensions.y - 1), ColouredChar::new('┘'));
|
||||
}
|
||||
}
|
||||
|
||||
impl CgComponent for CgContainer {
|
||||
fn render(&self) -> Result<Frame, GuiError> {
|
||||
fn render(&self) -> Result<Frame, RenderError> {
|
||||
let mut result = Frame::new(self.position, self.dimensions)?;
|
||||
|
||||
for widget in &self.elements {
|
||||
let frame = widget.render()?;
|
||||
match result.render_bounds_check(&frame, true) { // TODO: this needs to be set to false for production
|
||||
Ok(()) => result.render_element(&frame),
|
||||
Err(e) => return Err(GuiError::OutOfBounds(e)),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,80 +76,100 @@ pub struct CgTextBox {
|
||||
pub position: Position,
|
||||
pub dimensions: Dimensions,
|
||||
outlined: bool,
|
||||
wrap_words: bool // if false then will not wrap until the end of a word if possible
|
||||
}
|
||||
|
||||
impl CgTextBox {
|
||||
pub fn new(title: String, content: String, position: Position, dimensions: Dimensions, outlined: bool) -> CgTextBox {
|
||||
CgTextBox { title, content, position, dimensions, outlined }
|
||||
CgTextBox { title, content, position, dimensions, outlined, wrap_words: false }
|
||||
}
|
||||
|
||||
fn render_title(&self, frame: &mut Frame) {
|
||||
let title = self.title.chars();
|
||||
for (i, c) in title.enumerate() {
|
||||
if i + 2 == self.dimensions.x - 3 { // we dont want to write at the top of the text box
|
||||
frame.write_pos(Position::new(i + 1, 0), ColouredChar::new('.'));
|
||||
} else if i + 2 >= self.dimensions.x - 2 {
|
||||
frame.write_pos(Position::new(i + 1, 0), ColouredChar::new('.'));
|
||||
break;
|
||||
}
|
||||
frame.write_pos(Position::new(i + 2, 0), ColouredChar::new(c));
|
||||
}
|
||||
}
|
||||
pub fn wrap_words(&mut self, wrap: bool) {
|
||||
self.wrap_words = wrap;
|
||||
}
|
||||
}
|
||||
|
||||
impl CgComponent for CgTextBox {
|
||||
fn render(&self) -> Result<Frame, GuiError> {
|
||||
fn render(&self) -> Result<Frame, RenderError> {
|
||||
let mut result = Frame::new(self.position, self.dimensions)?;
|
||||
|
||||
if self.outlined {
|
||||
self.render_outline(&mut result);
|
||||
}
|
||||
|
||||
let title = self.title.chars();
|
||||
for (i, c) in title.enumerate() {
|
||||
if i + 2 == self.dimensions.x - 3 { // we dont want to write at the top of the text box
|
||||
result.set_pos(Position::new(i + 1, 0), ColouredChar::white('.'));
|
||||
} else if i + 2 >= self.dimensions.x - 2 {
|
||||
result.set_pos(Position::new(i + 1, 0), ColouredChar::white('.'));
|
||||
break;
|
||||
self.render_title(&mut result);
|
||||
|
||||
let (mut x, mut y) = (1, 1);
|
||||
|
||||
for word in self.content.split(' ') {
|
||||
if self.wrap_words {
|
||||
if word.len() > self.dimensions.x - 2 - x {
|
||||
if word.len() <= self.dimensions.x - 2 {
|
||||
x = 1;
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
result.set_pos(Position::new(i + 2, 0), ColouredChar::white(c));
|
||||
|
||||
for c in format!("{} ", word).chars() {
|
||||
if x == self.dimensions.x - 1 {
|
||||
x = 1;
|
||||
y += 1;
|
||||
if c == ' ' {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if y == self.dimensions.y - 1 {
|
||||
if c != ' ' {
|
||||
(2..5).for_each(|z| {
|
||||
result.write_pos(Position::new(self.dimensions.x - z, self.dimensions.y - 1), ColouredChar::new('.'));
|
||||
})
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
result.write_pos(Position::new(x, y), ColouredChar::new(c));
|
||||
x += 1;
|
||||
};
|
||||
}
|
||||
|
||||
let (mut x, mut y) = (1,1);
|
||||
|
||||
for c in self.content.chars() {
|
||||
if x == self.dimensions.x - 1 {
|
||||
x = 1;
|
||||
y += 1;
|
||||
if c == ' ' {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if y == self.dimensions.y - 1 {
|
||||
if c != ' ' {
|
||||
(2..5).for_each(|z| {
|
||||
result.set_pos(Position::new(self.dimensions.x - z, self.dimensions.y -1), ColouredChar::white('.'));
|
||||
})
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
result.set_pos(Position::new(x, y), ColouredChar::white(c));
|
||||
x += 1;
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
impl CgOutline for CgTextBox {
|
||||
fn render_outline(&self, frame: &mut Frame) {
|
||||
// draws the sides of the container
|
||||
for i in 0..frame.dimensions.x {
|
||||
frame.set_pos(Position::new(i, 0), ColouredChar::white('─'));
|
||||
frame.set_pos(Position::new(i, frame.dimensions.y - 1), ColouredChar::white('─'));
|
||||
frame.write_pos(Position::new(i, 0), ColouredChar::new('─'));
|
||||
frame.write_pos(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.set_pos(Position::new(0, i), ColouredChar::white('│'));
|
||||
frame.set_pos(Position::new(frame.dimensions.x - 1, i), ColouredChar::white('│'));
|
||||
frame.write_pos(Position::new(0, i), ColouredChar::new('│'));
|
||||
frame.write_pos(Position::new(frame.dimensions.x - 1, i), ColouredChar::new('│'));
|
||||
}
|
||||
|
||||
// draws the corners of the container
|
||||
frame.set_pos(Position::new(0, 0), ColouredChar::white('┌'));
|
||||
frame.set_pos(Position::new(self.dimensions.x - 1, 0), ColouredChar::white('┐'));
|
||||
frame.set_pos(Position::new(0, self.dimensions.y - 1), ColouredChar::white('└'));
|
||||
frame.set_pos(Position::new(self.dimensions.x - 1, self.dimensions.y - 1), ColouredChar::white('┘'));
|
||||
frame.write_pos(Position::new(0, 0), ColouredChar::new('┌'));
|
||||
frame.write_pos(Position::new(self.dimensions.x - 1, 0), ColouredChar::new('┐'));
|
||||
frame.write_pos(Position::new(0, self.dimensions.y - 1), ColouredChar::new('└'));
|
||||
frame.write_pos(Position::new(self.dimensions.x - 1, self.dimensions.y - 1), ColouredChar::new('┘'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,13 +194,13 @@ impl CgLabel {
|
||||
}
|
||||
|
||||
impl CgComponent for CgLabel {
|
||||
fn render(&self) -> Result<Frame, GuiError> {
|
||||
fn render(&self) -> Result<Frame, RenderError> {
|
||||
let mut result = Frame::new(self.position, self.dimensions)?;
|
||||
|
||||
let shortened_string = self.content.chars().take(self.dimensions.x).collect::<String>();
|
||||
|
||||
for (i, c) in shortened_string.chars().enumerate() {
|
||||
result.set_pos(Position::new(i, 0), ColouredChar::white(c));
|
||||
result.write_pos(Position::new(i, 0), ColouredChar::new(c));
|
||||
};
|
||||
|
||||
serial_println!("{:?}", result);
|
||||
@@ -192,6 +209,90 @@ impl CgComponent for CgLabel {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CgIndicatorWidget {
|
||||
content: String,
|
||||
colour: ColorCode,
|
||||
visible: bool,
|
||||
max_width: usize,
|
||||
}
|
||||
impl CgIndicatorWidget {
|
||||
pub fn new(content: String, max_width: usize) -> CgIndicatorWidget {
|
||||
CgIndicatorWidget {
|
||||
content,
|
||||
visible: true,
|
||||
colour: ColorCode::new(Color::White, Color::Black),
|
||||
max_width
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_colour(&mut self, colour: ColorCode) {
|
||||
self.colour = colour;
|
||||
}
|
||||
fn visible(&mut self, visible: bool) {
|
||||
self.visible = visible;
|
||||
}
|
||||
fn len(&self) -> usize {
|
||||
self.max_width
|
||||
}
|
||||
}
|
||||
|
||||
impl CgComponent for CgIndicatorWidget {
|
||||
fn render(&self) -> Result<Frame, RenderError> {
|
||||
if !self.visible {
|
||||
return Ok(Frame::new(Position::new(0, 0), Dimensions::new(0, 0))?);
|
||||
}
|
||||
let mut result = Frame::new(Position::new(0, 0), Dimensions::new(self.max_width, 1))?;
|
||||
|
||||
let shortened_string = self.content.chars().take(self.max_width).collect::<String>();
|
||||
for (i, c) in shortened_string.chars().enumerate() {
|
||||
result.write_pos(Position::new(i, 0), ColouredChar::coloured(c, self.colour));
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CgIndicatorBar {
|
||||
pub(crate) fields: Vec<CgIndicatorWidget>,
|
||||
position: Position,
|
||||
dimensions: Dimensions,
|
||||
}
|
||||
|
||||
impl CgIndicatorBar {
|
||||
pub fn new(position: Position, width: usize) -> CgIndicatorBar {
|
||||
CgIndicatorBar {
|
||||
fields: Vec::new(),
|
||||
position: Position::new(position.x, position.y),
|
||||
dimensions: Dimensions::new(width, 1),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_field(&mut self, field: CgIndicatorWidget) {
|
||||
self.fields.push(field);
|
||||
}
|
||||
}
|
||||
|
||||
impl CgComponent for CgIndicatorBar {
|
||||
fn render(&self) -> Result<Frame, RenderError> {
|
||||
let mut result = Frame::new(self.position, self.dimensions)?;
|
||||
|
||||
let mut width_idx = 0;
|
||||
|
||||
for widget in &self.fields {
|
||||
let mut frame = widget.render()?;
|
||||
frame.set_position(Position::new(width_idx, 0));
|
||||
width_idx += widget.len();
|
||||
|
||||
match result.render_bounds_check(&frame, true) {
|
||||
Ok(()) => result.render_element(&frame),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -221,11 +322,6 @@ impl CgComponent for CgLabel {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
pub mod libgui_old_archive;
|
||||
// pub mod libgui_old_archive;
|
||||
pub mod coords;
|
||||
pub mod libgui;
|
||||
|
||||
Reference in New Issue
Block a user