diff --git a/src/examples.rs b/src/examples.rs index 927e173..709242f 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -26,26 +26,30 @@ pub fn todo_app() -> Element { div { class: "tab", text { class: "title", "not started" } + text { class: "todo", "TODO: Something" } + } + div { + class: "tab", + text { class: "title", "completed" } } - // div { - // class: "tab", - // text { class: "title", "completed" } - // } } } pub fn styling() -> Css { css! { "tab" { - // x: 0 px, - // y: Auto, - // height: 50%, + x: Auto, + width: 50%, outline: true, } "title" { - // x: Center, - // color: Red, - // width: 15 px, + width: Auto, + color: Red, + } + "todo" { + x: 0 px, + y: Auto, + color: Green, } } } diff --git a/src/lib.rs b/src/lib.rs index fd7c91e..c3ec52a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,10 +84,10 @@ pub struct Document { #[derive(Debug)] pub struct Writer { - text: String, style: ui::StyleElement, focused: bool, size: (u16, u16), + absolute: (u16, u16), } ////////////////////////////////////////////////////////////////////////////////////////////////// @@ -143,10 +143,9 @@ impl Document { pub fn render(&self) { if !self.running.is_null() { let (width, height) = crossterm::terminal::size().unwrap(); - let mut frame = utils::Frame::new(width, height); - frame.render(true, unsafe { &*self.element }); + let mut frame = utils::Frame::new((0, 0), (width, height)); utils::clear(); - print!("{}", frame.output_nnl().replace("\n", "")); + frame.render(true, unsafe { &*self.element }); utils::flush(); } } @@ -228,17 +227,29 @@ impl Handler { } impl Writer { - pub fn new(focused: bool, style: ui::StyleElement, size: (u16, u16)) -> Writer { + pub fn new( + focused: bool, + style: ui::StyleElement, + absolute: (u16, u16), + size: (u16, u16), + ) -> Writer { Writer { - text: String::new(), style, focused, size, + absolute, } } pub fn write(&mut self, s: &str) { - self.text += self.style.write(s).as_str(); + for (i, line) in s.lines().enumerate() { + print!( + "\x1B[{};{}H{}", + self.absolute.1 + 1 + i as u16, + self.absolute.0 + 1, + self.style.write(line) + ); + } } pub fn get_focused(&self) -> bool { @@ -251,6 +262,10 @@ impl Writer { self.style.height.as_size(self.size.1, self.style.outline), ) } + + pub fn new_frame(&self) -> crate::utils::Frame { + crate::utils::Frame::new(self.absolute, self.get_size()) + } } impl Default for Handler { diff --git a/src/main.rs b/src/main.rs index b7a1c38..6c3666c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,12 +3,3 @@ use osui::{examples::todo_app, prelude::*}; fn main() { launch!(todo_app()) } - -// use osui::utils::overlay; - -// fn main() { -// let layer0 = " ".repeat(crossterm::terminal::size().unwrap().0 as usize); -// let layer1 = "\0\x1b[32m\0ABC"; -// let overlayed = overlay(&layer0, &layer1, 0).replace('\0', ""); -// println!("{overlayed}END"); -// } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index e25bcc5..f14999e 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -36,16 +36,13 @@ pub struct Div { impl ElementWidget for Div<'_> { fn render(&self, writer: &mut crate::Writer) { - let (width, height) = writer.get_size(); - let mut frame = crate::utils::Frame::new(width, height); + let mut frame = writer.new_frame(); if let Children::Children(children, child) = &self.children { for (i, elem) in children.iter().enumerate() { frame.render(writer.get_focused() && i == *child, elem); } } - - writer.write(&frame.output()); } fn event(&mut self, event: Event, document: &Document) { diff --git a/src/ui/styles.rs b/src/ui/styles.rs index 99d2a13..a859043 100644 --- a/src/ui/styles.rs +++ b/src/ui/styles.rs @@ -128,7 +128,7 @@ impl StyleElement { .into_iter() .map(|p| { format!( - "\0{}{}{}\0{p}\0\x1b[0m\0", + "{}{}{}{p}\x1b[0m", self.color.ansi(), self.background.ansi_bg(), self.font.ansi() @@ -317,11 +317,11 @@ impl Number { self.as_size_raw(frame_size) } } - pub fn as_position_y(&self, used: &Vec, content_size: u16, frame_size: u16) -> u16 { + pub fn as_position_y(&self, used: &Vec, 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 - content_size) / 2, + 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() { @@ -334,11 +334,11 @@ impl Number { } } } - pub fn as_position_x(&self, used: &u16, content_size: u16, frame_size: u16) -> u16 { + pub fn as_position_x(&self, used: &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 - content_size) / 2, + crate::ui::Number::Center => (frame_size) / 2, crate::ui::Number::Auto | crate::ui::Number::Default => *used, } } diff --git a/src/utils.rs b/src/utils.rs index 81b14db..36fc994 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,129 +1,45 @@ use std::io::{stdout, Write}; -pub fn overlay(layer0: &str, layer1: &str, mut index: usize) -> String { - let layer0: Vec = layer0.chars().collect(); - let layer1: Vec = layer1.chars().collect(); - let mut layer1_index = 0; - let mut result = String::new(); - let mut is_ansi = false; - let mut ansi = String::new(); - - for (i, &c) in layer0.iter().enumerate() { - if c == '\0' { - if is_ansi { - result.push_str(&ansi); - ansi.clear(); - } - is_ansi = !is_ansi; - index += 1; - } else if is_ansi { - ansi.push(c); - index += 1; - } else if i >= index && layer1_index < layer1.len() { - if layer1[layer1_index] == '\0' { - result.push(c); - } - result.push(layer1[layer1_index]); - layer1_index += 1; - } else { - result.push(c); - } - } - - result -} - pub struct Frame { - frame: Vec, - width: u16, used: Vec, + width: u16, + height: u16, + x: u16, + y: u16, } impl Frame { - pub fn new(width: u16, height: u16) -> Self { - Self { - frame: vec![" ".repeat(width.into()); height.into()], + pub fn new((x, y): (u16, u16), (width, height): (u16, u16)) -> Self { + Frame { + used: vec![0; height as usize], width, - used: vec![0; height.into()], + height, + x, + y, } } pub fn render(&mut self, focused: bool, element: &crate::Element) { let style = element.get_style().get(focused); - let mut writer = crate::Writer::new( - focused, - style.clone(), - (self.width, self.frame.len() as u16), - ); if style.visible { - let frame_height = self.frame.len() as u16; - let (width, height) = writer.get_size(); - let y = style.y.as_position_y(&self.used, height, frame_height) as usize; - if let Some(y_) = self.used.get(y) { - let x = style.x.as_position_x(y_, width, self.width) as usize; - if style.outline { - // { - // let frame_line = self.frame.get_mut(y).unwrap(); - // *frame_line = - // overlay(&frame_line, &"_".repeat(width as usize - 2), x as usize); - // // *self.used.get_mut(y - 1).unwrap() += (x as u16 + width + 1) as u16; - // } - // { - // if let Some(frame_line) = self.frame.get_mut(y + height as usize) { - // *frame_line = overlay( - // &frame_line, - // &"⎻".repeat(width as usize - 2), - // x as usize + 1, - // ); - // // *self.used.get_mut(y + height as usize).unwrap() += - // // (x as u16 + width + 1) as u16; - // } - // } - // y += 1; - } + let y = style.y.as_position_y(&self.used, self.height); + if let Some(y_) = self.used.get(y as usize) { + let x = style.x.as_position_x(y_, self.width); + let mut writer = crate::Writer::new( + focused, + style.clone(), + (x + self.x, y + self.y), + (self.width, self.height), + ); element.render(&mut writer); - for (i, line) in writer.text.lines().enumerate() { - if frame_height > (y + i) as u16 { - let frame_line = self.frame.get_mut(y + i).unwrap(); - if style.outline { - *frame_line = overlay(frame_line, &format!("a{line}b"), x as usize); - } else { - *frame_line = overlay(frame_line, line, x as usize); - } - // *self.used.get_mut(y + i).unwrap() += (x + formatted.len()) as u16; - } + let (width, height) = writer.get_size(); + for i in y..y + height { + *self.used.get_mut(i as usize).unwrap() += x + width; } } } } - /// Gets the frame output on a single string, rows separated by newlines - pub fn output(&self) -> String { - self.frame.join("\n") - } - - /// Gets the frame output on a single string with no newlines - pub fn output_nnl(&self) -> String { - self.frame.join("") - } - - pub fn output_array(&self) -> &Vec { - &self.frame - } } -// fn format_string(input: &str, width: usize, outline: bool) -> String { -// let truncated = if input.len() > width { -// let input_chars: Vec = input.chars().collect(); -// input_chars[..width].iter().collect::() -// } else { -// input.to_string() -// }; -// if outline { -// format!("a{: