diff --git a/src/css.rs b/src/css.rs index d0d8751..148ca52 100644 --- a/src/css.rs +++ b/src/css.rs @@ -19,7 +19,7 @@ macro_rules! __css { // Number ( - $_style:expr, $name:ident: $value:literal $(, $($other:tt)*)? + $_style:expr, $name:ident: $value:literal px $(, $($other:tt)*)? ) => {{ $_style.$name = Number::Px($value); $crate::__css!($_style, $($($other)*)?); diff --git a/src/examples.rs b/src/examples.rs index a20e7f8..fd420a7 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -4,7 +4,7 @@ pub fn examples() -> Element { rsx! { styling: Some(styling()), - button { class: "btn", "Click me!" } + button { class: "btn", "Click me!\nsdusajuda" } text { "Welcome!" } } @@ -13,8 +13,10 @@ pub fn examples() -> Element { pub fn styling() -> Css { css! { "btn" { + outline: true, x: Center, y: Center, + width: Auto, color: Red, } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index edcad7f..3691590 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -20,13 +20,9 @@ impl ElementWidget for Text<'_> { fn render(&self, focused: bool, _: usize, _: usize) -> RenderResult { let mut writer = RenderWriter::new(focused, self.style.clone()); - writer.write(&{ - if let Children::Text(text) = &self.children { - text.clone() - } else { - String::new() - } - }); + if let Children::Text(text) = &self.children { + writer.write(&text); + } writer.result() } diff --git a/src/ui/styles.rs b/src/ui/styles.rs index 9498aa6..69ddd76 100644 --- a/src/ui/styles.rs +++ b/src/ui/styles.rs @@ -75,12 +75,14 @@ pub enum StyleName { pub struct StyleElement { pub color: Color, pub background: Color, + pub outline_color: Color, pub font: Vec, pub x: Number, pub y: Number, pub width: Number, pub height: Number, pub visible: bool, + pub outline: bool, pub other: HashMap>, } @@ -123,12 +125,18 @@ impl Style { impl StyleElement { pub fn write(&self, s: &str) -> String { - format!( - "{}{}{}{s}\x1b[0m", - self.color.ansi(), - self.background.ansi_bg(), - self.font.ansi() - ) + s.split('\n') + .into_iter() + .map(|p| { + format!( + "{}{}{}{p}\x1b[0m", + self.color.ansi(), + self.background.ansi_bg(), + self.font.ansi() + ) + }) + .collect::>() + .join("\n") } } @@ -138,11 +146,13 @@ impl Default for StyleElement { color: Color::NoColor, background: Color::NoColor, font: Vec::new(), + outline_color: Color::NoColor, x: Number::Default, y: Number::Default, width: Number::Default, height: Number::Default, visible: true, + outline: false, other: HashMap::new(), } } @@ -293,3 +303,13 @@ impl StyleCore for Vec { self.len() == 0 } } + +impl Number { + pub fn as_size(&self) -> Option<&usize> { + match self { + Number::Px(s) => return Some(s), + _ => {} + } + None + } +} diff --git a/src/utils.rs b/src/utils.rs index 29a694f..a7d4e03 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -9,7 +9,6 @@ /// let frame = create_frame(50, 10); /// render_to_frame(crate::State::Normal, 50, &mut frame, &text_element); /// ``` -use crate::Element; use lazy_static::lazy_static; use regex::Regex; use std::{ @@ -29,11 +28,12 @@ pub fn compress_string(input: &str, re: &Regex) -> (String, HashMap (String, HashMap (String, String) { +fn merge_line( + frame_: &str, + (mut line_, lm): (String, HashMap), + x: usize, +) -> (String, String) { let (frame_, fm) = compress_string(frame_, &ANSI); - let (mut line_, lm) = compress_string(line_, &ANSI); if let Some(_) = lm.get(&line_.len()) { line_.push('\n'); @@ -98,11 +101,12 @@ impl Frame { used: vec![0; height], } } - pub fn render(&mut self, focused: bool, element: &Element) { + pub fn render(&mut self, focused: bool, element: &crate::Element) { let output = element.render(focused, self.width, self.frame.len()); if output.1.visible { let x; let mut y = 0; + let mut width = 0_usize; match output.1.y { crate::ui::Number::Px(_y) => { y = _y; @@ -148,14 +152,58 @@ impl Frame { x = 0; } } - for (i, line) in output.0.split('\n').enumerate() { + + let mut svec: Vec<(String, HashMap)> = Vec::new(); + + match output.1.width { + crate::ui::Number::Auto | crate::ui::Number::Default => { + for line in output.0.split('\n') { + let (line, lm) = compress_string(line, &ANSI); + if line.len() > width { + width = line.len(); + } + svec.push((line, lm)); + } + } + crate::ui::Number::Px(p) => { + width = p; + for line in output.0.split('\n') { + svec.push(compress_string(line, &ANSI)); + } + } + _ => {} + } + + if output.1.outline { + let frame_line = self.frame.get_mut(y).unwrap(); + *frame_line = merge_line(&frame_line, ("_".repeat(width), HashMap::new()), x + 1).0; + y += 1; + } + + for (i, (line, lm)) in svec.iter().enumerate() { if self.frame.len() > y + i { let frame_line = self.frame.get_mut(y + i).unwrap(); - let merged = merge_line(&frame_line, line, x); + let merged = if output.1.outline { + merge_line( + &frame_line, + ( + format!("|{}|", format_string(line, width)), + lm.into_iter().map(|(k, v)| (k + 1, v.clone())).collect(), + ), + x, + ) + } else { + merge_line(&frame_line, (format_string(line, width), lm.clone()), x) + }; *frame_line = merged.0; *self.used.get_mut(y + i).unwrap() += merged.1.len() - 1; } } + + if output.1.outline { + let frame_line = self.frame.get_mut(y + svec.len()).unwrap(); + *frame_line = merge_line(&frame_line, ("¯".repeat(width), HashMap::new()), x + 1).0; + } } } pub fn output(&self) -> String { @@ -166,6 +214,15 @@ impl Frame { } } +fn format_string(input: &str, width: usize) -> String { + let truncated = if input.len() > width { + &input[..width] + } else { + input + }; + format!("{: