some nice dynamic stuff

This commit is contained in:
2024-12-12 17:14:48 +01:00
parent 250528950a
commit b4c4e32aba
7 changed files with 129 additions and 135 deletions
+16 -40
View File
@@ -1,55 +1,31 @@
use crate::prelude::*; use crate::prelude::*;
pub fn examples() -> Element {
rsx! {
styling: Some(styling()),
button { class: "btn", on_click: fn(btn: &mut Button, _, document) {
let count = document.use_state::<u32>("count");
*count += 1;
btn.children.set_text(&count.to_string());
if *count == 10 {
document.exit();
}
}, "Click me!" }
text { "Welcome!" }
@count: i32;
}
}
pub fn todo_app() -> Element { pub fn todo_app() -> Element {
let count = State::new(0);
rsx! { rsx! {
styling: Some(styling()), styling: Some(styling()),
class: "root",
div { button { on_click: fn(_, _, _) @count {
class: "tab", let mut count = count.use_state();
text { class: "title", "not started" } *count += 1;
text { class: "todo", "TODO: Something" } }, class: "btn", "Count: {count}" }
}
div {
class: "tab",
text { class: "title", "completed" }
}
} }
} }
pub fn styling() -> Css { pub fn styling() -> Css {
css! { css! {
"tab" {
x: Auto,
width: 50%,
outline: true,
}
"title" { "title" {
width: Auto,
color: Red,
}
"todo" {
x: 0 px,
y: Auto,
color: Green, color: Green,
x: Center,
}
"container" {
width: 50%,
}
"btn": "clicked" {
color: Red
} }
} }
} }
+66 -24
View File
@@ -37,10 +37,10 @@ pub mod utils;
pub mod prelude { pub mod prelude {
pub use crate::ui::Color::*; pub use crate::ui::Color::*;
pub use crate::ui::Font::*; pub use crate::ui::Font::*;
pub use crate::ui::Number::*; pub use crate::ui::Number::{Auto, Center};
pub use crate::{self as osui, css, ersx, launch, rsx, ui::*, Handler}; pub use crate::{self as osui, css, ersx, launch, rsx, ui::*, Handler};
pub use crate::{call, Children, Element, ElementCore, ElementWidget}; pub use crate::{call, Children, Element, ElementCore, ElementWidget};
pub use crate::{style, Document}; pub use crate::{style, Document, State};
pub use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind}; pub use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind};
pub fn sleep(ms: u64) { pub fn sleep(ms: u64) {
std::thread::sleep(std::time::Duration::from_millis(ms)); std::thread::sleep(std::time::Duration::from_millis(ms));
@@ -88,19 +88,29 @@ pub struct Writer {
focused: bool, focused: bool,
size: (u16, u16), size: (u16, u16),
absolute: (u16, u16), absolute: (u16, u16),
written: (u16, u16),
} }
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
/// Enums /// Enums
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Debug)]
pub enum Children { pub enum Children {
None, None,
Text(String), Text(Arc<dyn Fn() -> String>),
Children(Vec<Element>, usize), Children(Vec<Element>, usize),
} }
impl std::fmt::Debug for Children {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&match self {
Self::None => String::new(),
Self::Children(a, b) => format!("({b}, {a:?})"),
Self::Text(a) => format!("{:?}", a()),
})
}
}
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
/// Implementations /// Implementations
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
@@ -152,12 +162,6 @@ impl Document {
pub fn draw(&mut self, element: &mut Element) { pub fn draw(&mut self, element: &mut Element) {
self.element = element; self.element = element;
} }
pub fn use_state<T>(&self, name: &str) -> &mut T {
&mut self
.get_element_by_id::<crate::ui::DataHolder<T>>(name)
.unwrap()
.data
}
} }
impl Default for Children { impl Default for Children {
@@ -175,31 +179,25 @@ impl Children {
} }
pub fn get_text(&self) -> String { pub fn get_text(&self) -> String {
match self { match self {
Children::Text(text) => text.clone(), Children::Text(text) => text(),
_ => String::new(), _ => String::new(),
} }
} }
pub fn get_text_mut(&mut self) -> Option<&mut String> { pub fn set_text(&mut self, text: Arc<dyn Fn() -> String>) {
match self {
Children::Text(text) => Some(text),
_ => None,
}
}
pub fn set_text(&mut self, text: &str) {
match self { match self {
Children::Text(t) => { Children::Text(t) => {
*t = text.to_string(); *t = text;
} }
_ => {} _ => {}
} }
} }
pub fn set_text_force(&mut self, text: &str) { pub fn set_text_force(&mut self, text: Arc<dyn Fn() -> String>) {
match self { match self {
Children::Text(t) => { Children::Text(t) => {
*t = text.to_string(); *t = text;
} }
_ => { _ => {
*self = Children::Text(text.to_string()); *self = Children::Text(text);
} }
} }
} }
@@ -238,6 +236,7 @@ impl Writer {
focused, focused,
size, size,
absolute, absolute,
written: (0, 1),
} }
} }
@@ -249,6 +248,11 @@ impl Writer {
self.absolute.0 + 1, self.absolute.0 + 1,
self.style.write(line) self.style.write(line)
); );
let line_len = line.len() as u16;
if line_len > self.written.0 {
self.written.0 = line_len;
}
self.written.1 += 1;
} }
} }
@@ -258,8 +262,23 @@ impl Writer {
pub fn get_size(&self) -> (u16, u16) { pub fn get_size(&self) -> (u16, u16) {
( (
self.style.width.as_size(self.size.0, self.style.outline), self.style
self.style.height.as_size(self.size.1, self.style.outline), .width
.as_size(self.size.0, self.size.0, self.style.outline),
self.style
.height
.as_size(self.size.1, self.size.1, self.style.outline),
)
}
pub fn get_size_root(&self) -> (u16, u16) {
(
self.style
.width
.as_size(self.written.0, self.size.0, self.style.outline),
self.style
.height
.as_size(self.written.1, self.size.1, self.style.outline),
) )
} }
@@ -306,3 +325,26 @@ pub fn run(element: &mut Element) -> bool {
unsafe { (*document.running).unwrap() } unsafe { (*document.running).unwrap() }
} }
pub struct State<T>(Arc<Mutex<T>>);
impl<T> State<T> {
pub fn new<'a>(v: T) -> State<T> {
State(Arc::new(Mutex::new(v)))
}
pub fn use_state<'a>(&'a self) -> std::sync::MutexGuard<'a, T> {
self.0.lock().unwrap()
}
pub fn copy_state<'a>(&'a self) -> State<T> {
State(Arc::clone(&self.0))
}
}
impl<T: std::fmt::Display> std::fmt::Display for State<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Acquire the lock, handle potential poisoning
match self.0.lock() {
Ok(guard) => write!(f, "{}", *guard),
Err(poisoned) => write!(f, "<Poisoned: {}>", *poisoned.into_inner()),
}
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
use osui::{examples::todo_app, prelude::*}; use osui::{examples::todo_app, launch};
fn main() { fn main() {
launch!(todo_app()) launch!(todo_app());
} }
+12 -21
View File
@@ -12,17 +12,6 @@ macro_rules! check_expr {
} }
#[macro_export] #[macro_export]
macro_rules! parse_rsx_param { macro_rules! parse_rsx_param {
// Data fields
($elem:expr, @$name:ident: $type:ty; $($rest:tt)*) => {
if $elem.children.is_none() {$elem.children = $crate::Children::Children(Vec::new(), 0)}
if let $crate::Children::Children(children, _) = &mut $elem.children {
let mut $name = $crate::ui::data_holder::<$type>();
$name.id = stringify!($name);
children.push($name);
}
osui::parse_rsx_param!($elem, $($rest)*)
};
($elem:expr, for ($($for:tt)*) $code:block $($rest:tt)*) => { ($elem:expr, for ($($for:tt)*) $code:block $($rest:tt)*) => {
if $elem.children.is_none() {$elem.children = $crate::Children::Children(Vec::new(), 0)} if $elem.children.is_none() {$elem.children = $crate::Children::Children(Vec::new(), 0)}
if let $crate::Children::Children(children, _) = &mut $elem.children { if let $crate::Children::Children(children, _) = &mut $elem.children {
@@ -34,7 +23,17 @@ macro_rules! parse_rsx_param {
}; };
($elem:expr, $($k:ident).+: fn($($params:tt)*) $code:block $(, $($rest:tt)*)?) => { ($elem:expr, $($k:ident).+: fn($($params:tt)*) $code:block $(, $($rest:tt)*)?) => {
$elem.$($k).+ = $crate::Handler::new(|$($params)*| $code); $elem.$($k).+ = $crate::Handler::new(move |$($params)*| $code);
osui::parse_rsx_param!($elem, $($($rest)*)?);
};
($elem:expr, $($k:ident).+: fn($($params:tt)*) @$($v:ident),* $code:block $(, $($rest:tt)*)?) => {
$elem.$($k).+ = $crate::Handler::new({
$(
let $v = $v.copy_state();
)*
move |$($params)*| $code
});
osui::parse_rsx_param!($elem, $($($rest)*)?); osui::parse_rsx_param!($elem, $($($rest)*)?);
}; };
@@ -78,16 +77,8 @@ macro_rules! parse_rsx_param {
osui::parse_rsx_param!($elem, $($rest)*) osui::parse_rsx_param!($elem, $($rest)*)
}; };
($elem:expr, $elem_path:path as $t:ty { $($inner:tt)* } $($rest:tt)*) => {
if $elem.children.is_none() {$elem.children = $crate::Children::Children(Vec::new(), 0)}
if let $crate::Children::Children(children, _) = &mut $elem.children {
children.push(osui::ersx!($elem_path as $t { $($inner)* }));
}
osui::parse_rsx_param!($elem, $($rest)*)
};
($elem:expr, $text:expr) => { ($elem:expr, $text:expr) => {
$elem.children.set_text_force(&format!($text)) $elem.children.set_text_force(std::sync::Arc::new(move || format!($text)))
}; };
($elem:expr, $text:expr, $($inner:tt)*) => { ($elem:expr, $text:expr, $($inner:tt)*) => {
+2 -24
View File
@@ -18,9 +18,7 @@ pub struct Text {
impl ElementWidget for Text<'_> { impl ElementWidget for Text<'_> {
fn render(&self, writer: &mut crate::Writer) { fn render(&self, writer: &mut crate::Writer) {
if let Children::Text(text) = &self.children { writer.write(&self.children.get_text());
writer.write(&text);
}
} }
fn event(&mut self, event: Event, document: &Document) { fn event(&mut self, event: Event, document: &Document) {
call!(self.on_event(event, document)); call!(self.on_event(event, document));
@@ -77,7 +75,7 @@ impl ElementWidget for Button<'_> {
self.style.set_state("clicked"); self.style.set_state("clicked");
call!(self.on_click(event, document)); call!(self.on_click(event, document));
document.render(); document.render();
sleep(100); sleep(65);
self.style.set_state(""); self.style.set_state("");
} }
} }
@@ -85,23 +83,3 @@ impl ElementWidget for Button<'_> {
} }
} }
} }
#[element]
#[derive(Debug)]
pub struct DataHolder<'a, T> {
pub data: T,
}
pub fn data_holder<'a, T: std::default::Default>() -> Box<DataHolder<'a, T>> {
Box::new(DataHolder {
style: Style::default(),
data: T::default(),
children: Children::None,
class: "",
id: "",
})
}
impl<'a, T: std::fmt::Debug + Send + Sync> ElementWidget for DataHolder<'a, T> {
fn render(&self, _writer: &mut crate::Writer) {}
}
+5 -20
View File
@@ -310,31 +310,16 @@ impl Number {
_ => frame_size, _ => frame_size,
} }
} }
pub fn as_size(&self, frame_size: u16, outline: bool) -> u16 { pub fn as_size(&self, written: u16, frame_size: u16, outline: bool) -> u16 {
if outline { if *self == Number::Auto || *self == Number::Default {
written
} else if outline {
self.as_size_raw(frame_size) - 2 self.as_size_raw(frame_size) - 2
} else { } else {
self.as_size_raw(frame_size) self.as_size_raw(frame_size)
} }
} }
pub fn as_position_y(&self, used: &Vec<u16>, frame_size: u16) -> u16 { pub fn as_position(&self, used: &u16, frame_size: u16) -> u16 {
match self {
crate::ui::Number::Px(px) => *px,
crate::ui::Number::Pe(pe) => (frame_size * pe) / 100,
crate::ui::Number::Center => (frame_size) / 2,
crate::ui::Number::Auto | crate::ui::Number::Default => {
let mut y = 0;
for (i, n) in used.iter().enumerate() {
if *n == 0 {
y = i as u16;
break;
}
}
y
}
}
}
pub fn as_position_x(&self, used: &u16, frame_size: u16) -> u16 {
match self { match self {
crate::ui::Number::Px(px) => *px, crate::ui::Number::Px(px) => *px,
crate::ui::Number::Pe(pe) => (frame_size * pe) / 100, crate::ui::Number::Pe(pe) => (frame_size * pe) / 100,
+26 -4
View File
@@ -1,5 +1,7 @@
use std::io::{stdout, Write}; use std::io::{stdout, Write};
use crossterm::terminal::disable_raw_mode;
pub struct Frame { pub struct Frame {
used: Vec<u16>, used: Vec<u16>,
width: u16, width: u16,
@@ -21,9 +23,21 @@ impl Frame {
pub fn render(&mut self, focused: bool, element: &crate::Element) { pub fn render(&mut self, focused: bool, element: &crate::Element) {
let style = element.get_style().get(focused); let style = element.get_style().get(focused);
if style.visible { if style.visible {
let y = style.y.as_position_y(&self.used, self.height); let y = style.y.as_position(
&{
let mut y_ = 0;
for n in self.used.iter().rev() {
if *n == 0 {
break;
}
y_ += 1;
}
y_
},
self.height,
);
if let Some(y_) = self.used.get(y as usize) { if let Some(y_) = self.used.get(y as usize) {
let x = style.x.as_position_x(y_, self.width); let x = style.x.as_position(y_, self.width);
let mut writer = crate::Writer::new( let mut writer = crate::Writer::new(
focused, focused,
style.clone(), style.clone(),
@@ -31,9 +45,17 @@ impl Frame {
(self.width, self.height), (self.width, self.height),
); );
element.render(&mut writer); element.render(&mut writer);
let (width, height) = writer.get_size(); let (width, height) = writer.get_size_root();
if style.outline {
clear();
show_cursor();
disable_raw_mode().unwrap();
panic!("the 'outline' option isn't available right now. please set 'outline' to 'false'")
}
for i in y..y + height { for i in y..y + height {
*self.used.get_mut(i as usize).unwrap() += x + width; if let Some(o) = self.used.get_mut(i as usize) {
*o += x + width;
}
} }
} }
} }