holy (crab) that was a lot of work
it works. the input function is working now, passing it a reference to your root gui widget and a reference to it's own widget and a function to check if it should exit works now gg
This commit is contained in:
@@ -18,3 +18,8 @@ pub enum Error {
|
||||
EmptyCommand,
|
||||
}
|
||||
|
||||
pub enum Exit {
|
||||
None,
|
||||
Exit,
|
||||
ExitWithError(Error),
|
||||
}
|
||||
+52
-56
@@ -3,9 +3,10 @@ use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
|
||||
use alloc::{boxed::Box, string::{String, ToString}, vec, vec::Vec};
|
||||
use futures_util::TryFutureExt;
|
||||
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, Exit}, user::bin::*};
|
||||
use crate::std::frame::{Dimensions, Position, ColorCode};
|
||||
use crate::std::io::{Color, write, Screen, Stdin, Serial, KeyStroke};
|
||||
use crate::std::random::Random;
|
||||
@@ -16,7 +17,7 @@ use crate::user::lib::libgui::{
|
||||
cg_widgets::{CgTextBox, CgContainer, CgIndicatorBar, CgIndicatorWidget, CgLabel, CgStatusBar},
|
||||
cg_inputs::CgLineEdit,
|
||||
};
|
||||
use crate::user::lib::libgui::cg_core::Widget;
|
||||
use crate::user::lib::libgui::cg_core::{CgTextInput, Widget};
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CMD: Mutex<CommandHandler> = Mutex::new(CommandHandler::new());
|
||||
@@ -184,10 +185,7 @@ async fn exec() -> Result<(), Error> {
|
||||
"test_features" => {
|
||||
Screen::Application.set_mode().unwrap();
|
||||
|
||||
setup_ui(|c| match c {
|
||||
KeyStroke::Char('`') => (c, true),
|
||||
_ => (c, false),
|
||||
}).await;
|
||||
setup_ui().await;
|
||||
|
||||
Screen::Terminal.set_mode().unwrap()
|
||||
|
||||
@@ -253,71 +251,69 @@ struct CmdHistory {
|
||||
history: Vec<String>,
|
||||
}
|
||||
|
||||
async fn setup_ui(input: impl Fn(KeyStroke) -> (KeyStroke, bool)) {
|
||||
async fn setup_ui() {
|
||||
let label= Widget::insert(CgLabel::new(
|
||||
String::from("test label"),
|
||||
Position::new(1, 1),
|
||||
40,
|
||||
));
|
||||
|
||||
let mut textbox = CgTextBox::new(
|
||||
let textbox = Widget::insert(CgTextBox::new(
|
||||
String::from("i'd just like to interject for a moment"),
|
||||
String::from("I'd just like to interject for a moment. What you're refering to as Linux, is in fact, GNU/Linux, or as I've recently taken to calling it, GNU plus Linux. Linux is not an operating system unto itself, but rather another free component of a fully functioning GNU system made useful by the GNU corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX. Many computer users run a modified version of the GNU system every day, without realizing it. Through a peculiar turn of events, the version of GNU which is widely used today is often called Linux, and many of its users are not aware that it is basically the GNU system, developed by the GNU Project. There really is a Linux, and these people are using it, but it is just a part of the system they use. Linux is the kernel: the program in the system that allocates the machine's resources to the other programs that you run. The kernel is an essential part of an operating system, but useless by itself; it can only function in the context of a complete operating system. Linux is normally used in combination with the GNU operating system: the whole system is basically GNU with Linux added, or GNU/Linux. All the so-called Linux distributions are really distributions of GNU/Linux!"),
|
||||
Position::new(2, 5),
|
||||
Dimensions::new(40, 12),
|
||||
true,
|
||||
);
|
||||
));
|
||||
|
||||
let mut label = CgLabel::new(
|
||||
String::from("test label"),
|
||||
Position::new(1, 1),
|
||||
40,
|
||||
);
|
||||
|
||||
test_new_datastore().await;
|
||||
|
||||
let mut statusbar = CgStatusBar::new(Position::new(0, 0), Dimensions::new(80, 1));
|
||||
|
||||
let mut textedit = CgLineEdit::new(
|
||||
let textedit = Widget::insert(CgLineEdit::new(
|
||||
Position::new(10, 20),
|
||||
60,
|
||||
String::from("enter text here >"),
|
||||
));
|
||||
|
||||
let statusbar = Widget::insert(CgStatusBar::new(Position::new(0, 0), Dimensions::new(80, 1)));
|
||||
let container = Widget::insert({
|
||||
let mut container = CgContainer::new(
|
||||
Position::new(0, 0),
|
||||
Dimensions::new(80, 25),
|
||||
true,
|
||||
);
|
||||
container.insert("textbox", textbox);
|
||||
container.insert("label", label);
|
||||
container.insert("textedit", textedit);
|
||||
container.insert("statusbar", statusbar);
|
||||
container
|
||||
});
|
||||
|
||||
let mut commandresult = String::new();
|
||||
if let Ok(frame) = container.render() {
|
||||
frame.write_to_screen().unwrap();
|
||||
} else {
|
||||
serial_println!("failed to write to screen");
|
||||
}
|
||||
|
||||
// while let (c, false) = input(Stdin::keystroke().await) {
|
||||
// let mut container = CgContainer::new(
|
||||
// Position::new(0, 0),
|
||||
// Dimensions::new(80, 25),
|
||||
// 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();
|
||||
// }
|
||||
// }
|
||||
|
||||
let exit = |x: KeyStroke| { match x {
|
||||
KeyStroke::Char('`') => (KeyStroke::None, Exit::Exit),
|
||||
_ => (x, Exit::None),
|
||||
}};
|
||||
|
||||
let container_copy = container.fetch::<CgContainer>().unwrap();
|
||||
let entry_ref = container_copy.fetch("textedit").unwrap();
|
||||
let mut entry = entry_ref.fetch::<CgLineEdit>().unwrap();
|
||||
|
||||
while let Ok((string, false)) = entry.input(exit, &entry_ref, &container).await {
|
||||
let textbox_ref = container_copy.fetch("textbox").unwrap();
|
||||
let mut textbox = textbox_ref.fetch::<CgTextBox>().unwrap();
|
||||
textbox.content = string;
|
||||
textbox_ref.update(textbox);
|
||||
if let Ok(frame) = container.render() {
|
||||
frame.write_to_screen().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async fn test_new_datastore() {
|
||||
let container = Widget::insert(CgContainer::new(
|
||||
Position::new(0, 0),
|
||||
|
||||
@@ -11,7 +11,10 @@ use alloc::{
|
||||
string::String,
|
||||
};
|
||||
use core::any::Any;
|
||||
use async_trait::async_trait;
|
||||
use lazy_static::lazy_static;
|
||||
use crate::std::application::Exit;
|
||||
use crate::std::io::KeyStroke;
|
||||
|
||||
/// implement this trait if you require the widget to be able to have an outline
|
||||
pub trait CgOutline: CgComponent {
|
||||
@@ -35,6 +38,11 @@ pub trait CgTextEdit: CgComponent {
|
||||
fn clear(&mut self);
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait CgTextInput: CgTextEdit {
|
||||
async fn input(&mut self, break_condition: fn(KeyStroke) -> (KeyStroke, Exit), id: &Widget, app: &Widget) -> Result<(String, bool), RenderError>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static ID_COUNTER: Mutex<usize> = Mutex::new(0);
|
||||
@@ -76,11 +84,13 @@ impl Widget {
|
||||
}
|
||||
|
||||
pub fn render(&self) -> Result<Frame, RenderError> {
|
||||
if let Some(frame) = GUITREE.lock().frame(self) {
|
||||
frame
|
||||
} else {
|
||||
panic!("CRITICAL: Widget not found in tree");
|
||||
}
|
||||
let component_arc_mutex = match GUITREE.lock().frame(self) {
|
||||
Some(component) => component,
|
||||
None => panic!("CRITICAL: Widget not found in tree"),
|
||||
};
|
||||
|
||||
let component = component_arc_mutex.lock();
|
||||
component.render()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,12 +131,9 @@ impl DataStore {
|
||||
})
|
||||
}
|
||||
|
||||
fn frame(&self, id: &Widget) -> Option<Result<Frame, RenderError>> {
|
||||
fn frame(&self, id: &Widget) -> Option<Arc<Mutex<dyn CgComponent + Send + Sync + 'static>>> {
|
||||
let items = self.items.lock();
|
||||
items.get(&id.id).and_then(|arc| {
|
||||
let item = arc.lock();
|
||||
Some(item.render())
|
||||
})
|
||||
items.get(&id.id).cloned()
|
||||
}
|
||||
|
||||
fn remove(&self, id: &Widget) {
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
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};
|
||||
use crate::user::lib::libgui::cg_core::{CgComponent, CgTextEdit};
|
||||
use crate::std::io::{KeyStroke, Stdin};
|
||||
use crate::user::lib::libgui::cg_core::{CgComponent, CgTextEdit, CgTextInput, Widget};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CgLineEdit {
|
||||
@@ -84,3 +89,53 @@ impl CgTextEdit for CgLineEdit {
|
||||
self.ptr = 0
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl CgTextInput for CgLineEdit {
|
||||
async fn input(&mut self, break_condition: fn(KeyStroke) -> (KeyStroke, Exit), id: &Widget, app: &Widget) -> Result<(String, bool), RenderError> {
|
||||
while let (c, Exit::None) = break_condition(Stdin::keystroke().await) {
|
||||
match c {
|
||||
KeyStroke::Char('\n') => break,
|
||||
KeyStroke::Char('\x08') => self.backspace(),
|
||||
KeyStroke::Backspace => self.backspace(),
|
||||
KeyStroke::Char(c) => self.write_char(c),
|
||||
KeyStroke::Left => self.move_cursor(false),
|
||||
KeyStroke::Right => self.move_cursor(true),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
id.update(self.clone());
|
||||
match app.render() {
|
||||
Ok(frame) => frame.write_to_screen()?,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
};
|
||||
let res = self.text.iter().collect();
|
||||
self.clear();
|
||||
id.update(self.clone());
|
||||
match app.render() {
|
||||
Ok(frame) => frame.write_to_screen()?,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
Ok((res, false))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ impl CgContainer {
|
||||
pub fn insert(&mut self, name: &'static str, element: Widget) {
|
||||
self.elements.insert(name,element);
|
||||
}
|
||||
pub fn fetch(&self, name: &'static str) -> Option<&Widget> {
|
||||
self.elements.get(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl CgOutline for CgContainer {
|
||||
@@ -55,8 +58,12 @@ impl CgOutline for CgContainer {
|
||||
|
||||
impl CgComponent for CgContainer {
|
||||
fn render(&self) -> Result<Frame, RenderError> {
|
||||
serial_println!("rendering");
|
||||
|
||||
let mut result = Frame::new(self.position, self.dimensions)?;
|
||||
|
||||
serial_println!("{:?}", self.elements);
|
||||
|
||||
for widget in &self.elements {
|
||||
let frame = widget.1.render()?;
|
||||
match result.render_bounds_check(&frame, true) { // TODO: this needs to be set to false for production
|
||||
|
||||
Reference in New Issue
Block a user