From 0878cad01cd68013e1397d7e2f12dccc6967b681 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Sat, 26 Jul 2025 00:26:30 +0200 Subject: [PATCH] Simple state management --- README.md | 14 +++++++++ src/elements/mod.rs | 1 + src/elements/state.rs | 68 +++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 48 +++++++----------------------- 4 files changed, 94 insertions(+), 37 deletions(-) create mode 100644 src/elements/state.rs diff --git a/README.md b/README.md index 6355cb6..157a9d4 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,20 @@ 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.

+```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) ## Features diff --git a/src/elements/mod.rs b/src/elements/mod.rs index f397332..f87b784 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -1,5 +1,6 @@ pub mod div; pub mod grid; +pub mod state; use crate::Element; diff --git a/src/elements/state.rs b/src/elements/state.rs new file mode 100644 index 0000000..cdbff7b --- /dev/null +++ b/src/elements/state.rs @@ -0,0 +1,68 @@ +use crate::{render_scope::RenderScope, widget::Element}; +use std::sync::{Arc, Mutex}; + +pub struct State { + pub value: *mut T, + dependents: Mutex>>>, +} + +pub fn use_state(mut v: T) -> Arc> { + Arc::new(State { + value: &mut v, + dependents: Mutex::new(Vec::new()), + }) +} + +impl State { + 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 Box + 'static + Send + Sync>( + self: &Arc, + mut element: F, + ) -> Arc> { + let d = Arc::new(Mutex::new(StateDependency((element)(), Box::new(element)))); + self.dependents.lock().unwrap().push(d.clone()); + d + } +} + +pub struct StateDependency( + Box, + pub Box Box + Send + Sync>, +); + +impl<'a> Element for Arc> { + 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 std::fmt::Display for State { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + unsafe { &*self.value }.fmt(f) + } +} + +unsafe impl Send for State {} +unsafe impl Sync for State {} diff --git a/src/main.rs b/src/main.rs index d1f4041..8a90309 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,44 +1,18 @@ -use osui::{ - elements::grid::VGrid, - extensions::{ - resources::VecResource, - tick::{TickEvent, TickExtension}, - Handler, - }, - style::Transform, - Screen, -}; +use osui::{elements::state::use_state, Screen}; -fn main() { +fn main() -> std::io::Result<()> { let screen = Screen::new(); - screen.extension(TickExtension(10)); + let count = use_state(0); - let items = >::new(); + screen.draw(count.draw({ + let count = count.clone(); + move || Box::new(format!("Count: {count}")) + })); - let vgrid = VGrid::new(0x000000, 0); - - 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({ - let screen = screen.clone(); - move |i| { - vgrid.draw( - screen - .draw((i.to_string(), 0xff0000)) - .component(Transform::new()), - ); - } + std::thread::spawn(move || loop { + std::thread::sleep(std::time::Duration::from_millis(500)); + count.set(unsafe { *count.value } + 1); }); - screen.run().unwrap(); + screen.run() }