From 210628336480c6096823913fa45345acce042b20 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Sat, 14 Dec 2024 14:17:08 +0100 Subject: [PATCH] dynamic text and styling, --- src/examples.rs | 37 ++++++++-------- src/lib.rs | 109 +++++++++++++++++++++++++++++++++++------------- src/macros.rs | 14 ++++++- src/main.rs | 7 +++- src/ui/mod.rs | 34 +++++++++++---- src/utils.rs | 11 ++--- 6 files changed, 146 insertions(+), 66 deletions(-) diff --git a/src/examples.rs b/src/examples.rs index d68f82c..5b5d468 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -1,31 +1,32 @@ use crate::prelude::*; pub fn todo_app() -> Element { - let count = State::new(0); + let todo = vec!["Foo", "Bar"]; rsx! { - styling: Some(styling()), - - button { on_click: fn(_, _, _) @count { - let mut count = count.use_state(); - *count += 1; - }, class: "btn", "Count: {count}" } + for (t in todo) { + ersx!( button{ class: "todo", on_click: fn(btn: &mut Button, _, _) { + btn.class = if btn.class == "todo" { + "complete" + } else { + "todo" + }; + }, "{t}" } ) + } } } -pub fn styling() -> Css { +pub fn todo_styling() -> Css { css! { - "title" { + "todo" { + x: 0 px, + y: Auto, + color: Red, + } + "complete" { + x: 0 px, + y: Auto, color: Green, - x: Center, - } - - "container" { - width: 50%, - } - - "btn": "clicked" { - color: Red } } } diff --git a/src/lib.rs b/src/lib.rs index d977a6c..1c8d872 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,6 +80,7 @@ pub struct Handler(pub Arc, + css: ui::Css, } #[derive(Debug)] @@ -98,6 +99,7 @@ pub struct Writer { pub enum Children { None, Text(Arc String>), + StaticText(String), Children(Vec, usize), } @@ -107,6 +109,7 @@ impl std::fmt::Debug for Children { Self::None => String::new(), Self::Children(a, b) => format!("({b}, {a:?})"), Self::Text(a) => format!("{:?}", a()), + Self::StaticText(a) => format!("{a:?}"), }) } } @@ -116,6 +119,13 @@ impl std::fmt::Debug for Children { ////////////////////////////////////////////////////////////////////////////////////////////////// impl Document { + pub fn with_elem(element: &mut Element) -> Document { + Document { + element, + running: &mut None, + css: HashMap::new(), + } + } pub fn exit(&self) { if !self.running.is_null() { unsafe { @@ -151,7 +161,10 @@ impl Document { } } 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 mut frame = utils::Frame::new((0, 0), (width, height)); utils::clear(); @@ -159,9 +172,34 @@ impl Document { utils::flush(); } } + pub fn set_css(&mut self, css: ui::Css) { + self.css = css; + } pub fn draw(&mut self, element: &mut 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 { @@ -180,6 +218,7 @@ impl Children { pub fn get_text(&self) -> String { match self { Children::Text(text) => text(), + Children::StaticText(text) => text.clone(), _ => 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) { if let Children::Children(children, _) = self { 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 { - children.get_mut(*child) + let l = children.len(); + (children.get_mut(*child), l) } 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, size, absolute, - written: (0, 1), + written: (0, 0), } } @@ -301,31 +375,6 @@ impl std::fmt::Debug for Handler { } } -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(Arc>); impl State { pub fn new<'a>(v: T) -> State { diff --git a/src/macros.rs b/src/macros.rs index b5db83a..ef57207 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -13,6 +13,18 @@ macro_rules! call { #[macro_export] macro_rules! launch { ($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; + } }; } diff --git a/src/main.rs b/src/main.rs index 5cd4e91..b391d23 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,8 @@ -use osui::{examples::todo_app, launch}; +use osui::{ + examples::{todo_app, todo_styling}, + launch, +}; fn main() { - launch!(todo_app()); + launch!(todo_app(), todo_styling()); } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 906d612..76fa2f2 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -12,17 +12,12 @@ use osui_element::{elem_fn, element}; #[element] #[elem_fn] #[derive(Default, Debug)] -pub struct Text { - pub on_event: Handler>, -} +pub struct Text {} impl ElementWidget for Text<'_> { fn render(&self, writer: &mut crate::Writer) { writer.write(&self.children.get_text()); } - fn event(&mut self, event: Event, document: &Document) { - call!(self.on_event(event, document)); - } } #[element] @@ -49,8 +44,31 @@ impl ElementWidget for Div<'_> { self.set_styling(&styling); } } - if let Some(child) = self.children.get_child() { - child.event(event, document); + if let (Some((child, i)), l) = self.children.get_child_idx() { + 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), + } } } } diff --git a/src/utils.rs b/src/utils.rs index 495fcc1..9caa5ae 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -25,14 +25,11 @@ impl Frame { if style.visible { let y = style.y.as_position( &{ - let mut y_ = 0; - for n in self.used.iter().rev() { - if *n == 0 { - break; - } - y_ += 1; + let mut y = 0; + while y < self.used.len() && self.used[y] != 0 { + y += 1; } - y_ + y as u16 }, self.height, );