hover event and x position wrapper (optional)

This commit is contained in:
2024-11-08 22:01:24 +01:00
parent 6d5abf2774
commit 9a87853042
6 changed files with 86 additions and 36 deletions
+7 -6
View File
@@ -1,4 +1,4 @@
use crate::key::Key; use crate::{key::Key, Element};
/// Enum defining commands that can be issued by an `Element`. /// Enum defining commands that can be issued by an `Element`.
#[derive(Clone)] #[derive(Clone)]
@@ -24,9 +24,9 @@ pub enum EventResponse {
/// Issues a list of commands. /// Issues a list of commands.
CommandList(Vec<Command>), CommandList(Vec<Command>),
/// Update the current element /// Update the current element
UpdateSelf(Box<dyn crate::Element>), UpdateSelf(Box<dyn Element>),
/// Update a element by a id /// Update a element by a id
UpdateElementById(String, Box<dyn crate::Element>), UpdateElementById(String, Box<dyn Element>),
/// Multiple Responses /// Multiple Responses
/// # DO NOT USE MANUALLY /// # DO NOT USE MANUALLY
Mul(Vec<EventResponse>), Mul(Vec<EventResponse>),
@@ -53,10 +53,10 @@ impl EventResponse {
_ => {} _ => {}
} }
} }
pub fn update_self(&mut self, elem: Box<dyn crate::Element>) { pub fn update_self(&mut self, elem: Box<dyn Element>) {
self.add_response(Self::UpdateSelf(elem)); self.add_response(Self::UpdateSelf(elem));
} }
pub fn update_element_by_id(&mut self, id: &str, elem: Box<dyn crate::Element>) { pub fn update_element_by_id(&mut self, id: &str, elem: Box<dyn Element>) {
self.add_response(Self::UpdateElementById(id.to_string(), elem)); self.add_response(Self::UpdateElementById(id.to_string(), elem));
} }
pub fn add_response(&mut self, response: EventResponse) { pub fn add_response(&mut self, response: EventResponse) {
@@ -80,10 +80,11 @@ impl EventResponse {
pub enum Event { pub enum Event {
Key(Key), Key(Key),
State(usize), State(usize),
Hover,
} }
/// A handler is a function that runs on a event of a element /// A handler is a function that runs on a event of a element
/// ///
/// # Params /// # Params
/// - &mut T: The element, /// - &mut T: The element,
/// - &mut EventResponse: The event response /// - &mut EventResponse: The event response
+7 -7
View File
@@ -57,7 +57,7 @@ pub mod app {
let (width, height) = get_term_size(); let (width, height) = get_term_size();
elem.update_data(width, height); elem.update_data(width, height);
let mut frame: Vec<String> = create_frame(Value::Custom(width), Value::Custom(height)); let mut frame: Vec<String> = create_frame(Value::Custom(width), Value::Custom(height));
render_to_frame(state, &mut frame, elem); render_to_frame(state, width, &mut frame, elem);
clear(); clear();
print!("{}", frame.join("")); print!("{}", frame.join(""));
flush(); flush();
@@ -150,12 +150,12 @@ pub mod app {
/// - `Default(usize)` - Uses a default value. /// - `Default(usize)` - Uses a default value.
/// - `Custom(usize)` - Allows specifying a custom value. /// - `Custom(usize)` - Allows specifying a custom value.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Value<T: Copy> { pub enum Value<T: Copy + PartialEq> {
Default(T), Default(T),
Custom(T), Custom(T),
} }
impl<T: Copy> Value<T> { impl<T: Copy + PartialEq> Value<T> {
/// Creates a new Value. /// Creates a new Value.
/// ///
/// # Returns /// # Returns
@@ -191,7 +191,7 @@ impl<T: Copy> Value<T> {
} }
} }
pub trait ToValue<T: Copy> { pub trait ToValue<T: Copy + PartialEq> {
fn to_value(&self) -> Value<T>; fn to_value(&self) -> Value<T>;
} }
@@ -254,13 +254,13 @@ clone_trait_object!(Element);
/// Struct holding data relevant to an `Element`, including position and size. /// Struct holding data relevant to an `Element`, including position and size.
pub struct ElementData { pub struct ElementData {
/// X coordinate of the `Element`. /// X coordinate of the `Element`.
pub x: usize, pub x: Value<usize>,
/// Y coordinate of the `Element`. /// Y coordinate of the `Element`.
pub y: usize, pub y: usize,
/// Width of the `Element`, which can be default or custom. /// Width of the `Element`, which can be default or custom.
pub width: crate::Value<usize>, pub width: Value<usize>,
/// Height of the `Element`, which can be default or custom. /// Height of the `Element`, which can be default or custom.
pub height: crate::Value<usize>, pub height: Value<usize>,
/// Children of the `Element` /// Children of the `Element`
pub children: Vec<Box<dyn Element>>, pub children: Vec<Box<dyn Element>>,
/// Active Child of the `Element` /// Active Child of the `Element`
+8 -3
View File
@@ -86,7 +86,7 @@ macro_rules! element {
$(#[$meta])* $(#[$meta])*
#[derive(Clone)] #[derive(Clone)]
pub struct $name<'a> { pub struct $name<'a> {
pub x: usize, pub x: Value<usize>,
pub y: usize, pub y: usize,
pub width: Value<usize>, pub width: Value<usize>,
pub height: Value<usize>, pub height: Value<usize>,
@@ -150,7 +150,7 @@ macro_rules! element {
pub fn new() -> $name<'a> { pub fn new() -> $name<'a> {
$name { $name {
children: Vec::new(), children: Vec::new(),
x: 0, x: Value::Default(0),
y: 0, y: 0,
width: Value::Default(0), width: Value::Default(0),
height: Value::Default(0), height: Value::Default(0),
@@ -212,8 +212,13 @@ macro_rules! parse_rsx_param {
($elem:expr, $p:path) => { ($elem:expr, $p:path) => {
$p; $p;
}; };
($elem:expr, $($k:ident).+, $($rest:tt)*) => {
$elem.$($k).+;
osui::parse_rsx_param!($elem, $($rest)*);
};
($elem:expr, $($k:ident).+., $($rest:tt)*) => { ($elem:expr, $($k:ident).+., $($rest:tt)*) => {
$elem.$($k)+.; $elem.$($k).
+.;
osui::parse_rsx_param!($elem, $($rest)*); osui::parse_rsx_param!($elem, $($rest)*);
}; };
+1 -2
View File
@@ -8,8 +8,7 @@ pub fn app() -> Box<dyn Element> {
response.update_element_by_id("my_id", rsx_elem! { response.update_element_by_id("my_id", rsx_elem! {
text { id: "my_id", y: 2, "{something}" } 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, "!" } text { id: "my_id", y: 2, "!" }
} }
} }
+13 -5
View File
@@ -4,7 +4,7 @@ use std::{
}; };
use crate::{ use crate::{
command, element, command, create_frame, element,
event::{Command, Event, Handler}, event::{Command, Event, Handler},
execute_response, execute_response,
key::Key, key::Key,
@@ -93,12 +93,12 @@ element! {
} }
fn render(&self, state: usize) -> String { 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() { for (i, child) in (&self.children).iter().enumerate() {
if i==self.child { if i==self.child {
render_to_frame(state, &mut frame, child); render_to_frame(state, self.width.get_value(), &mut frame, child);
} else { } else {
render_to_frame(0, &mut frame, child); render_to_frame(0, self.width.get_value(), &mut frame, child);
} }
} }
frame.join("\n") frame.join("\n")
@@ -110,8 +110,16 @@ element! {
Event::Key(k) => { Event::Key(k) => {
if let Some(direction) = self.keybinds.get(&k) { if let Some(direction) = self.keybinds.get(&k) {
self.child = crate::closest_component(&self.children, self.child, direction.clone()); 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() { } 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);
} }
} }
_ => {} _ => {}
+50 -13
View File
@@ -1,4 +1,4 @@
use crate::Element; use crate::{Element, Value};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex; use regex::Regex;
use std::{ use std::{
@@ -53,6 +53,9 @@ fn merge_line(frame_: &str, line_: &str, x: usize) -> String {
let llen = line.len(); let llen = line.len();
for i in 0..flen { 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 i >= x && i - x < llen && line[i - x] != '\t' {
if let Some(v) = lm.get(&(i - x)) { if let Some(v) = lm.get(&(i - x)) {
res.push_str(v); res.push_str(v);
@@ -63,9 +66,6 @@ fn merge_line(frame_: &str, line_: &str, x: usize) -> String {
res.push(line[i - x]); res.push(line[i - x]);
} }
} else { } else {
if let Some(v) = fm.get(&i) {
res.push_str(v);
}
res.push(frame[i]); res.push(frame[i]);
} }
} }
@@ -74,12 +74,30 @@ fn merge_line(frame_: &str, line_: &str, x: usize) -> String {
} }
/// Render to a frame /// Render to a frame
pub fn render_to_frame(state: usize, frame: &mut Vec<String>, element: &Box<dyn Element>) { pub fn render_to_frame(
state: usize,
width: usize,
frame: &mut Vec<String>,
element: &Box<dyn Element>,
) {
let data = element.get_data(); let data = element.get_data();
for (i, line) in element.render(state).split('\n').enumerate() { for (i, line) in element.render(state).split('\n').enumerate() {
if (data.y + i) < frame.len() { if (data.y + i) < frame.len() {
let frame_line = frame.get_mut(data.y + i).unwrap(); 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 components
.iter() .iter()
.enumerate() // Keep track of indices .enumerate() // Keep track of indices
.filter(|(_, comp_)| { .filter(|(i, comp_)| {
let comp = comp_.get_data(); let comp = comp_.get_data();
match direction { match direction {
Direction::Left => comp.x < current.x && comp.y == current.y, // Left Direction::Left => match comp.x {
Direction::Right => comp.x > current.x && comp.y == current.y, // Right Value::Custom(_) => {
Direction::Up => comp.y < current.y && comp.x == current.x, // Up comp.x.get_value() < current.x.get_value()
Direction::Down => comp.y > current.y && comp.x == current.x, // Down && 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_)| { .min_by_key(|(_, comp_)| {
let comp = comp_.get_data(); 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 }) // Find the closest component
.map(|(index, _)| index) // Return the index of 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 .unwrap_or(current_index) // If no component is found, return the current index
} }
pub fn create_frame(width: crate::Value<usize>, height: crate::Value<usize>) -> Vec<String> { pub fn create_frame(width: Value<usize>, height: Value<usize>) -> Vec<String> {
vec![" ".repeat(width.get_value()); height.get_value()] vec![" ".repeat(width.get_value()); height.get_value()]
} }