diff --git a/src/elements/div.rs b/src/elements/div.rs index f559784..8806ad7 100644 --- a/src/elements/div.rs +++ b/src/elements/div.rs @@ -29,7 +29,7 @@ impl Element for Div { if let Some(t) = elem.get() { scope.set_transform(&t); } - elem.0.lock().unwrap().render(scope); + elem.get_elem().render(scope); if let Some(t) = elem.get() { scope.set_transform(&t); } @@ -40,7 +40,7 @@ impl Element for Div { t.y += transform.y + transform.py; scope.draw(); - elem.0.lock().unwrap().after_render(scope); + elem.get_elem().after_render(scope); } scope.set_parent_size(w, h); self.size = (transform.width, transform.height); diff --git a/src/elements/flex.rs b/src/elements/flex.rs index 516007e..ab143dd 100644 --- a/src/elements/flex.rs +++ b/src/elements/flex.rs @@ -38,7 +38,7 @@ impl Element for FlexRow { if let Some(t) = elem.get() { scope.set_transform(&t); } - elem.0.lock().unwrap().render(scope); + elem.get_elem().render(scope); if let Some(t) = elem.get() { scope.set_transform(&t); } @@ -53,7 +53,7 @@ impl Element for FlexRow { scope.draw(); - elem.0.lock().unwrap().after_render(scope); + elem.get_elem().after_render(scope); } scope.set_parent_size(w, h); self.size = (transform.width, transform.height); @@ -104,7 +104,7 @@ impl Element for FlexCol { if let Some(t) = elem.get() { scope.set_transform(&t); } - elem.0.lock().unwrap().render(scope); + elem.get_elem().render(scope); if let Some(t) = elem.get() { scope.set_transform(&t); } @@ -119,7 +119,7 @@ impl Element for FlexCol { scope.draw(); - elem.0.lock().unwrap().after_render(scope); + elem.get_elem().after_render(scope); } scope.set_parent_size(w, h); self.size = (transform.width, transform.height); diff --git a/src/frontend.rs b/src/frontend.rs index d9fac25..4d8be49 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -2,12 +2,14 @@ use std::sync::Arc; use crate::{ state::DependencyHandler, - widget::{Widget, WidgetLoad}, + widget::{BoxedElement, Widget, WidgetLoad}, Screen, }; pub enum RsxElement { - Element( + Element(BoxedElement, Vec>, Rsx), + + DynElement( Box WidgetLoad + Send + Sync>, Vec>, Rsx, @@ -24,10 +26,25 @@ impl Rsx { pub fn draw_parent(self, screen: &Arc, parent: Option>) { for rsx_elem in self.0 { match rsx_elem { + RsxElement::DynElement(f, dep, child) => { + let w = if let Some(parent) = &parent { + let w = screen.draw_box_dyn(f); + parent.get_elem().draw_child(&w); + w + } else { + screen.draw_box_dyn(f) + }; + + for d in dep { + w.dependency_box(d); + } + child.draw_parent(screen, Some(w.clone())); + } + RsxElement::Element(f, dep, child) => { let w = if let Some(parent) = &parent { let w = screen.draw_box(f); - parent.0.lock().unwrap().draw_child(&w); + parent.get_elem().draw_child(&w); w } else { screen.draw_box(f) @@ -48,8 +65,11 @@ impl Rsx { dependencies: Vec>, children: Rsx, ) { - self.0 - .push(RsxElement::Element(Box::new(load), dependencies, children)); + self.0.push(RsxElement::DynElement( + Box::new(load), + dependencies, + children, + )); } pub fn expand(&mut self, other: &mut Rsx) { diff --git a/src/lib.rs b/src/lib.rs index 7530411..69817f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ use std::sync::{Arc, Mutex}; use crate::{ extensions::{Extension, Handler}, render_scope::RenderScope, - widget::{Element, Widget, WidgetLoad}, + widget::{BoxedElement, DynWidget, Element, StaticWidget, Widget, WidgetLoad}, }; pub mod elements; @@ -53,20 +53,34 @@ impl Screen { }) } - pub fn draw WidgetLoad + 'static + Send + Sync>( - self: &Arc, - element: F, - ) -> Arc { - let w = Arc::new(Widget::new(Box::new(element))); + pub fn draw(self: &Arc, element: E) -> Arc { + let w = Arc::new(Widget::Static(Arc::new(StaticWidget::new(Box::new( + element, + ))))); self.widgets.lock().unwrap().push(w.clone()); w } - pub fn draw_box( + pub fn draw_box(self: &Arc, element: BoxedElement) -> Arc { + let w = Arc::new(Widget::Static(Arc::new(StaticWidget::new(element)))); + self.widgets.lock().unwrap().push(w.clone()); + w + } + + pub fn draw_dyn WidgetLoad + 'static + Send + Sync>( + self: &Arc, + element: F, + ) -> Arc { + let w = Arc::new(Widget::Dynamic(Arc::new(DynWidget::new(element)))); + self.widgets.lock().unwrap().push(w.clone()); + w + } + + pub fn draw_box_dyn( self: &Arc, element: Box WidgetLoad + Send + Sync>, ) -> Arc { - let w = Arc::new(Widget::new(Box::new(element))); + let w = Arc::new(Widget::Dynamic(Arc::new(DynWidget::new(element)))); self.widgets.lock().unwrap().push(w.clone()); w } @@ -122,14 +136,14 @@ impl Screen { ext.lock().unwrap().render_widget(&mut scope, elem); } - elem.0.lock().unwrap().render(&mut scope); + elem.get_elem().render(&mut scope); if let Some(t) = elem.get() { scope.set_transform(&t); } scope.draw(); - elem.0.lock().unwrap().after_render(&mut scope); + elem.get_elem().after_render(&mut scope); } elem.auto_refresh(); diff --git a/src/main.rs b/src/main.rs index 7dce5e6..8c77013 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,33 +2,18 @@ use osui::prelude::*; fn main() -> std::io::Result<()> { let screen = Screen::new(); + let count = use_state(0); - app().draw(&screen); + rsx! { + %count // Dependency of count + "Count: {count}" + } + .draw(&screen); + + std::thread::spawn(move || loop { + **count.get() += 1; + std::thread::sleep(std::time::Duration::from_millis(100)); + }); screen.run() } - -fn app() -> Rsx { - rsx! { - @Transform::new().padding(3, 3); - @Style { background: Background::RoundedOutline(0xff0000), foreground: None }; - Div { - @Transform::new().padding(1, 1); - @Style { background: Background::RoundedOutline(0x00ff00), foreground: None }; - FlexCol { - @Transform::new().padding(1, 1); - "Hello, World!" - @Transform::new().padding(1, 1); - "Hello, World!" - @Transform::new().padding(1, 1); - "Hello, World!" - @Transform::new().padding(1, 1); - "Hello, World!" - @Transform::new().padding(1, 1); - "Hello, World!" - @Transform::new().padding(1, 1); - "Hello, World!" - } (2) - } - } -} diff --git a/src/widget.rs b/src/widget.rs index 5c87cdf..33dd49e 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -1,7 +1,7 @@ use std::{ any::{Any, TypeId}, collections::HashMap, - sync::{Arc, Mutex}, + sync::{Arc, Mutex, MutexGuard}, }; use crate::{render_scope::RenderScope, state::DependencyHandler}; @@ -25,15 +25,190 @@ pub trait Component: Send + Sync { fn as_any_mut(&mut self) -> &mut dyn Any; } -pub struct Widget( - pub Mutex, +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()) + } +} + +pub enum Widget { + Static(Arc), + Dynamic(Arc), +} + +// === Trait Implementation === +impl Widget { + pub fn get_elem(&self) -> MutexGuard { + match self { + Widget::Static(w) => w.get_elem(), + Widget::Dynamic(w) => w.get_elem(), + } + } + + pub fn after_render(&self) { + match self { + Widget::Static(w) => w.after_render(), + Widget::Dynamic(w) => w.after_render(), + } + } + + pub fn component(self: &Arc, c: C) -> &Arc { + match &**self { + Widget::Static(w) => { + w.component(c); + } + Widget::Dynamic(w) => { + w.component(c); + } + } + self + } + + pub fn set_component(self: &Arc, c: C) -> &Arc { + match &**self { + Widget::Static(w) => { + w.set_component(c); + } + Widget::Dynamic(w) => { + w.set_component(c); + } + } + self + } + + pub fn get(&self) -> Option { + match self { + Widget::Static(w) => w.get(), + Widget::Dynamic(w) => w.get(), + } + } + + pub fn inject WidgetLoad + 'static + Send + Sync>( + self: &Arc, + f: F, + ) { + match &**self { + Widget::Dynamic(w) => { + w.inject(f); + } + Widget::Static(_) => {} + } + } + + pub fn refresh(self: &Arc) { + match &**self { + Widget::Dynamic(w) => { + w.refresh(); + } + Widget::Static(_) => {} + } + } + + pub fn auto_refresh(self: &Arc) { + match &**self { + Widget::Dynamic(w) => { + w.auto_refresh(); + } + Widget::Static(_) => {} + } + } + + pub fn dependency(self: &Arc, d: D) -> &Arc { + match &**self { + Widget::Dynamic(w) => { + w.dependency(d); + } + Widget::Static(_) => {} + } + self + } + + pub fn dependency_box(self: &Arc, d: Box) -> &Arc { + match &**self { + Widget::Dynamic(w) => { + w.dependency_box(d); + } + Widget::Static(_) => {} + } + self + } +} + +// === Static Widget === +pub struct StaticWidget(Mutex, Mutex>); + +impl StaticWidget { + fn after_render(&self) {} + fn get_elem(&self) -> MutexGuard { + self.0.lock().unwrap() + } +} + +impl StaticWidget { + pub fn new(e: BoxedElement) -> Self { + Self(Mutex::new(e), Mutex::new(HashMap::new())) + } + + pub fn component(self: &Arc, c: C) -> &Arc { + self.1 + .lock() + .unwrap() + .entry(c.type_id()) + .or_insert_with(|| Box::new(c)); + self + } + + pub fn set_component(self: &Arc, c: C) -> &Arc { + self.1.lock().unwrap().insert(c.type_id(), Box::new(c)); + self + } + + pub fn get(&self) -> Option { + self.1 + .lock() + .unwrap() + .get(&TypeId::of::()) + .and_then(|c| c.as_any().downcast_ref::()) + .map(Clone::clone) + } +} + +// === Dynamic Widget === +pub struct DynWidget( + Mutex, Mutex>, Mutex WidgetLoad + Send + Sync>>, Mutex>>, Mutex WidgetLoad + Send + Sync>>>, ); -impl Widget { +impl DynWidget { + fn after_render(&self) {} + fn get_elem(&self) -> MutexGuard { + self.0.lock().unwrap() + } +} + +impl DynWidget { pub fn new WidgetLoad + 'static + Send + Sync>(mut e: F) -> Self { let wl = e(); Self( @@ -49,25 +224,19 @@ impl Widget { self: &Arc, f: F, ) { - { - *self.4.lock().unwrap() = Some(Box::new(f)); - } + *self.4.lock().unwrap() = Some(Box::new(f)); self.refresh(); } pub fn refresh(self: &Arc) { - let w = (self.2.lock().unwrap())(); - match &mut *self.4.lock().unwrap() { - Some(inject) => { - let w = inject(w); - *self.0.lock().unwrap() = w.0; - *self.1.lock().unwrap() = w.1; - } - None => { - *self.0.lock().unwrap() = w.0; - *self.1.lock().unwrap() = w.1; - } + let mut w = (self.2.lock().unwrap())(); + + if let Some(we) = &mut *self.4.lock().unwrap() { + w = (we)(w); } + + *self.0.lock().unwrap() = w.0; + *self.1.lock().unwrap() = w.1; } pub fn auto_refresh(self: &Arc) { @@ -110,31 +279,6 @@ impl Widget { .unwrap() .get(&TypeId::of::()) .and_then(|c| c.as_any().downcast_ref::()) - .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()) + .map(Clone::clone) } }