From d30da4dfe1d054a1de4c9f0aad803e8bb4c1b49a Mon Sep 17 00:00:00 2001 From: Leo dev Date: Tue, 4 Feb 2025 23:39:18 +0100 Subject: [PATCH] changed framing --- src/elements.rs | 13 ---- src/frame.rs | 147 ++++++++++++++++++++++++++++++++++++ src/lib.rs | 196 ++++++++---------------------------------------- src/main.rs | 29 ++++--- src/state.rs | 4 + src/utils.rs | 8 +- 6 files changed, 203 insertions(+), 194 deletions(-) delete mode 100644 src/elements.rs create mode 100644 src/frame.rs diff --git a/src/elements.rs b/src/elements.rs deleted file mode 100644 index b832081..0000000 --- a/src/elements.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::Element; - -impl Element for &str { - fn render(&self, frame: &mut String) { - *frame += self; - } -} - -impl Element for String { - fn render(&self, frame: &mut String) { - *frame += self; - } -} diff --git a/src/frame.rs b/src/frame.rs new file mode 100644 index 0000000..6dfe945 --- /dev/null +++ b/src/frame.rs @@ -0,0 +1,147 @@ +use crossterm::event::Event; + +use crate::style; + +// Structs +#[derive(Debug, Clone)] +pub struct Area { + pub x: u16, + pub y: u16, + pub width: u16, + pub height: u16, +} + +pub struct Frame { + pub area: Area, + pub event: Option, +} + +impl Frame { + pub fn new(area: Area) -> Frame { + Frame { area, event: None } + } + + pub fn draw(&self, c: &mut crate::Component, props: Props) { + let (width, height) = ( + props.width.get(0, self.area.width), + props.height.get(0, self.area.height), + ); + + let (x, y) = ( + props.x.get(0, self.area.width), + props.y.get(0, self.area.height), + ); + + let mut frame = Frame::new(Area { + x, + y, + width, + height, + }); + + c(&mut frame) + } + + pub fn draw_str(&self, s: &str, props: Props) { + let (written_width, written_height) = crate::utils::str_size(s); + + let (width, height) = ( + props.width.get_root(written_width, self.area.width), + props.height.get_root(written_height, self.area.height), + ); + + let (x, y) = ( + props.x.get(width, self.area.width), + props.y.get(height, self.area.height), + ); + + for (i, line) in s.lines().enumerate() { + println!( + "\x1b[{};{}H{}\x1b[0m", + (y + self.area.y + 1) as usize + i, + x + self.area.x + 1, + line, + ); + } + } +} + +#[derive(Debug, Clone)] +pub struct Props { + x: style::Position, + y: style::Position, + width: style::Dimension, + height: style::Dimension, +} + +impl Props { + pub fn new(x: u16, y: u16) -> Self { + Self { + x: style::Position::Num(x), + y: style::Position::Num(y), + width: style::Dimension::Auto, + height: style::Dimension::Auto, + } + } + + pub fn auto() -> Self { + Self::new(0, 0) + } + + pub fn center() -> Self { + Self { + x: style::Position::Center, + y: style::Position::Center, + width: style::Dimension::Auto, + height: style::Dimension::Auto, + } + } + + pub fn center_horizontal() -> Self { + Self { + x: style::Position::Center, + y: style::Position::Num(0), + width: style::Dimension::Auto, + height: style::Dimension::Auto, + } + } + + pub fn center_vertical() -> Self { + Self { + x: style::Position::Num(0), + y: style::Position::Center, + width: style::Dimension::Auto, + height: style::Dimension::Auto, + } + } + + pub fn x_percent(&mut self, p: u16) -> Self { + self.x = style::Position::Percent(p); + self.clone() + } + + pub fn y_percent(&mut self, p: u16) -> Self { + self.y = style::Position::Percent(p); + self.clone() + } + + pub fn width(&mut self, w: u16) -> Self { + self.width = style::Dimension::Num(w); + self.clone() + } + + pub fn height(&mut self, h: u16) -> Self { + self.height = style::Dimension::Num(h); + self.clone() + } + + pub fn width_percent(&mut self, w: u16) -> Self { + self.width = style::Dimension::Percent(w); + self.clone() + } + + pub fn height_percent(&mut self, h: u16) -> Self { + self.height = style::Dimension::Percent(h); + self.clone() + } +} diff --git a/src/lib.rs b/src/lib.rs index eb5f044..4379d6f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,153 +1,66 @@ -pub mod elements; +pub mod frame; #[cfg(feature = "state")] pub mod state; pub mod style; pub mod utils; +use crossterm::event::Event; +use frame::{Area, Frame}; pub use std::io::Result; pub mod prelude { pub use crate::{ + frame::{Frame, Props}, func, - state::State, style::{Color, Style}, utils::init, - Props, Result, Ui, + Component, Result, }; #[cfg(feature = "state")] - pub use crate::state::use_state; + pub use crate::state::{default_state, use_state, State}; - pub use crossterm::event::read; -} - -pub trait Element { - fn render(&self, frame: &mut String); - fn event(&self, event: crossterm::event::Event) { - _ = event - } + pub use crossterm::event::{read, Event, KeyCode, KeyEvent, KeyEventKind}; } // Types pub type Handler = std::sync::Arc>; -pub type Ui = Box; +pub type Component = Box; // Structs -pub struct Frame(Vec<(Box, Props)>); - -#[derive(Debug, Clone)] -pub struct Props { - x: style::Position, - y: style::Position, - width: style::Dimension, - height: style::Dimension, - style: style::Style, -} /// Represents the console state, containing a frame for rendering and a mouse capture flag. pub struct Console { mouse: bool, - width: u16, - height: u16, - pub mouse_position: Option<(u16, u16)>, -} - -impl Frame { - pub fn draw(&mut self, element: Box, props: Props) { - self.0.push((element, props)); - } -} - -impl Props { - pub fn new(x: u16, y: u16) -> Self { - Self { - x: style::Position::Num(x), - y: style::Position::Num(y), - width: style::Dimension::Auto, - height: style::Dimension::Auto, - style: style::Style::default(), - } - } - - pub fn auto() -> Self { - Self::new(0, 0) - } - - pub fn center() -> Self { - Self { - x: style::Position::Center, - y: style::Position::Center, - width: style::Dimension::Auto, - height: style::Dimension::Auto, - style: style::Style::default(), - } - } - - pub fn center_horizontal() -> Self { - Self { - x: style::Position::Center, - y: style::Position::Num(0), - width: style::Dimension::Auto, - height: style::Dimension::Auto, - style: style::Style::default(), - } - } - - pub fn center_vertical() -> Self { - Self { - x: style::Position::Num(0), - y: style::Position::Center, - width: style::Dimension::Auto, - height: style::Dimension::Auto, - style: style::Style::default(), - } - } - - pub fn x_percent(&mut self, p: u16) -> Self { - self.x = style::Position::Percent(p); - self.clone() - } - - pub fn y_percent(&mut self, p: u16) -> Self { - self.y = style::Position::Percent(p); - self.clone() - } - - pub fn style(&mut self, style: style::Style) -> Self { - self.style = style; - self.clone() - } - - pub fn width(&mut self, w: u16) -> Self { - self.width = style::Dimension::Num(w); - self.clone() - } - - pub fn height(&mut self, h: u16) -> Self { - self.height = style::Dimension::Num(h); - self.clone() - } - - pub fn width_percent(&mut self, w: u16) -> Self { - self.width = style::Dimension::Percent(w); - self.clone() - } - - pub fn height_percent(&mut self, h: u16) -> Self { - self.height = style::Dimension::Percent(h); - self.clone() - } } impl Console { - pub fn render(&mut self, ui: &Ui) -> Result<()> { - (self.width, self.height) = crossterm::terminal::size()?; + pub fn render(&mut self, ui: &mut Component) -> Result<()> { + let (width, height) = crossterm::terminal::size()?; utils::clear()?; - let mut frame = Frame(Vec::new()); + let mut frame = Frame::new(Area { + width, + height, + x: 0, + y: 0, + }); + ui(&mut frame); + Ok(()) + } + + pub fn event(&mut self, ui: &mut Component, event: Event) -> Result<()> { + let (width, height) = crossterm::terminal::size()?; + utils::clear()?; + let mut frame = Frame { + area: Area { + width, + height, + x: 0, + y: 0, + }, + event: Some(event), + }; ui(&mut frame); - for (e, _) in frame.0 { - self.draw(e.as_ref(), &Props::auto()); - } Ok(()) } @@ -159,51 +72,6 @@ impl Console { utils::show_cursor()?; utils::clear() } - - fn draw(&mut self, element: &dyn Element, props: &Props) { - let mut written = String::new(); - element.render(&mut written); - - let (written_width, written_height) = utils::str_size(&written); - - let (width, height) = ( - props.width.get_root(written_width, self.width), - props.height.get_root(written_height, self.height), - ); - - let (x, y) = ( - props.x.get(width, self.width), - props.y.get(height, self.height), - ); - - let ansi = if props.style.background == style::Color::NoColor { - format!("\x1b[{}m", props.style.color.ansi_number(true)) - } else { - format!( - "\x1b[{};{}m", - props.style.color.ansi_number(true), - props.style.background.ansi_number(false) - ) - }; - - let (x, y) = (x - props.style.px, y - props.style.py); - let px = " ".repeat(props.style.px as usize); - written - .push_str(&format!("\n{}", " ".repeat(width as usize)).repeat(props.style.py as usize)); - written.insert_str( - 0, - &format!("{}\n", " ".repeat(width as usize)).repeat(props.style.py as usize), - ); - - for (i, line) in written.lines().enumerate() { - println!( - "\x1b[{};{}H{ansi}{px}{}{px}\x1b[0m", - y as usize + i + 1, - x + 1, - line, - ); - } - } } pub fn func(t: T) -> Handler { diff --git a/src/main.rs b/src/main.rs index 49cb68c..49da96b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,32 @@ use osmium_engine::prelude::*; fn main() -> Result<()> { - let mut console = init(true)?; + let mut console = init(false)?; - let mut count = use_state(0); + let mut ui = app(use_state(0)); - let ui = app(count); + console.render(&mut ui)?; - loop { - console.render(&ui)?; - read()?; - count += 1; - } + read()?; console.close() } -pub fn app(count: State) -> Ui { +pub fn app(mut _count: State) -> Component { + let mut my_test = test(); Box::new(move |frame| { - frame.draw(Box::new(format!("Events: {count}")), Props::center()); + if let Some(_) = frame.event { + _count += 1; + } + + frame.draw(&mut my_test, Props::center_vertical()); + + my_test(frame); + }) +} + +fn test() -> Component { + Box::new(move |frame| { + frame.draw_str("Hello, World", Props::center()); }) } diff --git a/src/state.rs b/src/state.rs index 428446b..5acd193 100644 --- a/src/state.rs +++ b/src/state.rs @@ -21,6 +21,10 @@ pub fn use_state(v: T) -> State { State(Box::into_raw(Box::new(v))) } +pub fn default_state() -> State { + State(Box::into_raw(Box::new(T::default()))) +} + impl std::fmt::Display for State { /// Formats the value of the state for display. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/src/utils.rs b/src/utils.rs index d91ff45..7a0c4d2 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -107,11 +107,5 @@ pub fn init<'a>(mouse: bool) -> crate::Result { if mouse { crossterm::execute!(std::io::stdout(), crossterm::event::EnableMouseCapture)?; } - let (width, height) = crossterm::terminal::size()?; - Ok(crate::Console { - width, - height, - mouse, - mouse_position: None, - }) + Ok(crate::Console { mouse }) }