started working on dialogs
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use crate::system::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER, ScreenChar};
|
use crate::system::kernel::render::{RENDERER, ScreenChar};
|
||||||
use crate::std::io::{Color, Screen};
|
use crate::std::io::{Color, Screen};
|
||||||
|
|
||||||
/// TODO: get a working implementation for CLI apps
|
/// TODO: get a working implementation for CLI apps
|
||||||
@@ -12,7 +12,13 @@ use crate::std::io::{Color, Screen};
|
|||||||
/// 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 write_to_screen() method on the renderer
|
/// the write_to_screen() method on the renderer
|
||||||
|
|
||||||
pub use crate::system::kernel::render::{special_char, RenderError, ColorCode};
|
pub use crate::system::kernel::render::{
|
||||||
|
special_char,
|
||||||
|
RenderError,
|
||||||
|
ColorCode,
|
||||||
|
BUFFER_WIDTH,
|
||||||
|
BUFFER_HEIGHT
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
|||||||
@@ -12,3 +12,4 @@ mod gameoflife;
|
|||||||
mod tetris;
|
mod tetris;
|
||||||
mod asteroids;
|
mod asteroids;
|
||||||
mod crystalrpg;
|
mod crystalrpg;
|
||||||
|
mod pong;
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
use alloc::boxed::Box;
|
||||||
|
use alloc::string::String;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use core::fmt::Write;
|
||||||
|
use crate::std::application::{Application, Error};
|
||||||
|
use crate::std;
|
||||||
|
|
||||||
|
struct Game {
|
||||||
|
ball: Ball,
|
||||||
|
player1: Player,
|
||||||
|
player2: Player,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Application for Game {
|
||||||
|
fn new() -> Self {
|
||||||
|
Game {
|
||||||
|
ball: Ball::new(),
|
||||||
|
player1: Player::new(1),
|
||||||
|
player2: Player::new(2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run(&mut self, _: Vec<String>) -> Result<(), Error> {
|
||||||
|
loop {
|
||||||
|
self.ball.update(&self.player1, &self.player2);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Player {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
score: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Player {
|
||||||
|
fn new(y: i32) -> Self {
|
||||||
|
Player { x: 0, y, score: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Ball {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ball {
|
||||||
|
fn new() -> Self {
|
||||||
|
Ball { x: 0, y: 0 }
|
||||||
|
}
|
||||||
|
fn update(&mut self, player1: &Player, player2: &Player) {
|
||||||
|
self.x += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ use crate::user::lib::libgui::{
|
|||||||
cg_inputs::CgLineEdit,
|
cg_inputs::CgLineEdit,
|
||||||
};
|
};
|
||||||
use crate::user::lib::libgui::cg_core::{CgTextInput, Widget};
|
use crate::user::lib::libgui::cg_core::{CgTextInput, Widget};
|
||||||
|
use crate::user::lib::libgui::cg_widgets::CgDialog;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref CMD: Mutex<CommandHandler> = Mutex::new(CommandHandler::new());
|
pub static ref CMD: Mutex<CommandHandler> = Mutex::new(CommandHandler::new());
|
||||||
@@ -253,6 +254,18 @@ struct CmdHistory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn setup_ui() {
|
async fn setup_ui() {
|
||||||
|
let dialog = CgDialog::new(
|
||||||
|
Dimensions::new(40, 10),
|
||||||
|
String::from("test dialog"),
|
||||||
|
String::from("dialog body"),
|
||||||
|
String::from("[dialog footer]")
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Ok(frame) = dialog.render() {
|
||||||
|
frame.write_to_screen().unwrap();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
serial_println!("idk");
|
serial_println!("idk");
|
||||||
let label= Widget::insert(CgLabel::new(
|
let label= Widget::insert(CgLabel::new(
|
||||||
String::from("test label"),
|
String::from("test label"),
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ pub trait CgComponent: Any {
|
|||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// trait for components that can have editable text, such as search boxes, command palettes, terminals, text inputs etc.
|
/// trait for components that can have editable text, such as search boxes, command palettes, terminals, text inputs etc.
|
||||||
pub trait CgTextEdit: CgComponent {
|
pub trait CgTextEdit: CgComponent {
|
||||||
fn write_char(&mut self, c: char); // this can also be implemented in a way that inserts characters
|
fn write_char(&mut self, c: char); // this can also be implemented in a way that inserts characters
|
||||||
@@ -43,7 +42,10 @@ pub trait CgTextInput: CgTextEdit {
|
|||||||
async fn input(&mut self, break_condition: fn(KeyStroke) -> (KeyStroke, Exit), id: &Widget, app: &Widget) -> Result<(String, bool), RenderError>;
|
async fn input(&mut self, break_condition: fn(KeyStroke) -> (KeyStroke, Exit), id: &Widget, app: &Widget) -> Result<(String, bool), RenderError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait CgKeyboardCapture: CgComponent {
|
||||||
|
async fn keyboard_capture(&mut self, break_condition: fn(KeyStroke) -> (KeyStroke, Exit), app: Option<&Widget>) -> Result<bool, RenderError>;
|
||||||
|
}
|
||||||
|
|
||||||
static ID_COUNTER: Mutex<usize> = Mutex::new(0);
|
static ID_COUNTER: Mutex<usize> = Mutex::new(0);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
use crate::std::frame::{ColouredChar, Dimensions, Frame, Position};
|
||||||
|
|
||||||
|
pub(crate) fn render_outline(frame: &mut Frame, dimensions: Dimensions) {
|
||||||
|
// draws the sides of the container
|
||||||
|
for i in 0..frame.dimensions.x {
|
||||||
|
frame.write(Position::new(i, 0), ColouredChar::new('─'));
|
||||||
|
frame.write(Position::new(i, frame.dimensions.y - 1), ColouredChar::new('─'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// draws the top and bottom of the container
|
||||||
|
for i in 0..frame.dimensions.y {
|
||||||
|
frame.write(Position::new(0, i), ColouredChar::new('│'));
|
||||||
|
frame.write(Position::new(frame.dimensions.x - 1, i), ColouredChar::new('│'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// draws the corners of the container
|
||||||
|
frame.write(Position::new(0, 0), ColouredChar::new('┌'));
|
||||||
|
frame.write(Position::new(dimensions.x - 1, 0), ColouredChar::new('┐'));
|
||||||
|
frame.write(Position::new(0, dimensions.y - 1), ColouredChar::new('└'));
|
||||||
|
frame.write(Position::new(dimensions.x - 1, dimensions.y - 1), ColouredChar::new('┘'));
|
||||||
|
}
|
||||||
@@ -6,7 +6,8 @@ use core::cmp::{max, min};
|
|||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use crate::serial_println;
|
use crate::serial_println;
|
||||||
use super::cg_core::{CgComponent, CgOutline, Widget};
|
use super::cg_core::{CgComponent, CgOutline, Widget};
|
||||||
use crate::std::frame::{ColouredChar, Dimensions, Position, Frame, RenderError, ColorCode};
|
use super::cg_utils::render_outline;
|
||||||
|
use crate::std::frame::{ColouredChar, Dimensions, Position, Frame, RenderError, ColorCode, BUFFER_WIDTH, BUFFER_HEIGHT};
|
||||||
use crate::std::io::Color;
|
use crate::std::io::Color;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -33,29 +34,6 @@ impl CgContainer {
|
|||||||
self.elements.get(name)
|
self.elements.get(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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.write(Position::new(i, 0), ColouredChar::new('─'));
|
|
||||||
frame.write(Position::new(i, frame.dimensions.y - 1), ColouredChar::new('─'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// draws the top and bottom of the container
|
|
||||||
for i in 0..frame.dimensions.y {
|
|
||||||
frame.write(Position::new(0, i), ColouredChar::new('│'));
|
|
||||||
frame.write(Position::new(frame.dimensions.x - 1, i), ColouredChar::new('│'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// draws the corners of the container
|
|
||||||
frame.write(Position::new(0, 0), ColouredChar::new('┌'));
|
|
||||||
frame.write(Position::new(self.dimensions.x - 1, 0), ColouredChar::new('┐'));
|
|
||||||
frame.write(Position::new(0, self.dimensions.y - 1), ColouredChar::new('└'));
|
|
||||||
frame.write(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, RenderError> {
|
fn render(&self) -> Result<Frame, RenderError> {
|
||||||
let mut result = Frame::new(self.position, self.dimensions)?;
|
let mut result = Frame::new(self.position, self.dimensions)?;
|
||||||
@@ -68,7 +46,7 @@ impl CgComponent for CgContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.outlined {
|
if self.outlined {
|
||||||
self.render_outline(&mut result);
|
render_outline(&mut result, self.dimensions.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
@@ -115,7 +93,7 @@ impl CgComponent for CgTextBox {
|
|||||||
let mut result = Frame::new(self.position, self.dimensions)?;
|
let mut result = Frame::new(self.position, self.dimensions)?;
|
||||||
|
|
||||||
if self.outlined {
|
if self.outlined {
|
||||||
self.render_outline(&mut result);
|
render_outline(&mut result, self.dimensions.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.render_title(&mut result);
|
self.render_title(&mut result);
|
||||||
@@ -161,32 +139,6 @@ impl CgComponent for CgTextBox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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.write(Position::new(i, 0), ColouredChar::new('─'));
|
|
||||||
frame.write(Position::new(i, frame.dimensions.y - 1), ColouredChar::new('─'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// draws the top and bottom of the container
|
|
||||||
for i in 0..frame.dimensions.y {
|
|
||||||
frame.write(Position::new(0, i), ColouredChar::new('│'));
|
|
||||||
frame.write(Position::new(frame.dimensions.x - 1, i), ColouredChar::new('│'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// draws the corners of the container
|
|
||||||
frame.write(Position::new(0, 0), ColouredChar::new('┌'));
|
|
||||||
frame.write(Position::new(self.dimensions.x - 1, 0), ColouredChar::new('┐'));
|
|
||||||
frame.write(Position::new(0, self.dimensions.y - 1), ColouredChar::new('└'));
|
|
||||||
frame.write(Position::new(self.dimensions.x - 1, self.dimensions.y - 1), ColouredChar::new('┘'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CgLabel {
|
pub struct CgLabel {
|
||||||
content: String,
|
content: String,
|
||||||
@@ -349,7 +301,7 @@ impl CgComponent for CgStatusBar {
|
|||||||
fn render(&self) -> Result<Frame, RenderError> {
|
fn render(&self) -> Result<Frame, RenderError> {
|
||||||
let mut frame = Frame::new(self.position, self.dimensions)?;
|
let mut frame = Frame::new(self.position, self.dimensions)?;
|
||||||
|
|
||||||
(0..80).for_each(|x| frame[0][x] = ColouredChar::coloured(' ', ColorCode::new(Color::Black, Color::DarkGray)));
|
(0..BUFFER_WIDTH).for_each(|x| frame[0][x] = ColouredChar::coloured(' ', ColorCode::new(Color::Black, Color::DarkGray)));
|
||||||
|
|
||||||
// render window title centred
|
// render window title centred
|
||||||
let mut window_title = self.window_title.render()?;
|
let mut window_title = self.window_title.render()?;
|
||||||
@@ -393,10 +345,54 @@ impl CgStatusBar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum CgDialogType {
|
||||||
|
Information,
|
||||||
|
Confirmation,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CgDialog {
|
||||||
|
dimensions: Dimensions,
|
||||||
|
title: String,
|
||||||
|
content: String,
|
||||||
|
button_text: String,
|
||||||
|
accepted: bool,
|
||||||
|
outlined: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CgDialog {
|
||||||
|
pub(crate) fn new(dimensions: Dimensions, title: String, content: String, button_text: String) -> CgDialog {
|
||||||
|
CgDialog {
|
||||||
|
dimensions,
|
||||||
|
title,
|
||||||
|
content,
|
||||||
|
button_text,
|
||||||
|
accepted: false,
|
||||||
|
outlined: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CgComponent for CgDialog {
|
||||||
|
fn render(&self) -> Result<Frame, RenderError> {
|
||||||
|
if self.dimensions.x > BUFFER_WIDTH || self.dimensions.y > BUFFER_HEIGHT {
|
||||||
|
return Err(RenderError::OutOfBounds(self.dimensions.x > BUFFER_WIDTH, self.dimensions.y > BUFFER_HEIGHT));
|
||||||
|
}
|
||||||
|
let x_offset = (BUFFER_WIDTH - self.dimensions.x) / 2;
|
||||||
|
let y_offset = (BUFFER_HEIGHT - self.dimensions.y) / 2;
|
||||||
|
|
||||||
|
let mut frame = Frame::new(Position::new(x_offset, y_offset), Dimensions::new(self.dimensions.x, self.dimensions.y))?;
|
||||||
|
|
||||||
|
if self.outlined {
|
||||||
|
render_outline(&mut frame, self.dimensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub mod cg_core;
|
pub mod cg_core;
|
||||||
pub mod cg_widgets;
|
pub mod cg_widgets;
|
||||||
pub mod cg_inputs;
|
pub mod cg_inputs;
|
||||||
|
mod cg_utils;
|
||||||
|
|
||||||
|
|||||||
@@ -1,287 +0,0 @@
|
|||||||
use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER, ScreenChar};
|
|
||||||
use crate::system::std::frame::Frame;
|
|
||||||
use crate::{print, println};
|
|
||||||
use alloc::{
|
|
||||||
boxed::Box,
|
|
||||||
string::{String, ToString},
|
|
||||||
vec,
|
|
||||||
vec::Vec,
|
|
||||||
};
|
|
||||||
/*
|
|
||||||
|
|
||||||
- this library will provide useful structures for creating simple
|
|
||||||
command line based interfaces using ascii
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct Pos {
|
|
||||||
pub x: usize,
|
|
||||||
pub y: usize,
|
|
||||||
}
|
|
||||||
impl Pos {
|
|
||||||
pub fn new(x: usize, y: usize) -> Pos {
|
|
||||||
Pos { x, y }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// all interface elements must implement this trait in order to be
|
|
||||||
/// rendered on the screen
|
|
||||||
pub trait Element {
|
|
||||||
// default behaviour for all elements
|
|
||||||
|
|
||||||
fn render(&self) -> (Vec<Vec<char>>, Pos) {
|
|
||||||
// recursive method for rendering the
|
|
||||||
// specified frame to the screen
|
|
||||||
// insert rendering code for specific frame here
|
|
||||||
// this should also render all children of the element
|
|
||||||
(Vec::<Vec<char>>::new(), Pos::new(0, 0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Container<'a> {
|
|
||||||
// a simple container objects for grouping
|
|
||||||
// other containers together
|
|
||||||
frame: Vec<Vec<char>>,
|
|
||||||
elements: Vec<Box<&'a dyn Element>>,
|
|
||||||
position: Pos, // x,y
|
|
||||||
//
|
|
||||||
outlined: bool,
|
|
||||||
dimensions: Pos, // x,y
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Container<'a> {
|
|
||||||
fn new(position: Pos, dimensions: Pos, outlined: bool) -> Container<'a> {
|
|
||||||
Self {
|
|
||||||
frame: vec![vec![' '; dimensions.x as usize]; dimensions.y as usize],
|
|
||||||
elements: Vec::new(),
|
|
||||||
position,
|
|
||||||
outlined,
|
|
||||||
dimensions,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Element for Container<'_> {
|
|
||||||
fn render(&self) -> (Vec<Vec<char>>, Pos) {
|
|
||||||
// returns all elements as a single frame
|
|
||||||
|
|
||||||
let mut charmap = Vec::<Vec<char>>::new();
|
|
||||||
|
|
||||||
let mut frstline: Vec<char>;
|
|
||||||
let mut midlines: Vec<char>;
|
|
||||||
let mut lastline: Vec<char>;
|
|
||||||
|
|
||||||
if self.outlined {
|
|
||||||
charmap = gen_outline(self.dimensions);
|
|
||||||
}
|
|
||||||
|
|
||||||
// render child elements
|
|
||||||
|
|
||||||
for element in &self.elements {
|
|
||||||
let r = (*element).render();
|
|
||||||
|
|
||||||
// rendering code for child elements goes here
|
|
||||||
|
|
||||||
// code to render the object at the position marked by offset within the container
|
|
||||||
|
|
||||||
for (i, row) in r.0.iter().enumerate() {
|
|
||||||
for (j, chr) in row.iter().enumerate() {
|
|
||||||
// r.0 is the rendered element
|
|
||||||
// r.1.0 is the x offset
|
|
||||||
charmap[i + r.1.y][j + r.1.x] = *chr; // r.1.1 is the y offset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (charmap, self.position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct IndicatorBar {
|
|
||||||
length: usize,
|
|
||||||
filled: usize,
|
|
||||||
abs: usize,
|
|
||||||
position: Pos,
|
|
||||||
text: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndicatorBar {
|
|
||||||
fn new(position: Pos, length: usize) -> IndicatorBar {
|
|
||||||
IndicatorBar {
|
|
||||||
position,
|
|
||||||
length,
|
|
||||||
abs: 0,
|
|
||||||
filled: 0,
|
|
||||||
text: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn set_value(&mut self, value: usize) {
|
|
||||||
// takes a value from 1-100%
|
|
||||||
// and turns it into a corresponding length filled
|
|
||||||
self.filled = value;
|
|
||||||
}
|
|
||||||
fn set_text(&mut self, s: String) {
|
|
||||||
self.text = Some(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Element for IndicatorBar {
|
|
||||||
fn render(&self) -> (Vec<Vec<char>>, Pos) {
|
|
||||||
let numlen = (self.abs.to_string().as_str()).len();
|
|
||||||
let relfilled = (self.filled as f64 / 100.0 * ((self.length - numlen) as f64)) as usize;
|
|
||||||
|
|
||||||
let mut line = Vec::<char>::new();
|
|
||||||
if let Some(t) = &self.text {
|
|
||||||
line.append(&mut t.chars().collect());
|
|
||||||
line.push(':');
|
|
||||||
line.push(' ');
|
|
||||||
}
|
|
||||||
line.append(&mut (self.abs.to_string().chars().collect()));
|
|
||||||
line.append(&mut vec!['▓'; relfilled]);
|
|
||||||
line.append(&mut vec!['░'; self.length - numlen - relfilled]);
|
|
||||||
|
|
||||||
let mut rendered = Vec::new();
|
|
||||||
rendered.push(line);
|
|
||||||
|
|
||||||
println!("RENDERED: {:?}", rendered);
|
|
||||||
|
|
||||||
return (rendered, (self.position));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// functions that deal with the rendering and interaction between objects being
|
|
||||||
// rendered.
|
|
||||||
|
|
||||||
pub fn render_frame(elements: Vec<Container>) {
|
|
||||||
let mut buffer: Frame = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
|
|
||||||
|
|
||||||
for frame in elements.iter() {
|
|
||||||
let f = frame.render();
|
|
||||||
|
|
||||||
for (i, row) in f.0.iter().enumerate() {
|
|
||||||
for (j, chr) in row.iter().enumerate() {
|
|
||||||
let mut current = &buffer[i + f.1.y][j + f.1.x];
|
|
||||||
let newchar = overlap_check(current.character as char, *chr);
|
|
||||||
buffer[i + f.1.y][j + f.1.x] = ScreenChar::white(newchar as u8);
|
|
||||||
|
|
||||||
//print!("{}", buffer[i+frame.position.1][j+frame.position.0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//println!("{:?}", buffer);
|
|
||||||
|
|
||||||
RENDERER.lock().render_frame(buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn overlap_check(oldchar: char, newchar: char) -> char {
|
|
||||||
match (oldchar, newchar) {
|
|
||||||
//┌│└ ┐┘─
|
|
||||||
('│', '─') | ('┌', '┘') | ('└', '┐') => '┼',
|
|
||||||
('┌', '└') => '├',
|
|
||||||
('┐', '┐') => '┤',
|
|
||||||
|
|
||||||
(_, _) => newchar,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// function to return a charmap of the outline of an object
|
|
||||||
|
|
||||||
pub fn gen_outline(dimensions: Pos) -> Vec<Vec<char>> {
|
|
||||||
let mut charmap = Vec::<Vec<char>>::new();
|
|
||||||
|
|
||||||
let mut frstline = vec!['┌'];
|
|
||||||
let mut midlines = vec!['│'];
|
|
||||||
let mut lastline = vec!['└'];
|
|
||||||
|
|
||||||
frstline.append(&mut vec!['─'; dimensions.x - 2]);
|
|
||||||
midlines.append(&mut vec![' '; dimensions.x - 2]);
|
|
||||||
lastline.append(&mut vec!['─'; dimensions.x - 2]);
|
|
||||||
|
|
||||||
frstline.append(&mut vec!['┐']);
|
|
||||||
midlines.append(&mut vec!['│']);
|
|
||||||
lastline.append(&mut vec!['┘']);
|
|
||||||
|
|
||||||
charmap.push(frstline);
|
|
||||||
for _ in 0..dimensions.y - 2 {
|
|
||||||
charmap.push(midlines.clone());
|
|
||||||
}
|
|
||||||
charmap.push(lastline);
|
|
||||||
|
|
||||||
return charmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
// // testing functions
|
|
||||||
//
|
|
||||||
// pub fn test_elements() {
|
|
||||||
// use super::libgui_elements;
|
|
||||||
//
|
|
||||||
// let mut containers = Vec::<Container>::new();
|
|
||||||
//
|
|
||||||
// /*
|
|
||||||
//
|
|
||||||
// //for _ in 0..10 {
|
|
||||||
// // containers.push(generate_box());
|
|
||||||
// //}
|
|
||||||
//
|
|
||||||
// containers.push(Container::new((5, 5), (15, 5), true));
|
|
||||||
// containers.push(Container::new((10, 3), (50, 20), true));
|
|
||||||
//
|
|
||||||
// let mut bar = IndicatorBar::new((10, 6), 12);
|
|
||||||
// let mut bar2 = IndicatorBar::new((10, 7), 12);
|
|
||||||
//
|
|
||||||
// bar.set_value(43);
|
|
||||||
// bar.abs = 101;
|
|
||||||
// bar2.set_value(14);
|
|
||||||
// bar2.abs = 15;
|
|
||||||
// containers[1].elements.push(Box::new(bar));
|
|
||||||
// containers[1].elements.push(Box::new(bar2));
|
|
||||||
//
|
|
||||||
// let tbox = libgui_elements::TextBox::new(
|
|
||||||
// String::from("panic attack simps"),
|
|
||||||
// String::from("i have finally obtained evidence of his simpiness against tari and crystal, however i cannot reveal this evidence for now, however, once the contract is over NO ONE CAN STOP ME MWHAHAHAHAHA"),
|
|
||||||
// Pos::new(25, 10),
|
|
||||||
// Pos::new(10, 9),
|
|
||||||
// true,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// containers[1].elements.push(Box::new(tbox));
|
|
||||||
//
|
|
||||||
// */
|
|
||||||
//
|
|
||||||
// containers.push(Container::new(Pos::new(0, 1), Pos::new(80, 24), true));
|
|
||||||
//
|
|
||||||
// let tbox = libgui_elements::TextBox::new(
|
|
||||||
// String::from("ANNOUNCEMENTS"),
|
|
||||||
// String::from(
|
|
||||||
// "CrystalRPG coming soon! XD
|
|
||||||
// this is gonna be the best game ever",
|
|
||||||
// ),
|
|
||||||
// Pos::new(25, 10),
|
|
||||||
// Pos::new(0, 0),
|
|
||||||
// true,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// containers[0].elements.push(Box::new(&tbox));
|
|
||||||
//
|
|
||||||
// let mut bar = IndicatorBar::new(Pos::new(7, 7), 12);
|
|
||||||
// bar.set_value(70);
|
|
||||||
// bar.set_text(String::from("ayo"));
|
|
||||||
//
|
|
||||||
// containers[0].elements.push(Box::new(bar));
|
|
||||||
// render_frame(containers);
|
|
||||||
//
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function to generate a box in a random location on the screen.
|
|
||||||
|
|
||||||
fn generate_box() -> Container<'static> {
|
|
||||||
use crate::std::random::Random;
|
|
||||||
let width = Random::int(5, 20);
|
|
||||||
let height = Random::int(5, 10);
|
|
||||||
let xoffset = Random::int(5, 50);
|
|
||||||
let yoffset = Random::int(5, 10);
|
|
||||||
Container::new(Pos::new(width, height), Pos::new(xoffset, yoffset), true)
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
use super::libgui_core::{self, Pos};
|
|
||||||
use crate::std::io::println;
|
|
||||||
use alloc::{
|
|
||||||
string::{String, ToString},
|
|
||||||
vec::Vec,
|
|
||||||
};
|
|
||||||
|
|
||||||
// TEXT BOX
|
|
||||||
// a widget to display text in a box
|
|
||||||
// has a title and a body
|
|
||||||
pub struct TextBox {
|
|
||||||
dimensions: Pos,
|
|
||||||
position: Pos,
|
|
||||||
content: String,
|
|
||||||
title: String,
|
|
||||||
outlined: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
// implements all rendering for TextBox widget
|
|
||||||
impl libgui_core::Element for TextBox {
|
|
||||||
fn render(&self) -> (Vec<Vec<char>>, Pos) {
|
|
||||||
let mut charmap = Vec::<Vec<char>>::new();
|
|
||||||
let mut inner_dims = Pos::new(self.dimensions.x - 2, self.dimensions.y - 2);
|
|
||||||
|
|
||||||
// generate outline if required
|
|
||||||
if self.outlined {
|
|
||||||
charmap = libgui_core::gen_outline(self.dimensions);
|
|
||||||
}
|
|
||||||
|
|
||||||
// render title
|
|
||||||
let mut titlechars = self.title.chars().collect::<Vec<char>>();
|
|
||||||
for (i, char) in titlechars.iter().enumerate() {
|
|
||||||
if i < inner_dims.x {
|
|
||||||
charmap[0][i + 1] = *char;
|
|
||||||
} else {
|
|
||||||
charmap[0][inner_dims.x - 0] = '.';
|
|
||||||
charmap[0][inner_dims.x - 1] = '.';
|
|
||||||
charmap[0][inner_dims.x - 2] = '.';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// render text
|
|
||||||
let mut pos = Pos::new(0, 0);
|
|
||||||
|
|
||||||
for chr in self.content.chars().collect::<Vec<char>>() {
|
|
||||||
if pos.x < inner_dims.x {
|
|
||||||
if chr != '\n' {
|
|
||||||
charmap[pos.y + 1][pos.x + 1] = chr;
|
|
||||||
pos.x += 1;
|
|
||||||
} else {
|
|
||||||
pos.y += 1;
|
|
||||||
pos.x = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// next line
|
|
||||||
pos.y += 1;
|
|
||||||
pos.x = 1;
|
|
||||||
|
|
||||||
if pos.y < inner_dims.y {
|
|
||||||
charmap[pos.y + 1][1] = chr;
|
|
||||||
} else {
|
|
||||||
// handles overflow out of the end of the box
|
|
||||||
charmap[inner_dims.y][inner_dims.x] = '»';
|
|
||||||
charmap[inner_dims.y + 1][inner_dims.x - 0] = '.';
|
|
||||||
charmap[inner_dims.y + 1][inner_dims.x - 1] = '.';
|
|
||||||
charmap[inner_dims.y + 1][inner_dims.x - 2] = '.';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (charmap, self.position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TextBox {
|
|
||||||
pub fn new(
|
|
||||||
title: String,
|
|
||||||
content: String,
|
|
||||||
dimensions: Pos,
|
|
||||||
position: Pos,
|
|
||||||
outlined: bool,
|
|
||||||
) -> TextBox {
|
|
||||||
TextBox {
|
|
||||||
dimensions,
|
|
||||||
position,
|
|
||||||
content,
|
|
||||||
title,
|
|
||||||
outlined,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct IndicatorBox {
|
|
||||||
pub bars: Vec<libgui_core::IndicatorBar>,
|
|
||||||
position: Pos,
|
|
||||||
dimensions: Pos,
|
|
||||||
}
|
|
||||||
impl IndicatorBox {
|
|
||||||
pub fn new(position: Pos, dimensions: Pos) -> IndicatorBox {
|
|
||||||
Self {
|
|
||||||
bars: Vec::new(),
|
|
||||||
position,
|
|
||||||
dimensions,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn add_item(&mut self) {}
|
|
||||||
}
|
|
||||||
impl libgui_core::Element for IndicatorBox {
|
|
||||||
fn render(&self) -> (Vec<Vec<char>>, Pos) {
|
|
||||||
(Vec::<Vec<char>>::new(), Pos::new(0, 0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
pub mod libgui_core;
|
|
||||||
pub mod libgui_elements;
|
|
||||||
Reference in New Issue
Block a user