new frame and writing system
This commit is contained in:
+14
-10
@@ -26,26 +26,30 @@ pub fn todo_app() -> Element {
|
|||||||
div {
|
div {
|
||||||
class: "tab",
|
class: "tab",
|
||||||
text { class: "title", "not started" }
|
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 {
|
pub fn styling() -> Css {
|
||||||
css! {
|
css! {
|
||||||
"tab" {
|
"tab" {
|
||||||
// x: 0 px,
|
x: Auto,
|
||||||
// y: Auto,
|
width: 50%,
|
||||||
// height: 50%,
|
|
||||||
outline: true,
|
outline: true,
|
||||||
}
|
}
|
||||||
"title" {
|
"title" {
|
||||||
// x: Center,
|
width: Auto,
|
||||||
// color: Red,
|
color: Red,
|
||||||
// width: 15 px,
|
}
|
||||||
|
"todo" {
|
||||||
|
x: 0 px,
|
||||||
|
y: Auto,
|
||||||
|
color: Green,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-7
@@ -84,10 +84,10 @@ pub struct Document {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Writer {
|
pub struct Writer {
|
||||||
text: String,
|
|
||||||
style: ui::StyleElement,
|
style: ui::StyleElement,
|
||||||
focused: bool,
|
focused: bool,
|
||||||
size: (u16, u16),
|
size: (u16, u16),
|
||||||
|
absolute: (u16, u16),
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -143,10 +143,9 @@ impl Document {
|
|||||||
pub fn render(&self) {
|
pub fn render(&self) {
|
||||||
if !self.running.is_null() {
|
if !self.running.is_null() {
|
||||||
let (width, height) = crossterm::terminal::size().unwrap();
|
let (width, height) = crossterm::terminal::size().unwrap();
|
||||||
let mut frame = utils::Frame::new(width, height);
|
let mut frame = utils::Frame::new((0, 0), (width, height));
|
||||||
frame.render(true, unsafe { &*self.element });
|
|
||||||
utils::clear();
|
utils::clear();
|
||||||
print!("{}", frame.output_nnl().replace("\n", ""));
|
frame.render(true, unsafe { &*self.element });
|
||||||
utils::flush();
|
utils::flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,17 +227,29 @@ impl<T> Handler<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Writer {
|
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 {
|
Writer {
|
||||||
text: String::new(),
|
|
||||||
style,
|
style,
|
||||||
focused,
|
focused,
|
||||||
size,
|
size,
|
||||||
|
absolute,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(&mut self, s: &str) {
|
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 {
|
pub fn get_focused(&self) -> bool {
|
||||||
@@ -251,6 +262,10 @@ impl Writer {
|
|||||||
self.style.height.as_size(self.size.1, self.style.outline),
|
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<T> Default for Handler<T> {
|
impl<T> Default for Handler<T> {
|
||||||
|
|||||||
@@ -3,12 +3,3 @@ use osui::{examples::todo_app, prelude::*};
|
|||||||
fn main() {
|
fn main() {
|
||||||
launch!(todo_app())
|
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");
|
|
||||||
// }
|
|
||||||
|
|||||||
+1
-4
@@ -36,16 +36,13 @@ pub struct Div {
|
|||||||
|
|
||||||
impl ElementWidget for Div<'_> {
|
impl ElementWidget for Div<'_> {
|
||||||
fn render(&self, writer: &mut crate::Writer) {
|
fn render(&self, writer: &mut crate::Writer) {
|
||||||
let (width, height) = writer.get_size();
|
let mut frame = writer.new_frame();
|
||||||
let mut frame = crate::utils::Frame::new(width, height);
|
|
||||||
|
|
||||||
if let Children::Children(children, child) = &self.children {
|
if let Children::Children(children, child) = &self.children {
|
||||||
for (i, elem) in children.iter().enumerate() {
|
for (i, elem) in children.iter().enumerate() {
|
||||||
frame.render(writer.get_focused() && i == *child, elem);
|
frame.render(writer.get_focused() && i == *child, elem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.write(&frame.output());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event(&mut self, event: Event, document: &Document) {
|
fn event(&mut self, event: Event, document: &Document) {
|
||||||
|
|||||||
+5
-5
@@ -128,7 +128,7 @@ impl StyleElement {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
format!(
|
format!(
|
||||||
"\0{}{}{}\0{p}\0\x1b[0m\0",
|
"{}{}{}{p}\x1b[0m",
|
||||||
self.color.ansi(),
|
self.color.ansi(),
|
||||||
self.background.ansi_bg(),
|
self.background.ansi_bg(),
|
||||||
self.font.ansi()
|
self.font.ansi()
|
||||||
@@ -317,11 +317,11 @@ impl Number {
|
|||||||
self.as_size_raw(frame_size)
|
self.as_size_raw(frame_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn as_position_y(&self, used: &Vec<u16>, content_size: u16, frame_size: u16) -> u16 {
|
pub fn as_position_y(&self, used: &Vec<u16>, frame_size: u16) -> u16 {
|
||||||
match self {
|
match self {
|
||||||
crate::ui::Number::Px(px) => *px,
|
crate::ui::Number::Px(px) => *px,
|
||||||
crate::ui::Number::Pe(pe) => (frame_size * pe) / 100,
|
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 => {
|
crate::ui::Number::Auto | crate::ui::Number::Default => {
|
||||||
let mut y = 0;
|
let mut y = 0;
|
||||||
for (i, n) in used.iter().enumerate() {
|
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 {
|
match self {
|
||||||
crate::ui::Number::Px(px) => *px,
|
crate::ui::Number::Px(px) => *px,
|
||||||
crate::ui::Number::Pe(pe) => (frame_size * pe) / 100,
|
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,
|
crate::ui::Number::Auto | crate::ui::Number::Default => *used,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-103
@@ -1,129 +1,45 @@
|
|||||||
use std::io::{stdout, Write};
|
use std::io::{stdout, Write};
|
||||||
|
|
||||||
pub fn overlay(layer0: &str, layer1: &str, mut index: usize) -> String {
|
|
||||||
let layer0: Vec<char> = layer0.chars().collect();
|
|
||||||
let layer1: Vec<char> = 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 {
|
pub struct Frame {
|
||||||
frame: Vec<String>,
|
|
||||||
width: u16,
|
|
||||||
used: Vec<u16>,
|
used: Vec<u16>,
|
||||||
|
width: u16,
|
||||||
|
height: u16,
|
||||||
|
x: u16,
|
||||||
|
y: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
pub fn new(width: u16, height: u16) -> Self {
|
pub fn new((x, y): (u16, u16), (width, height): (u16, u16)) -> Self {
|
||||||
Self {
|
Frame {
|
||||||
frame: vec![" ".repeat(width.into()); height.into()],
|
used: vec![0; height as usize],
|
||||||
width,
|
width,
|
||||||
used: vec![0; height.into()],
|
height,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn render(&mut self, focused: bool, element: &crate::Element) {
|
pub fn render(&mut self, focused: bool, element: &crate::Element) {
|
||||||
let style = element.get_style().get(focused);
|
let style = element.get_style().get(focused);
|
||||||
|
if style.visible {
|
||||||
|
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(
|
let mut writer = crate::Writer::new(
|
||||||
focused,
|
focused,
|
||||||
style.clone(),
|
style.clone(),
|
||||||
(self.width, self.frame.len() as u16),
|
(x + self.x, y + self.y),
|
||||||
|
(self.width, self.height),
|
||||||
);
|
);
|
||||||
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;
|
|
||||||
}
|
|
||||||
element.render(&mut writer);
|
element.render(&mut writer);
|
||||||
for (i, line) in writer.text.lines().enumerate() {
|
let (width, height) = writer.get_size();
|
||||||
if frame_height > (y + i) as u16 {
|
for i in y..y + height {
|
||||||
let frame_line = self.frame.get_mut(y + i).unwrap();
|
*self.used.get_mut(i as usize).unwrap() += x + width;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/// 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<String> {
|
|
||||||
&self.frame
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn format_string(input: &str, width: usize, outline: bool) -> String {
|
|
||||||
// let truncated = if input.len() > width {
|
|
||||||
// let input_chars: Vec<char> = input.chars().collect();
|
|
||||||
// input_chars[..width].iter().collect::<String>()
|
|
||||||
// } else {
|
|
||||||
// input.to_string()
|
|
||||||
// };
|
|
||||||
// if outline {
|
|
||||||
// format!("a{:<width$}b", truncated, width = width)
|
|
||||||
// } else {
|
|
||||||
// format!("{:<width$}", truncated, width = width)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn clear() {
|
pub fn clear() {
|
||||||
print!("\x1B[2J\x1B[H");
|
print!("\x1B[2J\x1B[H");
|
||||||
stdout().flush().unwrap();
|
stdout().flush().unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user