diff --git a/osui-element/lib.rs b/osui-element/lib.rs index 7d44047..b6a85d0 100644 --- a/osui-element/lib.rs +++ b/osui-element/lib.rs @@ -2,6 +2,8 @@ use proc_macro::TokenStream; use quote::quote; use syn::{parse::Parser, parse_macro_input, DeriveInput, Fields, LifetimeParam}; +/// Sets the required values and traits for a struct to be a element. +/// You will still need to implement ElementCore yourself #[proc_macro_attribute] pub fn element(_args: TokenStream, input: TokenStream) -> TokenStream { let mut ast = parse_macro_input!(input as DeriveInput); @@ -60,7 +62,7 @@ pub fn element(_args: TokenStream, input: TokenStream) -> TokenStream { } let expanded_impl = quote! { - impl<'a> ElementComponent for #struct_name<'a> { + impl<'a> ElementCore for #struct_name<'a> { fn get_data(&self) -> (Value, usize, String) { (self.x, self.y, self.id.to_string()) } @@ -73,7 +75,7 @@ pub fn element(_args: TokenStream, input: TokenStream) -> TokenStream { } } } - fn get_element_by_id(&mut self, id: &str) -> Option<&mut Box> { + fn get_element_by_id(&mut self, id: &str) -> Option<&mut Element> { if let Children::Children(children, _) = &mut self.children { for elem in children { if elem.get_data().2 == id { @@ -83,7 +85,7 @@ pub fn element(_args: TokenStream, input: TokenStream) -> TokenStream { } None } - fn get_child(&mut self) -> Option<&mut Box> { + fn get_child(&mut self) -> Option<&mut Element> { if let Children::Children(children, child) = &mut self.children { children.get_mut(*child) } else { diff --git a/src/app.rs b/src/app.rs index dd3a4e8..276f60e 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,24 +1,18 @@ use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; use crate::{ - utils::{clear, create_frame, flush, get_term_size, hide_cursor, render_to_frame, show_cursor}, Element, - State, StateChanger, + utils::{clear, create_frame, flush, get_term_size, hide_cursor, render_to_frame, show_cursor}, + Element, State, StateChanger, }; use std::ffi::c_void; -pub struct ElementWrapper<'a> { - element: &'a mut Box, -} +struct ElementWrapper<'a>(&'a mut Element); impl<'a> ElementWrapper<'a> { - pub fn new(element: &'a mut Box) -> *mut c_void { - Box::into_raw(Box::new(ElementWrapper { element })) as *mut c_void - } - - pub unsafe fn from_raw(ptr: *mut c_void) -> &'a mut Box { + pub unsafe fn from_raw(ptr: *mut c_void) -> &'a mut Element { assert!(!ptr.is_null(), "Pointer to ElementWrapper is null"); let wrapper = ptr as *mut ElementWrapper; - (*wrapper).element + (*wrapper).0 } } @@ -56,13 +50,12 @@ pub extern "C" fn init_event(ptr: *mut c_void, state: *mut u32) { element.event(event, &StateChanger(state)); } -pub fn run(data: &mut Box) -> bool { +pub fn run(element: &mut Element) -> bool { hide_cursor(); enable_raw_mode().unwrap(); clear(); unsafe { - let element_ptr = ElementWrapper::new(data); - let c = c_run(element_ptr); + let c = c_run(&mut ElementWrapper(element) as *mut ElementWrapper as *mut c_void); show_cursor(); disable_raw_mode().unwrap(); clear(); diff --git a/src/lib.rs b/src/lib.rs index 34f8671..2b3b5ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ //! ## Example Usage //! //! ```rust -//! use osui::{self, rsx, ui::*}; +//! use osui::prelude::*; //! //! osui::app::run(&mut rsx! { //! text { "Hello, World!" } @@ -20,11 +20,29 @@ //! - `ui` - Contains all user interface components, enabling rich CLI experiences. //! - `utils` - Utility functions for common TUI tasks such as clearing the screen. +use crossterm::event::Event; + pub mod app; pub mod macros; pub mod ui; pub mod utils; +/// 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::{app::run, rsx, rsx_elem, ui::*, StateChanger}; + pub use crate::{Children, Component, Element, ElementCore, State, Value}; + pub use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind}; + pub fn sleep(ms: u64) { + std::thread::sleep(std::time::Duration::from_millis(ms)); + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +/// Value Enum +////////////////////////////////////////////////////////////////////////////////////////////////// + #[derive(Debug, Clone, Copy)] pub enum Value { Default(T), @@ -52,35 +70,49 @@ impl Default for Value { } } -pub trait ElementComponent: Send + Sync { +////////////////////////////////////////////////////////////////////////////////////////////////// +/// ElementCore 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 Box>; - fn get_child(&mut self) -> Option<&mut Box>; + fn get_element_by_id(&mut self, id: &str) -> Option<&mut Element>; + fn get_child(&mut self) -> Option<&mut Element>; } -pub trait Element: std::fmt::Debug + Send + Sync + ElementComponent { +pub trait Component: ElementCore + std::fmt::Debug { fn render(&self, state: State) -> String { _ = state; String::new() } - fn event(&mut self, event: crossterm::event::Event, state: &StateChanger) { + fn event(&mut self, event: Event, state: &StateChanger) { (_, _) = (event, state) } } -pub struct Handler(pub Box); +pub type Element = Box; + +////////////////////////////////////////////////////////////////////////////////////////////////// +/// Handler Struct +////////////////////////////////////////////////////////////////////////////////////////////////// + +pub struct Handler(pub Box); impl Handler { pub fn new(handler_fn: F) -> Handler where - F: FnMut(&T, crossterm::event::Event, &StateChanger) + 'static + Send, + F: FnMut(&T, Event, &StateChanger) + 'static + Send, { Handler(Box::new(handler_fn)) } } +////////////////////////////////////////////////////////////////////////////////////////////////// +/// State Enum and StateChanger Struct +////////////////////////////////////////////////////////////////////////////////////////////////// + #[derive(Debug, Clone, Copy, PartialEq)] pub enum State { Exit, @@ -100,6 +132,7 @@ impl State { _ => State::Custom((s - 4) as usize), } } + pub fn to_u32(&self) -> u32 { match self { State::Exit => 0, @@ -119,16 +152,21 @@ impl StateChanger { (*self.0) = s.to_u32(); } } + pub fn get_state(&self) -> State { State::from_u32(unsafe { *self.0 }) } } +////////////////////////////////////////////////////////////////////////////////////////////////// +/// Children Enum +////////////////////////////////////////////////////////////////////////////////////////////////// + #[derive(Debug)] pub enum Children { None, Text(String), - Children(Vec>, usize), + Children(Vec, usize), } impl Default for Children { @@ -144,4 +182,10 @@ impl Children { _ => false, } } + pub fn get_text(&self) -> String { + match self { + Children::Text(text) => text.clone(), + _ => String::new(), + } + } } diff --git a/src/macros.rs b/src/macros.rs index 89e55b9..ab8bc89 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,15 +1,51 @@ -/// Macro for parsing parameters and children for an OSUI element. +/// **parse_rsx_param!** - A macro for parsing and setting parameters on elements, allowing for dynamic handling of element properties and children. +/// +/// This macro enables flexible configuration of UI elements. It handles setting fields, adding children, invoking paths, and processing complex structures. /// -/// This macro updates the properties of an element based on provided key-value pairs, -/// and adds child elements to the parent element. +/// ## Example +/// ```rust +/// parse_rsx_param!(elem, title: "Hello", for (i in 0..5) { }, text: "World"); +/// ``` +/// +/// ## Syntax +/// +/// **Set property or field of an element:** +/// ```rust +/// parse_rsx_param!($elem, $($k:ident).+: $v:expr); +/// ``` /// -/// # Parameters -/// - `elem`: The element being updated. -/// - Various key-value pairs, child elements, and text content. even for loops +/// **Process multiple parameters:** +/// ```rust +/// parse_rsx_param!($elem, $($k:ident).+: $v:expr, $($rest:tt)*); +/// ``` +/// +/// **Handle path expression:** +/// ```rust +/// parse_rsx_param!($elem, $p:path); +/// ``` +/// +/// **Add nested children:** +/// ```rust +/// parse_rsx_param!($elem, for ($($for:tt)*) { $($inner:tt)* } $($rest:tt)*); +/// ``` +/// +/// **Add child element directly:** +/// ```rust +/// parse_rsx_param!($elem, {$ielem:expr} $($rest:tt)*); +/// ``` +/// +/// **Set element text:** +/// ```rust +/// parse_rsx_param!($elem, $text:expr); +/// ``` +/// +/// **Handle empty case:** +/// ```rust +/// parse_rsx_param!($elem, ); +/// ``` #[macro_export] macro_rules! parse_rsx_param { - // Properties - ($elem:expr, $($k:ident).+: $v:expr) => { + ($elem:expr, $($k:ident).+: $v:expr) => { $elem.$($k).+ = $v; }; @@ -18,8 +54,7 @@ macro_rules! parse_rsx_param { osui::parse_rsx_param!($elem, $($rest)*); }; - // for completion purposes - ($elem:expr, $p:path) => { + ($elem:expr, $p:path) => { $p; }; ($elem:expr, $($k:ident).+, $($rest:tt)*) => { @@ -40,8 +75,7 @@ macro_rules! parse_rsx_param { osui::parse_rsx_param!($elem, $($rest)*); }; - // For loop - ($elem:expr, for ($($for:tt)*) { $($inner:tt)* } $($rest:tt)*) => { + ($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)* { @@ -51,8 +85,7 @@ macro_rules! parse_rsx_param { osui::parse_rsx_param!($elem, $($rest)*); }; - // Expression - ($elem:expr, {$ielem:expr} $($rest:tt)*) => { + ($elem:expr, {$ielem: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({$ielem}); @@ -60,8 +93,7 @@ macro_rules! parse_rsx_param { osui::parse_rsx_param!($elem, $($rest)*); }; - // Element - ($elem:expr, $pelem:path { $($inner:tt)* } $($rest:tt)*) => { + ($elem:expr, $pelem: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!($pelem { $($inner)* })); @@ -69,75 +101,55 @@ macro_rules! parse_rsx_param { osui::parse_rsx_param!($elem, $($rest)*) }; - // Text - ($elem:expr, $text:expr) => { + ($elem:expr, $text:expr) => { if $elem.children.is_none() {$elem.children = $crate::Children::Text(format!($text))} }; ($elem:expr, $text:expr, $($inner:tt)*) => { if $elem.children.is_none() {$elem.children = $crate::Children::Text(format!($text, $($inner)*))} }; - // Empty - ($elem:expr, ) => {}; + ($elem:expr, ) => {}; } -/// Macro for creating an OSUI element with parsed parameters. +/// **rsx_elem!** - A macro to instantiate a UI element and apply parameters to it. +/// +/// This macro simplifies creating an element and applying a set of properties or children to it, enabling a declarative style of UI building. /// -/// # Example +/// ## Example +/// ```rust +/// let element = rsx_elem!(ui::Button { text: "Click me" }); /// ``` -/// rsx! { -/// text { "Hello, World!" } -/// div { -/// button { y: 2, "click me" } -/// } -/// } +/// +/// ## Syntax +/// ```rust +/// rsx_elem!($elem:path { $($inner:tt)* }) /// ``` -/// -/// # For loops -/// ``` -/// rsx! { -/// text { "Welcome!" } -/// for (i in 1..5) { // must be contained with () -/// rsx_elem!{text { y: i, "Text: {i}" }} -/// } -/// } -/// ``` -/// -/// This macro provides a clean way to express OSUI elements, functioning like a div that can -/// contain multiple components. #[macro_export] macro_rules! rsx_elem { ($elem:path { $($inner:tt)* }) => {{ #[allow(unused_mut)] let mut elem = $elem(); $crate::parse_rsx_param!(elem, $($inner)*); - elem as Box + elem as $crate::Element }}; } -#[macro_export] -macro_rules! rsx_elem_raw { - ($elem:path { $($inner:tt)* }) => {{ - #[allow(unused_mut)] - let mut elem = $elem(); - $crate::parse_rsx_param!(elem, $($inner)*); - elem - }}; -} - -/// Macro for defining a structured representation of UI elements in OSUI. +/// **rsx!** - A shorthand macro to create a `div` element and apply nested content to it. /// -/// # Example -/// ``` +/// This macro is a simple wrapper for `rsx_elem!`, making it easy to create a `div` element and add children to it. +/// +/// ## Example +/// ```rust /// rsx! { -/// text { "Hello, World!" } -/// div { -/// button { y: 2, "click me" } -/// } -/// } +/// text { "Hello, World" } +/// div { button {"Click me!"} } +/// } +/// ``` +/// +/// ## Syntax +/// ```rust +/// rsx!($($inner:tt)*) /// ``` -/// -/// This macro allows the creation of a root element that can contain other elements. #[macro_export] macro_rules! rsx { ($($inner:tt)*) => {{ @@ -145,29 +157,6 @@ macro_rules! rsx { }}; } -/// Macro for defining CSS styles in OSUI. -/// -/// # Example -/// ``` -/// css!(Style; color: Color::Red; background: "white"); -/// ``` -/// -/// This macro creates a new style based on the provided properties, applying default values -/// for any unspecified fields. -#[macro_export] -macro_rules! css { - ( - $style:path; - $($inner:tt)* - ) => {{ - $style { - $($inner)* - ..Default::default() - } - }}; -} - -/// Macro for defining a `Value< T >` #[macro_export] macro_rules! val { ($a:expr) => { @@ -175,21 +164,9 @@ macro_rules! val { }; } -/// Macro for writing when requested to render -/// -/// # Example -/// ``` -/// write!(self, clicked, "Hello, World!") // For custom styles, You need (color, background, font) -/// -/// write!((self, state), "Hello, World!") // When you don't need a custom style, you use () and put self and the state of the render -/// ``` -/// -/// This macro returns a `String` depending on the state or the kind of style -/// When on "state" mode it returns the default style if the state is 0 #[macro_export] macro_rules! write { - // Default state styling - (($self:ident, $state:expr), $expr:expr) => {{ + (($self:ident, $state:expr), $expr:expr) => {{ if $state == 0 { return format!( "{}{}{}{}\x1b[0m", @@ -208,8 +185,7 @@ macro_rules! write { ) }}; - // Custom styles - ($self:ident, $kind:ident, $expr:expr) => {{ + ($self:ident, $kind:ident, $expr:expr) => {{ use paste::paste; format!( "{}{}{}{}\x1b[0m", @@ -227,31 +203,6 @@ macro_rules! write { }}; } -#[macro_export] -macro_rules! execute_response { - ($self:expr, $res:expr) => { - for response in $res.execute() { - match response { - EventResponse::UpdateElementById(id, elem) => { - for old in &mut $self.children { - if old.get_id() == id { - *old = elem.clone(); - } - } - } - EventResponse::UpdateSelf(elem) => { - if let Some(child) = $self.get_child() { - *child = elem; - } - } - _ => { - return response; - } - } - } - }; -} - #[macro_export] macro_rules! run_handler { ($self:ident.$handler:ident ($renderer:expr, $event:expr)) => { diff --git a/src/main.rs b/src/main.rs index 986a1d9..de9f0eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,11 @@ -use osui::{app::run, rsx, ui::*, Element}; +use osui::prelude::*; fn main() { while run(&mut app()) {} } -fn app() -> Box { +fn app() -> Element { rsx! { - text { "Hello, World!" } + button { "This is a button!" } } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index b5a59c0..70606c2 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,18 +1,41 @@ -/// The `ui` module provides user interface components and utilities for building -/// a text-based user interface (TUI). It includes predefined styles and elements -/// such as text, buttons, and containers. +/// The `ui` module defines the basic building blocks for creating a terminal-based UI framework. +/// This includes elements like `Text` and `Div`, which can be combined to create complex layouts +/// and interactive UIs in the terminal. It also provides utility functions for rendering, event +/// handling, and managing child components. +/// +/// Key Components: +/// - `Text`: A simple text element that renders a string to the terminal. +/// - `Div`: A container element that holds and renders child components, allowing navigation +/// through them with keyboard events (Up, Down, Left, Right). +/// - `styles`: A module for defining UI styles. +/// - `utils`: Utility functions for rendering and managing state. pub mod styles; pub use styles::*; -use crate::{Children, Element, ElementComponent, Value}; +use crate::prelude::*; use osui_element::{elem_fn, element}; +/// The `Text` element represents a piece of static text in the terminal UI. +/// +/// It is used to render plain text within a UI component. The `Text` element does not interact +/// with events and only outputs the text when rendered. +/// +/// # Example +/// ```rust +/// let text = Text::default(); +/// let rendered_text = text.render(crate::State::Normal); +/// println!("{}", rendered_text); +/// ``` +/// +/// ## Methods +/// - `render(state: crate::State) -> String`: Renders the text to a string, depending on the state. +/// If the element contains text as a child, it returns that text. Otherwise, it returns an empty string. #[element] #[elem_fn] #[derive(Default, Debug)] pub struct Text {} -impl Element for Text<'_> { +impl Component for Text<'_> { fn render(&self, _: crate::State) -> String { if let Children::Text(text) = &self.children { text.clone() @@ -22,13 +45,33 @@ impl Element for Text<'_> { } } +/// The `Div` element represents a container for other UI elements. It can hold child components +/// and render them in a specific layout. The `Div` element also handles keyboard navigation through +/// its children. +/// +/// The `Div` element supports rendering a list of children and allows interactive navigation using +/// arrow keys (Up, Down, Left, Right). It renders the selected child element differently based on the state. +/// +/// # Example +/// ```rust +/// let div = Div::default(); +/// let rendered_div = div.render(crate::State::Normal); +/// println!("{}", rendered_div); +/// ``` +/// +/// ## Methods +/// - `render(state: crate::State) -> String`: Renders the `Div` and its child elements to a string. +/// The child elements are rendered according to the current selection (`child` index). +/// - `event(event: Event, state: &crate::StateChanger)`: Handles keyboard events for +/// navigation through child elements. Arrow keys (Up, Down, Left, Right) change the currently selected child. + #[element] #[elem_fn] #[derive(Default, Debug)] pub struct Div {} -impl Element for Div<'_> { - fn render(&self, state: crate::State) -> String { +impl Component for Div<'_> { + fn render(&self, state: State) -> String { let mut frame = crate::utils::create_frame(self.width.get_value(), self.height.get_value()); if let Children::Children(children, child) = &self.children { @@ -49,36 +92,41 @@ impl Element for Div<'_> { frame.join("\n") } - fn event(&mut self, event: crossterm::event::Event, state: &crate::StateChanger) { + fn event(&mut self, event: Event, state: &crate::StateChanger) { match event { - crossterm::event::Event::Key(key) => { + Event::Key(key) => { if let Children::Children(children, child) = &mut self.children { *child = match key.code { - crossterm::event::KeyCode::Up => crate::utils::closest_component( + KeyCode::Up => crate::utils::closest_component( children, *child, crate::utils::Direction::Up, ), - crossterm::event::KeyCode::Down => crate::utils::closest_component( + KeyCode::Down => crate::utils::closest_component( children, *child, crate::utils::Direction::Down, ), - crossterm::event::KeyCode::Left => crate::utils::closest_component( + KeyCode::Left => crate::utils::closest_component( children, *child, crate::utils::Direction::Left, ), - crossterm::event::KeyCode::Right => crate::utils::closest_component( + KeyCode::Right => crate::utils::closest_component( children, *child, crate::utils::Direction::Right, ), - _ => *child, + _ => { + if let Some(c) = children.get_mut(*child) { + c.event(event, state); + } + *child + } } } } @@ -90,3 +138,31 @@ impl Element for Div<'_> { } } } + +#[element] +#[elem_fn] +#[derive(Default, Debug)] +pub struct Button {} + +impl Component for Button<'_> { + fn render(&self, state: State) -> String { + match state { + State::Custom(_) => format!("\x1b[32m{}\x1b[0m", self.children.get_text()), + _ => self.children.get_text(), + } + } + + fn event(&mut self, event: Event, state: &StateChanger) { + match event { + Event::Key(key) => { + if key.code == KeyCode::Enter { + let prev_state = state.get_state(); + state.set_state(State::Custom(0)); + sleep(100); + state.set_state(prev_state); + } + } + _ => {} + } + } +} diff --git a/src/ui/styles.rs b/src/ui/styles.rs index 0a30369..483e5cc 100644 --- a/src/ui/styles.rs +++ b/src/ui/styles.rs @@ -1,4 +1,17 @@ -/// Represents different font styles that can be applied to TUI elements. +//! The `styles` module defines various styling options for UI elements. This includes colors, +//! fonts, padding, margins, and other visual properties that can be applied to UI components +//! to change their appearance. +//! +//! # Example +//! ```rust +//! use crate::ui::styles::{Style, Color}; +//! +//! let style = Style { +//! color: Color::Blue, +//! padding: 5, +//! }; +//! ``` + #[derive(Debug, Clone, PartialEq)] pub enum Font { None, @@ -7,11 +20,10 @@ pub enum Font { Italic, Reverse, Strike, - Mul(Vec), // Allows combining multiple font styles. + Mul(Vec), } impl Font { - /// Converts the font style to an ANSI sequence. pub fn ansi(&self) -> String { String::from(match self { Font::None => "", @@ -30,8 +42,8 @@ impl Font { }) } - /// Returns the prioritized font between `self` and `secondary`, favoring `secondary` - /// if it is not `None`. + + pub fn prioritize<'a>(&'a self, secondary: &'a Font) -> &Font { if secondary == &Font::None { self @@ -41,12 +53,12 @@ impl Font { } } -/// Represents color options for elements, supporting both named colors and RGB values. + #[derive(Debug, Clone, PartialEq)] pub enum Color { None, - /// Red, Green, blue - Rgb(u8, u8, u8), // RGB color representation. + + Rgb(u8, u8, u8), Hex(String), Black, Red, @@ -59,7 +71,7 @@ pub enum Color { } impl Color { - /// Converts the color to an ANSI foreground sequence. + pub fn ansi(&self) -> String { String::from(match self { Color::None => "", @@ -81,7 +93,7 @@ impl Color { }) } - /// Converts the color to an ANSI background sequence. + pub fn ansi_bg(&self) -> String { String::from(match self { Color::None => "", @@ -103,8 +115,8 @@ impl Color { }) } - /// Returns the prioritized color between `self` and `secondary`, favoring `secondary` - /// if it is not `None`. + + pub fn prioritize<'a>(&'a self, secondary: &'a Color) -> &Color { if secondary == &Color::None { self @@ -129,7 +141,7 @@ impl Default for Font { fn hex_to_rgb(hex: &str) -> (u8, u8, u8) { let hex = hex.trim_start_matches('#'); - // Expand 3-character hex codes to 6 characters + let hex = if hex.len() == 3 { format!( "{}{}{}{}{}{}", @@ -140,10 +152,10 @@ fn hex_to_rgb(hex: &str) -> (u8, u8, u8) { } else if hex.len() == 6 { hex.to_string() } else { - return (255, 255, 255); // Return white for invalid hex length + return (255, 255, 255); }; - // Parse each pair of characters as u8 + let r = u8::from_str_radix(&hex[0..2], 16).unwrap_or(255); let g = u8::from_str_radix(&hex[2..4], 16).unwrap_or(255); let b = u8::from_str_radix(&hex[4..6], 16).unwrap_or(255); diff --git a/src/utils.rs b/src/utils.rs index 23da4b8..becd5f6 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,15 @@ +/// The `utils` module contains helper functions and utilities that assist in rendering and +/// 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 crate::{Element, Value}; use lazy_static::lazy_static; use regex::Regex; @@ -78,7 +90,7 @@ pub fn render_to_frame( state: crate::State, width: usize, frame: &mut Vec, - element: &Box, + element: &Element, ) { let data = element.get_data(); for (i, line) in element.render(state).split('\n').enumerate() { @@ -130,7 +142,7 @@ pub enum Direction { } pub fn closest_component( - components: &[Box], + components: &[Element], current_index: usize, direction: Direction, ) -> usize {