Added after render and render on extension with child handlers #26

This commit is contained in:
2025-08-04 05:58:11 -05:00
parent 62e0c1eac1
commit ca4ee54e9d
12 changed files with 108 additions and 55 deletions
+14 -4
View File
@@ -20,12 +20,20 @@ impl Div {
} }
impl Element for Div { impl Element for Div {
fn render(&mut self, scope: &mut crate::render_scope::RenderScope) { fn render(
&mut self,
scope: &mut crate::render_scope::RenderScope,
_: &crate::extensions::Context,
) {
let (width, height) = scope.get_size_or(self.size.0, self.size.1); let (width, height) = scope.get_size_or(self.size.0, self.size.1);
scope.use_area(width, height); scope.use_area(width, height);
} }
fn after_render(&mut self, scope: &mut crate::render_scope::RenderScope) { fn after_render(
&mut self,
scope: &mut crate::render_scope::RenderScope,
ctx: &crate::extensions::Context,
) {
let mut transform = scope.get_transform().clone(); let mut transform = scope.get_transform().clone();
let (w, h) = scope.get_parent_size(); let (w, h) = scope.get_parent_size();
scope.set_parent_size(transform.width, transform.height); scope.set_parent_size(transform.width, transform.height);
@@ -43,7 +51,8 @@ impl Element for Div {
if let Some(t) = elem.get() { if let Some(t) = elem.get() {
scope.set_transform(&t); scope.set_transform(&t);
} }
elem.get_elem().render(scope); elem.get_elem().render(scope, ctx);
ctx.render(elem, scope);
if let Some(t) = elem.get() { if let Some(t) = elem.get() {
scope.set_transform(&t); scope.set_transform(&t);
} }
@@ -54,7 +63,8 @@ impl Element for Div {
t.y += transform.y + transform.py; t.y += transform.y + transform.py;
scope.draw(); scope.draw();
elem.get_elem().after_render(scope); elem.get_elem().after_render(scope, ctx);
ctx.after_render(elem, scope);
} }
scope.set_parent_size(w, h); scope.set_parent_size(w, h);
self.size = (transform.width, transform.height); self.size = (transform.width, transform.height);
+28 -8
View File
@@ -38,12 +38,20 @@ impl FlexCol {
} }
impl Element for FlexRow { impl Element for FlexRow {
fn render(&mut self, scope: &mut crate::render_scope::RenderScope) { fn render(
&mut self,
scope: &mut crate::render_scope::RenderScope,
_: &crate::extensions::Context,
) {
let (width, height) = scope.get_size_or(self.size.0, self.size.1); let (width, height) = scope.get_size_or(self.size.0, self.size.1);
scope.use_area(width, height); scope.use_area(width, height);
} }
fn after_render(&mut self, scope: &mut crate::render_scope::RenderScope) { fn after_render(
&mut self,
scope: &mut crate::render_scope::RenderScope,
ctx: &crate::extensions::Context,
) {
let mut transform = scope.get_transform().clone(); let mut transform = scope.get_transform().clone();
let (w, h) = scope.get_parent_size(); let (w, h) = scope.get_parent_size();
scope.set_parent_size(transform.width, transform.height); scope.set_parent_size(transform.width, transform.height);
@@ -62,7 +70,8 @@ impl Element for FlexRow {
if let Some(t) = elem.get() { if let Some(t) = elem.get() {
scope.set_transform(&t); scope.set_transform(&t);
} }
elem.get_elem().render(scope); elem.get_elem().render(scope, ctx);
ctx.render(elem, scope);
if let Some(t) = elem.get() { if let Some(t) = elem.get() {
scope.set_transform(&t); scope.set_transform(&t);
} }
@@ -77,7 +86,8 @@ impl Element for FlexRow {
scope.draw(); scope.draw();
elem.get_elem().after_render(scope); elem.get_elem().after_render(scope, ctx);
ctx.after_render(elem, scope);
} }
scope.set_parent_size(w, h); scope.set_parent_size(w, h);
self.size = (transform.width, transform.height); self.size = (transform.width, transform.height);
@@ -98,12 +108,20 @@ impl Element for FlexRow {
} }
impl Element for FlexCol { impl Element for FlexCol {
fn render(&mut self, scope: &mut crate::render_scope::RenderScope) { fn render(
&mut self,
scope: &mut crate::render_scope::RenderScope,
_: &crate::extensions::Context,
) {
let (width, height) = scope.get_size_or(self.size.0, self.size.1); let (width, height) = scope.get_size_or(self.size.0, self.size.1);
scope.use_area(width, height); scope.use_area(width, height);
} }
fn after_render(&mut self, scope: &mut crate::render_scope::RenderScope) { fn after_render(
&mut self,
scope: &mut crate::render_scope::RenderScope,
ctx: &crate::extensions::Context,
) {
let mut transform = scope.get_transform().clone(); let mut transform = scope.get_transform().clone();
let (w, h) = scope.get_parent_size(); let (w, h) = scope.get_parent_size();
scope.set_parent_size(transform.width, transform.height); scope.set_parent_size(transform.width, transform.height);
@@ -122,7 +140,8 @@ impl Element for FlexCol {
if let Some(t) = elem.get() { if let Some(t) = elem.get() {
scope.set_transform(&t); scope.set_transform(&t);
} }
elem.get_elem().render(scope); elem.get_elem().render(scope, ctx);
ctx.render(elem, scope);
if let Some(t) = elem.get() { if let Some(t) = elem.get() {
scope.set_transform(&t); scope.set_transform(&t);
} }
@@ -137,7 +156,8 @@ impl Element for FlexCol {
scope.draw(); scope.draw();
elem.get_elem().after_render(scope); elem.get_elem().after_render(scope, ctx);
ctx.after_render(elem, scope);
} }
scope.set_parent_size(w, h); scope.set_parent_size(w, h);
self.size = (transform.width, transform.height); self.size = (transform.width, transform.height);
+5 -1
View File
@@ -24,7 +24,11 @@ impl Heading {
} }
impl Element for Heading { impl Element for Heading {
fn render(&mut self, scope: &mut crate::prelude::RenderScope) { fn render(
&mut self,
scope: &mut crate::prelude::RenderScope,
_: &crate::extensions::Context,
) {
let mut s = String::new(); let mut s = String::new();
for element in &self.children { for element in &self.children {
if element.get::<NoRender>().is_some() { if element.get::<NoRender>().is_some() {
+5 -1
View File
@@ -11,7 +11,11 @@ pub struct Input {
} }
impl Element for Input { impl Element for Input {
fn render(&mut self, scope: &mut crate::prelude::RenderScope) { fn render(
&mut self,
scope: &mut crate::prelude::RenderScope,
_: &crate::extensions::Context,
) {
let s = self.state.get(); let s = self.state.get();
scope.draw_text(0, 0, &s); scope.draw_text(0, 0, &s);
if let Some(c) = s.chars().nth(self.cursor) { if let Some(c) = s.chars().nth(self.cursor) {
+5 -15
View File
@@ -13,7 +13,11 @@ pub use paginator::*;
use crate::Element; use crate::Element;
impl Element for String { impl Element for String {
fn render(&mut self, scope: &mut crate::render_scope::RenderScope) { fn render(
&mut self,
scope: &mut crate::render_scope::RenderScope,
_: &crate::extensions::Context,
) {
scope.draw_text(0, 0, self); scope.draw_text(0, 0, self);
} }
@@ -25,17 +29,3 @@ impl Element for String {
self self
} }
} }
impl Element for (String, u32) {
fn render(&mut self, scope: &mut crate::render_scope::RenderScope) {
scope.draw_text_colored(0, 0, &self.0, self.1);
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}
+13 -4
View File
@@ -24,12 +24,20 @@ impl Paginator {
} }
impl Element for Paginator { impl Element for Paginator {
fn render(&mut self, scope: &mut crate::render_scope::RenderScope) { fn render(
&mut self,
scope: &mut crate::render_scope::RenderScope,
_: &crate::extensions::Context,
) {
let (width, height) = scope.get_size_or(self.size.0, self.size.1); let (width, height) = scope.get_size_or(self.size.0, self.size.1);
scope.use_area(width, height); scope.use_area(width, height);
} }
fn after_render(&mut self, scope: &mut crate::render_scope::RenderScope) { fn after_render(
&mut self,
scope: &mut crate::render_scope::RenderScope,
ctx: &crate::extensions::Context,
) {
if let Some(elem) = self.children.get(self.index) { if let Some(elem) = self.children.get(self.index) {
if elem.get::<NoRender>().is_some() { if elem.get::<NoRender>().is_some() {
return; return;
@@ -46,7 +54,7 @@ impl Element for Paginator {
if let Some(t) = elem.get() { if let Some(t) = elem.get() {
scope.set_transform(&t); scope.set_transform(&t);
} }
elem.get_elem().render(scope); elem.get_elem().render(scope, ctx);
if let Some(t) = elem.get() { if let Some(t) = elem.get() {
scope.set_transform(&t); scope.set_transform(&t);
} }
@@ -57,7 +65,8 @@ impl Element for Paginator {
t.y += transform.y + transform.py; t.y += transform.y + transform.py;
scope.draw(); scope.draw();
elem.get_elem().after_render(scope); elem.get_elem().after_render(scope, ctx);
ctx.after_render(elem, scope);
scope.set_parent_size(w, h); scope.set_parent_size(w, h);
self.size = (transform.width, transform.height); self.size = (transform.width, transform.height);
+2 -2
View File
@@ -1,9 +1,9 @@
use crate::extensions::{Extension, ExtensionContext}; use crate::extensions::{Extension, Context};
pub struct InputExtension; pub struct InputExtension;
impl Extension for InputExtension { impl Extension for InputExtension {
fn init(&mut self, ctx: &ExtensionContext) { fn init(&mut self, ctx: &Context) {
let ctx = ctx.clone(); let ctx = ctx.clone();
crossterm::terminal::enable_raw_mode().unwrap(); crossterm::terminal::enable_raw_mode().unwrap();
std::thread::spawn(move || loop { std::thread::spawn(move || loop {
+24 -5
View File
@@ -21,10 +21,17 @@ use crate::{
}; };
pub trait Extension { pub trait Extension {
fn init(&mut self, _ctx: &ExtensionContext) {} fn init(&mut self, _ctx: &Context) {}
fn event(&mut self, _ctx: &ExtensionContext, _event: &dyn Event) {} fn event(&mut self, _ctx: &Context, _event: &dyn Event) {}
fn on_close(&mut self) {} fn on_close(&mut self) {}
fn render_widget(&mut self, _scope: &mut RenderScope, _widget: &Arc<Widget>) {} fn render_widget(&mut self, _ctx: &Context, _scope: &mut RenderScope, _widget: &Arc<Widget>) {}
fn after_render_widget(
&mut self,
_ctx: &Context,
_scope: &mut RenderScope,
_widget: &Arc<Widget>,
) {
}
} }
pub trait Event: Send + Sync { pub trait Event: Send + Sync {
@@ -32,7 +39,7 @@ pub trait Event: Send + Sync {
} }
#[derive(Clone)] #[derive(Clone)]
pub struct ExtensionContext { pub struct Context {
screen: Arc<Screen>, screen: Arc<Screen>,
} }
@@ -71,7 +78,7 @@ impl<'a> dyn Event + 'a {
} }
} }
impl ExtensionContext { impl Context {
pub fn new(screen: Arc<Screen>) -> Self { pub fn new(screen: Arc<Screen>) -> Self {
Self { screen } Self { screen }
} }
@@ -108,4 +115,16 @@ impl ExtensionContext {
} }
components components
} }
pub fn render(&self, w: &Arc<Widget>, scope: &mut RenderScope) {
for ext in self.screen.extensions.lock().unwrap().iter() {
ext.lock().unwrap().render_widget(self, scope, w);
}
}
pub fn after_render(&self, w: &Arc<Widget>, scope: &mut RenderScope) {
for ext in self.screen.extensions.lock().unwrap().iter() {
ext.lock().unwrap().after_render_widget(self, scope, w);
}
}
} }
+2 -2
View File
@@ -1,14 +1,14 @@
use std::fmt::Debug; use std::fmt::Debug;
use crate::event; use crate::event;
use crate::extensions::{Extension, ExtensionContext}; use crate::extensions::{Context, Extension};
pub struct TickExtension(pub u16); pub struct TickExtension(pub u16);
event!(TickEvent(pub u32)); event!(TickEvent(pub u32));
impl Extension for TickExtension { impl Extension for TickExtension {
fn init(&mut self, ctx: &ExtensionContext) { fn init(&mut self, ctx: &Context) {
let ctx = ctx.clone(); let ctx = ctx.clone();
let rate_dur = 1000 / self.0 as u64; let rate_dur = 1000 / self.0 as u64;
std::thread::spawn({ std::thread::spawn({
+1 -1
View File
@@ -42,7 +42,7 @@ impl VelocityExtension {
} }
impl Extension for VelocityExtension { impl Extension for VelocityExtension {
fn init(&mut self, ctx: &super::ExtensionContext) { fn init(&mut self, ctx: &super::Context) {
let ctx = ctx.clone(); let ctx = ctx.clone();
std::thread::spawn({ std::thread::spawn({
move || { move || {
+7 -10
View File
@@ -33,7 +33,7 @@ use std::sync::{Arc, Mutex};
use crate::{ use crate::{
extensions::{Extension, Handler}, extensions::{Extension, Handler},
prelude::ExtensionContext, prelude::Context,
render_scope::RenderScope, render_scope::RenderScope,
widget::{BoxedElement, DynWidget, Element, StaticWidget, Widget, WidgetLoad}, widget::{BoxedElement, DynWidget, Element, StaticWidget, Widget, WidgetLoad},
}; };
@@ -159,7 +159,7 @@ impl Screen {
/// ///
/// This method blocks and repeatedly renders the screen at a fixed interval. /// This method blocks and repeatedly renders the screen at a fixed interval.
pub fn run(self: &Arc<Self>) -> std::io::Result<()> { pub fn run(self: &Arc<Self>) -> std::io::Result<()> {
let ctx = ExtensionContext::new(self.clone()); let ctx = Context::new(self.clone());
for ext in self.extensions.lock().unwrap().iter() { for ext in self.extensions.lock().unwrap().iter() {
ext.lock().unwrap().init(&ctx); ext.lock().unwrap().init(&ctx);
@@ -168,7 +168,7 @@ impl Screen {
utils::hide_cursor()?; utils::hide_cursor()?;
while *self.running.lock().unwrap() { while *self.running.lock().unwrap() {
self.render()?; self.render(&ctx)?;
std::thread::sleep(std::time::Duration::from_millis(28)); std::thread::sleep(std::time::Duration::from_millis(28));
} }
@@ -178,7 +178,7 @@ impl Screen {
/// Renders all widgets and applies extensions. /// Renders all widgets and applies extensions.
/// ///
/// This method is called internally by `run`. /// This method is called internally by `run`.
pub fn render(self: &Arc<Self>) -> std::io::Result<()> { pub fn render(self: &Arc<Self>, ctx: &Context) -> std::io::Result<()> {
let mut scope = RenderScope::new(); let mut scope = RenderScope::new();
let (w, h) = crossterm::terminal::size().unwrap(); let (w, h) = crossterm::terminal::size().unwrap();
scope.set_parent_size(w, h); scope.set_parent_size(w, h);
@@ -186,9 +186,6 @@ impl Screen {
utils::clear()?; utils::clear()?;
for elem in self.widgets.lock().unwrap().iter() { for elem in self.widgets.lock().unwrap().iter() {
if elem.get::<NoRender>().is_some() || elem.get::<NoRenderRoot>().is_some() { if elem.get::<NoRender>().is_some() || elem.get::<NoRenderRoot>().is_some() {
for ext in self.extensions.lock().unwrap().iter() {
ext.lock().unwrap().render_widget(&mut scope, elem);
}
elem.auto_refresh(); elem.auto_refresh();
continue; continue;
} }
@@ -206,17 +203,17 @@ impl Screen {
} }
for ext in self.extensions.lock().unwrap().iter() { for ext in self.extensions.lock().unwrap().iter() {
ext.lock().unwrap().render_widget(&mut scope, elem); ext.lock().unwrap().render_widget(ctx, &mut scope, elem);
} }
elem.get_elem().render(&mut scope); elem.get_elem().render(&mut scope, ctx);
if let Some(t) = elem.get() { if let Some(t) = elem.get() {
scope.set_transform(&t); scope.set_transform(&t);
} }
scope.draw(); scope.draw();
elem.get_elem().after_render(&mut scope); elem.get_elem().after_render(&mut scope, ctx);
} }
elem.auto_refresh(); elem.auto_refresh();
+2 -2
View File
@@ -31,11 +31,11 @@ pub type BoxedComponent = Box<dyn Component + Send + Sync>;
pub trait Element: Send + Sync { pub trait Element: Send + Sync {
/// Called to perform rendering for the element. /// Called to perform rendering for the element.
#[allow(unused)] #[allow(unused)]
fn render(&mut self, scope: &mut RenderScope) {} fn render(&mut self, scope: &mut RenderScope, ctx: &crate::extensions::Context) {}
/// Called after rendering, for follow-up logic or cleanup. /// Called after rendering, for follow-up logic or cleanup.
#[allow(unused)] #[allow(unused)]
fn after_render(&mut self, scope: &mut RenderScope) {} fn after_render(&mut self, scope: &mut RenderScope, ctx: &crate::extensions::Context) {}
/// Called to draw child widgets, if any. /// Called to draw child widgets, if any.
#[allow(unused)] #[allow(unused)]