From f8fd990c671300272d7456cad23db3e80564cee9 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Mon, 25 Nov 2024 03:10:28 +0100 Subject: [PATCH] some refractoring --- src/app.c | 10 +- src/app.rs | 20 +--- src/examples.rs | 16 +-- src/lib.rs | 278 ++++++++++++++++++++++++-------------------- src/main.rs | 4 +- src/rsx.rs | 37 +++--- src/ui/mod.rs | 51 ++++----- src/ui/styles.rs | 293 +++++++++++++++++++++++++---------------------- src/utils.rs | 4 +- 9 files changed, 370 insertions(+), 343 deletions(-) diff --git a/src/app.c b/src/app.c index 81b63ac..b5df522 100644 --- a/src/app.c +++ b/src/app.c @@ -4,24 +4,18 @@ #include #include -extern boolean_t render_loop(void* args); extern void *event_loop(void* args); extern void *cmd_loop(void* args); boolean_t c_run(void* args) { pthread_t event_thread; - pthread_t cmd_thread; if (pthread_create(&event_thread, NULL, event_loop, args) != 0) { perror("Failed to create thread"); } - if (pthread_create(&cmd_thread, NULL, cmd_loop, args) != 0) - { - perror("Failed to create thread"); - } - - return render_loop(args); + cmd_loop(args); + return FALSE; } \ No newline at end of file diff --git a/src/app.rs b/src/app.rs index 501b0bb..41f421e 100644 --- a/src/app.rs +++ b/src/app.rs @@ -7,7 +7,7 @@ use crate::prelude::*; use crate::utils::{clear, flush, get_term_size, hide_cursor, show_cursor, Frame}; use std::{ffi::c_void, ptr::null, sync::mpsc}; -pub struct LArgs<'a> { +struct LArgs<'a> { pub element: &'a mut Element, // for sending commands @@ -55,18 +55,6 @@ pub fn run(element: &mut Element) -> bool { } } -#[no_mangle] -extern "C" fn render_loop(ptr: *mut c_void) -> bool { - if ptr.is_null() { - return false; - } - let args = unsafe { &mut *(ptr as *mut LArgs) }; - while args.running { - sleep(1000); - } - false -} - #[no_mangle] extern "C" fn event_loop(ptr: *mut c_void) -> *const c_void { if ptr.is_null() { @@ -87,10 +75,7 @@ extern "C" fn event_loop(ptr: *mut c_void) -> *const c_void { ); document.render(); - while args.running { - if ptr.is_null() { - break; - } + while args.running || !ptr.is_null() { event(args.element, crossterm::event::read().unwrap(), &document); document.render(); } @@ -102,6 +87,7 @@ extern "C" fn cmd_loop(ptr: *mut c_void) -> *const c_void { if ptr.is_null() { return null() as *const c_void; } + let args = unsafe { &mut *(ptr as *mut LArgs) }; loop { diff --git a/src/examples.rs b/src/examples.rs index 9e1f807..0bfd708 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -1,21 +1,23 @@ use crate::prelude::*; -pub fn event_logger() -> Element { +pub fn examples() -> Element { rsx! { styling: Some(styling()), - button { class: "txt", "Hello, World!" } + if (2 == 2) { + rsx_elem! { button { class: "btn", "Hello, World!" } } + } } } pub fn styling() -> Css { css! { - .txt { - x: Center, - y: Center, + .btn { + x: 30%, + y: Auto, color: Red, } - - .txt: clicked { + + .btn: clicked { color: Blue, } } diff --git a/src/lib.rs b/src/lib.rs index fe706c5..ce09ac5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,16 +38,12 @@ pub mod utils; pub use app::run; -/// The `prelude` module provides commonly used imports and macros to simplify the development -/// of UI elements. It re-exports commonly used traits, structs, and utility functions to make -/// the UI framework easier to use. pub mod prelude { pub use crate::ui::Color::*; pub use crate::ui::Number::*; pub use crate::{self as osui, css, rsx, rsx_elem, ui::*, Handler}; - pub use crate::{style, Command, Document, Element, Value}; - // useful for Element making pub use crate::{call, Children, ElementCore, ElementWidget}; + pub use crate::{style, Command, Document, Element, Value}; pub use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind}; pub fn sleep(ms: u64) { std::thread::sleep(std::time::Duration::from_millis(ms)); @@ -55,7 +51,54 @@ pub mod prelude { } ////////////////////////////////////////////////////////////////////////////////////////////////// -/// Value Enum +// Type aliases +////////////////////////////////////////////////////////////////////////////////////////////////// + +pub type Element = Box; + +////////////////////////////////////////////////////////////////////////////////////////////////// +/// Traits +////////////////////////////////////////////////////////////////////////////////////////////////// + +pub trait ElementCore: Send + Sync { + fn get_data(&self) -> (Value, usize, String); + fn update_data(&mut self, width: usize, height: usize); + fn get_element_by_id(&mut self, id: &str) -> Option<&mut Element>; + fn get_child(&mut self) -> Option<&mut Element>; + fn set_styling(&mut self, styling: &HashMap); +} + +pub trait ElementWidget: ElementCore + std::fmt::Debug { + fn render(&self, focused: bool) -> RenderResult; + + fn event(&mut self, event: Event, document: &Document) { + _ = (event, document) + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +/// Structs +////////////////////////////////////////////////////////////////////////////////////////////////// + +pub struct Handler(pub Arc>); + +pub struct Document { + cmd_sender: std::sync::mpsc::Sender, + cmd_recv: *const std::ffi::c_void, +} + +/// ``` +/// RenderResult(output, (x, y)) +/// ``` +pub struct RenderResult(String, ui::StyleElement); +pub struct RenderWriter { + w: String, + style: ui::Style, + focused: bool, +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +/// Enums ////////////////////////////////////////////////////////////////////////////////////////////////// #[derive(Debug, Clone, Copy)] @@ -64,6 +107,48 @@ pub enum Value { Custom(T), } +/// Child enum of an `Element` +/// +/// # Example +/// ``` +/// // Check if it's text +/// if let Children::Text(text) { +/// // do something +/// } +/// // Check if it's inner elements +/// if let Children::Children(text) { +/// // do something +/// } +/// // recommended: use get_text +/// children.get_text() // returns a empty string if it's not text +/// ``` +/// +/// # Useful for +/// - `Element::event` +/// - `Element::render` +/// - `Handler` +#[derive(Debug)] +pub enum Children { + None, + Text(String), + Children(Vec, usize), +} + +pub enum Command { + Exit, + Render, + GetElementById(String), +} + +pub enum CommandResult { + Element(*mut Element), + None, +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +/// Implementations +////////////////////////////////////////////////////////////////////////////////////////////////// + impl Value { pub fn get_value(&self) -> T { match self { @@ -85,89 +170,33 @@ impl Default for Value { } } -////////////////////////////////////////////////////////////////////////////////////////////////// -/// ElementCore Traits -////////////////////////////////////////////////////////////////////////////////////////////////// - -/// ``` -/// RenderResult(output, (x, y), (width, height)) -/// ``` -pub struct RenderResult(String, (ui::Number, ui::Number)); - -pub trait ElementCore: Send + Sync { - fn get_data(&self) -> (Value, usize, String); - fn update_data(&mut self, width: usize, height: usize); - fn get_element_by_id(&mut self, id: &str) -> Option<&mut Element>; - fn get_child(&mut self) -> Option<&mut Element>; - fn set_styling(&mut self, styling: &HashMap); -} - -pub trait ElementWidget: ElementCore + std::fmt::Debug { - fn render(&self, focused: bool) -> RenderResult; - - fn event(&mut self, event: Event, document: &Document) { - _ = (event, document) +impl Document { + pub fn exit(&self) { + self.cmd_sender.send(Command::Exit).unwrap(); } -} - -pub type Element = Box; - -////////////////////////////////////////////////////////////////////////////////////////////////// -/// Handler Struct -////////////////////////////////////////////////////////////////////////////////////////////////// - -pub struct Handler(pub Arc>); - -impl Handler { - pub fn new(handler_fn: F) -> Handler - where - F: FnMut(&mut T, Event, &Document) + 'static + Send + Sync, - { - Handler(Arc::new(Mutex::new(handler_fn))) + pub fn get_element_by_id(&self, id: &str) -> Option<&mut Box> { + if let Some(e) = self.get_element_by_id_raw(id) { + Some(convert(unsafe { &mut *e })) + } else { + None + } } -} - -impl Default for Handler { - fn default() -> Self { - Handler(Arc::new(Mutex::new(|_: &mut T, _: Event, _: &Document| {}))) + pub fn get_element_by_id_raw(&self, id: &str) -> Option<*mut Element> { + self.cmd_sender + .send(Command::GetElementById(id.to_string())) + .unwrap(); + let rx = unsafe { &*(self.cmd_recv as *const std::sync::mpsc::Receiver) }; + if let Ok(CommandResult::Element(e)) = rx.recv() { + Some(e) + } else { + None + } } -} - -impl std::fmt::Debug for Handler { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("Handler()") + pub fn render(&self) { + self.cmd_sender.send(Command::Render).unwrap(); } } -////////////////////////////////////////////////////////////////////////////////////////////////// -/// Children Enum -////////////////////////////////////////////////////////////////////////////////////////////////// - -/// Child enum of an `Element` -/// -/// # Example -/// ``` -/// // Check if it's text -/// if let Children::Text(text) { -/// // do something -/// } -/// // Check if it's inner elements -/// if let Children::Children(text) { -/// // do something -/// } -/// ``` -/// -/// # Useful for -/// - `Element::event` -/// - `Element::render` -/// - `Handler` -#[derive(Debug)] -pub enum Children { - None, - Text(String), - Children(Vec, usize), -} - impl Default for Children { fn default() -> Self { Self::None @@ -218,50 +247,45 @@ impl Children { } } -/// Converts a `Element` into the struct +impl Handler { + pub fn new(handler_fn: F) -> Handler + where + F: FnMut(&mut T, Event, &Document) + 'static + Send + Sync, + { + Handler(Arc::new(Mutex::new(handler_fn))) + } +} + +impl RenderWriter { + pub fn new(focused: bool, style: ui::Style) -> RenderWriter { + RenderWriter { + w: String::new(), + style, + focused, + } + } + + pub fn write(&mut self, s: &str) { + self.w += self.style.get(self.focused).write(s).as_str(); + } + + pub fn result(&self) -> RenderResult { + RenderResult(self.w.clone(), self.style.get(self.focused).clone()) + } +} + +impl Default for Handler { + fn default() -> Self { + Handler(Arc::new(Mutex::new(|_: &mut T, _: Event, _: &Document| {}))) + } +} + +impl std::fmt::Debug for Handler { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("Handler()") + } +} + pub fn convert(widget: &mut Box) -> &mut Box { unsafe { &mut *(widget as *mut _ as *mut Box) } } - -pub enum Command { - Exit, - Render, - GetElementById(String), -} - -pub enum CommandResult { - Element(*mut Element), - None, -} - -pub struct Document { - cmd_sender: std::sync::mpsc::Sender, - cmd_recv: *const std::ffi::c_void, -} - -impl Document { - pub fn exit(&self) { - self.cmd_sender.send(Command::Exit).unwrap(); - } - pub fn get_element_by_id(&self, id: &str) -> Option<&mut Box> { - if let Some(e) = self.get_element_by_id_raw(id) { - Some(convert(unsafe { &mut *e })) - } else { - None - } - } - pub fn get_element_by_id_raw(&self, id: &str) -> Option<*mut Element> { - self.cmd_sender - .send(Command::GetElementById(id.to_string())) - .unwrap(); - let rx = unsafe { &*(self.cmd_recv as *const std::sync::mpsc::Receiver) }; - if let Ok(CommandResult::Element(e)) = rx.recv() { - Some(e) - } else { - None - } - } - pub fn render(&self) { - self.cmd_sender.send(Command::Render).unwrap(); - } -} diff --git a/src/main.rs b/src/main.rs index c1682a3..83d651b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ -use osui::prelude::*; use osui::examples; +use osui::prelude::*; fn main() { - while osui::run(&mut examples::event_logger()) {} + while osui::run(&mut examples::examples()) {} } diff --git a/src/rsx.rs b/src/rsx.rs index ea010bf..0e261af 100644 --- a/src/rsx.rs +++ b/src/rsx.rs @@ -1,6 +1,23 @@ #[macro_export] macro_rules! parse_rsx_param { - ($elem:expr, $($k:ident).+: $v:expr) => { + ($elem:expr, for ($($for:tt)*) $code:block $($rest:tt)*) => { + if $elem.children.is_none() {$elem.children = $crate::Children::Children(Vec::new(), 0)} + if let $crate::Children::Children(children, _) = &mut $elem.children { + for $($for)* { + children.push($code) + } + } + osui::parse_rsx_param!($elem, $($rest)*); + }; + ($elem:expr, if ($($if:tt)*) $code:block $($rest:tt)*) => { + if $elem.children.is_none() {$elem.children = $crate::Children::Children(Vec::new(), 0)} + if let $crate::Children::Children(children, _) = &mut $elem.children { + if $($if)* {children.push($code)} + } + osui::parse_rsx_param!($elem, $($rest)*); + }; + + ($elem:expr, $($k:ident).+: $v:expr) => { $elem.$($k).+ = $v; }; @@ -29,17 +46,7 @@ macro_rules! parse_rsx_param { osui::parse_rsx_param!($elem, $($rest)*); }; - ($elem:expr, for ($($for:tt)*) { $($inner:tt)* } $($rest:tt)*) => { - if $elem.children.is_none() {$elem.children = $crate::Children::Children(Vec::new(), 0)} - if let $crate::Children::Children(children, _) = &mut $elem.children { - for $($for)* { - children.push({$($inner)*}) - } - } - osui::parse_rsx_param!($elem, $($rest)*); - }; - - ($elem:expr, {$inner_elem:expr} $($rest:tt)*) => { + ($elem:expr, {$inner_elem:expr} $($rest:tt)*) => { if $elem.children.is_none() {$elem.children = $crate::Children::Children(Vec::new(), 0)} if let $crate::Children::Children(children, _) = &mut $elem.children { children.push({$inner_elem}); @@ -47,7 +54,7 @@ macro_rules! parse_rsx_param { osui::parse_rsx_param!($elem, $($rest)*); }; - ($elem:expr, $elem_path:path { $($inner:tt)* } $($rest:tt)*) => { + ($elem:expr, $elem_path:path { $($inner:tt)* } $($rest:tt)*) => { if $elem.children.is_none() {$elem.children = $crate::Children::Children(Vec::new(), 0)} if let $crate::Children::Children(children, _) = &mut $elem.children { children.push(osui::rsx_elem!($elem_path { $($inner)* })); @@ -76,14 +83,14 @@ macro_rules! rsx_elem { } /// Makes a div and puts elements into it -/// +/// /// # Example /// ``` /// rsx! { /// button { class: "btn", "Click me!" } /// } /// ``` -/// +/// /// # Returns /// A `osui::Element` - Which is a `Box` #[macro_export] diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 6c64ef2..2f4daf1 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -5,7 +5,7 @@ pub mod styles; pub use styles::*; -use crate::{prelude::*, RenderResult}; +use crate::{prelude::*, RenderResult, RenderWriter}; use osui_element::{elem_fn, element}; /// The `Text` element represents a piece of static text in the terminal UI. @@ -31,17 +31,18 @@ pub struct Text { } impl ElementWidget for Text<'_> { - fn render(&self, _: bool) -> RenderResult { - self.style.result( - "", - self.style.write("", &{ - if let Children::Text(text) = &self.children { - text.clone() - } else { - String::new() - } - }), - ) + fn render(&self, focused: bool) -> RenderResult { + let mut writer = RenderWriter::new(focused, self.style.clone()); + + writer.write(&{ + if let Children::Text(text) = &self.children { + text.clone() + } else { + String::new() + } + }); + + writer.result() } fn event(&mut self, event: Event, document: &Document) { call!(self.on_event(event, document)); @@ -77,6 +78,7 @@ pub struct Div { impl ElementWidget for Div<'_> { fn render(&self, focused: bool) -> RenderResult { + let mut writer = RenderWriter::new(focused, self.style.clone()); let mut frame = crate::utils::Frame::new(crate::utils::get_term_size().0, 12); if let Children::Children(children, child) = &self.children { @@ -84,8 +86,9 @@ impl ElementWidget for Div<'_> { frame.render(focused && i == *child, elem); } } + writer.write(&frame.output()); - self.style.result("", frame.output()) + writer.result() } fn event(&mut self, event: Event, document: &Document) { @@ -145,25 +148,13 @@ impl ElementWidget for Div<'_> { #[derive(Default, Debug)] pub struct Button { pub on_click: Handler>, - pub state: &'a str, } impl ElementWidget for Button<'_> { fn render(&self, focused: bool) -> RenderResult { - if self.state != "" { - self.style.result( - self.state, - self.style.write(self.state, &self.children.get_text()), - ) - } else if focused { - self.style.result( - "hover", - self.style.write("hover", &self.children.get_text()), - ) - } else { - self.style - .result("", self.style.write("", &self.children.get_text())) - } + let mut writer = RenderWriter::new(focused, self.style.clone()); + writer.write(&self.children.get_text()); + writer.result() } fn event(&mut self, event: Event, document: &Document) { @@ -171,11 +162,11 @@ impl ElementWidget for Button<'_> { Event::Key(key) => { if key.code == KeyCode::Enter { document.render(); - self.state = "clicked"; + self.style.set_state("clicked"); call!(self.on_click(event, document)); document.render(); sleep(100); - self.state = ""; + self.style.set_state(""); } } _ => {} diff --git a/src/ui/styles.rs b/src/ui/styles.rs index 48a57d0..7573daf 100644 --- a/src/ui/styles.rs +++ b/src/ui/styles.rs @@ -6,16 +6,27 @@ use std::{collections::HashMap, fmt::Debug}; use dyn_clone::{clone_trait_object, DynClone}; -use crate::RenderResult; +////////////////////////////////////////////////////////////////////////////////////////////////// +// Type aliases +////////////////////////////////////////////////////////////////////////////////////////////////// + +pub type Css = HashMap; + +////////////////////////////////////////////////////////////////////////////////////////////////// +// Traits +////////////////////////////////////////////////////////////////////////////////////////////////// pub trait StyleCore: Debug + Send + Sync + DynClone { fn ansi(&self) -> String; fn ansi_bg(&self) -> String; fn is_null(&self) -> bool; } - clone_trait_object!(StyleCore); +////////////////////////////////////////////////////////////////////////////////////////////////// +// Enums +////////////////////////////////////////////////////////////////////////////////////////////////// + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Font { None, @@ -27,32 +38,6 @@ pub enum Font { Mul(Vec), } -impl StyleCore for Font { - fn ansi(&self) -> String { - String::from(match self { - Font::None => "", - Font::Bold => "\x1b[1m", - Font::Underline => "\x1b[4m", - Font::Italic => "\x1b[3m", - Font::Reverse => "\x1b[7m", - Font::Strike => "\x1b[9m", - Font::Mul(v) => { - let mut s = String::new(); - for n in v { - s += n.ansi().as_str(); - } - return s; - } - }) - } - fn ansi_bg(&self) -> String { - self.ansi() - } - fn is_null(&self) -> bool { - *self == Self::None - } -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Color { NoColor, @@ -68,6 +53,128 @@ pub enum Color { White, } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum Number { + Px(usize), + Pe(usize), + Center, + Auto, + Default, +} + +#[derive(PartialEq, Eq, Hash, Debug, Clone)] +pub enum StyleName { + Class(String), + Id(String), + Component(String), +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +// Structs +////////////////////////////////////////////////////////////////////////////////////////////////// + +#[derive(Debug, Clone)] +pub struct StyleElement { + pub color: Color, + pub background: Color, + pub font: Font, + pub x: Number, + pub y: Number, + pub width: Number, + pub height: Number, + pub other: HashMap>, +} + +#[derive(Debug, Clone)] +pub struct Style( + pub StyleElement, + pub HashMap, + pub String, +); + +////////////////////////////////////////////////////////////////////////////////////////////////// +// Implementations +////////////////////////////////////////////////////////////////////////////////////////////////// + +impl Default for Style { + fn default() -> Self { + Style(StyleElement::default(), HashMap::new(), String::new()) + } +} + +impl Style { + pub fn get(&self, hover: bool) -> StyleElement { + if let Some(style_element) = self.1.get(&self.2) { + self.0.clone().prioritize(style_element) + } else if hover { + if let Some(style_element) = self.1.get("hover") { + self.0.clone().prioritize(style_element) + } else { + self.0.clone() + } + } else { + self.0.clone() + } + } + + pub fn set_state(&mut self, state: &str) { + self.2 = state.to_string(); + } +} + +impl StyleElement { + pub fn write(&self, s: &str) -> String { + format!( + "{}{}{}{s}\x1b[0m", + self.color.ansi(), + self.background.ansi_bg(), + self.font.ansi() + ) + } +} + +impl Default for StyleElement { + fn default() -> Self { + StyleElement { + color: Color::NoColor, + background: Color::NoColor, + font: Font::None, + x: Number::Default, + y: Number::Default, + width: Number::Default, + height: Number::Default, + other: HashMap::new(), + } + } +} + +impl StyleElement { + pub fn prioritize(mut self, other: &Self) -> StyleElement { + if !other.color.is_null() { + self.color = other.color.clone(); + } + if !other.background.is_null() { + self.background = other.background.clone(); + } + if !other.font.is_null() { + self.font = other.font.clone(); + } + if other.x != Number::Default { + self.x = other.x.clone(); + } + if other.y != Number::Default { + self.y = other.y.clone(); + } + if other.width != Number::Default { + self.width = other.width.clone(); + } + if other.height != Number::Default { + self.height = other.height.clone(); + } + self + } +} + impl StyleCore for Color { fn ansi(&self) -> String { String::from(match self { @@ -153,112 +260,28 @@ fn hex_to_rgb(hex: &str) -> (u8, u8, u8) { (r, g, b) } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum Number { - Px(usize), - Pe(usize), - Center, - Auto, - Default, -} - -#[derive(PartialEq, Eq, Hash, Debug, Clone)] -pub enum StyleName { - Class(String), - Id(String), - Component(String), -} - -#[derive(Debug, Clone)] -pub struct StyleElement { - pub color: Color, - pub background: Color, - pub font: Font, - pub x: Number, - pub y: Number, - pub width: Number, - pub height: Number, - pub other: HashMap>, -} - -impl Default for StyleElement { - fn default() -> Self { - StyleElement { - color: Color::NoColor, - background: Color::NoColor, - font: Font::None, - x: Number::Default, - y: Number::Default, - width: Number::Default, - height: Number::Default, - other: HashMap::new(), - } +impl StyleCore for Font { + fn ansi(&self) -> String { + String::from(match self { + Font::None => "", + Font::Bold => "\x1b[1m", + Font::Underline => "\x1b[4m", + Font::Italic => "\x1b[3m", + Font::Reverse => "\x1b[7m", + Font::Strike => "\x1b[9m", + Font::Mul(v) => { + let mut s = String::new(); + for n in v { + s += n.ansi().as_str(); + } + return s; + } + }) + } + fn ansi_bg(&self) -> String { + self.ansi() + } + fn is_null(&self) -> bool { + *self == Self::None } } - -impl StyleElement { - pub fn prioritize(mut self, other: &Self) -> StyleElement { - if !other.color.is_null() { - self.color = other.color.clone(); - } - if !other.background.is_null() { - self.background = other.background.clone(); - } - if !other.font.is_null() { - self.font = other.font.clone(); - } - if other.x != Number::Default { - self.x = other.x.clone(); - } - if other.y != Number::Default { - self.y = other.y.clone(); - } - if other.width != Number::Default { - self.width = other.width.clone(); - } - if other.height != Number::Default { - self.height = other.height.clone(); - } - self - } -} - -#[derive(Debug, Clone)] -pub struct Style(pub StyleElement, pub HashMap); - -impl Default for Style { - fn default() -> Self { - Style(StyleElement::default(), HashMap::new()) - } -} - -impl Style { - pub fn write(&self, state: &str, s: &str) -> String { - if let Some(style_element) = self.1.get(state) { - style_element.write(s) - } else { - return self.0.write(s); - } - } - pub fn result(&self, state: &str, s: String) -> RenderResult { - if let Some(style_element) = self.1.get(state) { - let style_element = self.0.clone().prioritize(&style_element.clone()); - RenderResult(s, (style_element.x.clone(), style_element.y.clone())) - } else { - RenderResult(s, (self.0.x.clone(), self.0.y.clone())) - } - } -} - -impl StyleElement { - pub fn write(&self, s: &str) -> String { - format!( - "{}{}{}{s}\x1b[0m", - self.color.ansi(), - self.background.ansi_bg(), - self.font.ansi() - ) - } -} - -pub type Css = HashMap; diff --git a/src/utils.rs b/src/utils.rs index dd1a8bb..eb29c27 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -103,7 +103,7 @@ impl Frame { let output = element.render(focused); let x; let mut y = 0; - match output.1 .1 { + match output.1.y { crate::ui::Number::Px(_y) => { y = _y; } @@ -128,7 +128,7 @@ impl Frame { } } } - match output.1 .0 { + match output.1.x { crate::ui::Number::Px(_x) => { x = _x; }