Merge pull request #29 from osui-rs/iteration-patch

Added iteration and improved examples
This commit is contained in:
Leo Codes
2025-08-12 23:43:39 -04:00
committed by GitHub
9 changed files with 174 additions and 17 deletions
+32
View File
@@ -0,0 +1,32 @@
use osui::prelude::*;
fn main() -> std::io::Result<()> {
let screen = Screen::new();
app().draw(&screen);
screen.run()
}
pub fn app() -> Rsx {
let items: State<Vec<i32>> = use_state(vec![1, 2]);
std::thread::spawn({
let items = items.clone();
move || {
std::thread::sleep(std::time::Duration::from_millis(1000));
items.get().push(3);
std::thread::sleep(std::time::Duration::from_millis(1000));
items.get().remove(0);
}
});
rsx! {
FlexRow {
for item in items {
static "{item}"
static "Idk {item}"
}
}
}
}
+10
View File
@@ -2,6 +2,16 @@ use std::sync::Arc;
use osui::prelude::*; use osui::prelude::*;
fn main() -> std::io::Result<()> {
let screen = Screen::new();
screen.extension(InputExtension);
screen.extension(RelativeFocusExtension::new());
app(screen.clone()).draw(&screen);
screen.run()
}
pub fn app(screen: Arc<Screen>) -> Rsx { pub fn app(screen: Arc<Screen>) -> Rsx {
let count = use_state(0); let count = use_state(0);
+6
View File
@@ -78,6 +78,12 @@ impl Element for FlexRow {
element.inject(|w| w.component(NoRenderRoot)); element.inject(|w| w.component(NoRenderRoot));
} }
fn undraw_child(&mut self, element: &Arc<Widget>) {
if let Some(i) = self.children.iter().position(|v| Arc::ptr_eq(v, element)) {
self.children.remove(i);
}
}
fn is_ghost(&mut self) -> bool { fn is_ghost(&mut self) -> bool {
true true
} }
+1 -1
View File
@@ -96,7 +96,7 @@ impl Context {
} }
} }
pub fn get_widgets(&self) -> MutexGuard<Vec<Arc<Widget>>> { pub fn get_widgets(&'_ self) -> MutexGuard<'_, Vec<Arc<Widget>>> {
self.screen.widgets.lock().unwrap() self.screen.widgets.lock().unwrap()
} }
+70 -1
View File
@@ -25,6 +25,12 @@ pub enum RsxElement {
Vec<Box<dyn DependencyHandler>>, Vec<Box<dyn DependencyHandler>>,
Rsx, Rsx,
), ),
/// A dynamic iteration of widgets, keeping track of their state.
Iter(
Box<dyn FnMut() -> Rsx + Send + Sync>,
Box<dyn DependencyHandler>,
),
} }
/// A container representing a group of RSX elements. /// A container representing a group of RSX elements.
@@ -42,7 +48,13 @@ impl Rsx {
/// Recursively draws the RSX tree with an optional parent widget. /// Recursively draws the RSX tree with an optional parent widget.
/// ///
/// Used internally to establish parent-child widget relationships. /// Used internally to establish parent-child widget relationships.
pub fn draw_parent(self, screen: &Arc<Screen>, parent: Option<Arc<Widget>>) { pub fn draw_parent(
self,
screen: &Arc<Screen>,
parent: Option<Arc<Widget>>,
) -> Option<Arc<Widget>> {
let mut first_widget = None;
for rsx_elem in self.0 { for rsx_elem in self.0 {
match rsx_elem { match rsx_elem {
RsxElement::DynElement(f, dep, child) => { RsxElement::DynElement(f, dep, child) => {
@@ -57,6 +69,9 @@ impl Rsx {
} }
child.draw_parent(screen, Some(w.clone())); child.draw_parent(screen, Some(w.clone()));
if first_widget.is_none() {
first_widget = Some(w)
}
} }
RsxElement::Element(ws, child) => { RsxElement::Element(ws, child) => {
@@ -68,10 +83,50 @@ impl Rsx {
} }
child.draw_parent(screen, Some(w.clone())); child.draw_parent(screen, Some(w.clone()));
if first_widget.is_none() {
first_widget = Some(w)
}
}
RsxElement::Iter(mut rsx, dep) => {
#[allow(unused)]
let mut rsx_len = 0;
let mut fw = {
let r = rsx();
rsx_len = r.0.len();
r.draw_parent(screen, parent.clone())
};
let parent = parent.clone();
let s = screen.clone();
screen.add_dependency(vec![dep], move || {
if let Some(fww) = &fw {
{
let mut widgets = s.widgets.lock().unwrap();
if let Some(i) = widgets.iter().position(|v| Arc::ptr_eq(v, fww)) {
for v in (i..(i + rsx_len)).rev() {
if let Some(w) = widgets.get(v) {
if let Some(p) = &parent {
p.get_elem().undraw_child(w);
}
widgets.remove(v);
} }
} }
} }
} }
fw = {
let r = rsx();
rsx_len = r.0.len();
r.draw_parent(&s, parent.clone())
};
}
});
}
}
}
first_widget
}
/// Adds a dynamically constructed element to the RSX tree. /// Adds a dynamically constructed element to the RSX tree.
/// ///
@@ -96,8 +151,22 @@ impl Rsx {
self.0.push(RsxElement::Element(element, children)); self.0.push(RsxElement::Element(element, children));
} }
/// Adds a statically defined element to the RSX tree with its children.
pub fn iter<F: FnMut() -> Rsx + Send + Sync + 'static>(
&mut self,
rsx: F,
dependency: Box<dyn DependencyHandler>,
) {
self.0.push(RsxElement::Iter(Box::new(rsx), dependency));
}
/// Appends the elements from another `Rsx` tree into this one. /// Appends the elements from another `Rsx` tree into this one.
pub fn expand(&mut self, other: &mut Rsx) { pub fn expand(&mut self, other: &mut Rsx) {
self.0.append(&mut other.0); self.0.append(&mut other.0);
} }
/// Appends the elements from another `Rsx` tree into this one. nr stands for no reference
pub fn expand_nr(&mut self, mut other: Rsx) {
self.0.append(&mut other.0);
}
} }
+34
View File
@@ -35,6 +35,7 @@ use crate::{
extensions::Extension, extensions::Extension,
prelude::{Context, ElementRenderer}, prelude::{Context, ElementRenderer},
render_scope::RenderScope, render_scope::RenderScope,
state::DependencyHandler,
widget::{BoxedElement, DynWidget, Element, StaticWidget, Widget, WidgetLoad}, widget::{BoxedElement, DynWidget, Element, StaticWidget, Widget, WidgetLoad},
}; };
@@ -78,6 +79,13 @@ pub struct Screen {
extensions: Mutex<Vec<Arc<Mutex<Box<dyn Extension + Send + Sync>>>>>, extensions: Mutex<Vec<Arc<Mutex<Box<dyn Extension + Send + Sync>>>>>,
/// If it's still running /// If it's still running
running: Mutex<bool>, running: Mutex<bool>,
/// If it's still running
dependencies: Mutex<
Vec<(
Vec<Box<dyn DependencyHandler>>,
Box<dyn FnMut() + Send + Sync>,
)>,
>,
} }
event!(RenderWrapperEvent(*mut RenderScope)); event!(RenderWrapperEvent(*mut RenderScope));
@@ -104,6 +112,7 @@ impl Screen {
widgets: Mutex::new(Vec::new()), widgets: Mutex::new(Vec::new()),
extensions: Mutex::new(Vec::new()), extensions: Mutex::new(Vec::new()),
running: Mutex::new(true), running: Mutex::new(true),
dependencies: Mutex::new(Vec::new()),
}) })
} }
@@ -194,6 +203,14 @@ impl Screen {
scope.render_widget(&mut renderer, ctx, widget); scope.render_widget(&mut renderer, ctx, widget);
} }
for d in self.dependencies.lock().unwrap().iter_mut() {
for dh in &d.0 {
if dh.check() {
(d.1)();
break;
}
}
}
Ok(()) Ok(())
} }
@@ -208,6 +225,23 @@ impl Screen {
} }
} }
impl Screen {
pub fn add_dependency<F: FnMut() + Send + Sync + 'static>(
self: &Arc<Self>,
dependencies: Vec<Box<dyn DependencyHandler>>,
handler: F,
) {
for d in &dependencies {
d.add();
}
self.dependencies
.lock()
.unwrap()
.push((dependencies, Box::new(handler)));
}
}
struct ScreenRenderer; struct ScreenRenderer;
impl ElementRenderer for ScreenRenderer {} impl ElementRenderer for ScreenRenderer {}
+14
View File
@@ -240,6 +240,20 @@ macro_rules! rsx {
/// Would produce a nested `Rsx` tree of static and dynamic widgets. /// Would produce a nested `Rsx` tree of static and dynamic widgets.
#[macro_export] #[macro_export]
macro_rules! rsx_inner { macro_rules! rsx_inner {
// for loop (iter)
($r:expr, for $n:ident in $state:ident { $($inner:tt)* } $($rest:tt)*) => {
$r.iter({
let $state = $state.clone();
move || {
let mut r = $crate::frontend::Rsx(Vec::new());
for $n in $state.get().iter() {
r.expand_nr($crate::rsx!{ $($inner)* });
}
r
}}, Box::new($state));
$crate::rsx_inner! { $r, $($rest)* };
};
// static // static
($r:expr, $(@$comp:expr;)* static $s:literal $($rest:tt)*) => { ($r:expr, $(@$comp:expr;)* static $s:literal $($rest:tt)*) => {
let w = $crate::widget::StaticWidget::new(Box::new(format!($s))); let w = $crate::widget::StaticWidget::new(Box::new(format!($s)));
-12
View File
@@ -1,12 +0,0 @@
mod demos;
use osui::prelude::*;
fn main() -> std::io::Result<()> {
let screen = Screen::new();
screen.extension(InputExtension);
screen.extension(RelativeFocusExtension::new());
demos::app(screen.clone()).draw(&screen);
screen.run()
}
+7 -3
View File
@@ -51,6 +51,10 @@ pub trait Element: Send + Sync {
#[allow(unused)] #[allow(unused)]
fn draw_child(&mut self, element: &Arc<Widget>) {} fn draw_child(&mut self, element: &Arc<Widget>) {}
/// Called to undraw child widgets, if any.
#[allow(unused)]
fn undraw_child(&mut self, element: &Arc<Widget>) {}
#[allow(unused)] #[allow(unused)]
fn event(&mut self, event: &dyn Event) {} fn event(&mut self, event: &dyn Event) {}
@@ -166,7 +170,7 @@ impl Widget {
} }
} }
pub fn get_elem(&self) -> MutexGuard<BoxedElement> { pub fn get_elem(&'_ self) -> MutexGuard<'_, BoxedElement> {
match self { match self {
Widget::Static(w) => w.get_elem(), Widget::Static(w) => w.get_elem(),
Widget::Dynamic(w) => w.get_elem(), Widget::Dynamic(w) => w.get_elem(),
@@ -284,7 +288,7 @@ impl Widget {
impl StaticWidget { impl StaticWidget {
fn after_render(&self) {} fn after_render(&self) {}
fn get_elem(&self) -> MutexGuard<BoxedElement> { fn get_elem(&'_ self) -> MutexGuard<'_, BoxedElement> {
self.element.lock().unwrap() self.element.lock().unwrap()
} }
} }
@@ -325,7 +329,7 @@ impl StaticWidget {
impl DynWidget { impl DynWidget {
fn after_render(&self) {} fn after_render(&self) {}
fn get_elem(&self) -> MutexGuard<BoxedElement> { fn get_elem(&'_ self) -> MutexGuard<'_, BoxedElement> {
self.element.lock().unwrap() self.element.lock().unwrap()
} }
} }