From 82b847314e32181c0eafb22d76d00b4938f4e16d Mon Sep 17 00:00:00 2001 From: Leo dev Date: Thu, 26 Jun 2025 09:24:35 +0200 Subject: [PATCH] transform and components --- src/lib.rs | 59 +++++++++++++++++++++++++++++---- src/macros.rs | 50 ++++++++++++++++++++++++++++ src/main.rs | 6 ++-- src/render_scope.rs | 52 +++++++++++++++++++++++++++-- src/style.rs | 81 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 237 insertions(+), 11 deletions(-) create mode 100644 src/style.rs diff --git a/src/lib.rs b/src/lib.rs index 4798fd7..644bf33 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,20 @@ -use std::any::Any; +use std::{ + any::{Any, TypeId}, + collections::HashMap, +}; use crate::{ events::EventManager, extensions::{Extension, ExtensionManager}, render_scope::RenderScope, + style::Transform, }; pub mod events; pub mod extensions; pub mod macros; pub mod render_scope; +pub mod style; pub mod text; pub mod utils; @@ -21,8 +26,39 @@ pub trait Element { fn as_any(self: Box) -> Box; } +pub trait Component { + fn as_any(&self) -> &dyn Any; + fn as_any_mut(&mut self) -> &mut dyn Any; +} + +pub struct Widget(pub Box, HashMap>); + +impl Widget { + pub fn component(&mut self, c: C) -> &mut Self { + self.1.entry(c.type_id()).or_insert_with(|| Box::new(c)); + self + } + + pub fn set_component(&mut self, c: C) -> &mut Self { + self.1.insert(c.type_id(), Box::new(c)); + self + } + + pub fn get(&self) -> Option<&C> { + self.1 + .get(&TypeId::of::()) + .and_then(|c| c.as_any().downcast_ref::()) + } + + pub fn get_mut(&mut self) -> Option<&mut C> { + self.1 + .get_mut(&TypeId::of::()) + .and_then(|c| c.as_any_mut().downcast_mut::()) + } +} + pub struct Screen { - pub elements: Vec>, + pub elements: Vec, } impl Screen { @@ -32,8 +68,10 @@ impl Screen { } } - pub fn draw(&mut self, element: E) { - self.elements.push(Box::new(element)); + pub fn draw(&mut self, element: E) -> &mut Widget { + self.elements + .push(Widget(Box::new(element), HashMap::new())); + self.elements.last_mut().unwrap() } pub fn run( @@ -41,10 +79,11 @@ impl Screen { events: &mut EventManager, extensions: &mut ExtensionManager, ) -> std::io::Result<()> { - let mut scope = RenderScope {}; + let mut scope = RenderScope::new(); for elem in &mut self.elements { - elem.init(events); + elem.component(Transform::new()); + elem.0.init(events); } extensions.init(self, events); @@ -52,8 +91,14 @@ impl Screen { loop { extensions.tick_start(self, events); + utils::clear().unwrap(); for elem in &mut self.elements { - elem.render(&mut scope); + scope.clear(); + elem.0.render(&mut scope); + if let Some(t) = elem.get() { + scope.set_transform(t); + } + scope.draw(); } extensions.tick_end(self, events); diff --git a/src/macros.rs b/src/macros.rs index 3589fec..4ceda2f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -35,3 +35,53 @@ macro_rules! event { } }; } + +#[macro_export] +macro_rules! component { + ($name:ident) => { + #[derive(Debug, Clone)] + pub struct $name; + + impl $crate::Component for $name { + fn as_any(&self) -> &dyn std::any::Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn std::any::Any { + self + } + } + }; + + ($name:ident {$($inner:tt)*}) => { + #[derive(Debug, Clone)] + pub struct $name { + $($inner)* + } + + impl $crate::Component for $name { + fn as_any(&self) -> &dyn std::any::Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn std::any::Any { + self + } + } + }; + + ($name:ident ($($inner:tt)*)) => { + #[derive(Debug, Clone)] + pub struct $name ($($inner)*); + + impl $crate::Component for $name { + fn as_any(&self) -> &dyn std::any::Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn std::any::Any { + self + } + } + }; +} diff --git a/src/main.rs b/src/main.rs index 927e991..71e0ee6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use osui::{ events::EventManager, extensions::{keypress::KeyPressExtension, ExtensionManager}, + style::Transform, Screen, }; @@ -8,10 +9,11 @@ fn main() { let mut screen = Screen::new(); let mut extensions = ExtensionManager::new(); let mut events = EventManager::new(); - extensions.add(KeyPressExtension); - screen.draw("Hello, World".to_string()); + screen + .draw("Hello, World".to_string()) + .component(Transform::new()); screen.run(&mut events, &mut extensions).unwrap(); } diff --git a/src/render_scope.rs b/src/render_scope.rs index 604b8f6..092f169 100644 --- a/src/render_scope.rs +++ b/src/render_scope.rs @@ -1,7 +1,55 @@ -pub struct RenderScope {} +use crate::{ + style::{RawTransform, Transform}, + utils, +}; + +enum RenderMethod { + Text(String), +} + +pub struct RenderScope { + transform: RawTransform, + render_stack: Vec, + width: u16, + height: u16, + parent_width: u16, + parent_height: u16, +} impl RenderScope { + pub fn new() -> RenderScope { + RenderScope { + transform: RawTransform::new(), + render_stack: Vec::new(), + width: 0, + height: 0, + parent_width: 0, + parent_height: 0, + } + } + + pub fn set_transform(&mut self, transform: &Transform) { + transform.use_dimensions(&mut self.transform); + } + pub fn draw_text(&mut self, text: &str) { - println!("{text}"); + self.render_stack.push(RenderMethod::Text(text.to_string())); + let (w, h) = utils::str_size(text); + self.width = std::cmp::max(self.width, w); + self.height = std::cmp::max(self.height, h); + } + + pub fn draw(&self) { + for m in &self.render_stack { + match m { + RenderMethod::Text(t) => { + println!("\x1b[{};{}H{t}", self.transform.y + 1, self.transform.x + 1) + } + } + } + } + + pub fn clear(&mut self) { + self.render_stack.clear(); } } diff --git a/src/style.rs b/src/style.rs new file mode 100644 index 0000000..d437b44 --- /dev/null +++ b/src/style.rs @@ -0,0 +1,81 @@ +use crate::component; + +pub struct RawTransform { + pub x: u16, + pub y: u16, + pub width: u16, + pub height: u16, +} + +#[derive(Debug, Clone)] +pub enum Position { + Center, + Const(u16), +} + +#[derive(Debug, Clone)] +pub enum Dimension { + Auto, + Const(u16), +} + +component!(Transform { + pub x: Position, + pub y: Position, + pub width: Dimension, + pub height: Dimension, +}); + +impl Transform { + pub fn new() -> Transform { + Transform { + x: Position::Const(0), + y: Position::Const(0), + width: Dimension::Auto, + height: Dimension::Auto, + } + } + + pub fn center() -> Transform { + Transform { + x: Position::Center, + y: Position::Center, + width: Dimension::Auto, + height: Dimension::Auto, + } + } + + pub fn position(x: Position, y: Position) -> Transform { + Transform { + x, + y, + width: Dimension::Auto, + height: Dimension::Auto, + } + } + + pub fn use_dimensions(&self, raw: &mut RawTransform) { + self.width.use_dimension(&mut raw.width); + self.height.use_dimension(&mut raw.height); + } +} + +impl RawTransform { + pub fn new() -> RawTransform { + RawTransform { + x: 0, + y: 0, + width: 0, + height: 0, + } + } +} + +impl Dimension { + pub fn use_dimension(&self, r: &mut u16) { + match self { + Dimension::Auto => {} + Dimension::Const(n) => *r = *n, + } + } +}