we frikin did it bois
gui library works frrr implementation: - containers now store a Widget type. - every widget has a unique id - there is a data store that maps the id to the internally stored gui component. - the compoenents can be fetched from the datastore using their Widget type - the datastore uses a hashmap so fetching shouldnt have any real performance penalty. - widgets can be fetched, inserted, updated and rendered from the datastore - the render method can be called directly from the Widget type without having to know the underlying type that it references
This commit is contained in:
+41
-16
@@ -3,6 +3,7 @@ use alloc::{format, vec};
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
|
use core::any::Any;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use crate::{println, serial_println};
|
use crate::{println, serial_println};
|
||||||
@@ -17,18 +18,20 @@ use crate::user::lib::libgui::{
|
|||||||
cg_widgets::CgContainer,
|
cg_widgets::CgContainer,
|
||||||
cg_inputs::CgLineEdit,
|
cg_inputs::CgLineEdit,
|
||||||
};
|
};
|
||||||
use crate::user::lib::libgui::cg_core::CgTextEdit;
|
use crate::user::lib::libgui::cg_core::{CgTextEdit, Widget};
|
||||||
|
|
||||||
use super::calc;
|
use super::calc;
|
||||||
|
|
||||||
const OFFSET_X: i64 = 39;
|
const OFFSET_X: i64 = 39;
|
||||||
const OFFSET_Y: i64 = 10;
|
const OFFSET_Y: i64 = 10;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Grapher {
|
pub struct Grapher {
|
||||||
points: Vec<PointF64>,
|
points: Vec<PointF64>,
|
||||||
frame: Frame,
|
frame: Frame,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
struct PointF64 {
|
struct PointF64 {
|
||||||
x: f64,
|
x: f64,
|
||||||
y: f64,
|
y: f64,
|
||||||
@@ -71,35 +74,40 @@ impl Application for Grapher {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let mut entry_box = CgLineEdit::new(
|
let mut container = CgContainer::new(
|
||||||
|
Position::new(0, 0),
|
||||||
|
Dimensions::new(80, 25),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
container.insert("entry_box", Widget::insert(CgLineEdit::new(
|
||||||
Position::new(1, 23),
|
Position::new(1, 23),
|
||||||
78,
|
78,
|
||||||
String::from("function >")
|
String::from("function >")
|
||||||
);
|
)));
|
||||||
|
container.insert("grapher", Widget::insert(self.clone()));
|
||||||
|
|
||||||
let mut commandresult = String::new();
|
let mut commandresult = String::new();
|
||||||
|
|
||||||
while let c = Stdin::keystroke().await {
|
while let c = Stdin::keystroke().await {
|
||||||
let mut container = CgContainer::new(
|
|
||||||
Position::new(0, 0),
|
let mut entry_widget = container.elements.get("entry_box").unwrap();
|
||||||
Dimensions::new(80, 25),
|
let mut entry = entry_widget.fetch::<CgLineEdit>().unwrap();
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
match c {
|
match c {
|
||||||
KeyStroke::Char('\n') => {
|
KeyStroke::Char('\n') => {
|
||||||
commandresult = entry_box.text.iter().collect();
|
commandresult = entry.text.iter().collect();
|
||||||
entry_box.clear();
|
entry.clear();
|
||||||
},
|
},
|
||||||
KeyStroke::Char(Stdin::BACKSPACE) => {
|
KeyStroke::Char(Stdin::BACKSPACE) => {
|
||||||
entry_box.backspace()
|
entry.backspace()
|
||||||
},
|
},
|
||||||
KeyStroke::Char('`') => {
|
KeyStroke::Char('`') => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
KeyStroke::Char(c) => entry_box.write_char(c),
|
KeyStroke::Char(c) => entry.write_char(c),
|
||||||
KeyStroke::Left => entry_box.move_cursor(false),
|
KeyStroke::Left => entry.move_cursor(false),
|
||||||
KeyStroke::Right => entry_box.move_cursor(true),
|
KeyStroke::Right => entry.move_cursor(true),
|
||||||
KeyStroke::Alt => break,
|
KeyStroke::Alt => break,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -107,13 +115,27 @@ impl Application for Grapher {
|
|||||||
if commandresult.len() > 0 {
|
if commandresult.len() > 0 {
|
||||||
self.reset_frame();
|
self.reset_frame();
|
||||||
self.graph_equation(commandresult.clone());
|
self.graph_equation(commandresult.clone());
|
||||||
|
|
||||||
|
let self_widget = container.elements.get("grapher").unwrap();
|
||||||
|
self_widget.update(self.clone());
|
||||||
|
|
||||||
commandresult.clear();
|
commandresult.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
container.insert(Box::new(self));
|
serial_println!("{:?}", entry.text);
|
||||||
container.insert(Box::new(&entry_box));
|
entry_widget.update(entry);
|
||||||
|
|
||||||
if let Ok(frame) = container.render() {
|
if let Ok(frame) = container.render() {
|
||||||
|
|
||||||
|
let self_widget = container.elements.get("grapher").unwrap();
|
||||||
|
let self_clone = self_widget.fetch::<Grapher>().unwrap();
|
||||||
|
serial_println!("{:?}", self_clone.points);
|
||||||
|
|
||||||
|
let entry = container.elements.get("entry_box").unwrap();
|
||||||
|
let entry_clone = entry.fetch::<CgLineEdit>().unwrap();
|
||||||
|
serial_println!("{:?}", entry_clone.text);
|
||||||
|
|
||||||
|
|
||||||
frame.write_to_screen().map_err(|_| Error::ApplicationError(String::from("failed to write to screen")))?;
|
frame.write_to_screen().map_err(|_| Error::ApplicationError(String::from("failed to write to screen")))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,6 +193,9 @@ impl CgComponent for Grapher {
|
|||||||
fn render(&self) -> Result<Frame, RenderError> {
|
fn render(&self) -> Result<Frame, RenderError> {
|
||||||
Ok(self.frame.clone())
|
Ok(self.frame.clone())
|
||||||
}
|
}
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+58
-33
@@ -16,6 +16,7 @@ use crate::user::lib::libgui::{
|
|||||||
cg_widgets::{CgTextBox, CgContainer, CgIndicatorBar, CgIndicatorWidget, CgLabel, CgStatusBar},
|
cg_widgets::{CgTextBox, CgContainer, CgIndicatorBar, CgIndicatorWidget, CgLabel, CgStatusBar},
|
||||||
cg_inputs::CgLineEdit,
|
cg_inputs::CgLineEdit,
|
||||||
};
|
};
|
||||||
|
use crate::user::lib::libgui::cg_core::Widget;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref CMD: Mutex<CommandHandler> = Mutex::new(CommandHandler::new());
|
pub static ref CMD: Mutex<CommandHandler> = Mutex::new(CommandHandler::new());
|
||||||
@@ -268,6 +269,8 @@ async fn setup_ui(input: impl Fn(KeyStroke) -> (KeyStroke, bool)) {
|
|||||||
40,
|
40,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test_new_datastore().await;
|
||||||
|
|
||||||
let mut statusbar = CgStatusBar::new(Position::new(0, 0), Dimensions::new(80, 1));
|
let mut statusbar = CgStatusBar::new(Position::new(0, 0), Dimensions::new(80, 1));
|
||||||
|
|
||||||
let mut textedit = CgLineEdit::new(
|
let mut textedit = CgLineEdit::new(
|
||||||
@@ -278,41 +281,65 @@ async fn setup_ui(input: impl Fn(KeyStroke) -> (KeyStroke, bool)) {
|
|||||||
|
|
||||||
let mut commandresult = String::new();
|
let mut commandresult = String::new();
|
||||||
|
|
||||||
while let (c, false) = input(Stdin::keystroke().await) {
|
// while let (c, false) = input(Stdin::keystroke().await) {
|
||||||
let mut container = CgContainer::new(
|
// let mut container = CgContainer::new(
|
||||||
Position::new(0, 0),
|
// Position::new(0, 0),
|
||||||
Dimensions::new(80, 25),
|
// Dimensions::new(80, 25),
|
||||||
false,
|
// false,
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
|
// match c {
|
||||||
|
// KeyStroke::Char('\n') => {
|
||||||
|
// commandresult = textedit.text.iter().collect();
|
||||||
|
// textedit.clear();
|
||||||
|
// },
|
||||||
|
// KeyStroke::Char(Stdin::BACKSPACE) => {
|
||||||
|
// serial_println!("backspace");
|
||||||
|
// textedit.backspace()
|
||||||
|
// },
|
||||||
|
// KeyStroke::Char(c) => textedit.write_char(c),
|
||||||
|
// KeyStroke::Left => textedit.move_cursor(false),
|
||||||
|
// KeyStroke::Right => textedit.move_cursor(true),
|
||||||
|
// _ => {}
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if commandresult.len() > 0 {
|
||||||
|
// let string = commandresult.clone();
|
||||||
|
// textbox.content = string;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// container.insert(Box::new(textbox.clone()));
|
||||||
|
// container.insert(Box::new(statusbar.clone()));
|
||||||
|
// container.insert(Box::new(textedit.clone()));
|
||||||
|
//
|
||||||
|
// if let Ok(frame) = container.render() {
|
||||||
|
// frame.write_to_screen().unwrap();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
match c {
|
async fn test_new_datastore() {
|
||||||
KeyStroke::Char('\n') => {
|
let container = Widget::insert(CgContainer::new(
|
||||||
commandresult = textedit.text.iter().collect();
|
Position::new(0, 0),
|
||||||
textedit.clear();
|
Dimensions::new(80, 25),
|
||||||
},
|
true,
|
||||||
KeyStroke::Char(Stdin::BACKSPACE) => {
|
));
|
||||||
serial_println!("backspace");
|
|
||||||
textedit.backspace()
|
|
||||||
},
|
|
||||||
KeyStroke::Char(c) => textedit.write_char(c),
|
|
||||||
KeyStroke::Left => textedit.move_cursor(false),
|
|
||||||
KeyStroke::Right => textedit.move_cursor(true),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if commandresult.len() > 0 {
|
let textbox = Widget::insert(CgTextBox::new(
|
||||||
let string = commandresult.clone();
|
String::from("test textbox"),
|
||||||
textbox.content = string;
|
String::from("dam"),
|
||||||
}
|
Position::new(2, 5),
|
||||||
|
Dimensions::new(40, 12),
|
||||||
|
true,
|
||||||
|
));
|
||||||
|
|
||||||
container.insert(Box::new(&textbox));
|
let mut c = textbox.fetch::<CgTextBox>().unwrap();
|
||||||
container.insert(Box::new(&statusbar));
|
c.content = String::from("dam2");
|
||||||
container.insert(Box::new(&textedit));
|
textbox.update(c);
|
||||||
|
|
||||||
if let Ok(frame) = container.render() {
|
let c = textbox.fetch::<CgTextBox>().unwrap();
|
||||||
frame.write_to_screen().unwrap();
|
|
||||||
}
|
serial_println!("{}", c.content);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -333,8 +360,6 @@ async fn setup_ui(input: impl Fn(KeyStroke) -> (KeyStroke, bool)) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
use alloc::boxed::Box;
|
use hashbrown::HashMap;
|
||||||
use alloc::string::String;
|
use spin::{Mutex, MutexGuard};
|
||||||
use alloc::vec;
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use core::slice::from_mut;
|
|
||||||
use crate::{printerr, serial_println};
|
use crate::{printerr, serial_println};
|
||||||
use crate::std::frame::{ColouredChar, Dimensions, Position, special_char, Frame, RenderError, ColorCode};
|
use crate::std::frame::{ColouredChar, Dimensions, Position, special_char, Frame, RenderError, ColorCode};
|
||||||
use crate::user::lib::libgui::cg_inputs::CgLineEdit;
|
|
||||||
use crate::user::lib::libgui::cg_widgets::{CgContainer, CgTextBox, CgIndicatorBar, CgIndicatorWidget, CgLabel, CgStatusBar};
|
use alloc::{
|
||||||
|
boxed::Box,
|
||||||
|
sync::Arc,
|
||||||
|
vec::Vec,
|
||||||
|
vec,
|
||||||
|
string::String,
|
||||||
|
};
|
||||||
|
use core::any::Any;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
/// implement this trait if you require the widget to be able to have an outline
|
/// implement this trait if you require the widget to be able to have an outline
|
||||||
pub trait CgOutline: CgComponent {
|
pub trait CgOutline: CgComponent {
|
||||||
@@ -15,10 +20,13 @@ pub trait CgOutline: CgComponent {
|
|||||||
|
|
||||||
/// generic components for the user interface that defined a render method. this should be implemented for all types
|
/// generic components for the user interface that defined a render method. this should be implemented for all types
|
||||||
/// that can be rendered to the screen.
|
/// that can be rendered to the screen.
|
||||||
pub trait CgComponent {
|
pub trait CgComponent: Any {
|
||||||
fn render(&self) -> Result<Frame, RenderError>;
|
fn render(&self) -> Result<Frame, RenderError>;
|
||||||
|
|
||||||
|
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
|
||||||
@@ -26,3 +34,108 @@ pub trait CgTextEdit: CgComponent {
|
|||||||
fn move_cursor(&mut self, direction: bool); // true = right, false = left
|
fn move_cursor(&mut self, direction: bool); // true = right, false = left
|
||||||
fn clear(&mut self);
|
fn clear(&mut self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static ID_COUNTER: Mutex<usize> = Mutex::new(0);
|
||||||
|
|
||||||
|
lazy_static!(
|
||||||
|
static ref GUITREE: Mutex<DataStore> = Mutex::new(DataStore::new());
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
|
pub struct Widget {
|
||||||
|
id: usize,
|
||||||
|
}
|
||||||
|
impl Widget {
|
||||||
|
fn new() -> Self {
|
||||||
|
let mut id_counter = ID_COUNTER.lock();
|
||||||
|
let id = Widget {
|
||||||
|
id: *id_counter
|
||||||
|
};
|
||||||
|
*id_counter += 1;
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fetch<T: 'static + Send + Sync + Clone + CgComponent>(&self) -> Option<T> {
|
||||||
|
GUITREE.lock().fetch(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert<T: 'static + Send + Sync + Clone + CgComponent>(item: T) -> Self {
|
||||||
|
let mut id_counter = ID_COUNTER.lock();
|
||||||
|
let id = Widget { id: *id_counter };
|
||||||
|
*id_counter += 1;
|
||||||
|
GUITREE.lock().insert(&id, item);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update<T: 'static + Send + Sync + Clone + CgComponent>(&self, item: T) {
|
||||||
|
GUITREE.lock().insert(self, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self) -> Result<Frame, RenderError> {
|
||||||
|
if let Some(frame) = GUITREE.lock().frame(self) {
|
||||||
|
frame
|
||||||
|
} else {
|
||||||
|
panic!("CRITICAL: Widget not found in tree");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Widget {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
GUITREE.lock().remove(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct DataStore {
|
||||||
|
items: Mutex<HashMap<usize, Arc<Mutex<dyn CgComponent + Send + Sync>>>>,
|
||||||
|
id_counter: Mutex<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataStore {
|
||||||
|
fn new() -> Self {
|
||||||
|
DataStore {
|
||||||
|
items: Mutex::new(HashMap::new()),
|
||||||
|
id_counter: Mutex::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert<T: 'static + CgComponent + Send + Sync + Clone>(&self, id: &Widget, item: T) {
|
||||||
|
let mut items = self.items.lock();
|
||||||
|
items.insert(id.id, Arc::new(Mutex::new(item)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch<T: 'static + Send + Sync + Clone>(&self, id: &Widget) -> Option<T> where T: Any + Send + Sync {
|
||||||
|
let id = id.id;
|
||||||
|
|
||||||
|
let items = self.items.lock();
|
||||||
|
items.get(&id).and_then(|arc| {
|
||||||
|
let any_mutex = arc.lock();
|
||||||
|
let any_ref = any_mutex.as_any();
|
||||||
|
any_ref.downcast_ref::<T>().cloned()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(&self, id: &Widget) -> Option<Result<Frame, RenderError>> {
|
||||||
|
let items = self.items.lock();
|
||||||
|
items.get(&id.id).and_then(|arc| {
|
||||||
|
let item = arc.lock();
|
||||||
|
Some(item.render())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&self, id: &Widget) {
|
||||||
|
let mut items = self.items.lock();
|
||||||
|
items.remove(&id.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::any::Any;
|
||||||
use crate::std::frame::{ColouredChar, Dimensions, Frame, Position, RenderError};
|
use crate::std::frame::{ColouredChar, Dimensions, Frame, Position, RenderError};
|
||||||
use crate::user::lib::libgui::cg_core::{CgComponent, CgTextEdit};
|
use crate::user::lib::libgui::cg_core::{CgComponent, CgTextEdit};
|
||||||
|
|
||||||
@@ -56,6 +57,9 @@ impl CgComponent for CgLineEdit {
|
|||||||
|
|
||||||
Ok(frame)
|
Ok(frame)
|
||||||
}
|
}
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CgTextEdit for CgLineEdit {
|
impl CgTextEdit for CgLineEdit {
|
||||||
|
|||||||
@@ -1,36 +1,37 @@
|
|||||||
use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
|
use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
|
||||||
use alloc::fmt::format;
|
use alloc::fmt::format;
|
||||||
use alloc::string::ToString;
|
use alloc::string::ToString;
|
||||||
|
use core::any::Any;
|
||||||
use core::cmp::{max, min};
|
use core::cmp::{max, min};
|
||||||
|
use hashbrown::HashMap;
|
||||||
use crate::serial_println;
|
use crate::serial_println;
|
||||||
use super::cg_core::{
|
use super::cg_core::{CgComponent, CgOutline, Widget};
|
||||||
CgComponent, CgOutline
|
|
||||||
};
|
|
||||||
use crate::std::frame::{ColouredChar, Dimensions, Position, Frame, RenderError, ColorCode};
|
use crate::std::frame::{ColouredChar, Dimensions, Position, Frame, RenderError, ColorCode};
|
||||||
use crate::std::io::Color;
|
use crate::std::io::Color;
|
||||||
|
|
||||||
pub struct CgContainer<'a> {
|
#[derive(Debug, Clone)]
|
||||||
pub elements: Vec<Box<&'a dyn CgComponent>>,
|
pub struct CgContainer {
|
||||||
|
pub elements: HashMap<&'static str, Widget>,
|
||||||
pub position: Position,
|
pub position: Position,
|
||||||
pub dimensions: Dimensions,
|
pub dimensions: Dimensions,
|
||||||
pub outlined: bool,
|
pub outlined: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CgContainer<'a> {
|
impl CgContainer {
|
||||||
pub fn new(position: Position, dimensions: Dimensions, outlined: bool) -> CgContainer<'a> {
|
pub fn new(position: Position, dimensions: Dimensions, outlined: bool) -> CgContainer {
|
||||||
CgContainer {
|
CgContainer {
|
||||||
elements: Vec::new(),
|
elements: HashMap::new(),
|
||||||
position,
|
position,
|
||||||
dimensions,
|
dimensions,
|
||||||
outlined,
|
outlined,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn insert(&mut self, element: Box<&'a dyn CgComponent>) {
|
pub fn insert(&mut self, name: &'static str, element: Widget) {
|
||||||
self.elements.push(element);
|
self.elements.insert(name,element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CgOutline for CgContainer<'_> {
|
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 {
|
||||||
@@ -52,12 +53,12 @@ impl CgOutline for CgContainer<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)?;
|
||||||
|
|
||||||
for widget in &self.elements {
|
for widget in &self.elements {
|
||||||
let frame = widget.render()?;
|
let frame = widget.1.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.place_child_element(&frame),
|
Ok(()) => result.place_child_element(&frame),
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
@@ -70,6 +71,9 @@ impl CgComponent for CgContainer<'_> {
|
|||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -150,7 +154,9 @@ impl CgComponent for CgTextBox {
|
|||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -210,6 +216,9 @@ impl CgComponent for CgLabel {
|
|||||||
};
|
};
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -259,6 +268,9 @@ impl CgComponent for CgIndicatorWidget {
|
|||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -301,6 +313,9 @@ impl CgComponent for CgIndicatorBar {
|
|||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -333,6 +348,9 @@ impl CgComponent for CgStatusBar {
|
|||||||
|
|
||||||
Ok(frame)
|
Ok(frame)
|
||||||
}
|
}
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CgStatusBar {
|
impl CgStatusBar {
|
||||||
|
|||||||
Reference in New Issue
Block a user