dynamic text and styling,

This commit is contained in:
2024-12-14 14:17:08 +01:00
parent b4c4e32aba
commit 2106283364
6 changed files with 146 additions and 66 deletions
+19 -18
View File
@@ -1,31 +1,32 @@
use crate::prelude::*; use crate::prelude::*;
pub fn todo_app() -> Element { pub fn todo_app() -> Element {
let count = State::new(0); let todo = vec!["Foo", "Bar"];
rsx! { rsx! {
styling: Some(styling()), for (t in todo) {
ersx!( button{ class: "todo", on_click: fn(btn: &mut Button, _, _) {
button { on_click: fn(_, _, _) @count { btn.class = if btn.class == "todo" {
let mut count = count.use_state(); "complete"
*count += 1; } else {
}, class: "btn", "Count: {count}" } "todo"
};
}, "{t}" } )
}
} }
} }
pub fn styling() -> Css { pub fn todo_styling() -> Css {
css! { css! {
"title" { "todo" {
x: 0 px,
y: Auto,
color: Red,
}
"complete" {
x: 0 px,
y: Auto,
color: Green, color: Green,
x: Center,
}
"container" {
width: 50%,
}
"btn": "clicked" {
color: Red
} }
} }
} }
+79 -30
View File
@@ -80,6 +80,7 @@ pub struct Handler<T>(pub Arc<Mutex<dyn FnMut(&mut T, crossterm::event::Event, &
pub struct Document { pub struct Document {
element: *mut Element, element: *mut Element,
running: *mut Option<bool>, running: *mut Option<bool>,
css: ui::Css,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -98,6 +99,7 @@ pub struct Writer {
pub enum Children { pub enum Children {
None, None,
Text(Arc<dyn Fn() -> String>), Text(Arc<dyn Fn() -> String>),
StaticText(String),
Children(Vec<Element>, usize), Children(Vec<Element>, usize),
} }
@@ -107,6 +109,7 @@ impl std::fmt::Debug for Children {
Self::None => String::new(), Self::None => String::new(),
Self::Children(a, b) => format!("({b}, {a:?})"), Self::Children(a, b) => format!("({b}, {a:?})"),
Self::Text(a) => format!("{:?}", a()), Self::Text(a) => format!("{:?}", a()),
Self::StaticText(a) => format!("{a:?}"),
}) })
} }
} }
@@ -116,6 +119,13 @@ impl std::fmt::Debug for Children {
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
impl Document { impl Document {
pub fn with_elem(element: &mut Element) -> Document {
Document {
element,
running: &mut None,
css: HashMap::new(),
}
}
pub fn exit(&self) { pub fn exit(&self) {
if !self.running.is_null() { if !self.running.is_null() {
unsafe { unsafe {
@@ -151,7 +161,10 @@ impl Document {
} }
} }
pub fn render(&self) { pub fn render(&self) {
if !self.running.is_null() { if !self.element.is_null() {
unsafe {
(*self.element).set_styling(&self.css);
}
let (width, height) = crossterm::terminal::size().unwrap(); let (width, height) = crossterm::terminal::size().unwrap();
let mut frame = utils::Frame::new((0, 0), (width, height)); let mut frame = utils::Frame::new((0, 0), (width, height));
utils::clear(); utils::clear();
@@ -159,9 +172,34 @@ impl Document {
utils::flush(); utils::flush();
} }
} }
pub fn set_css(&mut self, css: ui::Css) {
self.css = css;
}
pub fn draw(&mut self, element: &mut Element) { pub fn draw(&mut self, element: &mut Element) {
self.element = element; self.element = element;
} }
pub fn run(&self) -> bool {
unsafe { *self.running = None }
let element = unsafe { &mut *self.element };
// Send initial event
element.event(crossterm::event::Event::FocusGained, self);
utils::hide_cursor();
crossterm::terminal::enable_raw_mode().unwrap();
utils::clear();
while unsafe { *self.running } == None {
self.render();
element.event(crossterm::event::read().unwrap(), self);
}
utils::show_cursor();
crossterm::terminal::disable_raw_mode().unwrap();
utils::clear();
unsafe { (*self.running).unwrap() }
}
} }
impl Default for Children { impl Default for Children {
@@ -180,6 +218,7 @@ impl Children {
pub fn get_text(&self) -> String { pub fn get_text(&self) -> String {
match self { match self {
Children::Text(text) => text(), Children::Text(text) => text(),
Children::StaticText(text) => text.clone(),
_ => String::new(), _ => String::new(),
} }
} }
@@ -201,16 +240,51 @@ impl Children {
} }
} }
} }
pub fn set_static_force(&mut self, text: String) {
*self = Children::StaticText(text);
}
pub fn add_child(&mut self, element: Element) { pub fn add_child(&mut self, element: Element) {
if let Children::Children(children, _) = self { if let Children::Children(children, _) = self {
children.push(element); children.push(element);
} }
} }
pub fn get_child(&mut self) -> Option<&mut Element> { pub fn get_child(&mut self) -> (Option<&mut Element>, usize) {
if let Children::Children(children, child) = self { if let Children::Children(children, child) = self {
children.get_mut(*child) let l = children.len();
(children.get_mut(*child), l)
} else { } else {
None (None, 0)
}
}
pub fn get_child_idx(&mut self) -> (Option<(&mut Element, &mut usize)>, usize) {
if let Children::Children(children, child) = self {
let l = children.len();
if let Some(d) = children.get_mut(*child) {
(Some((d, child)), l)
} else {
(None, 0)
}
} else {
(None, 0)
}
}
pub fn set_child(&mut self, index: usize) {
if let Children::Children(_, child) = self {
*child = index;
}
}
pub fn len(&self) -> usize {
if let Children::Children(children, _) = self {
children.len()
} else {
0
}
}
pub fn index(&self) -> usize {
if let Children::Children(_, c) = self {
*c
} else {
0
} }
} }
} }
@@ -236,7 +310,7 @@ impl Writer {
focused, focused,
size, size,
absolute, absolute,
written: (0, 1), written: (0, 0),
} }
} }
@@ -301,31 +375,6 @@ impl<T> std::fmt::Debug for Handler<T> {
} }
} }
pub fn run(element: &mut Element) -> bool {
let document = Document {
element: element,
running: &mut None,
};
// Send initial event
element.event(crossterm::event::Event::FocusGained, &document);
utils::hide_cursor();
crossterm::terminal::enable_raw_mode().unwrap();
utils::clear();
while unsafe { *document.running } == None {
document.render();
element.event(crossterm::event::read().unwrap(), &document);
}
utils::show_cursor();
crossterm::terminal::disable_raw_mode().unwrap();
utils::clear();
unsafe { (*document.running).unwrap() }
}
pub struct State<T>(Arc<Mutex<T>>); pub struct State<T>(Arc<Mutex<T>>);
impl<T> State<T> { impl<T> State<T> {
pub fn new<'a>(v: T) -> State<T> { pub fn new<'a>(v: T) -> State<T> {
+13 -1
View File
@@ -13,6 +13,18 @@ macro_rules! call {
#[macro_export] #[macro_export]
macro_rules! launch { macro_rules! launch {
($expr:expr) => { ($expr:expr) => {
while $crate::run(&mut $expr) {} let mut element = $expr;
let mut document = $crate::Document::with_elem(&mut element);
while document.run() {
element = $expr;
}
};
($expr:expr, $css:expr) => {
let mut element = $expr;
let mut document = $crate::Document::with_elem(&mut element);
document.set_css($css);
while document.run() {
element = $expr;
}
}; };
} }
+5 -2
View File
@@ -1,5 +1,8 @@
use osui::{examples::todo_app, launch}; use osui::{
examples::{todo_app, todo_styling},
launch,
};
fn main() { fn main() {
launch!(todo_app()); launch!(todo_app(), todo_styling());
} }
+26 -8
View File
@@ -12,17 +12,12 @@ use osui_element::{elem_fn, element};
#[element] #[element]
#[elem_fn] #[elem_fn]
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct Text { pub struct Text {}
pub on_event: Handler<Text<'a>>,
}
impl ElementWidget for Text<'_> { impl ElementWidget for Text<'_> {
fn render(&self, writer: &mut crate::Writer) { fn render(&self, writer: &mut crate::Writer) {
writer.write(&self.children.get_text()); writer.write(&self.children.get_text());
} }
fn event(&mut self, event: Event, document: &Document) {
call!(self.on_event(event, document));
}
} }
#[element] #[element]
@@ -49,8 +44,31 @@ impl ElementWidget for Div<'_> {
self.set_styling(&styling); self.set_styling(&styling);
} }
} }
if let Some(child) = self.children.get_child() { if let (Some((child, i)), l) = self.children.get_child_idx() {
child.event(event, document); match event {
Event::Key(k) => match k.code {
KeyCode::Tab => {
child.event(Event::FocusLost, document);
if *i < l - 1 {
*i += 1;
} else {
*i = 0;
}
child.event(Event::FocusGained, document);
}
KeyCode::BackTab => {
child.event(Event::FocusLost, document);
if *i > 0 {
*i -= 1;
} else {
*i = l - 1;
}
child.event(Event::FocusGained, document);
}
_ => child.event(event, document),
},
_ => child.event(event, document),
}
} }
} }
} }
+4 -7
View File
@@ -25,14 +25,11 @@ impl Frame {
if style.visible { if style.visible {
let y = style.y.as_position( let y = style.y.as_position(
&{ &{
let mut y_ = 0; let mut y = 0;
for n in self.used.iter().rev() { while y < self.used.len() && self.used[y] != 0 {
if *n == 0 { y += 1;
break;
}
y_ += 1;
} }
y_ y as u16
}, },
self.height, self.height,
); );