From 02bdca151b92503495ad1b8a54d1dd2f8a779324 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Mon, 28 Jul 2025 15:02:22 +0200 Subject: [PATCH] Dynamic Widget system --- src/dependency.rs | 93 ------------------------------------------ src/elements/mod.rs | 1 - src/elements/state.rs | 94 ------------------------------------------- src/frontend.rs | 11 ++--- src/lib.rs | 23 ++++++----- src/main.rs | 25 +++++------- src/widget.rs | 59 +++++++++++++++++++++++++-- 7 files changed, 82 insertions(+), 224 deletions(-) delete mode 100644 src/dependency.rs delete mode 100644 src/elements/state.rs diff --git a/src/dependency.rs b/src/dependency.rs deleted file mode 100644 index 5d1e94d..0000000 --- a/src/dependency.rs +++ /dev/null @@ -1,93 +0,0 @@ -use std::sync::Arc; - -use crate::widget::Element; - -pub trait DependencyHandler: std::fmt::Debug + Send + Sync { - fn add(&self); - fn check(&self) -> bool; -} - -pub struct Dependency { - handlers: Vec>, - element: T, - element_reset: Box T + Send + Sync>, -} - -impl Dependency { - pub fn new T + Send + Sync + 'static>(mut f: F) -> Self { - Self { - handlers: Vec::new(), - element: f(), - element_reset: Box::new(f), - } - } - - pub fn from( - mut f: Box T + Send + Sync>, - handlers: Vec>, - ) -> Self { - for h in &handlers { - h.add(); - } - - Self { - handlers, - element: f(), - element_reset: f, - } - } - - pub fn auto_reset(&mut self) { - for i in &self.handlers { - if i.check() { - self.element = (self.element_reset)(); - } - } - } - - pub fn add(mut self, dep: D) -> Self { - dep.add(); - self.handlers.push(Arc::new(dep)); - self - } -} - -impl Element for Dependency> { - fn render(&mut self, scope: &mut crate::render_scope::RenderScope) { - self.element.render(scope); - self.auto_reset(); - } - - fn after_render(&mut self, scope: &crate::render_scope::RenderScope) { - self.element.after_render(scope); - self.auto_reset(); - } - - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { - self - } -} - -impl Element for Dependency { - fn render(&mut self, scope: &mut crate::render_scope::RenderScope) { - self.element.render(scope); - self.auto_reset(); - } - - fn after_render(&mut self, scope: &crate::render_scope::RenderScope) { - self.element.after_render(scope); - self.auto_reset(); - } - - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { - self - } -} diff --git a/src/elements/mod.rs b/src/elements/mod.rs index f87b784..f397332 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -1,6 +1,5 @@ pub mod div; pub mod grid; -pub mod state; use crate::Element; diff --git a/src/elements/state.rs b/src/elements/state.rs deleted file mode 100644 index e1b14a3..0000000 --- a/src/elements/state.rs +++ /dev/null @@ -1,94 +0,0 @@ -use std::{ - fmt::{Debug, Display, Formatter, Result as FmtResult}, - ops::{Deref, DerefMut}, - sync::{Arc, Mutex, MutexGuard}, -}; - -use crate::dependency::DependencyHandler; - -#[derive(Debug, Clone)] -pub struct State { - inner: Arc>>, -} - -#[derive(Debug)] -pub struct Inner { - value: T, - dependencies: usize, - changed: usize, -} - -pub fn use_state(v: T) -> State { - State { - inner: Arc::new(Mutex::new(Inner { - value: v, - dependencies: 0, - changed: 0, - })), - } -} - -impl State { - /// Gets the cloned value, recommended for preventing deadlocks - pub fn get_dl(&self) -> T { - self.inner.lock().unwrap().value.clone() - } -} - -impl State { - /// Gets a lock on the state for read/write access. - pub fn get(&self) -> MutexGuard<'_, Inner> { - self.inner.lock().unwrap() - } - - /// Sets the value and marks it as changed. - pub fn set(&self, v: T) { - let mut inner = self.inner.lock().unwrap(); - inner.value = v; - inner.changed = inner.dependencies; - } - - /// Marks the state as updated. - pub fn update(&self) { - let mut inner = self.inner.lock().unwrap(); - inner.changed = inner.dependencies; - } -} - -impl DependencyHandler for State { - fn check(&self) -> bool { - let mut inner = self.inner.lock().unwrap(); - let i = inner.changed > 0; - if i { - inner.changed -= 1; - } - i - } - - fn add(&self) { - let mut inner = self.inner.lock().unwrap(); - inner.dependencies += 1; - } -} - -impl Display for State { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let inner = self.inner.lock().unwrap(); - write!(f, "{}", inner.value) - } -} - -impl Deref for Inner { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.value - } -} - -impl DerefMut for Inner { - fn deref_mut(&mut self) -> &mut Self::Target { - self.changed = self.dependencies; - &mut self.value - } -} diff --git a/src/frontend.rs b/src/frontend.rs index 0293e14..2ba0b87 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -1,14 +1,10 @@ use std::sync::Arc; -use crate::{ - dependency::{Dependency, DependencyHandler}, - widget::{Element, Widget}, - Screen, -}; +use crate::{state::DependencyHandler, widget::WidgetLoad, Screen}; pub struct Rsx( pub Vec<( - Box Box + Send + Sync>, + Box WidgetLoad + Send + Sync>, Vec>, )>, ); @@ -16,8 +12,7 @@ pub struct Rsx( impl Rsx { pub fn draw(self, screen: &Arc) { for i in self.0 { - let d = Dependency::from(i.0, i.1); - screen.draw_widget(Widget::new(Box::new(d))); + screen.draw_box(i.0); } } } diff --git a/src/lib.rs b/src/lib.rs index 0edf1fc..e6b146b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,16 +3,15 @@ use std::sync::{Arc, Mutex}; use crate::{ extensions::{Extension, Handler}, render_scope::RenderScope, - style::Transform, - widget::{Element, Widget}, + widget::{Element, Widget, WidgetLoad}, }; -pub mod dependency; pub mod elements; pub mod extensions; pub mod frontend; pub mod macros; pub mod render_scope; +pub mod state; pub mod style; pub mod utils; pub mod widget; @@ -41,14 +40,20 @@ impl Screen { }) } - pub fn draw(self: &Arc, element: E) -> Arc { + pub fn draw WidgetLoad + 'static + Send + Sync>( + self: &Arc, + element: F, + ) -> Arc { let w = Arc::new(Widget::new(Box::new(element))); self.widgets.lock().unwrap().push(w.clone()); w } - pub fn draw_widget(self: &Arc, w: Widget) -> Arc { - let w = Arc::new(w); + pub fn draw_box( + self: &Arc, + element: Box WidgetLoad + Send + Sync>, + ) -> Arc { + let w = Arc::new(Widget::new(Box::new(element))); self.widgets.lock().unwrap().push(w.clone()); w } @@ -61,10 +66,6 @@ impl Screen { } pub fn run(self: &Arc) -> std::io::Result<()> { - for elem in self.widgets.lock().unwrap().iter() { - elem.component(Transform::new()); - } - for ext in self.extensions.lock().unwrap().iter() { ext.lock().unwrap().init(self.clone()); } @@ -104,6 +105,8 @@ impl Screen { scope.draw(); elem.0.lock().unwrap().after_render(&scope); + + elem.auto_refresh(); } } Ok(()) diff --git a/src/main.rs b/src/main.rs index c719752..a69a53c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,7 @@ -use std::sync::Arc; - -use osui::{elements::state::use_state, frontend::Rsx, rsx, Screen}; +use osui::{state::use_state, widget::WidgetLoad, Screen}; fn main() -> std::io::Result<()> { let screen = Screen::new(); - - app().draw(&screen); - - screen.run() -} - -fn app() -> Rsx { let count = use_state(0); std::thread::spawn({ @@ -18,12 +9,16 @@ fn app() -> Rsx { move || loop { std::thread::sleep(std::time::Duration::from_millis(50)); **count.get() += 1; + count.update(); } }); - rsx! { - %count - @Transform::center(); - "{count}" - } + screen + .draw({ + let count = count.clone(); + move || WidgetLoad::new(format!("Hello, World {count}")) + }) + .dependency(count); + + screen.run() } diff --git a/src/widget.rs b/src/widget.rs index 40ec5a4..76c14d4 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -4,7 +4,7 @@ use std::{ sync::{Arc, Mutex}, }; -use crate::render_scope::RenderScope; +use crate::{render_scope::RenderScope, state::DependencyHandler}; pub type BoxedElement = Box; pub type BoxedComponent = Box; @@ -26,11 +26,39 @@ pub trait Component: Send + Sync { pub struct Widget( pub Mutex, Mutex>, + Mutex WidgetLoad + Send + Sync>>, + Mutex>>, ); impl Widget { - pub fn new(e: Box) -> Self { - Self(Mutex::new(e), Mutex::new(HashMap::new())) + pub fn new WidgetLoad + 'static + Send + Sync>(mut e: F) -> Self { + let wl = e(); + Self( + Mutex::new(wl.0), + Mutex::new(wl.1), + Mutex::new(Box::new(e)), + Mutex::new(Vec::new()), + ) + } + + pub fn refresh(self: &Arc) { + let w = (self.2.lock().unwrap())(); + *self.0.lock().unwrap() = w.0; + *self.1.lock().unwrap() = w.1; + } + + pub fn auto_refresh(self: &Arc) { + for d in self.3.lock().unwrap().iter() { + if d.check() { + self.refresh(); + } + } + } + + pub fn dependency(self: &Arc, d: D) -> &Arc { + d.add(); + self.3.lock().unwrap().push(Box::new(d)); + self } pub fn component(self: &Arc, c: C) -> &Arc { @@ -56,3 +84,28 @@ impl Widget { .map(|c| c.clone()) } } + +pub struct WidgetLoad(BoxedElement, HashMap); + +impl WidgetLoad { + pub fn new(e: E) -> Self { + Self(Box::new(e), HashMap::new()) + } + + pub fn component(mut self, c: C) -> Self { + self.1.entry(c.type_id()).or_insert_with(|| Box::new(c)); + self + } + + pub fn set_component(mut self, c: C) -> Self { + self.1.insert(c.type_id(), Box::new(c)); + self + } + + pub fn get(&self) -> Option { + self.1 + .get(&TypeId::of::()) + .and_then(|c| c.as_any().downcast_ref::()) + .map(|c| c.clone()) + } +}