diff --git a/Cargo.toml b/Cargo.toml index a7b33db..f7797f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ documentation = "https://osui.netlify.app/docs/" [features] no_rsx = [] -portable = [] no_elem = [] [lib] diff --git a/src/console.rs b/src/console.rs index 16530d5..7979f85 100644 --- a/src/console.rs +++ b/src/console.rs @@ -71,8 +71,19 @@ impl Console { if let Event::Resize(w, h) = event { self.0.width = w; self.0.height = h; + } else if let Event::Mouse(crossterm::event::MouseEvent { + kind: crossterm::event::MouseEventKind::Moved, + row, + column, + .. + }) = event + { + self.0.mouse_pos = Some((column, row)); + + self.draw(ui.clone(), None)?; + } else { + self.draw(ui.clone(), Some(event))?; } - self.draw(ui.clone(), Some(event))?; } } diff --git a/src/elements.rs b/src/elements.rs index f78a9ec..856749a 100644 --- a/src/elements.rs +++ b/src/elements.rs @@ -40,7 +40,7 @@ impl Widget for Button { } impl Button { - pub fn draw(&mut self, w: &W, props: crate::Area) -> crate::Result<()> + pub fn draw(&mut self, w: &W, props: crate::Props) -> crate::Result<()> where W: Widget, { diff --git a/src/lib.rs b/src/lib.rs index 5c6eca4..82603a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,9 +20,11 @@ pub mod utils; /// Commonly used imports for convenience. pub mod prelude { + pub use crate::console::*; pub use crate::elements::*; - pub use crate::*; - pub use console::Event; + pub use crate::rsx; + pub use crate::utils; + pub use crate::{Element, Frame, Pos, Props, Result, Size, Widget}; pub use crossterm::event::{KeyCode, KeyEvent}; } @@ -46,9 +48,9 @@ pub trait Widget { } } -/// Struct representing a rectangular area in the terminal. +/// Struct representing a rectangular props in the terminal. #[derive(Debug, Clone, Copy)] -pub struct Area { +pub struct Props { pub width: Size, pub height: Size, pub x: Pos, @@ -60,6 +62,7 @@ pub struct Area { pub struct Frame { pub width: u16, pub height: u16, + mouse_pos: Option<(u16, u16)>, last_elem: (u16, u16), } @@ -111,61 +114,14 @@ impl Size { } } -impl Area { - /// Creates a new `Area` with default values. +impl Props { + /// Creates a new `Props` with default values. pub fn new() -> Self { Self::default() } - - /// Center the `Area` horizontally. Only available with the `portable` feature. - #[cfg(feature = "portable")] - pub fn center_x() -> Self { - let mut s = Self::default(); - s.x = Pos::center; - s - } - - /// Center the `Area` vertically. Only available with the `portable` feature. - #[cfg(feature = "portable")] - pub fn center_y() -> Self { - let mut s = Self::default(); - s.y = Pos::center; - s - } - - /// Center the `Area` both horizontally and vertically. Only available with the `portable` feature. - #[cfg(feature = "portable")] - pub fn center() -> Self { - let mut s = Self::default(); - s.x = Pos::center; - s.y = Pos::center; - s - } - - // Additional utility methods for setting properties are available with the `portable` feature. - #[cfg(feature = "portable")] - pub fn set_width(&mut self, w: Size) -> Self { - self.width = w; - *self - } - #[cfg(feature = "portable")] - pub fn set_height(&mut self, h: Size) -> Self { - self.height = h; - *self - } - #[cfg(feature = "portable")] - pub fn set_x(&mut self, x: Pos) -> Self { - self.x = x; - *self - } - #[cfg(feature = "portable")] - pub fn set_y(&mut self, y: Pos) -> Self { - self.y = y; - *self - } } -impl Default for Area { +impl Default for Props { fn default() -> Self { Self { width: Size::Auto, @@ -178,7 +134,7 @@ impl Default for Area { impl Frame { /// Draws a widget on the frame. - pub fn draw(&mut self, w: &W, props: Area) -> Result<()> + pub fn draw(&mut self, w: &W, props: Props) -> Result<()> where W: Widget, { @@ -196,13 +152,23 @@ impl Frame { props.y.get(self.last_elem.1, height, self.height), ); + let ansi = if let Some((mouse_x, mouse_y)) = &self.mouse_pos { + if (x..x + width).contains(mouse_x) && (y..y + height).contains(mouse_y) { + "\x1b[32m" + } else { + "" + } + } else { + "" + }; + for (i, line) in written.lines().enumerate() { if i as u16 > height { break; } println!( - "\x1b[{};{}H{}", + "\x1b[{};{}H{ansi}{}\x1b[0m", y + (i as u16) + 1, x + 1, line.chars().take(width as usize).collect::() @@ -228,6 +194,7 @@ impl Frame { width, height, last_elem: (0, 0), + mouse_pos: None, } } } diff --git a/src/main.rs b/src/main.rs index f406ee4..b018ebf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use osui::prelude::*; -fn main() -> osui::Result<()> { - let mut con = console::init(false)?; +fn main() -> Result<()> { + let mut con = init(true)?; con.run(app())?; @@ -10,8 +10,6 @@ fn main() -> osui::Result<()> { pub fn app() -> Element { rsx! { - btn { on_click: Box::new(|| { - panic!("Testing"); - }), "Click me" } + btn { "Click me" } (x-center y-center) } } diff --git a/src/rsx.rs b/src/rsx.rs index e17bfca..694db95 100644 --- a/src/rsx.rs +++ b/src/rsx.rs @@ -35,6 +35,14 @@ macro_rules! rsx { /// **Don't use this macro manually** use `rsx!` instead #[macro_export] macro_rules! rsx_inner { + // Field + ($frame:expr, $event:expr; + $n:ident: $v:expr + $(, $($rest:tt)*)?) => { + $frame.$n = $v; + $crate::rsx_inner!($frame, $event; $($($rest)*)?); + }; + // For loop ($frame:expr, $event:expr; for ($i:pat in $e:expr) $(%$s:ident),* {$($inner:tt)*} @@ -77,59 +85,44 @@ macro_rules! rsx_inner { ($frame:expr, $event:expr; $elem:literal ($($inner:tt)*) $($rest:tt)*) => { - let mut area = $crate::Area::new(); - $crate::tw_area!(area, $($inner)*); - $frame.draw(&format!($elem), area)?; + let mut props = $crate::Props::new(); + $crate::tw_props!(props, $($inner)*); + $frame.draw(&format!($elem), props)?; $crate::rsx_inner!($frame, $event; $($rest)*); }; ($frame:expr, $event:expr; $elem:literal $($rest:tt)*) => { - $frame.draw(&format!($elem), Area::new())?; + $frame.draw(&format!($elem), Props::new())?; $crate::rsx_inner!($frame, $event; $($rest)*); }; - // Name { rsx } ( area ) + // Name { rsx } ( props ) ($frame:expr, $event:expr; $elem:path { - $($n:ident: $v:expr),+ - $(, - $($inner:tt)* - )? - } ($($area_inner:tt)*) + $($inner:tt)* + } ($($props_inner:tt)*) $($rest:tt)*) => { - let mut area = $crate::Area::new(); - $crate::tw_area!(area, $($area_inner)*); - let mut e = $elem(); - $( - e.$n = $v; - )* - $( - $crate::rsx_inner!(e, $event; $($inner)*); - )? + let mut props = $crate::Props::new(); + $crate::tw_props!(props, $($props_inner)*); - $frame.draw(&e, area)?; + let mut e = $elem(); + $crate::rsx_inner!(e, $event; $($inner)*); + + $frame.draw(&e, props)?; $crate::rsx_inner!($frame, $event; $($rest)*); }; // Name { rsx } ($frame:expr, $event:expr; $elem:path { - $($n:ident: $v:expr),+ - $(, - $($inner:tt)* - )? + $($inner:tt)* } $($rest:tt)*) => { let mut e = $elem(); - $( - e.$n = $v; - )* - $( - $crate::rsx_inner!(e, $event; $($inner)*); - )? + $crate::rsx_inner!(e, $event; $($inner)*); - $frame.draw(&e, $crate::Area::new())?; + $frame.draw(&e, $crate::Props::new())?; $crate::rsx_inner!($frame, $event; $($rest)*); }; @@ -140,7 +133,7 @@ macro_rules! rsx_inner { /// /// **Don't use this macro manually** use `rsx!` instead #[macro_export] -macro_rules! tw_area { +macro_rules! tw_props { ($a:expr, $n:ident) => { $a.$n; }; @@ -148,45 +141,45 @@ macro_rules! tw_area { // X ($a:expr, x-$v:ident $($rest:tt)*) => { $a.x = $crate::Pos::$v; - $crate::tw_area!($a, $($rest)*); + $crate::tw_props!($a, $($rest)*); }; ($a:expr, x-$v:literal $($rest:tt)*) => { $a.x = $crate::Pos::Num($v); - $crate::tw_area!($a, $($rest)*); + $crate::tw_props!($a, $($rest)*); }; // Y ($a:expr, y-$v:ident $($rest:tt)*) => { $a.y = $crate::Pos::$v; - $crate::tw_area!($a, $($rest)*); + $crate::tw_props!($a, $($rest)*); }; ($a:expr, y-$v:literal $($rest:tt)*) => { $a.y = $crate::Pos::Num($v); - $crate::tw_area!($a, $($rest)*); + $crate::tw_props!($a, $($rest)*); }; // Width ($a:expr, width-$v:ident $($rest:tt)*) => { $a.width = $crate::Size::$v; - $crate::tw_area!($a, $($rest)*); + $crate::tw_props!($a, $($rest)*); }; ($a:expr, width-$v:literal $($rest:tt)*) => { $a.width = $crate::Size::Num($v); - $crate::tw_area!($a, $($rest)*); + $crate::tw_props!($a, $($rest)*); }; // Height ($a:expr, height-$v:ident $($rest:tt)*) => { $a.height = $crate::Size::$v; - $crate::tw_area!($a, $($rest)*); + $crate::tw_props!($a, $($rest)*); }; ($a:expr, height-$v:literal $($rest:tt)*) => { $a.height = $crate::Size::Num($v); - $crate::tw_area!($a, $($rest)*); + $crate::tw_props!($a, $($rest)*); }; ($a:expr,) => {};