some refractoring and dataholder
This commit is contained in:
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)*);
|
||||||
};
|
};
|
||||||
|
|||||||
+31
-48
@@ -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,51 +98,11 @@ 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) => {
|
|
||||||
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);
|
child.event(event, document);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[element]
|
#[element]
|
||||||
#[elem_fn]
|
#[elem_fn]
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+3
-50
@@ -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,8 +99,7 @@ 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 {
|
||||||
@@ -156,6 +155,7 @@ impl Frame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pub fn output(&self) -> String {
|
pub fn output(&self) -> String {
|
||||||
self.frame.join("\n")
|
self.frame.join("\n")
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user