diff --git a/src/examples.rs b/src/examples.rs index fc938cc..5345acc 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -3,7 +3,7 @@ pub mod counter_example { #[component] pub fn App() -> Element { - let count = State::new(0); + let count = use_state(0); rsx! { @SetStyle(styling()) diff --git a/src/lib.rs b/src/lib.rs index 78f0c6b..5f9a2c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,6 +44,7 @@ use std::{ use crossterm::event::Event; use ui::{Style, StyleCore}; +use utils::VisibleLength; pub mod css; pub mod examples; @@ -58,13 +59,16 @@ pub mod prelude { pub use crate::ui::Number::{Auto, Center}; pub use crate::Instruction::*; pub use crate::{self as osui, css, ersx, launch, rsx, ui::*, Handler}; - pub use crate::{style, Component, Document, Instruction, State}; + pub use crate::{style, Component, Document}; pub use crate::{Children, Element, ElementCore, ElementWidget}; pub use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind}; pub use osui_element::component; pub fn sleep(ms: u64) { std::thread::sleep(std::time::Duration::from_millis(ms)); } + pub fn use_state<'a, T>(v: T) -> crate::State { + crate::State::new(v) + } } ////////////////////////////////////////////////////////////////////////////////////////////////// @@ -261,6 +265,7 @@ impl Children { _ => false, } } + pub fn get_text(&self) -> String { match self { Children::Text(text) => text(), @@ -268,6 +273,7 @@ impl Children { _ => String::new(), } } + pub fn set_text(&mut self, text: Arc String>) { match self { Children::Text(t) => { @@ -276,19 +282,11 @@ impl Children { _ => {} } } - pub fn set_text_force(&mut self, text: Arc String>) { - match self { - Children::Text(t) => { - *t = text; - } - _ => { - *self = Children::Text(text); - } - } - } - pub fn set_static_force(&mut self, text: String) { + + pub fn set_static(&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); @@ -333,6 +331,13 @@ impl Children { 0 } } + pub fn index_mut(&mut self) -> Option<&mut usize> { + if let Children::Children(_, c) = self { + Some(c) + } else { + None + } + } pub fn insert(&mut self, index: usize, element: Element) { if let Children::Children(children, _) = self { children.insert(index, element); @@ -362,7 +367,7 @@ impl Writer { pub fn after_render(&self, width: u16, height: u16) { if self.style.outline.1 { let ol = self.style.write_outline("│"); - let hl = "─".repeat(width as usize - 2); + let hl = "─".repeat(width as usize); self.write_abs_outline(&self.style.write_outline(&format!("╭{}╮", hl)), (0, 0)); for i in 1..height { self.write_abs_outline(&ol, (0, i)); @@ -373,18 +378,6 @@ impl Writer { } pub fn write(&mut self, s: &str) { - // let width = self.get_size().0 as usize; - // let s = s - // .lines() - // .map(|l| { - // if l.len() > width { - // l.chars().take(width).collect::() - // } else { - // l.to_string() - // } - // }) - // .collect::>() - // .join("\n"); self.write_abs(&self.style.write(&s), (0, 0)); } @@ -415,7 +408,7 @@ impl Writer { } else { l.to_string() }; - max_written = max_written.max(truncated.len() as u16); + max_written = max_written.max(truncated.visible_len() as u16); lines_written += 1; truncated }) diff --git a/src/main.rs b/src/main.rs index 51147c5..1b4fdd6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,19 +5,13 @@ fn main() { } #[component] -pub fn App() { - rsx! { - @SetStyle(css! { - div { - outline: true, - width: 33%, - x: Auto, - y: 0 px, - } - }) +fn App() { + let count = use_state(20); - div { class: "div" } - div { class: "div" } - div { class: "div" } + rsx! { + %text { "Hello" } + button { on_click: fn (_, _, _) @count { + count += 1 + }, "World: {count}" } } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 8478ec1..6c2a451 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -32,7 +32,7 @@ pub fn text<'a>(class: &'a str, id: &'a str, children: Children, style: Style) - #[element] #[derive(Default, Debug)] pub struct Div { - pub instructions: Vec>, + pub instructions: Vec>, pub ghosts: Vec, } @@ -92,26 +92,37 @@ impl ElementWidget for Div<'_> { } fn initialize(&mut self, document: &mut Document) { + let l = self.children.len(); + if let Some(i) = self.children.index_mut() { + while self.ghosts.get(*i).is_some() { + if *i < l - 1 { + *i += 1; + } else { + *i = 0; + break; + } + } + } let mut load_funcs = Vec::new(); for inst in &self.instructions { match inst { - Instruction::SetStyle(s) => { + crate::Instruction::SetStyle(s) => { document.css.extend(s.clone().into_iter()); } - Instruction::SetChild(c) => { + crate::Instruction::SetChild(c) => { self.children.set_index(*c); } - Instruction::Ghost(idx) => { + crate::Instruction::Ghost(idx) => { self.ghosts.push(*idx); } - Instruction::Load(f) => { + crate::Instruction::Load(f) => { load_funcs.push(f.clone()); } } } self.instructions.clear(); - for l in load_funcs { - l.call(self, Event::FocusGained, document) + for i in load_funcs { + i.call(self, Event::FocusGained, document) } } } @@ -122,7 +133,7 @@ pub fn div<'a>( id: &'a str, children: Children, style: Style, - instructions: Vec>, + instructions: Vec>, ghosts: Vec, ) -> Box> { Box::new(Div { diff --git a/src/ui/styles.rs b/src/ui/styles.rs index 35d2ddd..02fceaa 100644 --- a/src/ui/styles.rs +++ b/src/ui/styles.rs @@ -322,11 +322,7 @@ impl Number { } pub fn as_size(&self, written: u16, frame_size: u16, outline: bool) -> u16 { if *self == Number::Auto { - if written > 0 { - written - 1 - } else { - written - } + written } else if outline { self.as_size_raw(frame_size) - 2 } else { diff --git a/src/utils.rs b/src/utils.rs index 056c017..62ffd1e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -34,62 +34,61 @@ impl<'a> Frame<'a> { } } - if style_element.visible.1 { - let y = style_element.y.1.as_position( - style_element.outline.1, - &{ - let mut y = 0; - while y < self.used.len() && self.used[y] != 0 { - y += 1; - } - y as u16 - }, - self.writer.size.1, - ); - if let Some(y_) = self.used.get(y as usize) { - let x = - style_element - .x - .1 - .as_position(style_element.outline.1, y_, self.writer.size.0); - let mut writer = crate::Writer { - focused, - style: style_element.clone(), - pos: (x, y), - size: self.writer.size, - css, - parent: Some(self.writer), - written: (0, 0), - }; - element.render(&mut writer); - let (mut width, mut height) = writer.get_size_root(); - if style_element.outline.1 { - width += 2; - height += 2; - } - { - let (mut x, mut y) = (x, y); - if style_element.outline.1 { - x -= 1; - y -= 1; - } - let height = if style_element.outline.1 { - height + 1 - } else { - height - }; + if !style_element.visible.1 { + return; + } - for i in y..y + height { - if let Some(o) = self.used.get_mut(i as usize) { - if style_element.x.1 != crate::ui::Number::Auto { - *o += x; - } - *o += width + 1; + let y = style_element.y.1.as_position( + style_element.outline.1, + &{ + let mut y = 0; + while y < self.used.len() && self.used[y] != 0 { + y += 1; + } + y as u16 + }, + self.writer.size.1, + ); + + if let Some(y_) = self.used.get(y as usize) { + let x = style_element + .x + .1 + .as_position(style_element.outline.1, y_, self.writer.size.0); + + let mut writer = crate::Writer { + focused, + style: style_element.clone(), + pos: (x, y), + size: self.writer.size, + css, + parent: Some(self.writer), + written: (0, 0), + }; + element.render(&mut writer); + let (width, height) = writer.get_size_root(); + { + let (mut x, mut y) = (x, y); + if style_element.outline.1 { + x -= 1; + y -= 1; + } + let height = if style_element.outline.1 { + height + 1 + } else { + height + }; + + for i in y..y + height { + if let Some(o) = self.used.get_mut(i as usize) { + if style_element.x.1 != crate::ui::Number::Auto { + *o += x; } + *o += width; } } - writer.after_render(width, height); } + writer.after_render(width, height); } } } @@ -112,3 +111,28 @@ pub fn show_cursor() { pub fn flush() { stdout().flush().unwrap(); } + +pub trait VisibleLength { + fn visible_len(&self) -> usize; +} + +impl VisibleLength for String { + fn visible_len(&self) -> usize { + let mut length = 0; + let mut in_escape = false; + + for c in self.chars() { + if c == '\x1b' { + in_escape = true; + } else if in_escape { + if c.is_ascii_alphabetic() { + in_escape = false; + } + } else { + length += 1; + } + } + + length + } +}