- added a new API for switching between terminal and application mode

- removed unneeded imports to reduce the dumb amount of warnings from the compiler
- added a bounds check in frame.rs to avoid a panic when a frame tries to render a character out of bounds, instead returning an error
This commit is contained in:
FantasyPvP
2024-03-22 00:12:15 +00:00
parent 5c6ec299ee
commit d5d9e031d5
29 changed files with 439 additions and 436 deletions
+2 -5
View File
@@ -1,13 +1,10 @@
use hashbrown::HashMap;
use spin::{Mutex, MutexGuard};
use crate::{printerr, serial_println};
use crate::std::frame::{ColouredChar, Dimensions, Position, special_char, Frame, RenderError, ColorCode};
use spin::{Mutex};
use crate::std::frame::{Frame, RenderError};
use alloc::{
boxed::Box,
sync::Arc,
vec::Vec,
vec,
string::String,
};
use core::any::Any;
+8 -9
View File
@@ -2,7 +2,6 @@ use alloc::string::String;
use alloc::vec::Vec;
use alloc::boxed::Box;
use core::any::Any;
use core::task::ready;
use async_trait::async_trait;
use crate::std::application::Exit;
use crate::std::frame::{ColouredChar, Dimensions, Frame, Position, RenderError};
@@ -23,7 +22,7 @@ impl CgLineEdit {
CgLineEdit {
position,
dimensions: Dimensions::new(width, 1),
prompt: prompt,
prompt,
text: Vec::new(),
ptr: 0
}
@@ -39,24 +38,24 @@ impl CgComponent for CgLineEdit {
if idx >= self.dimensions.x {
break;
}
frame.write(Position::new(idx, 0), ColouredChar::new(c));
frame.write(Position::new(idx, 0), ColouredChar::new(c)).unwrap();
idx += 1
}
idx += 1; // create a space between the prompt and the text
if idx + self.text.len() > self.dimensions.x {
frame.write(Position::new(idx, 0), ColouredChar::new('['));
frame.write(Position::new(idx + 1, 0), ColouredChar::new('.'));
frame.write(Position::new(idx + 2, 0), ColouredChar::new('.'));
frame.write(Position::new(idx + 3, 0), ColouredChar::new('.'));
frame.write(Position::new(idx + 4, 0), ColouredChar::new(']'));
frame.write(Position::new(idx, 0), ColouredChar::new('[')).unwrap();
frame.write(Position::new(idx + 1, 0), ColouredChar::new('.')).unwrap();
frame.write(Position::new(idx + 2, 0), ColouredChar::new('.')).unwrap();
frame.write(Position::new(idx + 3, 0), ColouredChar::new('.')).unwrap();
frame.write(Position::new(idx + 4, 0), ColouredChar::new(']')).unwrap();
idx += 5
}
self.text.iter().rev().take(self.dimensions.x - idx).rev().for_each(|c| {
frame.write(Position::new(idx, 0), ColouredChar::new(*c));
frame.write(Position::new(idx, 0), ColouredChar::new(*c)).unwrap();
idx += 1
});
+12 -10
View File
@@ -1,21 +1,23 @@
use crate::std::frame::{ColouredChar, Dimensions, Frame, Position};
use crate::std::frame::{ColouredChar, Dimensions, Frame, Position, RenderError};
pub(crate) fn render_outline(frame: &mut Frame, dimensions: Dimensions) {
pub(crate) fn render_outline(frame: &mut Frame, dimensions: Dimensions) -> Result<(), RenderError> {
// draws the sides of the container
for i in 0..frame.dimensions.x {
frame.write(Position::new(i, 0), ColouredChar::new('─'));
frame.write(Position::new(i, frame.dimensions.y - 1), ColouredChar::new('─'));
frame.write(Position::new(i, 0), ColouredChar::new('─'))?;
frame.write(Position::new(i, frame.dimensions.y - 1), ColouredChar::new('─'))?;
}
// draws the top and bottom of the container
for i in 0..frame.dimensions.y {
frame.write(Position::new(0, i), ColouredChar::new('│'));
frame.write(Position::new(frame.dimensions.x - 1, i), ColouredChar::new('│'));
frame.write(Position::new(0, i), ColouredChar::new('│'))?;
frame.write(Position::new(frame.dimensions.x - 1, i), ColouredChar::new('│'))?;
}
// draws the corners of the container
frame.write(Position::new(0, 0), ColouredChar::new('┌'));
frame.write(Position::new(dimensions.x - 1, 0), ColouredChar::new('┐'));
frame.write(Position::new(0, dimensions.y - 1), ColouredChar::new('└'));
frame.write(Position::new(dimensions.x - 1, dimensions.y - 1), ColouredChar::new('┘'));
frame.write(Position::new(0, 0), ColouredChar::new('┌'))?;
frame.write(Position::new(dimensions.x - 1, 0), ColouredChar::new('┐'))?;
frame.write(Position::new(0, dimensions.y - 1), ColouredChar::new('└'))?;
frame.write(Position::new(dimensions.x - 1, dimensions.y - 1), ColouredChar::new('┘'))?;
Ok(())
}
+23 -22
View File
@@ -1,13 +1,11 @@
use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
use alloc::fmt::format;
use alloc::{boxed::Box, format, string::String, vec::Vec};
use alloc::string::ToString;
use core::any::Any;
use core::cmp::{max, min};
use async_trait::async_trait;
use hashbrown::HashMap;
use crate::serial_println;
use crate::std::application::Exit;
use super::cg_core::{CgComponent, CgKeyboardCapture, CgOutline, Widget};
use super::cg_core::{CgComponent, CgKeyboardCapture, Widget};
use super::cg_utils::render_outline;
use crate::std::frame::{ColouredChar, Dimensions, Position, Frame, RenderError, ColorCode, BUFFER_WIDTH, BUFFER_HEIGHT};
use crate::std::io::{Color, KeyStroke, Stdin};
@@ -48,7 +46,7 @@ impl CgComponent for CgContainer {
}
if self.outlined {
render_outline(&mut result, self.dimensions.clone());
render_outline(&mut result, self.dimensions.clone())?;
}
Ok(result)
@@ -73,17 +71,18 @@ impl CgTextBox {
CgTextBox { title, content, position, dimensions, outlined, wrap_words: true }
}
fn render_title(&self, frame: &mut Frame) {
fn render_title(&self, frame: &mut Frame) -> Result<(), RenderError>{
let title = self.title.chars();
for (i, c) in title.enumerate() {
if i + 2 == self.dimensions.x - 3 { // we don't want to write at the top of the text box
frame.write(Position::new(i + 1, 0), ColouredChar::new('.'));
frame.write(Position::new(i + 1, 0), ColouredChar::new('.'))?;
} else if i + 2 >= self.dimensions.x - 2 {
frame.write(Position::new(i + 1, 0), ColouredChar::new('.'));
frame.write(Position::new(i + 1, 0), ColouredChar::new('.'))?;
break;
}
frame.write(Position::new(i + 2, 0), ColouredChar::new(c));
}
frame.write(Position::new(i + 2, 0), ColouredChar::new(c))?;
};
Ok(())
}
pub fn wrap_words(&mut self, wrap: bool) {
self.wrap_words = wrap;
@@ -95,10 +94,10 @@ impl CgComponent for CgTextBox {
let mut result = Frame::new(self.position, self.dimensions)?;
if self.outlined {
render_outline(&mut result, self.dimensions.clone());
render_outline(&mut result, self.dimensions.clone())?;
}
self.render_title(&mut result);
self.render_title(&mut result)?;
let (mut x, mut y) = (1, 1);
@@ -123,13 +122,13 @@ impl CgComponent for CgTextBox {
if y == self.dimensions.y - 1 {
if c != ' ' {
(2..5).for_each(|z| {
result.write(Position::new(self.dimensions.x - z, self.dimensions.y - 1), ColouredChar::new('.'));
result.write(Position::new(self.dimensions.x - z, self.dimensions.y - 1), ColouredChar::new('.')).unwrap();
})
}
break;
}
result.write(Position::new(x, y), ColouredChar::new(c));
result.write(Position::new(x, y), ColouredChar::new(c))?;
x += 1;
};
}
@@ -180,11 +179,11 @@ impl CgComponent for CgLabel {
for (i, c) in shortened_string.chars().enumerate() {
if i + left >= self.dimensions.x {
(0..3).for_each(|z| {
result.write(Position::new(self.dimensions.x - z + left, self.dimensions.y - 1), ColouredChar::new('.'));
result.write(Position::new(self.dimensions.x - z + left, self.dimensions.y - 1), ColouredChar::new('.')).expect("failed to write");
});
break;
}
result.write(Position::new(i + left, 0), ColouredChar::new(c));
result.write(Position::new(i + left, 0), ColouredChar::new(c))?;
};
Ok(result)
}
@@ -235,7 +234,7 @@ impl CgComponent for CgIndicatorWidget {
let shortened_string = self.content.chars().take(self.max_width).collect::<String>();
for (i, c) in shortened_string.chars().enumerate() {
result.write(Position::new(i, 0), ColouredChar::coloured(c, self.colour));
result.write(Position::new(i, 0), ColouredChar::coloured(c, self.colour)).expect("failed to render indicator widget");
};
Ok(result)
@@ -419,7 +418,9 @@ impl CgComponent for CgDialog {
// now that we know the X and Y offsets, we can start to draw the frame
let mut frame = Frame::new(Position::new(x_offset, y_offset), Dimensions::new(width, height))?;
render_outline(&mut frame, Dimensions::new(width, height));
if let Err(e) = render_outline(&mut frame, Dimensions::new(width, height)) {
return Err(e);
}
// render title
@@ -449,7 +450,7 @@ impl CgComponent for CgDialog {
break;
}
frame.write(Position::new(x, y), ColouredChar::new(c));
frame.write(Position::new(x, y), ColouredChar::new(c)).unwrap();
x += 1;
};
}
@@ -462,7 +463,7 @@ impl CgComponent for CgDialog {
frame.write(Position::new(button_x_offset + i, height - 3), ColouredChar {
character: c,
colour: ColorCode::new(Color::Cyan, Color::Black),
});
}).expect("failed to write to frame, perhaps buttons were placed wrongly or width too great");
})
}
CgDialogType::Confirmation => {
@@ -483,7 +484,7 @@ impl CgComponent for CgDialog {
let button_x_offset = (width - button_fmt.len()) / 2;
button_fmt.into_iter().enumerate().for_each(|(i, c)| {
frame.write(Position::new(button_x_offset + i, height - 3), c);
frame.write(Position::new(button_x_offset + i, height - 3), c).expect("failed to write to frame, perhaps buttons were placed wrongly or width too great");
})
},
CgDialogType::Selection(options) => {
@@ -504,7 +505,7 @@ impl CgComponent for CgDialog {
let button_x_offset = (width - button_fmt.len()) / 2;
button_fmt.into_iter().enumerate().for_each(|(i, c)| {
frame.write(Position::new(button_x_offset + i, height - 3), c);
frame.write(Position::new(button_x_offset + i, height - 3), c).expect("failed to write to frame, perhaps buttons were placed wrongly or width too great");
})
}
};