buggy af
This commit is contained in:
+42
-154
@@ -3,181 +3,40 @@ macro_rules! __css {
|
|||||||
($_style:expr,)=>{};
|
($_style:expr,)=>{};
|
||||||
// percentage (n%)
|
// percentage (n%)
|
||||||
(
|
(
|
||||||
$_style:expr, $name:ident: $value:literal% $(, $($other:tt)*)?
|
$_style:expr, $name:ident: $value:literal% $(, $($rest:tt)*)?
|
||||||
) => {{
|
) => {{
|
||||||
$_style.$name = Number::Pe($value);
|
$_style.$name = Number::Pe($value);
|
||||||
$crate::__css!($_style, $($($other)*)?);
|
$crate::__css!($_style, $($($rest)*)?);
|
||||||
}};
|
|
||||||
(
|
|
||||||
$_style:expr, $name:literal: $value:literal% $(, $($other:tt)*)?
|
|
||||||
) => {{
|
|
||||||
$_style.other.insert($name.to_string(), Box::new(
|
|
||||||
Number::Pe($value)
|
|
||||||
));
|
|
||||||
$crate::__css!($_style, $($($other)*)?);
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// Number
|
// Number
|
||||||
(
|
(
|
||||||
$_style:expr, $name:ident: $value:literal px $(, $($other:tt)*)?
|
$_style:expr, $name:ident: $value:literal px $(, $($rest:tt)*)?
|
||||||
) => {{
|
) => {{
|
||||||
$_style.$name = Number::Px($value);
|
$_style.$name = Number::Px($value);
|
||||||
$crate::__css!($_style, $($($other)*)?);
|
$crate::__css!($_style, $($($rest)*)?);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// Vector
|
// Vector
|
||||||
(
|
(
|
||||||
$_style:expr, $name:ident: [$($inner:tt),*] $(, $($other:tt)*)?
|
$_style:expr, $name:ident: [$($inner:tt),*] $(, $($rest:tt)*)?
|
||||||
) => {{
|
) => {{
|
||||||
$_style.$name = vec![$($inner),*];
|
$_style.$name = vec![$($inner),*];
|
||||||
$crate::__css!($_style, $($($other)*)?);
|
$crate::__css!($_style, $($($rest)*)?);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// Normal
|
// Normal
|
||||||
(
|
(
|
||||||
$_style:expr, $name:ident: $value:expr $(, $($other:tt)*)?
|
$_style:expr, $name:ident: $value:expr $(, $($rest:tt)*)?
|
||||||
) => {{
|
) => {{
|
||||||
$_style.$name = $value;
|
$_style.$name = $value;
|
||||||
$crate::__css!($_style, $($($other)*)?);
|
$crate::__css!($_style, $($($rest)*)?);
|
||||||
}};
|
|
||||||
|
|
||||||
(
|
|
||||||
$_style:expr, $name:literal: $value:expr $(, $($other:tt)*)?
|
|
||||||
) => {{
|
|
||||||
$_style.other.insert($name.to_string(), Box::new($value));
|
|
||||||
$crate::__css!($_style, $($($other)*)?);
|
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! _css {
|
macro_rules! _css {
|
||||||
($_style:expr,) => {};
|
($_style:expr,) => {};
|
||||||
(
|
|
||||||
$hm:expr, .$name:ident { $($inner:tt)* } $($rest:tt)*
|
|
||||||
) => {{
|
|
||||||
let name = $crate::ui::StyleName::Class(stringify!($name).to_string());
|
|
||||||
if let Some(_style) = $hm.get_mut(&name) {
|
|
||||||
$crate::__css!(_style.0, $($inner)*);
|
|
||||||
} else {
|
|
||||||
let mut _style = $crate::ui::Style::default();
|
|
||||||
|
|
||||||
$crate::__css!(_style.0, $($inner)*);
|
|
||||||
|
|
||||||
$hm.insert(
|
|
||||||
name,
|
|
||||||
_style,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$crate::_css!($hm, $($rest)*);
|
|
||||||
}};
|
|
||||||
(
|
|
||||||
$hm:expr, .$name:ident:$kind:ident { $($inner:tt)* } $($rest:tt)*
|
|
||||||
) => {{
|
|
||||||
let name = $crate::ui::StyleName::Class(stringify!($name).to_string());
|
|
||||||
if let Some(_style) = $hm.get_mut(&name) {
|
|
||||||
let mut style_elem = $crate::ui::StyleElement::default();
|
|
||||||
$crate::__css!(style_elem, $($inner)*);
|
|
||||||
_style.1.insert(stringify!($kind).to_string(), style_elem);
|
|
||||||
} else {
|
|
||||||
let mut _style = $crate::ui::Style::default();
|
|
||||||
|
|
||||||
let mut style_elem = $crate::ui::StyleElement::default();
|
|
||||||
$crate::__css!(style_elem, $($inner)*);
|
|
||||||
_style.1.insert(stringify!($kind).to_string(), style_elem);
|
|
||||||
|
|
||||||
$hm.insert(
|
|
||||||
name,
|
|
||||||
_style,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$crate::_css!($hm, $($rest)*);
|
|
||||||
}};
|
|
||||||
|
|
||||||
|
|
||||||
(
|
|
||||||
$hm:expr, #$name:ident { $($inner:tt)* } $($rest:tt)*
|
|
||||||
) => {{
|
|
||||||
let name = $crate::ui::StyleName::Id(stringify!($name).to_string());
|
|
||||||
if let Some(_style) = $hm.get_mut(&name) {
|
|
||||||
$crate::__css!(_style.0, $($inner)*);
|
|
||||||
} else {
|
|
||||||
let mut _style = $crate::ui::Style::default();
|
|
||||||
|
|
||||||
$crate::__css!(_style.0, $($inner)*);
|
|
||||||
|
|
||||||
$hm.insert(
|
|
||||||
name,
|
|
||||||
_style,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$crate::_css!($hm, $($rest)*);
|
|
||||||
}};
|
|
||||||
(
|
|
||||||
$hm:expr, #$name:ident:$kind:ident { $($inner:tt)* } $($rest:tt)*
|
|
||||||
) => {{
|
|
||||||
let name = $crate::ui::StyleName::Id(stringify!($name).to_string());
|
|
||||||
if let Some(_style) = $hm.get_mut(&name) {
|
|
||||||
let mut style_elem = $crate::ui::StyleElement::default();
|
|
||||||
$crate::__css!(style_elem, $($inner)*);
|
|
||||||
_style.1.insert(stringify!($kind).to_string(), style_elem);
|
|
||||||
} else {
|
|
||||||
let mut _style = $crate::ui::Style::default();
|
|
||||||
|
|
||||||
let mut style_elem = $crate::ui::StyleElement::default();
|
|
||||||
$crate::__css!(style_elem, $($inner)*);
|
|
||||||
_style.1.insert(stringify!($kind).to_string(), style_elem);
|
|
||||||
|
|
||||||
$hm.insert(
|
|
||||||
name,
|
|
||||||
_style,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$crate::_css!($hm, $($rest)*);
|
|
||||||
}};
|
|
||||||
|
|
||||||
|
|
||||||
(
|
|
||||||
$hm:expr, $name:ident { $($inner:tt)* } $($rest:tt)*
|
|
||||||
) => {{
|
|
||||||
let name = $crate::ui::StyleName::Component(stringify!($name).to_string());
|
|
||||||
if let Some(_style) = $hm.get_mut(&name) {
|
|
||||||
$crate::__css!(_style.0, $($inner)*);
|
|
||||||
} else {
|
|
||||||
let mut _style = $crate::ui::Style::default();
|
|
||||||
|
|
||||||
$crate::__css!(_style.0, $($inner)*);
|
|
||||||
|
|
||||||
$hm.insert(
|
|
||||||
name,
|
|
||||||
_style,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$crate::_css!($hm, $($rest)*);
|
|
||||||
}};
|
|
||||||
(
|
|
||||||
$hm:expr, $name:ident:$kind:ident { $($inner:tt)* } $($rest:tt)*
|
|
||||||
) => {{
|
|
||||||
let name = $crate::ui::StyleName::Component(stringify!($name).to_string());
|
|
||||||
if let Some(_style) = $hm.get_mut(&name) {
|
|
||||||
let mut style_elem = $crate::ui::StyleElement::default();
|
|
||||||
$crate::__css!(style_elem, $($inner)*);
|
|
||||||
_style.1.insert(stringify!($kind).to_string(), style_elem);
|
|
||||||
} else {
|
|
||||||
let mut _style = $crate::ui::Style::default();
|
|
||||||
|
|
||||||
let mut style_elem = $crate::ui::StyleElement::default();
|
|
||||||
$crate::__css!(style_elem, $($inner)*);
|
|
||||||
_style.1.insert(stringify!($kind).to_string(), style_elem);
|
|
||||||
|
|
||||||
$hm.insert(
|
|
||||||
name,
|
|
||||||
_style,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$crate::_css!($hm, $($rest)*);
|
|
||||||
}};
|
|
||||||
|
|
||||||
|
|
||||||
(
|
(
|
||||||
$hm:expr, $name:literal { $($inner:tt)* } $($rest:tt)*
|
$hm:expr, $name:literal { $($inner:tt)* } $($rest:tt)*
|
||||||
) => {{
|
) => {{
|
||||||
@@ -197,19 +56,19 @@ macro_rules! _css {
|
|||||||
$crate::_css!($hm, $($rest)*);
|
$crate::_css!($hm, $($rest)*);
|
||||||
}};
|
}};
|
||||||
(
|
(
|
||||||
$hm:expr, $name:literal:$kind:ident { $($inner:tt)* } $($rest:tt)*
|
$hm:expr, $name:literal: $kind:literal { $($inner:tt)* } $($rest:tt)*
|
||||||
) => {{
|
) => {{
|
||||||
let name = $crate::ui::StyleName::Class(String::from($name));
|
let name = $crate::ui::StyleName::Class(String::from($name));
|
||||||
if let Some(_style) = $hm.get_mut(&name) {
|
if let Some(_style) = $hm.get_mut(&name) {
|
||||||
let mut style_elem = $crate::ui::StyleElement::default();
|
let mut style_elem = $crate::ui::StyleElement::default();
|
||||||
$crate::__css!(style_elem, $($inner)*);
|
$crate::__css!(style_elem, $($inner)*);
|
||||||
_style.1.insert(stringify!($kind).to_string(), style_elem);
|
_style.1.insert($kind.to_string(), style_elem);
|
||||||
} else {
|
} else {
|
||||||
let mut _style = $crate::ui::Style::default();
|
let mut _style = $crate::ui::Style::default();
|
||||||
|
|
||||||
let mut style_elem = $crate::ui::StyleElement::default();
|
let mut style_elem = $crate::ui::StyleElement::default();
|
||||||
$crate::__css!(style_elem, $($inner)*);
|
$crate::__css!(style_elem, $($inner)*);
|
||||||
_style.1.insert(stringify!($kind).to_string(), style_elem);
|
_style.1.insert($kind.to_string(), style_elem);
|
||||||
|
|
||||||
$hm.insert(
|
$hm.insert(
|
||||||
name,
|
name,
|
||||||
@@ -224,8 +83,11 @@ macro_rules! _css {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// .btn: clicked {
|
/// "btn" {
|
||||||
/// color: Blue
|
/// color: Red,
|
||||||
|
/// }
|
||||||
|
/// "btn": "clicked" {
|
||||||
|
/// color: Blue,
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
@@ -245,6 +107,32 @@ macro_rules! css {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! style {
|
macro_rules! style {
|
||||||
|
(
|
||||||
|
$key:ident: $value:literal% $(, $($rest:tt)*)?
|
||||||
|
) => {{
|
||||||
|
let mut _style = $crate::ui::Style::default();
|
||||||
|
$crate::__css!(_style.0, $key: $crate::ui::Number::Pe($value));
|
||||||
|
$crate::style!{ _style; $($($rest)*)? }
|
||||||
|
}};
|
||||||
|
(
|
||||||
|
$key:ident: $value:literal px $(, $($rest:tt)*)?
|
||||||
|
) => {{
|
||||||
|
let mut _style = $crate::ui::Style::default();
|
||||||
|
$crate::__css!(_style.0, $key: $crate::ui::Number::Px($value));
|
||||||
|
$crate::style!{ _style; $($($rest)*)? }
|
||||||
|
}};
|
||||||
|
(
|
||||||
|
$style:expr; $key:ident: $value:literal% $(, $($rest:tt)*)?
|
||||||
|
) => {{
|
||||||
|
$crate::__css!($style.0, $key: $crate::ui::Number::Pe($value));
|
||||||
|
$crate::style!{ $style; $($($rest)*)? }
|
||||||
|
}};
|
||||||
|
(
|
||||||
|
$style:expr; $key:ident: $value:literal px $(, $($rest:tt)*)?
|
||||||
|
) => {{
|
||||||
|
$crate::__css!($style.0, $key: $crate::ui::Number::Px($value));
|
||||||
|
$crate::style!{ $style; $($($rest)*)? }
|
||||||
|
}};
|
||||||
(
|
(
|
||||||
$key:ident: $value:expr $(, $($rest:tt)*)?
|
$key:ident: $value:expr $(, $($rest:tt)*)?
|
||||||
) => {{
|
) => {{
|
||||||
|
|||||||
+13
-18
@@ -24,33 +24,28 @@ pub fn todo_app() -> Element {
|
|||||||
styling: Some(styling()),
|
styling: Some(styling()),
|
||||||
class: "root",
|
class: "root",
|
||||||
div {
|
div {
|
||||||
class: "first",
|
class: "tab",
|
||||||
text { class: "title", "not started" }
|
text { class: "title", "not started" }
|
||||||
}
|
}
|
||||||
div {
|
// div {
|
||||||
class: "second",
|
// class: "tab",
|
||||||
text { class: "title", "completed" }
|
// text { class: "title", "completed" }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn styling() -> Css {
|
pub fn styling() -> Css {
|
||||||
css! {
|
css! {
|
||||||
"first" {
|
"tab" {
|
||||||
x: Auto,
|
// x: 0 px,
|
||||||
y: 0 px,
|
// y: Auto,
|
||||||
width: 50%,
|
// height: 50%,
|
||||||
}
|
outline: true,
|
||||||
"second" {
|
|
||||||
x: Auto,
|
|
||||||
y: 0 px,
|
|
||||||
width: 50%,
|
|
||||||
}
|
|
||||||
"root" {
|
|
||||||
width: 100%,
|
|
||||||
}
|
}
|
||||||
"title" {
|
"title" {
|
||||||
x: Center
|
// x: Center,
|
||||||
|
// color: Red,
|
||||||
|
// width: 15 px,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-8
@@ -82,9 +82,10 @@ pub struct Document {
|
|||||||
running: *mut Option<bool>,
|
running: *mut Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Writer {
|
pub struct Writer {
|
||||||
text: String,
|
text: String,
|
||||||
style: Style,
|
style: ui::StyleElement,
|
||||||
focused: bool,
|
focused: bool,
|
||||||
size: (u16, u16),
|
size: (u16, u16),
|
||||||
}
|
}
|
||||||
@@ -145,7 +146,7 @@ impl Document {
|
|||||||
let mut frame = utils::Frame::new(width, height);
|
let mut frame = utils::Frame::new(width, height);
|
||||||
frame.render(true, unsafe { &*self.element });
|
frame.render(true, unsafe { &*self.element });
|
||||||
utils::clear();
|
utils::clear();
|
||||||
print!("{}", frame.output_nnl());
|
print!("{}", frame.output_nnl().replace("\n", ""));
|
||||||
utils::flush();
|
utils::flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,7 +228,7 @@ impl<T> Handler<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Writer {
|
impl Writer {
|
||||||
pub fn new(focused: bool, style: ui::Style, size: (u16, u16)) -> Writer {
|
pub fn new(focused: bool, style: ui::StyleElement, size: (u16, u16)) -> Writer {
|
||||||
Writer {
|
Writer {
|
||||||
text: String::new(),
|
text: String::new(),
|
||||||
style,
|
style,
|
||||||
@@ -237,16 +238,19 @@ impl Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(&mut self, s: &str) {
|
pub fn write(&mut self, s: &str) {
|
||||||
self.text += self.style.get(self.focused).write(s).as_str();
|
self.text += self.style.write(s).as_str();
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_size(&self) -> (u16, u16) {
|
|
||||||
self.size
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_focused(&self) -> bool {
|
pub fn get_focused(&self) -> bool {
|
||||||
self.focused
|
self.focused
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_size(&self) -> (u16, u16) {
|
||||||
|
(
|
||||||
|
self.style.width.as_size(self.size.0, self.style.outline),
|
||||||
|
self.style.height.as_size(self.size.1, self.style.outline),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Default for Handler<T> {
|
impl<T> Default for Handler<T> {
|
||||||
|
|||||||
@@ -3,3 +3,12 @@ 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");
|
||||||
|
// }
|
||||||
|
|||||||
+14
-11
@@ -83,7 +83,6 @@ pub struct StyleElement {
|
|||||||
pub height: Number,
|
pub height: Number,
|
||||||
pub visible: bool,
|
pub visible: bool,
|
||||||
pub outline: bool,
|
pub outline: bool,
|
||||||
pub other: HashMap<String, Box<dyn StyleCore>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -129,7 +128,7 @@ impl StyleElement {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
format!(
|
format!(
|
||||||
"{}{}{}{p}\x1b[0m",
|
"\0{}{}{}\0{p}\0\x1b[0m\0",
|
||||||
self.color.ansi(),
|
self.color.ansi(),
|
||||||
self.background.ansi_bg(),
|
self.background.ansi_bg(),
|
||||||
self.font.ansi()
|
self.font.ansi()
|
||||||
@@ -148,12 +147,11 @@ impl Default for StyleElement {
|
|||||||
font: Vec::new(),
|
font: Vec::new(),
|
||||||
outline_color: Color::NoColor,
|
outline_color: Color::NoColor,
|
||||||
x: Number::Default,
|
x: Number::Default,
|
||||||
y: Number::Default,
|
y: Number::Px(0),
|
||||||
width: Number::Default,
|
width: Number::Default,
|
||||||
height: Number::Default,
|
height: Number::Default,
|
||||||
visible: true,
|
visible: true,
|
||||||
outline: false,
|
outline: false,
|
||||||
other: HashMap::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -305,13 +303,18 @@ impl StyleCore for Vec<Font> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Number {
|
impl Number {
|
||||||
pub fn as_size(&self, text_size: u16, frame_size: u16) -> u16 {
|
pub fn as_size_raw(&self, frame_size: u16) -> u16 {
|
||||||
match self {
|
match self {
|
||||||
Number::Px(s) => *s,
|
Number::Px(s) => *s,
|
||||||
Number::Pe(pe) => (frame_size * pe) / 100,
|
Number::Pe(pe) => (frame_size * pe) / 100,
|
||||||
Number::Default => frame_size,
|
_ => frame_size,
|
||||||
crate::ui::Number::Auto => text_size,
|
}
|
||||||
_ => 0,
|
}
|
||||||
|
pub fn as_size(&self, frame_size: u16, outline: bool) -> u16 {
|
||||||
|
if outline {
|
||||||
|
self.as_size_raw(frame_size) - 2
|
||||||
|
} else {
|
||||||
|
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>, content_size: u16, frame_size: u16) -> u16 {
|
||||||
@@ -320,14 +323,14 @@ impl Number {
|
|||||||
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 - content_size) / 2,
|
||||||
crate::ui::Number::Auto | crate::ui::Number::Default => {
|
crate::ui::Number::Auto | crate::ui::Number::Default => {
|
||||||
let mut x = 0;
|
let mut y = 0;
|
||||||
for (i, n) in used.iter().enumerate() {
|
for (i, n) in used.iter().enumerate() {
|
||||||
if *n == 0 {
|
if *n == 0 {
|
||||||
x = i as u16;
|
y = i as u16;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
x
|
y
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+77
-100
@@ -1,86 +1,36 @@
|
|||||||
/// The `utils` module contains helper functions and utilities that assist in rendering and
|
use std::io::{stdout, Write};
|
||||||
/// managing UI state. These functions are used by UI elements like `Div` and `Text` for common
|
|
||||||
/// tasks such as frame creation, event handling, and component selection.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```rust
|
|
||||||
/// use crate::ui::utils::{create_frame, render_to_frame};
|
|
||||||
///
|
|
||||||
/// let frame = create_frame(50, 10);
|
|
||||||
/// render_to_frame(crate::State::Normal, 50, &mut frame, &text_element);
|
|
||||||
/// ```
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use regex::Regex;
|
|
||||||
use std::{
|
|
||||||
collections::HashMap,
|
|
||||||
io::{stdout, Write},
|
|
||||||
};
|
|
||||||
|
|
||||||
lazy_static! {
|
pub fn overlay(layer0: &str, layer1: &str, mut index: usize) -> String {
|
||||||
pub static ref ANSI: Regex = Regex::new(r"(\x1b\[([0-9;]*)[a-zA-Z])+").unwrap();
|
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;
|
||||||
/// Compress a string by a regex pattern
|
index += 1;
|
||||||
pub fn compress_string(input: &str, re: &Regex) -> (String, HashMap<usize, String>) {
|
} else if is_ansi {
|
||||||
let mut matches_map = HashMap::new();
|
ansi.push(c);
|
||||||
let mut res = String::new();
|
index += 1;
|
||||||
let input_chars: Vec<char> = input.chars().collect();
|
} else if i >= index && layer1_index < layer1.len() {
|
||||||
|
if layer1[layer1_index] == '\0' {
|
||||||
let mut i = 0;
|
result.push(c);
|
||||||
while i < input_chars.len() {
|
}
|
||||||
let remaining_input: String = input_chars[i..].iter().collect();
|
result.push(layer1[layer1_index]);
|
||||||
if let Some(loc) = re.find(&remaining_input) {
|
layer1_index += 1;
|
||||||
if loc.start() == 0 {
|
|
||||||
let matched_chars: String = input_chars[i..i + loc.end()].iter().collect();
|
|
||||||
matches_map.insert(res.len(), matched_chars.clone());
|
|
||||||
i += loc.end();
|
|
||||||
} else {
|
} else {
|
||||||
res.push(input_chars[i]);
|
result.push(c);
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res.push(input_chars[i]);
|
|
||||||
i += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(res, matches_map)
|
result
|
||||||
}
|
|
||||||
|
|
||||||
/// Merges a frame withe a line by x
|
|
||||||
fn merge_line(frame_: &str, (mut line_, lm): (String, HashMap<usize, String>), x: usize) -> String {
|
|
||||||
let (frame_, fm) = compress_string(frame_, &ANSI);
|
|
||||||
|
|
||||||
if let Some(_) = lm.get(&line_.len()) {
|
|
||||||
line_.push('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut res = String::new();
|
|
||||||
let frame: Vec<char> = frame_.chars().collect();
|
|
||||||
let line: Vec<char> = (line_).chars().collect();
|
|
||||||
|
|
||||||
let flen = frame.len();
|
|
||||||
let llen = line.len();
|
|
||||||
|
|
||||||
for i in 0..flen {
|
|
||||||
if let Some(v) = fm.get(&i) {
|
|
||||||
res.push_str(v);
|
|
||||||
}
|
|
||||||
if i >= x && i - x < llen && line[i - x] != '\t' {
|
|
||||||
if let Some(v) = lm.get(&(i - x)) {
|
|
||||||
res.push_str(v);
|
|
||||||
}
|
|
||||||
if line[i - x] == '\n' {
|
|
||||||
res.push(frame[i]);
|
|
||||||
} else {
|
|
||||||
res.push(line[i - x]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res.push(frame[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Frame {
|
pub struct Frame {
|
||||||
@@ -98,31 +48,49 @@ impl Frame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 mut writer = crate::Writer::new(
|
let mut writer = crate::Writer::new(
|
||||||
focused,
|
focused,
|
||||||
element.get_style().clone(),
|
style.clone(),
|
||||||
(self.width, self.frame.len() as u16),
|
(self.width, self.frame.len() as u16),
|
||||||
);
|
);
|
||||||
let style = writer.style.get(focused);
|
|
||||||
element.render(&mut writer);
|
|
||||||
if style.visible {
|
if style.visible {
|
||||||
let frame_height = self.frame.len() as u16;
|
let frame_height = self.frame.len() as u16;
|
||||||
let width = style.width.as_size(writer.text.len() as u16, self.width);
|
let (width, height) = writer.get_size();
|
||||||
let height = style.height.as_size(0, frame_height);
|
|
||||||
let y = style.y.as_position_y(&self.used, height, frame_height) as usize;
|
let y = style.y.as_position_y(&self.used, height, frame_height) as usize;
|
||||||
let x = style
|
if let Some(y_) = self.used.get(y) {
|
||||||
.x
|
let x = style.x.as_position_x(y_, width, self.width) as usize;
|
||||||
.as_position_x(self.used.get(y).unwrap(), width, self.width)
|
if style.outline {
|
||||||
as usize;
|
// {
|
||||||
|
// 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);
|
||||||
for (i, line) in writer.text.lines().enumerate() {
|
for (i, line) in writer.text.lines().enumerate() {
|
||||||
if frame_height > (y + i) as u16 {
|
if frame_height > (y + i) as u16 {
|
||||||
let frame_line = self.frame.get_mut(y + i).unwrap();
|
let frame_line = self.frame.get_mut(y + i).unwrap();
|
||||||
let (line_, lm) = compress_string(line, &ANSI);
|
if style.outline {
|
||||||
let formatted = format_string(&line_, width as usize);
|
*frame_line = overlay(frame_line, &format!("a{line}b"), x as usize);
|
||||||
*frame_line =
|
} else {
|
||||||
merge_line(&frame_line, (formatted.clone(), lm.clone()), x as usize);
|
*frame_line = overlay(frame_line, line, x as usize);
|
||||||
*self.used.get_mut(y + i).unwrap() += (x + formatted.len()) as u16;
|
}
|
||||||
|
// *self.used.get_mut(y + i).unwrap() += (x + formatted.len()) as u16;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,16 +104,25 @@ impl Frame {
|
|||||||
pub fn output_nnl(&self) -> String {
|
pub fn output_nnl(&self) -> String {
|
||||||
self.frame.join("")
|
self.frame.join("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn output_array(&self) -> &Vec<String> {
|
||||||
|
&self.frame
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_string(input: &str, width: usize) -> String {
|
// fn format_string(input: &str, width: usize, outline: bool) -> String {
|
||||||
let truncated = if input.len() > width {
|
// let truncated = if input.len() > width {
|
||||||
&input[..width]
|
// let input_chars: Vec<char> = input.chars().collect();
|
||||||
} else {
|
// input_chars[..width].iter().collect::<String>()
|
||||||
input
|
// } else {
|
||||||
};
|
// input.to_string()
|
||||||
format!("{:<width$}", truncated, width = width)
|
// };
|
||||||
}
|
// 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");
|
||||||
|
|||||||
Reference in New Issue
Block a user