hover event and x position wrapper (optional)
This commit is contained in:
+7
-6
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user