working divs

This commit is contained in:
2025-07-05 04:40:05 -05:00
parent cec25c02d5
commit ec963707a1
8 changed files with 155 additions and 61 deletions
+56 -12
View File
@@ -1,13 +1,27 @@
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use crate::widget::{Element, Widget};
use crate::{
extensions::Handler,
style::RawTransform,
widget::{Element, Widget},
RenderWrapperEvent,
};
#[derive(Default)]
pub struct Div {
pub children: Vec<Arc<Widget>>,
transform: Mutex<RawTransform>,
color: u32,
}
impl Element for Div {
impl Element for Arc<Div> {
fn render(&mut self, scope: &mut crate::render_scope::RenderScope) {
let (w, h) = scope.get_size_or_parent();
scope.draw_rect(w, h, self.color);
}
fn after_render(&mut self, scope: &crate::render_scope::RenderScope) {
*self.transform.lock().unwrap() = scope.get_transform().clone();
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
@@ -18,14 +32,44 @@ impl Element for Div {
}
impl Div {
pub fn new() -> Self {
Div {
children: Vec::new(),
}
pub fn new(color: u32) -> Arc<Self> {
Arc::new(Div {
transform: Mutex::new(RawTransform::new()),
color,
})
}
pub fn draw<E: Element + 'static>(&mut self, element: E) -> &Arc<Widget> {
self.children.push(Arc::new(Widget::new(Box::new(element))));
self.children.last().unwrap()
pub fn draw(self: &Arc<Self>, element: &Arc<Widget>) -> Arc<Self> {
let r2 = self.clone();
let r = self.clone();
element.component(Handler::new(move |elem, e: &RenderWrapperEvent| {
let scope = e.get_scope();
scope.clear();
let transform = r2.transform.lock().unwrap();
let (w, h) = scope.get_parent_size();
scope.set_parent_size(transform.width, transform.height);
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
elem.0.lock().unwrap().render(scope);
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
let elem_transform = scope.get_transform_mut();
elem_transform.x += transform.x;
elem_transform.y += transform.y;
scope.draw();
elem.0.lock().unwrap().after_render(&scope);
scope.set_parent_size(w, h);
}));
r
}
}
+9 -23
View File
@@ -3,7 +3,7 @@ pub mod tick;
pub mod velocity;
use std::{
any::{Any, TypeId},
any::Any,
fmt::Debug,
sync::{Arc, Mutex},
};
@@ -23,12 +23,9 @@ pub trait Event: Send + Sync {
}
#[derive(Clone)]
pub struct Handler(
Arc<Mutex<dyn FnMut(&Arc<Widget>, &dyn Event) + Send + Sync>>,
TypeId,
);
pub struct Handler<E: Event>(Arc<Mutex<dyn FnMut(&Arc<Widget>, &E) + Send + Sync>>);
impl Component for Handler {
impl<E: Event + 'static> Component for Handler<E> {
fn as_any(&self) -> &dyn Any {
self
}
@@ -38,28 +35,17 @@ impl Component for Handler {
}
}
impl Handler {
pub fn new<E: Event + 'static, F: FnMut(&Arc<Widget>, &E) + Send + Sync + 'static>(
mut f: F,
) -> Handler {
Handler(
Arc::new(Mutex::new(move |w: &Arc<Widget>, e: &dyn Event| {
if let Some(e) = e.as_any().downcast_ref::<E>() {
f(w, e)
}
})),
TypeId::of::<E>(),
)
impl<E: Event + 'static> Handler<E> {
pub fn new<F: FnMut(&Arc<Widget>, &E) + Send + Sync + 'static>(f: F) -> Handler<E> {
Handler(Arc::new(Mutex::new(f)))
}
pub fn call<E: Event>(&self, w: &Arc<Widget>, e: &E) {
if e.as_any().type_id() == self.1 {
(self.0.lock().unwrap())(w, e)
}
pub fn call(&self, w: &Arc<Widget>, e: &E) {
(self.0.lock().unwrap())(w, e)
}
}
impl Debug for Handler {
impl<T: Event> Debug for Handler<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Handler")
}
+1 -1
View File
@@ -15,7 +15,7 @@ impl Extension for TickExtension {
let mut tick = 0;
loop {
for w in &widgets {
if let Some(on_tick) = w.get::<Handler>() {
if let Some(on_tick) = w.get::<Handler<TickEvent>>() {
on_tick.call(&w, &TickEvent(tick))
}
}
+31 -12
View File
@@ -1,7 +1,7 @@
use std::sync::{Arc, Mutex};
use crate::{
extensions::Extension,
extensions::{Extension, Handler},
render_scope::RenderScope,
style::Transform,
widget::{Element, Widget},
@@ -20,6 +20,17 @@ pub struct Screen {
extensions: Vec<Arc<Mutex<Box<dyn Extension>>>>,
}
event!(RenderWrapperEvent(*mut RenderScope));
impl RenderWrapperEvent {
pub fn get_scope(&self) -> &mut RenderScope {
unsafe { &mut *self.0 }
}
}
unsafe impl Send for RenderWrapperEvent {}
unsafe impl Sync for RenderWrapperEvent {}
impl Screen {
pub fn new() -> Screen {
Screen {
@@ -56,24 +67,32 @@ impl Screen {
pub fn render(&self) -> std::io::Result<()> {
let mut scope = RenderScope::new();
let (w, h) = crossterm::terminal::size().unwrap();
scope.set_parent_size(w, h);
utils::clear()?;
for elem in &self.widgets {
scope.clear();
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
if let Some(wrapper) = elem.get::<Handler<RenderWrapperEvent>>() {
wrapper.call(elem, &RenderWrapperEvent(&mut scope));
} else {
scope.clear();
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
for ext in &self.extensions {
ext.lock().unwrap().render_widget(&mut scope, elem);
}
for ext in &self.extensions {
ext.lock().unwrap().render_widget(&mut scope, elem);
}
elem.0.lock().unwrap().render(&mut scope);
elem.0.lock().unwrap().render(&mut scope);
if let Some(t) = elem.get() {
scope.set_transform(&t);
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
scope.draw();
elem.0.lock().unwrap().after_render(&scope);
}
scope.draw();
}
Ok(())
}
+12 -12
View File
@@ -1,9 +1,6 @@
use osui::{
extensions::{
id::{Id, IdExtension},
tick::{TickEvent, TickExtension},
Handler,
},
elements::div::Div,
extensions::{id::IdExtension, tick::TickExtension},
style::Transform,
Screen,
};
@@ -14,14 +11,17 @@ fn main() {
screen.extension(document.clone());
screen.extension(TickExtension(10));
let my_div = Div::new(0xff0000);
screen
.draw(format!("Hello, World!"))
.component(Handler::new(move |w, e: &TickEvent| {
if e.0 == 30 {
w.set_component(Transform::center());
}
}))
.component(Id(69));
.draw(my_div.clone())
.component(Transform::center().dimensions(21, 3));
my_div.draw(
screen
.draw(format!("Hello, World!"))
.component(Transform::center()),
);
screen.run().unwrap();
}
+38 -1
View File
@@ -1,13 +1,17 @@
use std::fmt::Debug;
use crate::{
style::{RawTransform, Transform},
utils::{self, hex_ansi_bg},
};
#[derive(Clone)]
enum RenderMethod {
Text(String),
Rectangle(u16, u16, u32),
}
#[derive(Clone)]
pub struct RenderScope {
transform: RawTransform,
render_stack: Vec<RenderMethod>,
@@ -26,7 +30,6 @@ impl RenderScope {
}
pub fn set_transform(&mut self, transform: &Transform) {
(self.parent_width, self.parent_height) = crossterm::terminal::size().unwrap();
transform.use_dimensions(&mut self.transform);
transform.use_position(self.parent_width, self.parent_height, &mut self.transform);
}
@@ -76,7 +79,41 @@ impl RenderScope {
(self.transform.width, self.transform.height)
}
pub fn get_size_or_parent(&self) -> (u16, u16) {
(
if self.transform.width == 0 {
self.parent_width
} else {
self.transform.width
},
if self.transform.height == 0 {
self.parent_height
} else {
self.transform.height
},
)
}
pub fn get_parent_size(&self) -> (u16, u16) {
(self.parent_width, self.parent_height)
}
pub fn set_parent_size(&mut self, width: u16, height: u16) {
self.parent_width = width;
self.parent_height = height;
}
pub fn get_transform_mut(&mut self) -> &mut RawTransform {
&mut self.transform
}
pub fn get_transform(&self) -> &RawTransform {
&self.transform
}
}
impl Debug for RenderScope {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "RenderScope")
}
}
+6
View File
@@ -1,5 +1,6 @@
use crate::component;
#[derive(Clone)]
pub struct RawTransform {
pub x: u16,
pub y: u16,
@@ -57,6 +58,11 @@ impl Transform {
self
}
pub fn right(mut self) -> Self {
self.x = Position::End;
self
}
pub fn margin(mut self, x: i32, y: i32) -> Self {
self.mx = x;
self.my = y;
+2
View File
@@ -12,6 +12,8 @@ pub type BoxedComponent = Box<dyn Component + Send + Sync>;
pub trait Element: Send + Sync {
#[allow(unused)]
fn render(&mut self, scope: &mut RenderScope) {}
#[allow(unused)]
fn after_render(&mut self, scope: &RenderScope) {}
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}