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::*;
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 {
let count = State::new(0);
rsx! {
styling: Some(styling()),
class: "root",
div {
class: "tab",
text { class: "title", "not started" }
text { class: "todo", "TODO: Something" }
}
div {
class: "tab",
text { class: "title", "completed" }
}
button { on_click: fn(_, _, _) @count {
let mut count = count.use_state();
*count += 1;
}, class: "btn", "Count: {count}" }
}
}
pub fn styling() -> Css {
css! {
"tab" {
x: Auto,
width: 50%,
outline: true,
}
"title" {
width: Auto,
color: Red,
}
"todo" {
x: 0 px,
y: Auto,
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 use crate::ui::Color::*;
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::{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 fn sleep(ms: u64) {
std::thread::sleep(std::time::Duration::from_millis(ms));
@@ -88,19 +88,29 @@ pub struct Writer {
focused: bool,
size: (u16, u16),
absolute: (u16, u16),
written: (u16, u16),
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/// Enums
//////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Debug)]
pub enum Children {
None,
Text(String),
Text(Arc<dyn Fn() -> String>),
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
//////////////////////////////////////////////////////////////////////////////////////////////////
@@ -152,12 +162,6 @@ impl Document {
pub fn draw(&mut self, element: &mut 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 {
@@ -175,31 +179,25 @@ impl Children {
}
pub fn get_text(&self) -> String {
match self {
Children::Text(text) => text.clone(),
Children::Text(text) => text(),
_ => String::new(),
}
}
pub fn get_text_mut(&mut self) -> Option<&mut String> {
match self {
Children::Text(text) => Some(text),
_ => None,
}
}
pub fn set_text(&mut self, text: &str) {
pub fn set_text(&mut self, text: Arc<dyn Fn() -> String>) {
match self {
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 {
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,
size,
absolute,
written: (0, 1),
}
}
@@ -249,6 +248,11 @@ impl Writer {
self.absolute.0 + 1,
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) {
(
self.style.width.as_size(self.size.0, self.style.outline),
self.style.height.as_size(self.size.1, self.style.outline),
self.style
.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() }
}
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() {
launch!(todo_app())
launch!(todo_app());
}
+12 -21
View File
@@ -12,17 +12,6 @@ macro_rules! check_expr {
}
#[macro_export]
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)*) => {
if $elem.children.is_none() {$elem.children = $crate::Children::Children(Vec::new(), 0)}
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.$($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)*)?);
};
@@ -78,16 +77,8 @@ macro_rules! parse_rsx_param {
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.children.set_text_force(&format!($text))
$elem.children.set_text_force(std::sync::Arc::new(move || format!($text)))
};
($elem:expr, $text:expr, $($inner:tt)*) => {
+2 -24
View File
@@ -18,9 +18,7 @@ pub struct Text {
impl ElementWidget for Text<'_> {
fn render(&self, writer: &mut crate::Writer) {
if let Children::Text(text) = &self.children {
writer.write(&text);
}
writer.write(&self.children.get_text());
}
fn event(&mut self, event: Event, document: &Document) {
call!(self.on_event(event, document));
@@ -77,7 +75,7 @@ impl ElementWidget for Button<'_> {
self.style.set_state("clicked");
call!(self.on_click(event, document));
document.render();
sleep(100);
sleep(65);
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,
}
}
pub fn as_size(&self, frame_size: u16, outline: bool) -> u16 {
if outline {
pub fn as_size(&self, written: u16, frame_size: u16, outline: bool) -> u16 {
if *self == Number::Auto || *self == Number::Default {
written
} else if outline {
self.as_size_raw(frame_size) - 2
} else {
self.as_size_raw(frame_size)
}
}
pub fn as_position_y(&self, used: &Vec<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 {
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,
+26 -4
View File
@@ -1,5 +1,7 @@
use std::io::{stdout, Write};
use crossterm::terminal::disable_raw_mode;
pub struct Frame {
used: Vec<u16>,
width: u16,
@@ -21,9 +23,21 @@ impl Frame {
pub fn render(&mut self, focused: bool, element: &crate::Element) {
let style = element.get_style().get(focused);
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) {
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(
focused,
style.clone(),
@@ -31,9 +45,17 @@ impl Frame {
(self.width, self.height),
);
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 {
*self.used.get_mut(i as usize).unwrap() += x + width;
if let Some(o) = self.used.get_mut(i as usize) {
*o += x + width;
}
}
}
}