Simple state management
This commit is contained in:
@@ -20,6 +20,20 @@
|
|||||||
<b>OSUI is a customizable terminal user interface (TUI) library written in Rust. It provides a set of components and rsx to build interactive command-line interfaces with ease.</b>
|
<b>OSUI is a customizable terminal user interface (TUI) library written in Rust. It provides a set of components and rsx to build interactive command-line interfaces with ease.</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use osui::{style::Transform, Screen};
|
||||||
|
|
||||||
|
fn main() -> std::io::Result<()> {
|
||||||
|
let screen = Screen::new();
|
||||||
|
|
||||||
|
screen
|
||||||
|
.draw(format!("Hello, World"))
|
||||||
|
.component(Transform::center());
|
||||||
|
|
||||||
|
screen.run()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## [Documentation](https://osui.netlify.app/docs)
|
## [Documentation](https://osui.netlify.app/docs)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
pub mod div;
|
pub mod div;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
|
pub mod state;
|
||||||
|
|
||||||
use crate::Element;
|
use crate::Element;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
use crate::{render_scope::RenderScope, widget::Element};
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
pub struct State<T> {
|
||||||
|
pub value: *mut T,
|
||||||
|
dependents: Mutex<Vec<Arc<Mutex<StateDependency>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn use_state<T>(mut v: T) -> Arc<State<T>> {
|
||||||
|
Arc::new(State {
|
||||||
|
value: &mut v,
|
||||||
|
dependents: Mutex::new(Vec::new()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> State<T> {
|
||||||
|
pub fn set(&self, v: T) {
|
||||||
|
unsafe {
|
||||||
|
*self.value = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
for d in self.dependents.lock().unwrap().iter() {
|
||||||
|
let mut d = d.lock().unwrap();
|
||||||
|
d.0 = (d.1)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw<F: FnMut() -> Box<dyn Element> + 'static + Send + Sync>(
|
||||||
|
self: &Arc<Self>,
|
||||||
|
mut element: F,
|
||||||
|
) -> Arc<Mutex<StateDependency>> {
|
||||||
|
let d = Arc::new(Mutex::new(StateDependency((element)(), Box::new(element))));
|
||||||
|
self.dependents.lock().unwrap().push(d.clone());
|
||||||
|
d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StateDependency(
|
||||||
|
Box<dyn Element>,
|
||||||
|
pub Box<dyn FnMut() -> Box<dyn Element> + Send + Sync>,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl<'a> Element for Arc<Mutex<StateDependency>> {
|
||||||
|
fn render(&mut self, scope: &mut RenderScope) {
|
||||||
|
self.lock().unwrap().0.render(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_render(&mut self, scope: &RenderScope) {
|
||||||
|
self.lock().unwrap().0.after_render(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: std::fmt::Display> std::fmt::Display for State<T> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
unsafe { &*self.value }.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T> Send for State<T> {}
|
||||||
|
unsafe impl<T> Sync for State<T> {}
|
||||||
+10
-36
@@ -1,44 +1,18 @@
|
|||||||
use osui::{
|
use osui::{elements::state::use_state, Screen};
|
||||||
elements::grid::VGrid,
|
|
||||||
extensions::{
|
|
||||||
resources::VecResource,
|
|
||||||
tick::{TickEvent, TickExtension},
|
|
||||||
Handler,
|
|
||||||
},
|
|
||||||
style::Transform,
|
|
||||||
Screen,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main() {
|
fn main() -> std::io::Result<()> {
|
||||||
let screen = Screen::new();
|
let screen = Screen::new();
|
||||||
screen.extension(TickExtension(10));
|
let count = use_state(0);
|
||||||
|
|
||||||
let items = <VecResource<&str>>::new();
|
screen.draw(count.draw({
|
||||||
|
let count = count.clone();
|
||||||
let vgrid = VGrid::new(0x000000, 0);
|
move || Box::new(format!("Count: {count}"))
|
||||||
|
|
||||||
screen
|
|
||||||
.draw(vgrid.clone())
|
|
||||||
.component(Transform::center())
|
|
||||||
.component(Handler::new({
|
|
||||||
let items = items.clone();
|
|
||||||
move |_, e: &TickEvent| {
|
|
||||||
if e.0 == 1 {
|
|
||||||
items.push("Hello?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
items.iterate({
|
std::thread::spawn(move || loop {
|
||||||
let screen = screen.clone();
|
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||||
move |i| {
|
count.set(unsafe { *count.value } + 1);
|
||||||
vgrid.draw(
|
|
||||||
screen
|
|
||||||
.draw((i.to_string(), 0xff0000))
|
|
||||||
.component(Transform::new()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
screen.run().unwrap();
|
screen.run()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user