added C for threading
This commit is contained in:
+4
-1
@@ -18,4 +18,7 @@ Cargo.lock
|
|||||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
#.idea/
|
||||||
|
|
||||||
|
*.a
|
||||||
|
*.o
|
||||||
@@ -66,6 +66,10 @@ OSUI provides several macros to simplify the definition and usage of elements:
|
|||||||
- **rsx!**: Create a nested structure of UI components easily.
|
- **rsx!**: Create a nested structure of UI components easily.
|
||||||
- **command!**: Simplify command creation for updates.
|
- **command!**: Simplify command creation for updates.
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
Credit to priz.js (discord) for the idea of using C
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Contributions are welcome! If you have suggestions or improvements, feel free to submit a pull request or open an issue.
|
Contributions are welcome! If you have suggestions or improvements, feel free to submit a pull request or open an issue.
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("cargo:rustc-link-search=native=lib");
|
||||||
|
println!("cargo:rustc-link-lib=static=app");
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
rm -rf ./lib/
|
||||||
|
mkdir lib
|
||||||
|
gcc -c -o lib/app.o src/app.c
|
||||||
|
ar rcs lib/libapp.a lib/app.o
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t* state;
|
||||||
|
void* element;
|
||||||
|
} EventArgs;
|
||||||
|
|
||||||
|
extern void render(void* element, uint32_t state);
|
||||||
|
extern void event(void* element, uint32_t* state);
|
||||||
|
|
||||||
|
void sleep_ms(long milliseconds) {
|
||||||
|
struct timespec ts;
|
||||||
|
ts.tv_sec = milliseconds / 1000;
|
||||||
|
ts.tv_nsec = (milliseconds % 1000) * 1000000;
|
||||||
|
nanosleep(&ts, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *event_checker(void *args)
|
||||||
|
{
|
||||||
|
EventArgs* event_args = (EventArgs*)args;
|
||||||
|
while (1) {
|
||||||
|
if (event_args->state == 0) { return NULL; }
|
||||||
|
event(event_args->element, event_args->state);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean_t c_run(void* element)
|
||||||
|
{
|
||||||
|
pthread_t thread;
|
||||||
|
uint32_t state = 2;
|
||||||
|
EventArgs event_args = { .element = element, .state = &state };
|
||||||
|
|
||||||
|
if (pthread_create(&thread, NULL, event_checker, &event_args) != 0) {
|
||||||
|
perror("Failed to create thread");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (state == 0) {
|
||||||
|
free(element);
|
||||||
|
return 0;
|
||||||
|
} else if (state == 1) {
|
||||||
|
free(element);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
render(element, state);
|
||||||
|
sleep_ms(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
+39
-68
@@ -1,79 +1,50 @@
|
|||||||
use std::sync::{mpsc, Arc};
|
use crossterm::terminal::enable_raw_mode;
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{clear, create_frame, flush, get_term_size, render_to_frame, Element, State, StateChanger, Value};
|
||||||
clear, create_frame, flush, get_term_size, hide_cursor, render_to_frame, Element, State, Value,
|
use std::ffi::c_void;
|
||||||
};
|
|
||||||
|
|
||||||
/// Renders an element with a given state to the terminal.
|
pub struct ElementWrapper<'a> {
|
||||||
///
|
element: &'a mut Box<dyn Element>,
|
||||||
/// This macro handles the process of creating a frame, rendering the element to it,
|
|
||||||
/// clearing the terminal, and then printing the rendered frame.
|
|
||||||
///
|
|
||||||
/// # Parameters
|
|
||||||
///
|
|
||||||
/// * `$element` - The element to be rendered.
|
|
||||||
/// * `$state` - The current state of the element.
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
///
|
|
||||||
/// This macro does not return a value. It performs side effects by printing to the terminal.
|
|
||||||
macro_rules! render {
|
|
||||||
($element:expr, $state:expr) => {
|
|
||||||
let (width, height) = get_term_size();
|
|
||||||
let mut frame: Vec<String> = create_frame(Value::new(width), Value::new(height));
|
|
||||||
render_to_frame($state, width, &mut frame, $element);
|
|
||||||
clear();
|
|
||||||
print!("{}", frame.join(""));
|
|
||||||
flush();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(element: Arc<dyn Element>) -> bool {
|
impl<'a> ElementWrapper<'a> {
|
||||||
hide_cursor();
|
pub fn new(element: &'a mut Box<dyn Element>) -> *mut c_void {
|
||||||
crossterm::terminal::enable_raw_mode().unwrap();
|
Box::into_raw(Box::new(ElementWrapper { element })) as *mut c_void
|
||||||
clear();
|
}
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel();
|
pub unsafe fn from_raw(ptr: *mut c_void) -> &'a mut Box<dyn Element> {
|
||||||
|
assert!(!ptr.is_null(), "Pointer to ElementWrapper is null");
|
||||||
|
let wrapper = ptr as *mut ElementWrapper;
|
||||||
|
(*wrapper).element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (exit_tx, exit_) = mpsc::channel::<()>();
|
extern "C" {
|
||||||
|
fn c_run(element: *mut c_void) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
thread::spawn({
|
#[no_mangle]
|
||||||
let element_thread = Arc::clone(&element);
|
pub extern "C" fn render(ptr: *mut c_void, state: u32) {
|
||||||
move || loop {
|
let element = unsafe { ElementWrapper::from_raw(ptr) };
|
||||||
if exit_.try_recv().is_ok() {
|
let (width, height) = get_term_size();
|
||||||
break;
|
let mut frame: Vec<String> = create_frame(Value::new(width), Value::new(height));
|
||||||
}
|
render_to_frame(State::from_u32(state), width, &mut frame, element);
|
||||||
let event = crossterm::event::read().unwrap();
|
clear();
|
||||||
let e = Arc::clone(&element_thread);
|
print!("{}", frame.join(""));
|
||||||
let command_handler = crate::CommandHandler(tx.clone());
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
thread::spawn(move || {
|
#[no_mangle]
|
||||||
e.event(&command_handler, event);
|
pub extern "C" fn event(ptr: *mut c_void, state: *mut u32) {
|
||||||
});
|
let event = crossterm::event::read().unwrap();
|
||||||
}
|
let element = unsafe { ElementWrapper::from_raw(ptr) };
|
||||||
});
|
element.event(event, &StateChanger(state));
|
||||||
|
}
|
||||||
|
|
||||||
let mut current_state = State::Hover;
|
pub fn run(data: &mut Box<dyn Element>) -> bool {
|
||||||
loop {
|
enable_raw_mode().unwrap();
|
||||||
if let Ok(command) = rx.try_recv() {
|
unsafe {
|
||||||
match command {
|
let element_ptr = ElementWrapper::new(data);
|
||||||
crate::Command::SetState(state) => {
|
return c_run(element_ptr);
|
||||||
current_state = state;
|
|
||||||
}
|
|
||||||
crate::Command::Exit => {
|
|
||||||
exit_tx.send(()).unwrap();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
crate::Command::Rebuild => {
|
|
||||||
exit_tx.send(()).unwrap();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
render!(&element, current_state.clone());
|
|
||||||
}
|
|
||||||
thread::sleep(std::time::Duration::from_millis(20));
|
|
||||||
}
|
}
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-40
@@ -22,13 +22,10 @@
|
|||||||
pub mod macros;
|
pub mod macros;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
use std::sync::{mpsc, Arc, Mutex};
|
|
||||||
|
|
||||||
pub use utils::*;
|
pub use utils::*;
|
||||||
pub mod app;
|
pub mod app;
|
||||||
|
|
||||||
mod test;
|
|
||||||
|
|
||||||
/// Enum representing the wether it's the default or custom.
|
/// Enum representing the wether it's the default or custom.
|
||||||
///
|
///
|
||||||
/// - `Default(usize)` - Uses a default value.
|
/// - `Default(usize)` - Uses a default value.
|
||||||
@@ -81,67 +78,70 @@ impl<T: Copy + PartialEq> Value<T> {
|
|||||||
pub trait Element: Send + Sync {
|
pub trait Element: Send + Sync {
|
||||||
fn get_data(&self) -> (Value<usize>, usize, String);
|
fn get_data(&self) -> (Value<usize>, usize, String);
|
||||||
|
|
||||||
fn update_data(&self, width: usize, height: usize);
|
fn update_data(&mut self, width: usize, height: usize);
|
||||||
|
|
||||||
fn get_element_by_id(&self, id: &str) -> Option<std::sync::Arc<dyn Element>>;
|
fn get_element_by_id(&mut self, id: &str) -> Option<&mut Box<dyn Element>>;
|
||||||
|
|
||||||
fn render(&self, state: State) -> String {
|
fn render(&self, state: State) -> String {
|
||||||
_ = state;
|
_ = state;
|
||||||
String::new()
|
String::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event(&self, ch: &CommandHandler, event: crossterm::event::Event) {
|
fn event(&mut self, event: crossterm::event::Event, state: &StateChanger) {
|
||||||
_ = (ch, event);
|
(_, _) = (event, state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Handler<T>(pub Box<dyn FnMut(&T, &CommandHandler, crossterm::event::Event) + Send>);
|
pub struct Handler<T>(pub Box<dyn FnMut(&T, &StateChanger, crossterm::event::Event) + Send>);
|
||||||
|
|
||||||
impl<T> Handler<T> {
|
impl<T> Handler<T> {
|
||||||
pub fn new<F>(handler_fn: F) -> Handler<T>
|
pub fn new<F>(handler_fn: F) -> Handler<T>
|
||||||
where
|
where
|
||||||
F: FnMut(&T, &CommandHandler, crossterm::event::Event) + 'static + Send,
|
F: FnMut(&T, &StateChanger, crossterm::event::Event) + 'static + Send,
|
||||||
{
|
{
|
||||||
Handler(Box::new(handler_fn))
|
Handler(Box::new(handler_fn))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CommandHandler(mpsc::Sender<Command>);
|
|
||||||
|
|
||||||
impl CommandHandler {
|
|
||||||
pub fn set_state(&self, state: State) {
|
|
||||||
self.0.send(Command::SetState(state)).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exit(&self) {
|
|
||||||
self.0.send(Command::Exit).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_element_by_id(&self) {
|
|
||||||
self.0.send(Command::Exit).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rebuild(&self) -> bool {
|
|
||||||
self.0.send(Command::Rebuild).is_ok()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum Command {
|
|
||||||
SetState(State),
|
|
||||||
Exit,
|
|
||||||
Rebuild,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum State {
|
pub enum State {
|
||||||
|
Exit,
|
||||||
|
Rebuild,
|
||||||
Normal,
|
Normal,
|
||||||
Hover,
|
Hover,
|
||||||
Custom(usize),
|
Custom(usize),
|
||||||
CustomString(String),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_test() {
|
impl State {
|
||||||
let i = Arc::new(Mutex::new(0));
|
pub fn from_u32(s: u32) -> State {
|
||||||
while app::run(test::app(Arc::clone(&i))) {}
|
match s {
|
||||||
|
0 => State::Exit,
|
||||||
|
1 => State::Rebuild,
|
||||||
|
2 => State::Normal,
|
||||||
|
3 => State::Hover,
|
||||||
|
_ => State::Custom((s - 4) as usize),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn to_u32(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
State::Exit => 0,
|
||||||
|
State::Rebuild => 1,
|
||||||
|
State::Normal => 2,
|
||||||
|
State::Hover => 3,
|
||||||
|
State::Custom(s) => (4 + s) as u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StateChanger(*mut u32);
|
||||||
|
|
||||||
|
impl StateChanger {
|
||||||
|
pub fn set_state(&self, s: State) {
|
||||||
|
unsafe {
|
||||||
|
(*self.0) = s.to_u32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn get_state(&self) -> State {
|
||||||
|
State::from_u32(unsafe { *self.0 })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+57
-59
@@ -85,35 +85,34 @@ macro_rules! element {
|
|||||||
) => {
|
) => {
|
||||||
$(#[$meta])*
|
$(#[$meta])*
|
||||||
pub struct $name<'a> {
|
pub struct $name<'a> {
|
||||||
pub x: std::sync::Mutex<$crate::Value<usize>>,
|
pub x: $crate::Value<usize>,
|
||||||
pub y: std::sync::Mutex<usize>,
|
pub y: usize,
|
||||||
pub width: std::sync::Mutex<$crate::Value<usize>>,
|
pub width: $crate::Value<usize>,
|
||||||
pub height: std::sync::Mutex<$crate::Value<usize>>,
|
pub height: $crate::Value<usize>,
|
||||||
pub children: std::sync::Mutex<Vec<std::sync::Arc<dyn $crate::Element>>>,
|
pub children: Vec<Box<dyn $crate::Element>>,
|
||||||
pub child: std::sync::Mutex<usize>,
|
pub child: usize,
|
||||||
pub text: std::sync::Mutex<String>,
|
pub text: String,
|
||||||
pub id: std::sync::Mutex<&'a str>,
|
pub id: &'a str,
|
||||||
$( $inner )*
|
$( $inner )*
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $crate::Element for $name<'_> {
|
impl $crate::Element for $name<'_> {
|
||||||
fn get_data(&self) -> ($crate::Value<usize>, usize, String) {
|
fn get_data(&self) -> ($crate::Value<usize>, usize, String) {
|
||||||
(self.x.lock().unwrap().clone(), self.y.lock().unwrap().clone(), self.id.lock().unwrap().to_string())
|
(self.x, self.y, self.id.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_data(&self, width: usize, height: usize) {
|
fn update_data(&mut self, width: usize, height: usize) {
|
||||||
self.width.lock().unwrap().try_set_value(width);
|
self.width.try_set_value(width);
|
||||||
self.height.lock().unwrap().try_set_value(height);
|
self.height.try_set_value(height);
|
||||||
let children = self.children.lock().unwrap();
|
for child in &mut self.children {
|
||||||
for child in children.iter() {
|
|
||||||
child.update_data(width, height);
|
child.update_data(width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_element_by_id(&self, id: &str) -> Option<std::sync::Arc<(dyn $crate::Element + 'static)>> {
|
fn get_element_by_id(&mut self, id: &str) -> Option<&mut Box<dyn $crate::Element>> {
|
||||||
for elem in &mut self.children.lock().unwrap().iter() {
|
for elem in &mut self.children {
|
||||||
if elem.get_data().2 == id {
|
if elem.get_data().2 == id {
|
||||||
return Some(std::sync::Arc::clone(elem));
|
return Some(elem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@@ -125,7 +124,7 @@ macro_rules! element {
|
|||||||
impl<'a> $name<'_> {
|
impl<'a> $name<'_> {
|
||||||
/// Creates a new instance of the element with default values.
|
/// Creates a new instance of the element with default values.
|
||||||
pub fn new() -> $name<'a> {
|
pub fn new() -> $name<'a> {
|
||||||
$crate::def_!($name {
|
$name {
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
x: $crate::Value::Default(0),
|
x: $crate::Value::Default(0),
|
||||||
y: 0,
|
y: 0,
|
||||||
@@ -135,16 +134,15 @@ macro_rules! element {
|
|||||||
text: String::new(),
|
text: String::new(),
|
||||||
id: "",
|
id: "",
|
||||||
$( $defaults )*
|
$( $defaults )*
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_child(&self) -> Option<std::sync::Arc<dyn $crate::Element>> {
|
/// Retrieves a mutable reference to the current child element, if any.
|
||||||
if let Ok(elements) = self.children.lock() {
|
///
|
||||||
if let Some(e) = elements.get(*self.child.lock().unwrap()) {
|
/// # Returns
|
||||||
return Some(std::sync::Arc::clone(e));
|
/// An `Option` containing a mutable reference to the child `Element` or `None`.
|
||||||
}
|
pub fn get_child(&mut self) -> Option<&mut Box<dyn $crate::Element>> {
|
||||||
}
|
self.children.get_mut(self.child)
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -188,63 +186,63 @@ macro_rules! command {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! parse_rsx_param {
|
macro_rules! parse_rsx_param {
|
||||||
// Properties
|
// Properties
|
||||||
($elem:expr, $a:ident $($k:ident).+: $v:expr) => {
|
($elem:expr, $($k:ident).+: $v:expr) => {
|
||||||
$elem.$a.lock().unwrap().$($k).+ = $v;
|
$elem.$($k).+ = $v;
|
||||||
};
|
};
|
||||||
|
|
||||||
($elem:expr, $a:ident $(.$($k:ident).+)?: $v:expr, $($rest:tt)*) => {
|
($elem:expr, $($k:ident).+: $v:expr, $($rest:tt)*) => {
|
||||||
*$elem.$a.lock().unwrap()$($($k).+)? = $v;
|
$elem.$($k).+ = $v;
|
||||||
$crate::parse_rsx_param!($elem, $($rest)*);
|
osui::parse_rsx_param!($elem, $($rest)*);
|
||||||
};
|
};
|
||||||
|
|
||||||
// for completion purposes
|
// for completion purposes
|
||||||
// ($elem:expr, $p:path) => {
|
($elem:expr, $p:path) => {
|
||||||
// $p;
|
$p;
|
||||||
// };
|
};
|
||||||
// ($elem:expr, $a:ident . $($k:ident).+, $($rest:tt)*) => {
|
($elem:expr, $($k:ident).+, $($rest:tt)*) => {
|
||||||
// $elem.$a.lock().unwrap().$($k).+;
|
$elem.$($k).+;
|
||||||
// $crate::parse_rsx_param!($elem, $($rest)*);
|
osui::parse_rsx_param!($elem, $($rest)*);
|
||||||
// };
|
};
|
||||||
// ($elem:expr, $a:ident . $($k:ident).+., $($rest:tt)*) => {
|
($elem:expr, $($k:ident).+., $($rest:tt)*) => {
|
||||||
// $elem.$a.lock().unwrap().$($k).
|
$elem.$($k).
|
||||||
// +.;
|
+.;
|
||||||
// $crate::parse_rsx_param!($elem, $($rest)*);
|
osui::parse_rsx_param!($elem, $($rest)*);
|
||||||
// };
|
};
|
||||||
|
|
||||||
// ($elem:expr, $a:ident . $($k:ident).+.: $v:expr) => {
|
($elem:expr, $($k:ident).+.: $v:expr) => {
|
||||||
// $elem.$a.lock().unwrap().$($k).+. = $v;
|
$elem.$($k).+. = $v;
|
||||||
// };
|
};
|
||||||
// ($elem:expr, $a:ident . $($k:ident).*: $v:expr, $($rest:tt)*) => {
|
($elem:expr, $($k:ident).+.: $v:expr, $($rest:tt)*) => {
|
||||||
// $elem.$a.lock().unwrap().$($k).+. = $v;
|
$elem.$($k).+. = $v;
|
||||||
// $crate::parse_rsx_param!($elem, $($rest)*);
|
osui::parse_rsx_param!($elem, $($rest)*);
|
||||||
// };
|
};
|
||||||
|
|
||||||
// For loop
|
// For loop
|
||||||
($elem:expr, for ($($for:tt)*) { $($inner:tt)* } $($rest:tt)*) => {
|
($elem:expr, for ($($for:tt)*) { $($inner:tt)* } $($rest:tt)*) => {
|
||||||
for $($for)* {
|
for $($for)* {
|
||||||
$elem.children.lock().unwrap().push({$($inner)*})
|
$elem.children.push({$($inner)*})
|
||||||
}
|
}
|
||||||
$crate::parse_rsx_param!($elem, $($rest)*);
|
osui::parse_rsx_param!($elem, $($rest)*);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Expression
|
// Expression
|
||||||
($elem:expr, {$ielem:expr} $($rest:tt)*) => {
|
($elem:expr, {$ielem:expr} $($rest:tt)*) => {
|
||||||
$elem.children.lock().unwrap().push($ielem);
|
$elem.children.push($ielem);
|
||||||
$crate::parse_rsx_param!($elem, $($rest)*);
|
osui::parse_rsx_param!($elem, $($rest)*);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Element
|
// Element
|
||||||
($elem:expr, $pelem:path { $($inner:tt)* } $($rest:tt)*) => {
|
($elem:expr, $pelem:path { $($inner:tt)* } $($rest:tt)*) => {
|
||||||
$elem.children.lock().unwrap().push($crate::rsx_elem!($pelem { $($inner)* }));
|
$elem.children.push(osui::rsx_elem!($pelem { $($inner)* }));
|
||||||
$crate::parse_rsx_param!($elem, $($rest)*)
|
osui::parse_rsx_param!($elem, $($rest)*)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Text
|
// Text
|
||||||
($elem:expr, $text:expr) => {
|
($elem:expr, $text:expr) => {
|
||||||
*$elem.text.lock().unwrap() = format!($text);
|
$elem.text = format!($text);
|
||||||
};
|
};
|
||||||
($elem:expr, $text:expr, $($inner:tt)*) => {
|
($elem:expr, $text:expr, $($inner:tt)*) => {
|
||||||
*$elem.text.lock().unwrap() = format!($text, $($inner)*);
|
$elem.text = format!($text, $($inner)*);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Empty
|
// Empty
|
||||||
@@ -281,7 +279,7 @@ macro_rules! rsx_elem {
|
|||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut elem = $elem();
|
let mut elem = $elem();
|
||||||
$crate::parse_rsx_param!(elem, $($inner)*);
|
$crate::parse_rsx_param!(elem, $($inner)*);
|
||||||
elem as std::sync::Arc<dyn $crate::Element>
|
elem as Box<dyn $crate::Element>
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -1,4 +1,5 @@
|
|||||||
use osui::run_test;
|
use osui::{app::run, rsx_elem, ui::text};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
run_test();
|
run(&mut rsx_elem! { text { "Hello, World!" } });
|
||||||
}
|
}
|
||||||
|
|||||||
-16
@@ -1,16 +0,0 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
use crate::{rsx_elem, ui::*, Element, Handler};
|
|
||||||
|
|
||||||
pub(crate) fn app(i: Arc<Mutex<i32>>) -> std::sync::Arc<dyn Element> {
|
|
||||||
let i1 = Arc::clone(&i);
|
|
||||||
rsx_elem! { text { on_click: Handler::new(move |t: &Text, ch, _| {
|
|
||||||
*i1.lock().unwrap() += 1;
|
|
||||||
ch.rebuild();
|
|
||||||
// {
|
|
||||||
// let mut i = i1.lock().unwrap();
|
|
||||||
// *i += 1;
|
|
||||||
// *t.text.lock().unwrap() = i.to_string();
|
|
||||||
// }
|
|
||||||
}), "{}", i.lock().unwrap() } }
|
|
||||||
}
|
|
||||||
+5
-34
@@ -1,38 +1,9 @@
|
|||||||
use std::sync::Mutex;
|
use crate::{element, State};
|
||||||
|
|
||||||
use crate::{element, Handler, State};
|
|
||||||
|
|
||||||
element! {
|
element! {
|
||||||
Text {
|
Text {}
|
||||||
pub on_click: Mutex<Handler<Text<'a>>>
|
|
||||||
}
|
|
||||||
defaults {
|
|
||||||
on_click: Handler::new(|_, _, _| {})
|
|
||||||
}
|
|
||||||
fn render(&self, _: State) -> String {
|
|
||||||
self.text.lock().unwrap().clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event(&self, ch: &crate::CommandHandler, event: crossterm::event::Event) {
|
|
||||||
(*self.on_click.lock().unwrap().0)(self, ch, event);
|
|
||||||
// *self.text.lock().unwrap() = "Done!".to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
element! {
|
|
||||||
Div {}
|
|
||||||
defaults {}
|
defaults {}
|
||||||
fn render(&self, s: State) -> String {
|
fn render(&self, _state: State) -> String {
|
||||||
if let Some(child) = self.get_child() {
|
self.text.clone()
|
||||||
child.render(s)
|
|
||||||
} else {
|
|
||||||
format!("None")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fn event(&self, ch: &crate::CommandHandler, event: crossterm::event::Event) {
|
|
||||||
if let Some(e) = self.get_element_by_id("test") {
|
|
||||||
e.event(ch, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-5
@@ -7,10 +7,7 @@ pub use styles::*;
|
|||||||
pub mod elements;
|
pub mod elements;
|
||||||
pub use elements::*;
|
pub use elements::*;
|
||||||
|
|
||||||
pub fn text<'a>() -> std::sync::Arc<Text<'a>> {
|
|
||||||
std::sync::Arc::new(Text::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn div<'a>() -> std::sync::Arc<Div<'a>> {
|
pub fn text<'a>() -> Box<Text<'a>> {
|
||||||
std::sync::Arc::new(Div::new())
|
Box::new(Text::new())
|
||||||
}
|
}
|
||||||
+3
-3
@@ -78,7 +78,7 @@ pub fn render_to_frame(
|
|||||||
state: crate::State,
|
state: crate::State,
|
||||||
width: usize,
|
width: usize,
|
||||||
frame: &mut Vec<String>,
|
frame: &mut Vec<String>,
|
||||||
element: &std::sync::Arc<dyn Element>,
|
element: &mut Box<dyn Element>,
|
||||||
) {
|
) {
|
||||||
let data = element.get_data();
|
let data = element.get_data();
|
||||||
for (i, line) in element.render(state).split('\n').enumerate() {
|
for (i, line) in element.render(state).split('\n').enumerate() {
|
||||||
@@ -130,7 +130,7 @@ pub enum Direction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn closest_component(
|
pub fn closest_component(
|
||||||
components: &[std::sync::Arc<dyn Element>],
|
components: &[&mut dyn Element],
|
||||||
current_index: usize,
|
current_index: usize,
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
@@ -138,7 +138,7 @@ pub fn closest_component(
|
|||||||
|
|
||||||
components
|
components
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate() // Keep track of indices
|
.enumerate()
|
||||||
.filter(|(i, comp_)| {
|
.filter(|(i, comp_)| {
|
||||||
let comp = comp_.get_data();
|
let comp = comp_.get_data();
|
||||||
match direction {
|
match direction {
|
||||||
|
|||||||
Reference in New Issue
Block a user