some refractoring

This commit is contained in:
2024-11-25 03:10:28 +01:00
parent 33843688d8
commit f8fd990c67
9 changed files with 370 additions and 343 deletions
+151 -127
View File
@@ -38,16 +38,12 @@ pub mod utils;
pub use app::run;
/// The `prelude` module provides commonly used imports and macros to simplify the development
/// of UI elements. It re-exports commonly used traits, structs, and utility functions to make
/// the UI framework easier to use.
pub mod prelude {
pub use crate::ui::Color::*;
pub use crate::ui::Number::*;
pub use crate::{self as osui, css, rsx, rsx_elem, ui::*, Handler};
pub use crate::{style, Command, Document, Element, Value};
// useful for Element making
pub use crate::{call, Children, ElementCore, ElementWidget};
pub use crate::{style, Command, Document, Element, Value};
pub use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind};
pub fn sleep(ms: u64) {
std::thread::sleep(std::time::Duration::from_millis(ms));
@@ -55,7 +51,54 @@ pub mod prelude {
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/// Value Enum
// Type aliases
//////////////////////////////////////////////////////////////////////////////////////////////////
pub type Element = Box<dyn ElementWidget>;
//////////////////////////////////////////////////////////////////////////////////////////////////
/// Traits
//////////////////////////////////////////////////////////////////////////////////////////////////
pub trait ElementCore: Send + Sync {
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_child(&mut self) -> Option<&mut Element>;
fn set_styling(&mut self, styling: &HashMap<crate::ui::StyleName, crate::ui::Style>);
}
pub trait ElementWidget: ElementCore + std::fmt::Debug {
fn render(&self, focused: bool) -> RenderResult;
fn event(&mut self, event: Event, document: &Document) {
_ = (event, document)
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/// Structs
//////////////////////////////////////////////////////////////////////////////////////////////////
pub struct Handler<T>(pub Arc<Mutex<dyn FnMut(&mut T, Event, &Document) + Send + Sync>>);
pub struct Document {
cmd_sender: std::sync::mpsc::Sender<Command>,
cmd_recv: *const std::ffi::c_void,
}
/// ```
/// RenderResult(output, (x, y))
/// ```
pub struct RenderResult(String, ui::StyleElement);
pub struct RenderWriter {
w: String,
style: ui::Style,
focused: bool,
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/// Enums
//////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Debug, Clone, Copy)]
@@ -64,6 +107,48 @@ pub enum Value<T: Copy + PartialEq> {
Custom(T),
}
/// Child enum of an `Element`
///
/// # Example
/// ```
/// // Check if it's text
/// if let Children::Text(text) {
/// // do something
/// }
/// // Check if it's inner elements
/// if let Children::Children(text) {
/// // do something
/// }
/// // recommended: use get_text
/// children.get_text() // returns a empty string if it's not text
/// ```
///
/// # Useful for
/// - `Element::event`
/// - `Element::render`
/// - `Handler`
#[derive(Debug)]
pub enum Children {
None,
Text(String),
Children(Vec<Element>, usize),
}
pub enum Command {
Exit,
Render,
GetElementById(String),
}
pub enum CommandResult {
Element(*mut Element),
None,
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/// Implementations
//////////////////////////////////////////////////////////////////////////////////////////////////
impl<T: Copy + PartialEq> Value<T> {
pub fn get_value(&self) -> T {
match self {
@@ -85,89 +170,33 @@ impl<T: Copy + PartialEq + Default> Default for Value<T> {
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/// ElementCore Traits
//////////////////////////////////////////////////////////////////////////////////////////////////
/// ```
/// RenderResult(output, (x, y), (width, height))
/// ```
pub struct RenderResult(String, (ui::Number, ui::Number));
pub trait ElementCore: Send + Sync {
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_child(&mut self) -> Option<&mut Element>;
fn set_styling(&mut self, styling: &HashMap<crate::ui::StyleName, crate::ui::Style>);
}
pub trait ElementWidget: ElementCore + std::fmt::Debug {
fn render(&self, focused: bool) -> RenderResult;
fn event(&mut self, event: Event, document: &Document) {
_ = (event, document)
impl Document {
pub fn exit(&self) {
self.cmd_sender.send(Command::Exit).unwrap();
}
}
pub type Element = Box<dyn ElementWidget>;
//////////////////////////////////////////////////////////////////////////////////////////////////
/// Handler Struct
//////////////////////////////////////////////////////////////////////////////////////////////////
pub struct Handler<T>(pub Arc<Mutex<dyn FnMut(&mut T, Event, &Document) + Send + Sync>>);
impl<T> Handler<T> {
pub fn new<F>(handler_fn: F) -> Handler<T>
where
F: FnMut(&mut T, Event, &Document) + 'static + Send + Sync,
{
Handler(Arc::new(Mutex::new(handler_fn)))
pub fn get_element_by_id<T>(&self, id: &str) -> Option<&mut Box<T>> {
if let Some(e) = self.get_element_by_id_raw(id) {
Some(convert(unsafe { &mut *e }))
} else {
None
}
}
}
impl<T> Default for Handler<T> {
fn default() -> Self {
Handler(Arc::new(Mutex::new(|_: &mut T, _: Event, _: &Document| {})))
pub fn get_element_by_id_raw(&self, id: &str) -> Option<*mut Element> {
self.cmd_sender
.send(Command::GetElementById(id.to_string()))
.unwrap();
let rx = unsafe { &*(self.cmd_recv as *const std::sync::mpsc::Receiver<CommandResult>) };
if let Ok(CommandResult::Element(e)) = rx.recv() {
Some(e)
} else {
None
}
}
}
impl<T> std::fmt::Debug for Handler<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Handler()")
pub fn render(&self) {
self.cmd_sender.send(Command::Render).unwrap();
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/// Children Enum
//////////////////////////////////////////////////////////////////////////////////////////////////
/// Child enum of an `Element`
///
/// # Example
/// ```
/// // Check if it's text
/// if let Children::Text(text) {
/// // do something
/// }
/// // Check if it's inner elements
/// if let Children::Children(text) {
/// // do something
/// }
/// ```
///
/// # Useful for
/// - `Element::event`
/// - `Element::render`
/// - `Handler`
#[derive(Debug)]
pub enum Children {
None,
Text(String),
Children(Vec<Element>, usize),
}
impl Default for Children {
fn default() -> Self {
Self::None
@@ -218,50 +247,45 @@ impl Children {
}
}
/// Converts a `Element` into the struct
impl<T> Handler<T> {
pub fn new<F>(handler_fn: F) -> Handler<T>
where
F: FnMut(&mut T, Event, &Document) + 'static + Send + Sync,
{
Handler(Arc::new(Mutex::new(handler_fn)))
}
}
impl RenderWriter {
pub fn new(focused: bool, style: ui::Style) -> RenderWriter {
RenderWriter {
w: String::new(),
style,
focused,
}
}
pub fn write(&mut self, s: &str) {
self.w += self.style.get(self.focused).write(s).as_str();
}
pub fn result(&self) -> RenderResult {
RenderResult(self.w.clone(), self.style.get(self.focused).clone())
}
}
impl<T> Default for Handler<T> {
fn default() -> Self {
Handler(Arc::new(Mutex::new(|_: &mut T, _: Event, _: &Document| {})))
}
}
impl<T> std::fmt::Debug for Handler<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Handler()")
}
}
pub fn convert<T>(widget: &mut Box<dyn ElementWidget>) -> &mut Box<T> {
unsafe { &mut *(widget as *mut _ as *mut Box<T>) }
}
pub enum Command {
Exit,
Render,
GetElementById(String),
}
pub enum CommandResult {
Element(*mut Element),
None,
}
pub struct Document {
cmd_sender: std::sync::mpsc::Sender<Command>,
cmd_recv: *const std::ffi::c_void,
}
impl Document {
pub fn exit(&self) {
self.cmd_sender.send(Command::Exit).unwrap();
}
pub fn get_element_by_id<T>(&self, id: &str) -> Option<&mut Box<T>> {
if let Some(e) = self.get_element_by_id_raw(id) {
Some(convert(unsafe { &mut *e }))
} else {
None
}
}
pub fn get_element_by_id_raw(&self, id: &str) -> Option<*mut Element> {
self.cmd_sender
.send(Command::GetElementById(id.to_string()))
.unwrap();
let rx = unsafe { &*(self.cmd_recv as *const std::sync::mpsc::Receiver<CommandResult>) };
if let Ok(CommandResult::Element(e)) = rx.recv() {
Some(e)
} else {
None
}
}
pub fn render(&self) {
self.cmd_sender.send(Command::Render).unwrap();
}
}