some refractoring and dataholder

This commit is contained in:
2024-11-25 14:30:59 +01:00
parent f8fd990c67
commit 0266c26d34
7 changed files with 116 additions and 184 deletions
+1 -1
View File
@@ -22,6 +22,6 @@ crossterm = "0.28.1"
regex = "1.11.1" regex = "1.11.1"
lazy_static = "1.4" lazy_static = "1.4"
paste = "1.0.15" paste = "1.0.15"
osui-element = "0.1.8"
dyn-clone = "1.0.17" dyn-clone = "1.0.17"
flume = "=0.10.12" flume = "=0.10.12"
osui-element = "0.1.11"
+8 -17
View File
@@ -1,7 +1,4 @@
use crossterm::{ use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
event::Event,
terminal::{disable_raw_mode, enable_raw_mode},
};
use crate::prelude::*; use crate::prelude::*;
use crate::utils::{clear, flush, get_term_size, hide_cursor, show_cursor, Frame}; use crate::utils::{clear, flush, get_term_size, hide_cursor, show_cursor, Frame};
@@ -24,13 +21,6 @@ extern "C" {
fn c_run(args: *mut c_void) -> bool; fn c_run(args: *mut c_void) -> bool;
} }
fn event(element: &mut Element, event: Event, document: &Document) {
if let crossterm::event::Event::Resize(width, height) = event {
element.update_data(width as usize, height as usize);
}
element.event(event, document);
}
pub fn run(element: &mut Element) -> bool { pub fn run(element: &mut Element) -> bool {
hide_cursor(); hide_cursor();
enable_raw_mode().unwrap(); enable_raw_mode().unwrap();
@@ -67,16 +57,17 @@ extern "C" fn event_loop(ptr: *mut c_void) -> *const c_void {
}; };
let (width, height) = get_term_size(); let (width, height) = get_term_size();
args.element.update_data(width, height); args.element.event(
event( crossterm::event::Event::Resize(width as u16, height as u16),
args.element,
crossterm::event::Event::FocusGained,
&document, &document,
); );
args.element
.event(crossterm::event::Event::FocusGained, &document);
document.render(); document.render();
while args.running || !ptr.is_null() { while args.running || !ptr.is_null() {
event(args.element, crossterm::event::read().unwrap(), &document); args.element
.event(crossterm::event::read().unwrap(), &document);
document.render(); document.render();
} }
null() as *const c_void null() as *const c_void
@@ -100,7 +91,7 @@ extern "C" fn cmd_loop(ptr: *mut c_void) -> *const c_void {
args.rtx args.rtx
.send(if let Some(e) = args.element.get_element_by_id(&id) { .send(if let Some(e) = args.element.get_element_by_id(&id) {
crate::CommandResult::Element(e as *mut Element) crate::CommandResult::Element(e as *mut Element)
} else if args.element.get_data().2 == id { } else if args.element.get_id() == id {
crate::CommandResult::Element(args.element as *mut Element) crate::CommandResult::Element(args.element as *mut Element)
} else { } else {
crate::CommandResult::None crate::CommandResult::None
+10 -2
View File
@@ -3,8 +3,16 @@ use crate::prelude::*;
pub fn examples() -> Element { pub fn examples() -> Element {
rsx! { rsx! {
styling: Some(styling()), styling: Some(styling()),
if (2 == 2) { button { class: "btn", on_click: Handler::new(|btn: &mut Button, _, document| {
rsx_elem! { button { class: "btn", "Hello, World!" } } let data = document.get_element_by_id::<DataHolder<'_, String>>("my_data").unwrap();
data.data += "!";
btn.children.set_text(&data.data);
}), "Hello, World!" }
{
let mut data = dataholder::<String>();
data.id = "my_data";
data
} }
} }
} }
+13 -9
View File
@@ -42,8 +42,8 @@ pub mod prelude {
pub use crate::ui::Color::*; pub use crate::ui::Color::*;
pub use crate::ui::Number::*; pub use crate::ui::Number::*;
pub use crate::{self as osui, css, rsx, rsx_elem, ui::*, Handler}; pub use crate::{self as osui, css, rsx, rsx_elem, ui::*, Handler};
pub use crate::{call, Children, ElementCore, ElementWidget}; pub use crate::{call, Children, ElementCore, ElementWidget, Element};
pub use crate::{style, Command, Document, Element, Value}; pub use crate::{style, Command, Document, RenderResult, RenderWriter, Value};
pub use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind}; pub use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind};
pub fn sleep(ms: u64) { pub fn sleep(ms: u64) {
std::thread::sleep(std::time::Duration::from_millis(ms)); std::thread::sleep(std::time::Duration::from_millis(ms));
@@ -60,17 +60,14 @@ pub type Element = Box<dyn ElementWidget>;
/// Traits /// Traits
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
pub trait ElementCore: Send + Sync { pub trait ElementCore {
fn get_data(&self) -> (Value<usize>, usize, String);
fn update_data(&mut self, width: usize, height: usize);
fn get_element_by_id(&mut self, id: &str) -> Option<&mut Element>; fn get_element_by_id(&mut self, id: &str) -> Option<&mut Element>;
fn get_child(&mut self) -> Option<&mut Element>;
fn set_styling(&mut self, styling: &HashMap<crate::ui::StyleName, crate::ui::Style>); fn set_styling(&mut self, styling: &HashMap<crate::ui::StyleName, crate::ui::Style>);
fn get_id(&self) -> String;
} }
pub trait ElementWidget: ElementCore + std::fmt::Debug { pub trait ElementWidget: ElementCore + std::fmt::Debug + Send + Sync {
fn render(&self, focused: bool) -> RenderResult; fn render(&self, focused: bool) -> Option<RenderResult>;
fn event(&mut self, event: Event, document: &Document) { fn event(&mut self, event: Event, document: &Document) {
_ = (event, document) _ = (event, document)
} }
@@ -245,6 +242,13 @@ impl Children {
children.push(element); children.push(element);
} }
} }
pub fn get_child(&mut self) -> Option<&mut Element> {
if let Children::Children(children, child) = self {
children.get_mut(*child)
} else {
None
}
}
} }
impl<T> Handler<T> { impl<T> Handler<T> {
+2 -9
View File
@@ -9,13 +9,6 @@ macro_rules! parse_rsx_param {
} }
osui::parse_rsx_param!($elem, $($rest)*); osui::parse_rsx_param!($elem, $($rest)*);
}; };
($elem:expr, if ($($if:tt)*) $code:block $($rest:tt)*) => {
if $elem.children.is_none() {$elem.children = $crate::Children::Children(Vec::new(), 0)}
if let $crate::Children::Children(children, _) = &mut $elem.children {
if $($if)* {children.push($code)}
}
osui::parse_rsx_param!($elem, $($rest)*);
};
($elem:expr, $($k:ident).+: $v:expr) => { ($elem:expr, $($k:ident).+: $v:expr) => {
$elem.$($k).+ = $v; $elem.$($k).+ = $v;
@@ -46,10 +39,10 @@ macro_rules! parse_rsx_param {
osui::parse_rsx_param!($elem, $($rest)*); osui::parse_rsx_param!($elem, $($rest)*);
}; };
($elem:expr, {$inner_elem:expr} $($rest:tt)*) => { ($elem:expr, $code:block $($rest:tt)*) => {
if $elem.children.is_none() {$elem.children = $crate::Children::Children(Vec::new(), 0)} if $elem.children.is_none() {$elem.children = $crate::Children::Children(Vec::new(), 0)}
if let $crate::Children::Children(children, _) = &mut $elem.children { if let $crate::Children::Children(children, _) = &mut $elem.children {
children.push({$inner_elem}); children.push($code);
} }
osui::parse_rsx_param!($elem, $($rest)*); osui::parse_rsx_param!($elem, $($rest)*);
}; };
+32 -49
View File
@@ -3,9 +3,10 @@
/// # Modules /// # Modules
/// - `styles`: A module for defining UI styles. /// - `styles`: A module for defining UI styles.
pub mod styles; pub mod styles;
pub use styles::*; pub use styles::*;
use crate::{prelude::*, RenderResult, RenderWriter}; use crate::prelude::*;
use osui_element::{elem_fn, element}; use osui_element::{elem_fn, element};
/// The `Text` element represents a piece of static text in the terminal UI. /// The `Text` element represents a piece of static text in the terminal UI.
@@ -31,7 +32,7 @@ pub struct Text {
} }
impl ElementWidget for Text<'_> { impl ElementWidget for Text<'_> {
fn render(&self, focused: bool) -> RenderResult { fn render(&self, focused: bool) -> Option<RenderResult> {
let mut writer = RenderWriter::new(focused, self.style.clone()); let mut writer = RenderWriter::new(focused, self.style.clone());
writer.write(&{ writer.write(&{
@@ -42,7 +43,7 @@ impl ElementWidget for Text<'_> {
} }
}); });
writer.result() Some(writer.result())
} }
fn event(&mut self, event: Event, document: &Document) { fn event(&mut self, event: Event, document: &Document) {
call!(self.on_event(event, document)); call!(self.on_event(event, document));
@@ -77,7 +78,7 @@ pub struct Div {
} }
impl ElementWidget for Div<'_> { impl ElementWidget for Div<'_> {
fn render(&self, focused: bool) -> RenderResult { fn render(&self, focused: bool) -> Option<RenderResult> {
let mut writer = RenderWriter::new(focused, self.style.clone()); let mut writer = RenderWriter::new(focused, self.style.clone());
let mut frame = crate::utils::Frame::new(crate::utils::get_term_size().0, 12); let mut frame = crate::utils::Frame::new(crate::utils::get_term_size().0, 12);
@@ -88,7 +89,7 @@ impl ElementWidget for Div<'_> {
} }
writer.write(&frame.output()); writer.write(&frame.output());
writer.result() Some(writer.result())
} }
fn event(&mut self, event: Event, document: &Document) { fn event(&mut self, event: Event, document: &Document) {
@@ -97,48 +98,8 @@ impl ElementWidget for Div<'_> {
self.set_styling(&styling); self.set_styling(&styling);
} }
} }
match event { if let Some(child) = self.children.get_child() {
Event::Key(key) => { child.event(event, document);
if let Children::Children(children, child) = &mut self.children {
*child = match key.code {
KeyCode::Up => crate::utils::closest_component(
children,
*child,
crate::utils::Direction::Up,
),
KeyCode::Down => crate::utils::closest_component(
children,
*child,
crate::utils::Direction::Down,
),
KeyCode::Left => crate::utils::closest_component(
children,
*child,
crate::utils::Direction::Left,
),
KeyCode::Right => crate::utils::closest_component(
children,
*child,
crate::utils::Direction::Right,
),
_ => {
if let Some(c) = children.get_mut(*child) {
c.event(event, document);
}
*child
}
}
}
}
_ => {
if let Some(child) = self.get_child() {
child.event(event, document);
}
}
} }
} }
} }
@@ -151,10 +112,10 @@ pub struct Button {
} }
impl ElementWidget for Button<'_> { impl ElementWidget for Button<'_> {
fn render(&self, focused: bool) -> RenderResult { fn render(&self, focused: bool) -> Option<RenderResult> {
let mut writer = RenderWriter::new(focused, self.style.clone()); let mut writer = RenderWriter::new(focused, self.style.clone());
writer.write(&self.children.get_text()); writer.write(&self.children.get_text());
writer.result() Some(writer.result())
} }
fn event(&mut self, event: Event, document: &Document) { fn event(&mut self, event: Event, document: &Document) {
@@ -173,3 +134,25 @@ impl ElementWidget for Button<'_> {
} }
} }
} }
#[element]
#[derive(Debug)]
pub struct DataHolder<'a, T> {
pub data: T,
}
pub fn dataholder<'a, T: std::default::Default>() -> Box<DataHolder<'a, T>> {
Box::new(DataHolder {
style: Style::default(),
data: T::default(),
children: Children::None,
class: "",
id: "",
})
}
impl<'a, T: std::fmt::Debug + Send + Sync> ElementWidget for DataHolder<'a, T> {
fn render(&self, _: bool) -> Option<RenderResult> {
None
}
}
+50 -97
View File
@@ -9,7 +9,7 @@
/// let frame = create_frame(50, 10); /// let frame = create_frame(50, 10);
/// render_to_frame(crate::State::Normal, 50, &mut frame, &text_element); /// render_to_frame(crate::State::Normal, 50, &mut frame, &text_element);
/// ``` /// ```
use crate::{Element, Value}; use crate::Element;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex; use regex::Regex;
use std::{ use std::{
@@ -99,60 +99,60 @@ impl Frame {
} }
} }
pub fn render(&mut self, focused: bool, element: &Element) { pub fn render(&mut self, focused: bool, element: &Element) {
// let data = element.get_data(); if let Some(output) = element.render(focused) {
let output = element.render(focused); let x;
let x; let mut y = 0;
let mut y = 0; match output.1.y {
match output.1.y { crate::ui::Number::Px(_y) => {
crate::ui::Number::Px(_y) => { y = _y;
y = _y; }
} crate::ui::Number::Pe(p) => y = (self.frame.len() * p) / 100,
crate::ui::Number::Pe(p) => y = (self.frame.len() * p) / 100, crate::ui::Number::Center => {
crate::ui::Number::Center => { y = (self.frame.len() - output.0.matches('\n').count() + 1) / 2
y = (self.frame.len() - output.0.matches('\n').count() + 1) / 2 }
} crate::ui::Number::Auto => {
crate::ui::Number::Auto => { for (i, n) in self.used.iter().enumerate() {
for (i, n) in self.used.iter().enumerate() { if *n == 0 {
if *n == 0 { y = i;
y = i; break;
break; }
}
}
crate::ui::Number::Default => {
for (i, n) in self.used.iter().enumerate() {
if *n == 0 {
y = i;
break;
}
} }
} }
} }
crate::ui::Number::Default => { match output.1.x {
for (i, n) in self.used.iter().enumerate() { crate::ui::Number::Px(_x) => {
if *n == 0 { x = _x;
y = i; }
break; crate::ui::Number::Pe(p) => x = (self.width * p) / 100,
} crate::ui::Number::Center => {
x = (self.width
- ANSI
.replace_all(&output.0.lines().next().unwrap_or(""), "")
.len())
/ 2;
}
crate::ui::Number::Auto => {
x = *self.used.get(y).unwrap();
}
crate::ui::Number::Default => {
x = 0;
} }
} }
} for (i, line) in output.0.split('\n').enumerate() {
match output.1.x { if self.frame.len() > y + i {
crate::ui::Number::Px(_x) => { let frame_line = self.frame.get_mut(y + i).unwrap();
x = _x; let merged = merge_line(&frame_line, line, x);
} *frame_line = merged.0;
crate::ui::Number::Pe(p) => x = (self.width * p) / 100, *self.used.get_mut(y + i).unwrap() += merged.1.len() - 1;
crate::ui::Number::Center => { }
x = (self.width
- ANSI
.replace_all(&output.0.lines().next().unwrap_or(""), "")
.len())
/ 2;
}
crate::ui::Number::Auto => {
x = *self.used.get(y).unwrap();
}
crate::ui::Number::Default => {
x = 0;
}
}
for (i, line) in output.0.split('\n').enumerate() {
if self.frame.len() > y + i {
let frame_line = self.frame.get_mut(y + i).unwrap();
let merged = merge_line(&frame_line, line, x);
*frame_line = merged.0;
*self.used.get_mut(y + i).unwrap() += merged.1.len() - 1;
} }
} }
} }
@@ -183,53 +183,6 @@ pub fn flush() {
stdout().flush().unwrap(); stdout().flush().unwrap();
} }
#[derive(Debug, Clone)]
pub enum Direction {
Left,
Right,
Up,
Down,
}
pub fn closest_component(
components: &[Element],
current_index: usize,
direction: Direction,
) -> usize {
let current = &components[current_index].get_data();
components
.iter()
.enumerate()
.filter(|(i, comp_)| {
let comp = comp_.get_data();
match direction {
Direction::Left => match comp.0 {
Value::Custom(_) => {
comp.0.get_value() < current.0.get_value() && comp.1 == current.1
}
Value::Default(_) => *i < current_index,
}, // Left
Direction::Right => match comp.0 {
Value::Custom(_) => {
comp.0.get_value() > current.0.get_value() && comp.1 == current.1
}
Value::Default(_) => *i > current_index,
}, // Right
Direction::Up => comp.1 < current.1 && comp.0.get_value() == current.0.get_value(), // Up
Direction::Down => {
comp.1 > current.1 && comp.0.get_value() == current.0.get_value()
} // Down
}
})
.min_by_key(|(_, comp_)| {
let comp = comp_.get_data();
current.0.get_value().abs_diff(comp.0.get_value()) + current.1.abs_diff(comp.1)
}) // 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 get_term_size() -> (usize, usize) { pub fn get_term_size() -> (usize, usize) {
let (width, height) = crossterm::terminal::size().unwrap(); let (width, height) = crossterm::terminal::size().unwrap();
(width as usize, height as usize) (width as usize, height as usize)