Dynamic Widget system
This commit is contained in:
@@ -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<T> {
|
|
||||||
handlers: Vec<std::sync::Arc<dyn DependencyHandler>>,
|
|
||||||
element: T,
|
|
||||||
element_reset: Box<dyn FnMut() -> T + Send + Sync>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Dependency<T> {
|
|
||||||
pub fn new<F: FnMut() -> 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<dyn FnMut() -> T + Send + Sync>,
|
|
||||||
handlers: Vec<std::sync::Arc<dyn DependencyHandler>>,
|
|
||||||
) -> 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<D: DependencyHandler + 'static>(mut self, dep: D) -> Self {
|
|
||||||
dep.add();
|
|
||||||
self.handlers.push(Arc::new(dep));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Element for Dependency<Box<dyn Element>> {
|
|
||||||
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<T: Element + 'static> Element for Dependency<T> {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
pub mod div;
|
pub mod div;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
pub mod state;
|
|
||||||
|
|
||||||
use crate::Element;
|
use crate::Element;
|
||||||
|
|
||||||
|
|||||||
@@ -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<T> {
|
|
||||||
inner: Arc<Mutex<Inner<T>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Inner<T> {
|
|
||||||
value: T,
|
|
||||||
dependencies: usize,
|
|
||||||
changed: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn use_state<T>(v: T) -> State<T> {
|
|
||||||
State {
|
|
||||||
inner: Arc::new(Mutex::new(Inner {
|
|
||||||
value: v,
|
|
||||||
dependencies: 0,
|
|
||||||
changed: 0,
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone> State<T> {
|
|
||||||
/// Gets the cloned value, recommended for preventing deadlocks
|
|
||||||
pub fn get_dl(&self) -> T {
|
|
||||||
self.inner.lock().unwrap().value.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> State<T> {
|
|
||||||
/// Gets a lock on the state for read/write access.
|
|
||||||
pub fn get(&self) -> MutexGuard<'_, Inner<T>> {
|
|
||||||
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<T: Debug + Send + Sync> DependencyHandler for State<T> {
|
|
||||||
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<T: Display> Display for State<T> {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
|
||||||
let inner = self.inner.lock().unwrap();
|
|
||||||
write!(f, "{}", inner.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Deref for Inner<T> {
|
|
||||||
type Target = T;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> DerefMut for Inner<T> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
self.changed = self.dependencies;
|
|
||||||
&mut self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+3
-8
@@ -1,14 +1,10 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{state::DependencyHandler, widget::WidgetLoad, Screen};
|
||||||
dependency::{Dependency, DependencyHandler},
|
|
||||||
widget::{Element, Widget},
|
|
||||||
Screen,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Rsx(
|
pub struct Rsx(
|
||||||
pub Vec<(
|
pub Vec<(
|
||||||
Box<dyn FnMut() -> Box<dyn Element> + Send + Sync>,
|
Box<dyn FnMut() -> WidgetLoad + Send + Sync>,
|
||||||
Vec<std::sync::Arc<dyn DependencyHandler>>,
|
Vec<std::sync::Arc<dyn DependencyHandler>>,
|
||||||
)>,
|
)>,
|
||||||
);
|
);
|
||||||
@@ -16,8 +12,7 @@ pub struct Rsx(
|
|||||||
impl Rsx {
|
impl Rsx {
|
||||||
pub fn draw(self, screen: &Arc<Screen>) {
|
pub fn draw(self, screen: &Arc<Screen>) {
|
||||||
for i in self.0 {
|
for i in self.0 {
|
||||||
let d = Dependency::from(i.0, i.1);
|
screen.draw_box(i.0);
|
||||||
screen.draw_widget(Widget::new(Box::new(d)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-10
@@ -3,16 +3,15 @@ use std::sync::{Arc, Mutex};
|
|||||||
use crate::{
|
use crate::{
|
||||||
extensions::{Extension, Handler},
|
extensions::{Extension, Handler},
|
||||||
render_scope::RenderScope,
|
render_scope::RenderScope,
|
||||||
style::Transform,
|
widget::{Element, Widget, WidgetLoad},
|
||||||
widget::{Element, Widget},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod dependency;
|
|
||||||
pub mod elements;
|
pub mod elements;
|
||||||
pub mod extensions;
|
pub mod extensions;
|
||||||
pub mod frontend;
|
pub mod frontend;
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
pub mod render_scope;
|
pub mod render_scope;
|
||||||
|
pub mod state;
|
||||||
pub mod style;
|
pub mod style;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod widget;
|
pub mod widget;
|
||||||
@@ -41,14 +40,20 @@ impl Screen {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw<E: Element + 'static>(self: &Arc<Self>, element: E) -> Arc<Widget> {
|
pub fn draw<F: FnMut() -> WidgetLoad + 'static + Send + Sync>(
|
||||||
|
self: &Arc<Self>,
|
||||||
|
element: F,
|
||||||
|
) -> Arc<Widget> {
|
||||||
let w = Arc::new(Widget::new(Box::new(element)));
|
let w = Arc::new(Widget::new(Box::new(element)));
|
||||||
self.widgets.lock().unwrap().push(w.clone());
|
self.widgets.lock().unwrap().push(w.clone());
|
||||||
w
|
w
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_widget(self: &Arc<Self>, w: Widget) -> Arc<Widget> {
|
pub fn draw_box(
|
||||||
let w = Arc::new(w);
|
self: &Arc<Self>,
|
||||||
|
element: Box<dyn FnMut() -> WidgetLoad + Send + Sync>,
|
||||||
|
) -> Arc<Widget> {
|
||||||
|
let w = Arc::new(Widget::new(Box::new(element)));
|
||||||
self.widgets.lock().unwrap().push(w.clone());
|
self.widgets.lock().unwrap().push(w.clone());
|
||||||
w
|
w
|
||||||
}
|
}
|
||||||
@@ -61,10 +66,6 @@ impl Screen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(self: &Arc<Self>) -> std::io::Result<()> {
|
pub fn run(self: &Arc<Self>) -> std::io::Result<()> {
|
||||||
for elem in self.widgets.lock().unwrap().iter() {
|
|
||||||
elem.component(Transform::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
for ext in self.extensions.lock().unwrap().iter() {
|
for ext in self.extensions.lock().unwrap().iter() {
|
||||||
ext.lock().unwrap().init(self.clone());
|
ext.lock().unwrap().init(self.clone());
|
||||||
}
|
}
|
||||||
@@ -104,6 +105,8 @@ impl Screen {
|
|||||||
scope.draw();
|
scope.draw();
|
||||||
|
|
||||||
elem.0.lock().unwrap().after_render(&scope);
|
elem.0.lock().unwrap().after_render(&scope);
|
||||||
|
|
||||||
|
elem.auto_refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
+10
-15
@@ -1,16 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use osui::{state::use_state, widget::WidgetLoad, Screen};
|
||||||
|
|
||||||
use osui::{elements::state::use_state, frontend::Rsx, rsx, Screen};
|
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
let screen = Screen::new();
|
let screen = Screen::new();
|
||||||
|
|
||||||
app().draw(&screen);
|
|
||||||
|
|
||||||
screen.run()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn app() -> Rsx {
|
|
||||||
let count = use_state(0);
|
let count = use_state(0);
|
||||||
|
|
||||||
std::thread::spawn({
|
std::thread::spawn({
|
||||||
@@ -18,12 +9,16 @@ fn app() -> Rsx {
|
|||||||
move || loop {
|
move || loop {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||||
**count.get() += 1;
|
**count.get() += 1;
|
||||||
|
count.update();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
rsx! {
|
screen
|
||||||
%count
|
.draw({
|
||||||
@Transform::center();
|
let count = count.clone();
|
||||||
"{count}"
|
move || WidgetLoad::new(format!("Hello, World {count}"))
|
||||||
}
|
})
|
||||||
|
.dependency(count);
|
||||||
|
|
||||||
|
screen.run()
|
||||||
}
|
}
|
||||||
|
|||||||
+56
-3
@@ -4,7 +4,7 @@ use std::{
|
|||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::render_scope::RenderScope;
|
use crate::{render_scope::RenderScope, state::DependencyHandler};
|
||||||
|
|
||||||
pub type BoxedElement = Box<dyn Element + Send + Sync>;
|
pub type BoxedElement = Box<dyn Element + Send + Sync>;
|
||||||
pub type BoxedComponent = Box<dyn Component + Send + Sync>;
|
pub type BoxedComponent = Box<dyn Component + Send + Sync>;
|
||||||
@@ -26,11 +26,39 @@ pub trait Component: Send + Sync {
|
|||||||
pub struct Widget(
|
pub struct Widget(
|
||||||
pub Mutex<BoxedElement>,
|
pub Mutex<BoxedElement>,
|
||||||
Mutex<HashMap<TypeId, BoxedComponent>>,
|
Mutex<HashMap<TypeId, BoxedComponent>>,
|
||||||
|
Mutex<Box<dyn FnMut() -> WidgetLoad + Send + Sync>>,
|
||||||
|
Mutex<Vec<Box<dyn DependencyHandler>>>,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl Widget {
|
impl Widget {
|
||||||
pub fn new(e: Box<dyn Element>) -> Self {
|
pub fn new<F: FnMut() -> WidgetLoad + 'static + Send + Sync>(mut e: F) -> Self {
|
||||||
Self(Mutex::new(e), Mutex::new(HashMap::new()))
|
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<Self>) {
|
||||||
|
let w = (self.2.lock().unwrap())();
|
||||||
|
*self.0.lock().unwrap() = w.0;
|
||||||
|
*self.1.lock().unwrap() = w.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn auto_refresh(self: &Arc<Self>) {
|
||||||
|
for d in self.3.lock().unwrap().iter() {
|
||||||
|
if d.check() {
|
||||||
|
self.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dependency<D: DependencyHandler + 'static>(self: &Arc<Self>, d: D) -> &Arc<Self> {
|
||||||
|
d.add();
|
||||||
|
self.3.lock().unwrap().push(Box::new(d));
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn component<C: Component + 'static>(self: &Arc<Self>, c: C) -> &Arc<Self> {
|
pub fn component<C: Component + 'static>(self: &Arc<Self>, c: C) -> &Arc<Self> {
|
||||||
@@ -56,3 +84,28 @@ impl Widget {
|
|||||||
.map(|c| c.clone())
|
.map(|c| c.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct WidgetLoad(BoxedElement, HashMap<TypeId, BoxedComponent>);
|
||||||
|
|
||||||
|
impl WidgetLoad {
|
||||||
|
pub fn new<E: Element + 'static>(e: E) -> Self {
|
||||||
|
Self(Box::new(e), HashMap::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn component<C: Component + 'static>(mut self, c: C) -> Self {
|
||||||
|
self.1.entry(c.type_id()).or_insert_with(|| Box::new(c));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_component<C: Component + 'static>(mut self, c: C) -> Self {
|
||||||
|
self.1.insert(c.type_id(), Box::new(c));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get<C: Component + 'static + Clone>(&self) -> Option<C> {
|
||||||
|
self.1
|
||||||
|
.get(&TypeId::of::<C>())
|
||||||
|
.and_then(|c| c.as_any().downcast_ref::<C>())
|
||||||
|
.map(|c| c.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user