From 9a87853042d2f12fb72f9193bb5f60f306f0689a Mon Sep 17 00:00:00 2001 From: Leo dev Date: Fri, 8 Nov 2024 22:01:24 +0100 Subject: [PATCH] hover event and x position wrapper (optional) --- src/event.rs | 13 +++++----- src/lib.rs | 14 +++++------ src/macros.rs | 11 +++++--- src/test/mod.rs | 3 +-- src/ui/elements.rs | 18 +++++++++---- src/utils.rs | 63 ++++++++++++++++++++++++++++++++++++---------- 6 files changed, 86 insertions(+), 36 deletions(-) diff --git a/src/event.rs b/src/event.rs index 7ce5412..f08d84f 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,4 +1,4 @@ -use crate::key::Key; +use crate::{key::Key, Element}; /// Enum defining commands that can be issued by an `Element`. #[derive(Clone)] @@ -24,9 +24,9 @@ pub enum EventResponse { /// Issues a list of commands. CommandList(Vec), /// Update the current element - UpdateSelf(Box), + UpdateSelf(Box), /// Update a element by a id - UpdateElementById(String, Box), + UpdateElementById(String, Box), /// Multiple Responses /// # DO NOT USE MANUALLY Mul(Vec), @@ -53,10 +53,10 @@ impl EventResponse { _ => {} } } - pub fn update_self(&mut self, elem: Box) { + pub fn update_self(&mut self, elem: Box) { self.add_response(Self::UpdateSelf(elem)); } - pub fn update_element_by_id(&mut self, id: &str, elem: Box) { + pub fn update_element_by_id(&mut self, id: &str, elem: Box) { self.add_response(Self::UpdateElementById(id.to_string(), elem)); } pub fn add_response(&mut self, response: EventResponse) { @@ -80,10 +80,11 @@ impl EventResponse { pub enum Event { Key(Key), State(usize), + Hover, } /// A handler is a function that runs on a event of a element -/// +/// /// # Params /// - &mut T: The element, /// - &mut EventResponse: The event response diff --git a/src/lib.rs b/src/lib.rs index 2f6cbe5..4b17ce9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,7 +57,7 @@ pub mod app { let (width, height) = get_term_size(); elem.update_data(width, height); let mut frame: Vec = create_frame(Value::Custom(width), Value::Custom(height)); - render_to_frame(state, &mut frame, elem); + render_to_frame(state, width, &mut frame, elem); clear(); print!("{}", frame.join("")); flush(); @@ -150,12 +150,12 @@ pub mod app { /// - `Default(usize)` - Uses a default value. /// - `Custom(usize)` - Allows specifying a custom value. #[derive(Debug, Clone, Copy)] -pub enum Value { +pub enum Value { Default(T), Custom(T), } -impl Value { +impl Value { /// Creates a new Value. /// /// # Returns @@ -191,7 +191,7 @@ impl Value { } } -pub trait ToValue { +pub trait ToValue { fn to_value(&self) -> Value; } @@ -254,13 +254,13 @@ clone_trait_object!(Element); /// Struct holding data relevant to an `Element`, including position and size. pub struct ElementData { /// X coordinate of the `Element`. - pub x: usize, + pub x: Value, /// Y coordinate of the `Element`. pub y: usize, /// Width of the `Element`, which can be default or custom. - pub width: crate::Value, + pub width: Value, /// Height of the `Element`, which can be default or custom. - pub height: crate::Value, + pub height: Value, /// Children of the `Element` pub children: Vec>, /// Active Child of the `Element` diff --git a/src/macros.rs b/src/macros.rs index 9fa3646..96d85c4 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -86,7 +86,7 @@ macro_rules! element { $(#[$meta])* #[derive(Clone)] pub struct $name<'a> { - pub x: usize, + pub x: Value, pub y: usize, pub width: Value, pub height: Value, @@ -150,7 +150,7 @@ macro_rules! element { pub fn new() -> $name<'a> { $name { children: Vec::new(), - x: 0, + x: Value::Default(0), y: 0, width: Value::Default(0), height: Value::Default(0), @@ -212,8 +212,13 @@ macro_rules! parse_rsx_param { ($elem:expr, $p:path) => { $p; }; + ($elem:expr, $($k:ident).+, $($rest:tt)*) => { + $elem.$($k).+; + osui::parse_rsx_param!($elem, $($rest)*); + }; ($elem:expr, $($k:ident).+., $($rest:tt)*) => { - $elem.$($k)+.; + $elem.$($k). + +.; osui::parse_rsx_param!($elem, $($rest)*); }; diff --git a/src/test/mod.rs b/src/test/mod.rs index 11cd08c..08b89f9 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -8,8 +8,7 @@ pub fn app() -> Box { response.update_element_by_id("my_id", rsx_elem! { text { id: "my_id", y: 2, "{something}" } }); - }), style.clicked_background: Color::Green, "click me" } - + }), style.clicked_background: Color::Green, style.hover_background: Color::Magenta, "click me" } text { id: "my_id", y: 2, "!" } } } diff --git a/src/ui/elements.rs b/src/ui/elements.rs index 1cd9080..3f79904 100644 --- a/src/ui/elements.rs +++ b/src/ui/elements.rs @@ -4,7 +4,7 @@ use std::{ }; use crate::{ - command, element, + command, create_frame, element, event::{Command, Event, Handler}, execute_response, key::Key, @@ -93,12 +93,12 @@ element! { } fn render(&self, state: usize) -> String { - let mut frame = crate::create_frame(self.width, self.height); + let mut frame = create_frame(self.width, self.height); for (i, child) in (&self.children).iter().enumerate() { if i==self.child { - render_to_frame(state, &mut frame, child); + render_to_frame(state, self.width.get_value(), &mut frame, child); } else { - render_to_frame(0, &mut frame, child); + render_to_frame(0, self.width.get_value(), &mut frame, child); } } frame.join("\n") @@ -110,8 +110,16 @@ element! { Event::Key(k) => { if let Some(direction) = self.keybinds.get(&k) { self.child = crate::closest_component(&self.children, self.child, direction.clone()); + if let Some(child) = self.get_child() { + child.event(Event::Hover); + } } else if let Some(child) = self.get_child() { - res = child.event(event.clone()); + res = child.event(event); + } + } + Event::Hover => { + if let Some(child) = self.get_child() { + res = child.event(event); } } _ => {} diff --git a/src/utils.rs b/src/utils.rs index eb3f8f1..657d382 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,4 @@ -use crate::Element; +use crate::{Element, Value}; use lazy_static::lazy_static; use regex::Regex; use std::{ @@ -53,6 +53,9 @@ fn merge_line(frame_: &str, line_: &str, x: usize) -> String { 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); @@ -63,9 +66,6 @@ fn merge_line(frame_: &str, line_: &str, x: usize) -> String { res.push(line[i - x]); } } else { - if let Some(v) = fm.get(&i) { - res.push_str(v); - } res.push(frame[i]); } } @@ -74,12 +74,30 @@ fn merge_line(frame_: &str, line_: &str, x: usize) -> String { } /// Render to a frame -pub fn render_to_frame(state: usize, frame: &mut Vec, element: &Box) { +pub fn render_to_frame( + state: usize, + width: usize, + frame: &mut Vec, + element: &Box, +) { let data = element.get_data(); for (i, line) in element.render(state).split('\n').enumerate() { if (data.y + i) < frame.len() { let frame_line = frame.get_mut(data.y + i).unwrap(); - *frame_line = merge_line(&frame_line, line, data.x); + match data.x { + Value::Custom(x) => { + *frame_line = merge_line(&frame_line, line, x); + } + _ => { + for (x, c) in frame_line.chars().rev().enumerate() { + if c != ' ' { + *frame_line = merge_line(&frame_line, line, width - x); + return; + } + } + *frame_line = merge_line(&frame_line, line, 0); + } + } } } } @@ -121,24 +139,43 @@ pub fn closest_component( components .iter() .enumerate() // Keep track of indices - .filter(|(_, comp_)| { + .filter(|(i, comp_)| { let comp = comp_.get_data(); match direction { - Direction::Left => comp.x < current.x && comp.y == current.y, // Left - Direction::Right => comp.x > current.x && comp.y == current.y, // Right - Direction::Up => comp.y < current.y && comp.x == current.x, // Up - Direction::Down => comp.y > current.y && comp.x == current.x, // Down + Direction::Left => match comp.x { + Value::Custom(_) => { + comp.x.get_value() < current.x.get_value() + && comp.y == current.y + } + Value::Default(_) => *i < current_index, + }, // Left + Direction::Right => match comp.x { + Value::Custom(_) => { + comp.x.get_value() > current.x.get_value() + && comp.y == current.y + } + Value::Default(_) => *i > current_index, + }, // Right + Direction::Up => { + comp.y < current.y + && comp.x.get_value() == current.x.get_value() + } // Up + Direction::Down => { + comp.y > current.y + && comp.x.get_value() == current.x.get_value() + } // Down } }) .min_by_key(|(_, comp_)| { let comp = comp_.get_data(); - current.x.abs_diff(comp.x) + current.y.abs_diff(comp.y) + current.x.get_value().abs_diff(comp.x.get_value()) + + current.y.abs_diff(comp.y) }) // Find the closest component .map(|(index, _)| index) // Return the index of the closest component .unwrap_or(current_index) // If no component is found, return the current index } -pub fn create_frame(width: crate::Value, height: crate::Value) -> Vec { +pub fn create_frame(width: Value, height: Value) -> Vec { vec![" ".repeat(width.get_value()); height.get_value()] }