From cc0ea4a9f5159c2b6def1c786301bd1818d3ff45 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Fri, 22 Nov 2024 09:33:02 +0100 Subject: [PATCH] commands and get_element_by_id --- Cargo.toml | 2 +- src/app.c | 34 +++++--------------- src/app.rs | 87 +++++++++++++++++++++++++++++++++------------------ src/lib.rs | 46 ++++++++++++++++++++++----- src/main.rs | 15 ++++++--- src/ui/mod.rs | 16 +++++----- 6 files changed, 123 insertions(+), 77 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ae01d54..223a066 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,6 @@ crossterm = "0.28.1" regex = "1.11.1" lazy_static = "1.4" paste = "1.0.15" -osui-element = "0.1.5" +osui-element = "0.1.8" dyn-clone = "1.0.17" flume = "=0.10.12" diff --git a/src/app.c b/src/app.c index 027523a..81b63ac 100644 --- a/src/app.c +++ b/src/app.c @@ -4,44 +4,24 @@ #include #include -typedef struct { - void* element; - void* sender; - void* receiver; - boolean_t running; -} LArgs; +extern boolean_t render_loop(void* args); +extern void *event_loop(void* args); +extern void *cmd_loop(void* args); -extern boolean_t render(void* element); -extern void *event_loop(void* element); -extern void *cmd_loop(void* element); - -void sleep_ms(long milliseconds) -{ - struct timespec ts; - ts.tv_sec = milliseconds / 1000; - ts.tv_nsec = (milliseconds % 1000) * 1000000; - nanosleep(&ts, NULL); -} - -boolean_t c_run(void* element, void* sender, void* receiver) +boolean_t c_run(void* args) { pthread_t event_thread; pthread_t cmd_thread; - LArgs args = { .element = element, .sender = sender, .receiver = receiver, .running = 1 }; - if (pthread_create(&event_thread, NULL, event_loop, &args) != 0) + if (pthread_create(&event_thread, NULL, event_loop, args) != 0) { perror("Failed to create thread"); } - if (pthread_create(&cmd_thread, NULL, cmd_loop, &args) != 0) + if (pthread_create(&cmd_thread, NULL, cmd_loop, args) != 0) { perror("Failed to create thread"); } - while (render(element) && args.running) - { - sleep_ms(20); - } - return 0; + return render_loop(args); } \ No newline at end of file diff --git a/src/app.rs b/src/app.rs index d20ecd1..5863f13 100644 --- a/src/app.rs +++ b/src/app.rs @@ -9,22 +9,28 @@ use crate::utils::{ }; use std::{ffi::c_void, ptr::null, sync::mpsc}; -pub struct LArgs { - pub element: *mut c_void, - pub sender: *const c_void, - pub receiver: *const c_void, +pub struct LArgs<'a> { + pub element: &'a mut Element, + + // for sending commands + pub stx: mpsc::Sender, + pub srx: mpsc::Receiver, + + // for returning command output + pub rtx: mpsc::Sender>, + pub rrx: mpsc::Receiver>, pub running: bool, } extern "C" { - fn c_run(element: *mut c_void, sender: *const c_void, receiver: *const c_void) -> bool; + fn c_run(args: *mut c_void) -> bool; } -fn event(element: &mut Element, event: Event) { +fn event(element: &mut Element, event: Event, document: &Document) { if let crossterm::event::Event::Resize(width, height) = event { element.update_data(width as usize, height as usize); } - element.event(event); + element.event(event, document); } pub fn run(element: &mut Element) -> bool { @@ -32,12 +38,16 @@ pub fn run(element: &mut Element) -> bool { enable_raw_mode().unwrap(); clear(); unsafe { - let (tx, rx) = mpsc::channel::(); - let c = c_run( - element as *mut Element as *mut c_void, - &tx as *const mpsc::Sender as *const c_void, - &rx as *const mpsc::Receiver as *const c_void, - ); + let (stx, srx) = mpsc::channel(); + let (rtx, rrx) = mpsc::channel(); + let c = c_run(&mut LArgs { + running: true, + element, + stx, + srx, + rtx, + rrx, + } as *mut LArgs as *mut c_void); if !c { show_cursor(); disable_raw_mode().unwrap(); @@ -48,18 +58,20 @@ pub fn run(element: &mut Element) -> bool { } #[no_mangle] -extern "C" fn render(ptr: *mut c_void) -> bool { +extern "C" fn render_loop(ptr: *mut c_void) -> bool { if ptr.is_null() { return false; } - let element = unsafe { &mut *(ptr as *mut Element) }; - let (width, height) = get_term_size(); - let mut frame: Vec = create_frame(width, height); - render_to_frame(true, width, &mut frame, element); - clear(); - print!("{}", frame.join("")); - flush(); - true + let args = unsafe { &mut *(ptr as *mut LArgs) }; + while args.running { + let (width, height) = get_term_size(); + let mut frame: Vec = create_frame(width, height); + render_to_frame(true, width, &mut frame, args.element); + clear(); + print!("{}", frame.join("")); + flush(); + } + false } #[no_mangle] @@ -68,19 +80,24 @@ extern "C" fn event_loop(ptr: *mut c_void) -> *const c_void { return null() as *const c_void; } let args = unsafe { &mut *(ptr as *mut LArgs) }; - let element = unsafe { &mut *(args.element as *mut Element) }; - let tx = unsafe { &*(args.sender as *const mpsc::Sender) }; + let document = Document { + cmd_sender: args.stx.clone(), + cmd_recv: &args.rrx as *const mpsc::Receiver> as *const c_void, + }; let (width, height) = get_term_size(); - element.update_data(width, height); - event(element, crossterm::event::Event::FocusGained); + args.element.update_data(width, height); + event( + args.element, + crossterm::event::Event::FocusGained, + &document, + ); while args.running { if ptr.is_null() { break; } - event(element, crossterm::event::read().unwrap()); - tx.send(Command::Exit).unwrap(); + event(args.element, crossterm::event::read().unwrap(), &document); } null() as *const c_void } @@ -91,14 +108,22 @@ extern "C" fn cmd_loop(ptr: *mut c_void) -> *const c_void { return null() as *const c_void; } let args = unsafe { &mut *(ptr as *mut LArgs) }; - let _element = unsafe { &mut *(args.element as *mut Element) }; - let rx = unsafe { &*(args.receiver as *const mpsc::Receiver) }; + loop { - match rx.recv().unwrap() { + match args.srx.recv().unwrap() { Command::Exit => { args.running = false; break; } + Command::GetElementById(id) => { + args.rtx + .send(if let Some(e) = args.element.get_element_by_id(&id) { + Some(e as *mut Element) + } else { + None + }) + .unwrap(); + } } } null() diff --git a/src/lib.rs b/src/lib.rs index 3cead75..27b3449 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,7 @@ pub use app::run; pub mod prelude { pub use crate::ui::Color::*; pub use crate::{self as osui, css, rsx, rsx_elem, ui::*, Handler}; - pub use crate::{style, Command, Element, Value, Document}; + pub use crate::{style, Command, Document, Element, Value}; // useful for Element making pub use crate::{run_handler, Children, ElementCore, ElementWidget}; pub use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind}; @@ -101,8 +101,8 @@ pub trait ElementWidget: ElementCore + std::fmt::Debug { String::new() } - fn event(&mut self, event: Event) { - _ = event + fn event(&mut self, event: Event, document: &Document) { + _ = (event, document) } } @@ -112,12 +112,12 @@ pub type Element = Box; /// Handler Struct ////////////////////////////////////////////////////////////////////////////////////////////////// -pub struct Handler(pub Arc>); +pub struct Handler(pub Arc>); impl Handler { pub fn new(handler_fn: F) -> Handler where - F: FnMut(&mut T, Event) + 'static + Send + Sync, + F: FnMut(&mut T, Event, &Document) + 'static + Send + Sync, { Handler(Arc::new(Mutex::new(handler_fn))) } @@ -125,7 +125,7 @@ impl Handler { impl Default for Handler { fn default() -> Self { - Handler(Arc::new(Mutex::new(|_: &mut T, _: Event| {}))) + Handler(Arc::new(Mutex::new(|_: &mut T, _: Event, _: &Document| {}))) } } @@ -189,6 +189,24 @@ impl Children { _ => None, } } + pub fn set_text(&mut self, text: &str) { + match self { + Children::Text(t) => { + *t = text.to_string(); + } + _ => {} + } + } + pub fn set_text_force(&mut self, text: &str) { + match self { + Children::Text(t) => { + *t = text.to_string(); + } + _ => { + *self = Children::Text(text.to_string()); + } + } + } } /// Converts a `Element` into the struct @@ -198,14 +216,28 @@ pub fn convert(widget: &mut Box) -> &mut Box { pub enum Command { Exit, + GetElementById(String), } pub struct Document { cmd_sender: std::sync::mpsc::Sender, + cmd_recv: *const std::ffi::c_void, } impl Document { pub fn exit(&self) { self.cmd_sender.send(Command::Exit).unwrap(); } -} \ No newline at end of file + pub fn get_element_by_id(&self, id: &str) -> Option<&mut Box> { + self.cmd_sender + .send(Command::GetElementById(id.to_string())) + .unwrap(); + let rx = + unsafe { &*(self.cmd_recv as *const std::sync::mpsc::Receiver>) }; + if let Ok(Some(e)) = rx.recv() { + Some(convert(unsafe { &mut *e })) + } else { + None + } + } +} diff --git a/src/main.rs b/src/main.rs index 2962035..c42bc85 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,21 @@ -// use std::sync::Arc; - use osui::prelude::*; pub struct App {} fn main() { - // let something = Arc::new(App {}); while osui::run(&mut app()) {} } fn app() -> Element { rsx! { styling: Some(styles()), - button { class: "btn", "Hello, World!" } + button { class: "btn", on_click: Handler::new(|_, _, document| { + + if let Some(txt) = document.get_element_by_id::("txt") { + txt.children.set_text("edited"); + } + + }), "Hello, World!" } + text { id: "txt", "Some text!" } } } @@ -20,5 +24,8 @@ fn styles() -> Css { .btn: clicked { color: Blue } + .btn: hover { + color: Red + } } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 981fdf8..6512cce 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -83,9 +83,11 @@ impl ElementWidget for Div<'_> { frame.join("\n") } - fn event(&mut self, event: Event) { - if let Some(styling) = self.styling.clone() { - self.set_styling(&styling); + fn event(&mut self, event: Event, document: &Document) { + if event == Event::FocusGained { + if let Some(styling) = self.styling.clone() { + self.set_styling(&styling); + } } match event { Event::Key(key) => { @@ -117,7 +119,7 @@ impl ElementWidget for Div<'_> { _ => { if let Some(c) = children.get_mut(*child) { - c.event(event); + c.event(event, document); } *child } @@ -126,7 +128,7 @@ impl ElementWidget for Div<'_> { } _ => { if let Some(child) = self.get_child() { - child.event(event); + child.event(event, document); } } } @@ -153,12 +155,12 @@ impl ElementWidget for Button<'_> { } } - fn event(&mut self, event: Event) { + fn event(&mut self, event: Event, document: &Document) { match event { Event::Key(key) => { if key.code == KeyCode::Enter { self.state = "clicked"; - run_handler!(self.on_click(event)); + run_handler!(self.on_click(event, document)); sleep(100); self.state = ""; }