- 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:
FantasyPvP
2023-11-23 00:29:04 +00:00
parent 0ac21cd0b1
commit 461c9d9c6a
11 changed files with 488 additions and 501 deletions
+15 -13
View File
@@ -6,6 +6,7 @@ use volatile::Volatile;
use alloc::borrow::ToOwned; use alloc::borrow::ToOwned;
use alloc::vec; use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;
use crate::kernel::render::RenderError::InvalidRenderMode;
use crate::serial_println; use crate::serial_println;
use crate::std::io::Screen; use crate::std::io::Screen;
@@ -48,6 +49,14 @@ pub struct ScreenChar {
pub colour: ColorCode, 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 { impl ScreenChar {
pub fn null() -> ScreenChar { pub fn null() -> ScreenChar {
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 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]; let mut processed_frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
for (i, row) in frame.iter().enumerate() { for (i, row) in frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() { for (j, col) in row.iter().enumerate() {
processed_frame[i][j] = match special_char(col.character as char) { processed_frame[i][j] = match special_char(col.character as char) {
@@ -128,9 +136,9 @@ impl Renderer {
self.internal_render(); self.internal_render();
} }
pub fn application_mode(&mut self) -> Result<(), ()> { pub fn application_mode(&mut self) -> Result<(), RenderError> {
if self.application_mode { if self.application_mode {
return Err(()); return Err(InvalidRenderMode);
} else { } else {
self.application_mode = true; self.application_mode = true;
self.internal_render(); 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 { if !self.application_mode {
return Err(()); return Err(InvalidRenderMode);
} else { } else {
self.application_mode = false; self.application_mode = false;
self.internal_render(); self.internal_render();
@@ -172,7 +180,7 @@ impl Renderer {
self.internal_render(); self.internal_render();
} }
pub fn backspace(&mut self) -> Result<(), ()> { pub fn backspace(&mut self) -> Result<(), RenderError> {
if self.application_mode { return Ok(()); }; if self.application_mode { return Ok(()); };
loop { 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; let mut should_break = false;
if self.col_pos == 0 { if self.col_pos == 0 {
@@ -327,12 +335,6 @@ pub fn special_char(ch: char) -> Option<u8> {
} }
impl fmt::Write for Renderer { impl fmt::Write for Renderer {
fn write_str(&mut self, string: &str) -> fmt::Result { fn write_str(&mut self, string: &str) -> fmt::Result {
self.write_string(string, None); self.write_string(string, None);
+189 -120
View File
@@ -1,9 +1,11 @@
use alloc::string::String; use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER, ScreenChar}; use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, ColorCode, RENDERER, ScreenChar};
use crate::println; use crate::{println, serial_println};
use spin::Mutex; use spin::Mutex;
use crate::std::io::{Color, Screen};
/// 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
@@ -13,145 +15,212 @@ use spin::Mutex;
/// nothing will appear on the screen until the frame is actually rendered by /// nothing will appear on the screen until the frame is actually rendered by
/// the render_frame method on the renderer /// 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 { #[derive(Clone, Copy, Debug, PartialEq)]
frame: Vec<Vec<char>>, pub struct ColouredChar {
dimensions: (u8, u8) pub character: char,
pub colour: ColorCode,
}
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],
})
} }
impl Element {
pub fn from_str(elemstr: String) -> Self { 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") { for line in elemstr.split("\n") {
let mut ln = Vec::<char>::new(); element.frame.push(
for col in line.chars() { line
ln.push(col) .chars()
}; .map(|c| ColouredChar::new(c))
element.frame.push(ln); .collect::<Vec<ColouredChar>>()
);
} }
for row in element.clone().frame { for row in element.clone().frame {
let n = row.len(); let n = row.len();
if n > element.dimensions.0 as usize { if n > element.dimensions.x as usize {
element.dimensions.0 = n as u8; element.dimensions.x = n;
} }
} }
element element
} }
pub fn generate(frame: Vec::<Vec<char>>, dims: (u8, u8)) -> Self { pub fn render(&self) -> Vec<Vec<ColouredChar>> {
Element { frame, dimensions: dims } self.frame.clone()
} }
pub fn render(&mut self, pos: (u8, u8)) { // x,y pub fn render_to_screen(&self) -> Result<(), RenderError> {
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 {
let mut frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT]; let mut frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
Self { frame: Frame::from(frame) } for (i, row) in self.frame.iter().enumerate() {
} for (j, col) in row.iter().enumerate() {
//println!("{} {} {}", i, j, col);
fn set_frame(&mut self, frame: Frame) { frame[i + self.position.y as usize][j + self.position.x as usize] = col.as_screen_char();
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>());
}; };
}
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(()) 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]
}
}
+29 -32
View File
@@ -10,7 +10,6 @@ use alloc::{borrow::ToOwned, format, string::{String, ToString}, vec::Vec, boxed
use crate::{ use crate::{
std::{ std::{
io::{self, println, serial_println}, io::{self, println, serial_println},
frame::FRAMEGEN,
random, random,
}, },
std::application::{ std::application::{
@@ -18,8 +17,6 @@ use crate::{
Error, Error,
}, },
}; };
use crate::system::std::frame::Element;
pub struct GameLoop; pub struct GameLoop;
@@ -61,7 +58,7 @@ impl Application for GameLoop {
println!("[{}\n[{}", player, enemy); println!("[{}\n[{}", player, enemy);
} }
FRAMEGEN.lock().render_frame(); // FRAMEGEN.lock().render_frame();
let string = String::from(format!( let string = String::from(format!(
@@ -70,34 +67,34 @@ impl Application for GameLoop {
{} / {} {} / {}
└────────────────────────────┘" └────────────────────────────┘"
, player.username, player.health_points, player.max_health_points)); , player.username, player.health_points, player.max_health_points));
let mut healthbar = Element::from_str(string); // let mut healthbar = Element::from_str(string);
healthbar.render((1, 1)); // healthbar.render((1, 1));
//
let new2 = String::from("[an element]"); // let new2 = String::from("[an element]");
let mut new = Element::from_str(new2); // let mut new = Element::from_str(new2);
//
//
new.render((10, 10)); // new.render((10, 10));
new.render((10, 15)); // new.render((10, 15));
new.render((5, 20)); // new.render((5, 20));
new.render((34, 16)); // new.render((34, 16));
//
//
FRAMEGEN.lock().render_frame(); // FRAMEGEN.lock().render_frame();
//
let fr = FRAMEGEN.lock().get_frame().to_owned(); // let fr = FRAMEGEN.lock().get_frame().to_owned();
serial_println!("{}", { // serial_println!("{}", {
let mut string = String::new(); // let mut string = String::new();
for row in fr { // for row in fr {
let mut r = String::new(); // let mut r = String::new();
for col in row { // for col in row {
r.push(col.character as char); // r.push(col.character as char);
} // }
string.push_str(&r); // string.push_str(&r);
string.push('\n') // string.push('\n')
}; // };
string // string
}); // });
loop { loop {
+32 -20
View File
@@ -5,15 +5,15 @@ use alloc::vec::Vec;
use alloc::boxed::Box; 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::kernel::render::{Color, ColorCode, ScreenChar}; use crate::kernel::render::{Color, ColorCode};
use crate::{println, serial_println}; 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::io::{Screen, Stdin};
use crate::std::time::wait; use crate::std::time::wait;
use crate::user::bin::snake::Game; use crate::user::bin::snake::Game;
pub struct GameOfLife { pub struct GameOfLife {
frame: [[ScreenChar; 80]; 25], frame: Frame
} }
const LOOP_SPEED: f64 = 0.1; const LOOP_SPEED: f64 = 0.1;
@@ -22,7 +22,7 @@ const LOOP_SPEED: f64 = 0.1;
impl Application for GameOfLife { impl Application for GameOfLife {
fn new() -> Self { fn new() -> Self {
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> { async fn run(&mut self, args: Vec<String>) -> Result<(), Error> {
@@ -65,7 +65,7 @@ impl Application for GameOfLife {
impl GameOfLife { impl GameOfLife {
fn activate(&mut self, x: u8, y: u8) { 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> { fn mainloop(&mut self) -> Result<(), Error> {
'mainloop: loop { 'mainloop: loop {
@@ -81,43 +81,55 @@ impl GameOfLife {
// TODO: Logic goes here // 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)| { self.frame.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); frame[y][x] = self.get_new_value(x as u8, y as u8);
})); }));
self.frame = new_frame; self.frame = frame;
} }
Ok(()) 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)| { 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) (x as i32 + relx, y as i32 + rely)
}).filter(|(absx, absy)| { }).filter(|(absx, absy)| {
0 <= *absx && *absx < 80 && 0 <= *absy && *absy < 25 0 <= *absx && *absx < 80 && 0 <= *absy && *absy < 25
}).collect::<Vec<(i32, i32)>>(); }).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 alive == 2 {
if self.frame[y as usize][x as usize] == 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 ScreenChar::new('#' as u8, ColorCode::new(Color::Green, Color::Black)); return ColouredChar::coloured('#', ColorCode::new(Color::Green, Color::Black));
} else { } else {
return ScreenChar::null(); return ColouredChar::null();
} }
} else if alive == 3 { } else if alive == 3 {
ScreenChar::new('#' as u8, ColorCode::new(Color::Green, Color::Black)) ColouredChar::coloured('#', ColorCode::new(Color::Green, Color::Black))
} else { } else {
ScreenChar::null() ColouredChar::null()
} }
} }
fn render(&self) -> Result<(), ()> { fn render(&self) -> Result<(), RenderError> {
let cloned_frame = self.frame.iter().map(|r| r.iter().map(|c| c.clone()).collect::<Vec<ScreenChar>>()).collect::<Vec<Vec<ScreenChar>>>(); self.frame.render_to_screen()?;
let mut elem = ColouredElement::generate(cloned_frame, (80, 25));
elem.render((0,0));
Ok(()) Ok(())
} }
} }
+8 -7
View File
@@ -3,10 +3,10 @@ use alloc::{format, vec};
use alloc::vec::Vec; use alloc::vec::Vec;
use alloc::boxed::Box; use alloc::boxed::Box;
use async_trait::async_trait; use async_trait::async_trait;
use crate::println; use crate::{println, serial_println};
use crate::shell::command_handler; use crate::shell::command_handler;
use crate::std::application::{Application, Error}; 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}; use crate::std::io::{Screen, Stdin};
const OFFSET_X: i64 = 40; const OFFSET_X: i64 = 40;
@@ -14,7 +14,7 @@ const OFFSET_Y: i64 = 12;
pub struct Grapher { pub struct Grapher {
points: Vec<PointF64>, points: Vec<PointF64>,
frame: Vec<Vec<char>>, frame: Frame,
} }
struct PointF64 { struct PointF64 {
@@ -32,7 +32,7 @@ impl Application for Grapher {
fn new() -> Self { fn new() -> Self {
Self { Self {
points: Vec::new(), 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> { 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_x = point.x + OFFSET_X;
let offset_y = point.y + OFFSET_Y; 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) { fn display(&mut self) {
let mut elem = Element::generate(self.frame.clone(), (80, 25)); self.frame.render_to_screen().unwrap();
elem.render((0, 0));
} }
} }
+27 -33
View File
@@ -1,24 +1,22 @@
use async_trait::async_trait; use async_trait::async_trait;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use spin::Mutex; use spin::Mutex;
use x86_64::instructions::interrupts;
use alloc::{boxed::Box, string::{String, ToString}, vec, vec::Vec}; use alloc::{boxed::Box, string::{String, ToString}, vec, vec::Vec};
use vga::writers::{GraphicsWriter, PrimitiveDrawing}; use vga::writers::{GraphicsWriter, PrimitiveDrawing};
use crate::{print, printerr, println, serial_println, std, std::application::{Application, Error}, user::bin::*}; use crate::{print, printerr, println, serial_println, std, std::application::{Application, Error}, user::bin::*};
use crate::kernel::render::ScreenChar; use crate::kernel::render::ColorCode;
use crate::std::frame::ColouredElement; use crate::std::frame::{Dimensions, Position};
use crate::std::io::{Color, write, Screen, Stdin, Serial}; use crate::std::io::{Color, write, Screen, Stdin, Serial};
use crate::std::random::Random; use crate::std::random::Random;
use crate::user::bin::gigachad_detector::GigachadDetector; use crate::user::bin::gigachad_detector::GigachadDetector;
use crate::user::bin::grapher::Grapher; use crate::user::bin::grapher::Grapher;
use crate::user::lib::libgui;
use crate::user::lib::libgui::{ use crate::user::lib::libgui::{
cg_core::{Frame, Position, Dimensions, CgComponent}, cg_core::{CgComponent},
cg_widgets::{CgTextBox, CgContainer}, cg_widgets::{CgTextBox, CgContainer},
}; };
use crate::user::lib::libgui::cg_widgets::CgLabel; use crate::user::lib::libgui::cg_widgets::{CgIndicatorBar, CgIndicatorWidget, CgLabel};
lazy_static! { lazy_static! {
pub static ref CMD: Mutex<CommandHandler> = Mutex::new(CommandHandler::new()); pub static ref CMD: Mutex<CommandHandler> = Mutex::new(CommandHandler::new());
@@ -44,7 +42,7 @@ pub async fn eventloop() {
CMD.lock().prompt(); CMD.lock().prompt();
loop { loop {
let string = crate::std::io::Stdin::readline().await; let string = Stdin::readline().await;
CMD.lock().current.push_str(&string); CMD.lock().current.push_str(&string);
match exec().await { match exec().await {
Ok(_) => { Ok(_) => {
@@ -187,53 +185,49 @@ async fn exec() -> Result<(), Error> {
"test_features" => { "test_features" => {
std::io::Screen::application_mode(); std::io::Screen::application_mode();
serial_println!("OK");
let textbox = CgTextBox::new( 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"),
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!"), 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), Dimensions::new(40, 12),
true, true,
); );
let textbox2 = CgTextBox::new( let mut indicatorbar = CgIndicatorBar::new(
String::from("i'd just like to interject for a moment"), Position::new(0, 0),
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!"), 80
Position::new(10, 5),
Dimensions::new(40, 12),
true,
); );
let mut w1 = CgIndicatorWidget::new(
let mut label = CgLabel::new( String::from("test"),
String::from("i'd just like to interject for a moment"), 5
Position::new(5, 16),
15,
); );
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( let mut container = CgContainer::new(
Position::new(2, 2), Position::new(0, 0),
Dimensions::new(65, 20), Dimensions::new(80, 25),
true, false,
); );
container.elements.push(Box::new(textbox)); container.elements.push(Box::new(textbox));
container.elements.push(Box::new(textbox2)); container.elements.push(Box::new(indicatorbar));
container.elements.push(Box::new(label));
let res = if let Ok(frame) = container.render() { if let Ok(frame) = container.render() {
frame frame.render_to_screen().unwrap();
} else { } else {
return Err(Error::CommandFailed("failed to render frame".to_string())) 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(); //std::io::Screen::terminal_mode();
+19 -19
View File
@@ -12,8 +12,9 @@ use lazy_static::lazy_static;
use crate::kernel::render::{ColorCode, ScreenChar}; use crate::kernel::render::{ColorCode, ScreenChar};
use crate::{println, serial_println}; 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};
use crate::std::random::Random; use crate::std::random::Random;
use crate::system::std::frame::ColouredElement; use crate::system::std::frame;
use super::super::lib::coords::{Line, Position, Direction}; use super::super::lib::coords::{Line, Position, Direction};
#[derive(PartialEq)] #[derive(PartialEq)]
@@ -171,35 +172,34 @@ impl Game {
self.new_poi(); self.new_poi();
} }
fn render(&mut self) -> Result<(), ()> { fn render(&mut self) -> Result<(), RenderError> {
let mut frame = vec![vec![ScreenChar::null(); 80]; 25];
let mut frame = Frame::new(frame::Position::new(0, 0), Dimensions::new(80, 25))?;
let mut curr_colour = ColorCode::new(Color::LightBlue, Color::Black); let mut curr_colour = ColorCode::new(Color::LightBlue, Color::Black);
for s in self.snakes.clone() { for s in self.snakes.clone() {
curr_colour = if s.ai_controlled { curr_colour = match s.ai_controlled {
ColorCode::new(Color::Cyan, Color::Black) true => ColorCode::new(Color::Cyan, Color::Black),
} else { false => ColorCode::new(Color::LightGreen, Color::Black),
ColorCode::new(Color::LightGreen, Color::Black)
}; };
for point in s.tail.iter() { 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| { 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 literal = format!("snake go brr score: {}", self.score);
let msg = Game::centre_text(80, literal); let msg = Game::centre_text(80, literal);
msg.chars().enumerate().for_each(|(i, c)| { msg.chars().enumerate().for_each(|(i, c)| {
if 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)); frame.render_to_screen()?;
elem.render((0,0));
Ok(()) Ok(())
} }
@@ -214,15 +214,15 @@ impl Game {
msg msg
} }
fn render_end_screen(&mut self) -> Result<(), ()> { fn render_end_screen(&mut self) -> Result<(), RenderError> {
let mut frame = vec![vec![ScreenChar::null(); 80]; 25]; 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[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| ScreenChar::new(c as u8, ColorCode::new(Color::LightGreen, 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| ScreenChar::new(c as u8, ColorCode::new(Color::Red, 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)); frame.render_to_screen()?;
elem.render((0,0)) Ok(())
} }
} }
-1
View File
@@ -8,7 +8,6 @@ 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::Screen;
use crate::user::lib::coords::{Direction, Position, PositionReal}; use crate::user::lib::coords::{Direction, Position, PositionReal};
use crate::user::lib::libgui_old_archive::libgui_core::Pos;
pub(crate) struct TetrisEngine { pub(crate) struct TetrisEngine {
+3 -186
View File
@@ -3,201 +3,18 @@ use alloc::string::String;
use alloc::vec; use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::slice::from_mut; 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::{printerr, serial_println};
use crate::std::frame::special_char; use crate::std::frame::{ColouredChar, Dimensions, Position, special_char, Frame};
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,
}
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 { pub trait CgOutline {
fn render_outline(&self, frame: &mut Frame); fn render_outline(&self, frame: &mut Frame);
} }
pub trait CgComponent { pub trait CgComponent {
fn render(&self) -> Result<Frame, GuiError>; fn render(&self) -> Result<Frame, RenderError>;
} }
+146 -50
View File
@@ -1,15 +1,12 @@
use alloc::{ use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
boxed::Box, use alloc::fmt::format;
string::String, use crate::kernel::render::{ColorCode, RenderError};
vec,
vec::Vec,
};
use crate::serial_println; use crate::serial_println;
use super::cg_core::{ 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 { pub struct CgContainer {
@@ -34,33 +31,33 @@ impl CgOutline for CgContainer {
fn render_outline(&self, frame: &mut Frame) { fn render_outline(&self, frame: &mut Frame) {
// 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.set_pos(Position::new(i, 0), ColouredChar::white('─')); frame.write_pos(Position::new(i, 0), ColouredChar::new('─'));
frame.set_pos(Position::new(i, frame.dimensions.y - 1), ColouredChar::white('─')); frame.write_pos(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.set_pos(Position::new(0, i), ColouredChar::white('│')); frame.write_pos(Position::new(0, i), ColouredChar::new('│'));
frame.set_pos(Position::new(frame.dimensions.x - 1, i), ColouredChar::white('│')); frame.write_pos(Position::new(frame.dimensions.x - 1, i), ColouredChar::new('│'));
} }
// draws the corners of the container // draws the corners of the container
frame.set_pos(Position::new(0, 0), ColouredChar::white('┌')); frame.write_pos(Position::new(0, 0), ColouredChar::new('┌'));
frame.set_pos(Position::new(self.dimensions.x - 1, 0), ColouredChar::white('┐')); frame.write_pos(Position::new(self.dimensions.x - 1, 0), ColouredChar::new('┐'));
frame.set_pos(Position::new(0, self.dimensions.y - 1), ColouredChar::white('└')); frame.write_pos(Position::new(0, self.dimensions.y - 1), ColouredChar::new('└'));
frame.set_pos(Position::new(self.dimensions.x - 1, self.dimensions.y - 1), ColouredChar::white('┘')); frame.write_pos(Position::new(self.dimensions.x - 1, self.dimensions.y - 1), ColouredChar::new('┘'));
} }
} }
impl CgComponent for CgContainer { 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)?; let mut result = Frame::new(self.position, self.dimensions)?;
for widget in &self.elements { for widget in &self.elements {
let frame = widget.render()?; let frame = widget.render()?;
match result.render_bounds_check(&frame, true) { // TODO: this needs to be set to false for production match result.render_bounds_check(&frame, true) { // TODO: this needs to be set to false for production
Ok(()) => result.render_element(&frame), Ok(()) => result.render_element(&frame),
Err(e) => return Err(GuiError::OutOfBounds(e)), Err(e) => return Err(e),
} }
} }
@@ -79,37 +76,54 @@ pub struct CgTextBox {
pub position: Position, pub position: Position,
pub dimensions: Dimensions, pub dimensions: Dimensions,
outlined: bool, outlined: bool,
wrap_words: bool // if false then will not wrap until the end of a word if possible
} }
impl CgTextBox { impl CgTextBox {
pub fn new(title: String, content: String, position: Position, dimensions: Dimensions, outlined: bool) -> 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 { 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)?; let mut result = Frame::new(self.position, self.dimensions)?;
if self.outlined { if self.outlined {
self.render_outline(&mut result); self.render_outline(&mut result);
} }
let title = self.title.chars(); self.render_title(&mut result);
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;
}
result.set_pos(Position::new(i + 2, 0), ColouredChar::white(c));
}
let (mut x, mut y) = (1, 1); let (mut x, mut y) = (1, 1);
for c in self.content.chars() { 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;
}
}
}
for c in format!("{} ", word).chars() {
if x == self.dimensions.x - 1 { if x == self.dimensions.x - 1 {
x = 1; x = 1;
y += 1; y += 1;
@@ -120,39 +134,42 @@ 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.set_pos(Position::new(self.dimensions.x - z, self.dimensions.y -1), ColouredChar::white('.')); result.write_pos(Position::new(self.dimensions.x - z, self.dimensions.y - 1), ColouredChar::new('.'));
}) })
} }
break; break;
} }
result.set_pos(Position::new(x, y), ColouredChar::white(c)); result.write_pos(Position::new(x, y), ColouredChar::new(c));
x += 1; x += 1;
}; };
}
Ok(result) Ok(result)
} }
} }
impl CgOutline for CgTextBox { impl CgOutline for CgTextBox {
fn render_outline(&self, frame: &mut Frame) { fn render_outline(&self, frame: &mut Frame) {
// 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.set_pos(Position::new(i, 0), ColouredChar::white('─')); frame.write_pos(Position::new(i, 0), ColouredChar::new('─'));
frame.set_pos(Position::new(i, frame.dimensions.y - 1), ColouredChar::white('─')); frame.write_pos(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.set_pos(Position::new(0, i), ColouredChar::white('│')); frame.write_pos(Position::new(0, i), ColouredChar::new('│'));
frame.set_pos(Position::new(frame.dimensions.x - 1, i), ColouredChar::white('│')); frame.write_pos(Position::new(frame.dimensions.x - 1, i), ColouredChar::new('│'));
} }
// draws the corners of the container // draws the corners of the container
frame.set_pos(Position::new(0, 0), ColouredChar::white('┌')); frame.write_pos(Position::new(0, 0), ColouredChar::new('┌'));
frame.set_pos(Position::new(self.dimensions.x - 1, 0), ColouredChar::white('┐')); frame.write_pos(Position::new(self.dimensions.x - 1, 0), ColouredChar::new('┐'));
frame.set_pos(Position::new(0, self.dimensions.y - 1), ColouredChar::white('└')); frame.write_pos(Position::new(0, self.dimensions.y - 1), ColouredChar::new('└'));
frame.set_pos(Position::new(self.dimensions.x - 1, self.dimensions.y - 1), ColouredChar::white('┘')); 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 { 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 mut result = Frame::new(self.position, self.dimensions)?;
let shortened_string = self.content.chars().take(self.dimensions.x).collect::<String>(); let shortened_string = self.content.chars().take(self.dimensions.x).collect::<String>();
for (i, c) in shortened_string.chars().enumerate() { 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); 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
View File
@@ -1,3 +1,3 @@
pub mod libgui_old_archive; // pub mod libgui_old_archive;
pub mod coords; pub mod coords;
pub mod libgui; pub mod libgui;