Added ExtensionContext #26

This commit is contained in:
2025-08-04 04:45:55 -05:00
parent 14602f95c8
commit 48397c06fa
5 changed files with 68 additions and 22 deletions
+5 -6
View File
@@ -1,20 +1,19 @@
use crate::extensions::Extension; use crate::extensions::{Extension, ExtensionContext};
pub struct InputExtension; pub struct InputExtension;
impl Extension for InputExtension { impl Extension for InputExtension {
fn init(&mut self, screen: std::sync::Arc<crate::Screen>) { fn init(&mut self, ctx: &ExtensionContext) {
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 {
if let Ok(e) = crossterm::event::read() { if let Ok(e) = crossterm::event::read() {
for widget in screen.widgets.lock().unwrap().iter() { ctx.event(&e);
widget.event(&e);
}
} }
}); });
} }
fn on_close(&mut self, _screen: std::sync::Arc<crate::Screen>) { fn on_close(&mut self) {
crossterm::terminal::disable_raw_mode().unwrap(); crossterm::terminal::disable_raw_mode().unwrap();
} }
} }
+49 -4
View File
@@ -11,7 +11,7 @@ pub use velocity::*;
use std::{ use std::{
any::{type_name, Any}, any::{type_name, Any},
fmt::Debug, fmt::Debug,
sync::{Arc, Mutex}, sync::{Arc, Mutex, MutexGuard},
}; };
use crate::{ use crate::{
@@ -21,15 +21,25 @@ use crate::{
}; };
pub trait Extension { pub trait Extension {
fn init(&mut self, _screen: Arc<Screen>) {} fn init(&mut self, _ctx: &ExtensionContext) {}
fn on_close(&mut self, _screen: Arc<Screen>) {} fn on_close(&mut self) {}
fn render_widget(&mut self, _scope: &mut RenderScope, _widget: &Arc<Widget>) {} fn render_widget(
&mut self,
_scope: &mut RenderScope,
_widget: &Arc<Widget>,
) {
}
} }
pub trait Event: Send + Sync { pub trait Event: Send + Sync {
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
} }
#[derive(Clone)]
pub struct ExtensionContext {
screen: Arc<Screen>,
}
#[derive(Clone)] #[derive(Clone)]
pub struct Handler<E: Event>(Arc<Mutex<dyn FnMut(&Arc<Widget>, &E) + Send + Sync>>); pub struct Handler<E: Event>(Arc<Mutex<dyn FnMut(&Arc<Widget>, &E) + Send + Sync>>);
@@ -64,3 +74,38 @@ impl<'a> dyn Event + 'a {
self.as_any().downcast_ref() self.as_any().downcast_ref()
} }
} }
impl ExtensionContext {
pub fn new(screen: Arc<Screen>) -> Self {
Self { screen }
}
pub fn event<E: Event + Clone + 'static>(&self, e: &E) {
for widget in self.screen.widgets.lock().unwrap().iter() {
widget.event(e);
}
}
pub fn get_widgets(&self) -> MutexGuard<Vec<Arc<Widget>>> {
self.screen.widgets.lock().unwrap()
}
pub fn iter_components<C: Component + 'static + Clone, F: FnMut(&Arc<Widget>, Option<C>)>(
&self,
mut iterator: F,
) {
for widget in self.screen.widgets.lock().unwrap().iter() {
iterator(widget, widget.get());
}
}
pub fn get_components<C: Component + 'static + Clone>(&self) -> Vec<C> {
let mut components = Vec::new();
for widget in self.screen.widgets.lock().unwrap().iter() {
if let Some(c) = widget.get() {
components.push(c);
}
}
components
}
}
+6 -7
View File
@@ -1,22 +1,21 @@
use std::{fmt::Debug, sync::Arc}; use std::fmt::Debug;
use crate::extensions::Extension; use crate::event;
use crate::{event, Screen}; use crate::extensions::{Extension, ExtensionContext};
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, screen: Arc<Screen>) { fn init(&mut self, ctx: &ExtensionContext) {
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({
move || { move || {
let mut tick = 0; let mut tick = 0;
loop { loop {
for w in screen.widgets.lock().unwrap().iter() { ctx.event(&TickEvent(tick));
w.event(&TickEvent(tick));
}
tick += 1; tick += 1;
std::thread::sleep(std::time::Duration::from_millis(rate_dur)); std::thread::sleep(std::time::Duration::from_millis(rate_dur));
} }
+3 -3
View File
@@ -5,7 +5,6 @@ use crate::{
extensions::Extension, extensions::Extension,
style::{Position, Transform}, style::{Position, Transform},
widget::Widget, widget::Widget,
Screen,
}; };
pub struct VelocityExtension; pub struct VelocityExtension;
@@ -43,12 +42,13 @@ impl VelocityExtension {
} }
impl Extension for VelocityExtension { impl Extension for VelocityExtension {
fn init(&mut self, screen: Arc<Screen>) { fn init(&mut self, ctx: &super::ExtensionContext) {
let ctx = ctx.clone();
std::thread::spawn({ std::thread::spawn({
move || { move || {
let mut tick = 0; let mut tick = 0;
loop { loop {
for widget in screen.widgets.lock().unwrap().iter() { for widget in ctx.get_widgets().iter() {
Self::apply_velocity_xy(tick, widget); Self::apply_velocity_xy(tick, widget);
} }
if tick > 1000 { if tick > 1000 {
+5 -2
View File
@@ -33,6 +33,7 @@ use std::sync::{Arc, Mutex};
use crate::{ use crate::{
extensions::{Extension, Handler}, extensions::{Extension, Handler},
prelude::ExtensionContext,
render_scope::RenderScope, render_scope::RenderScope,
widget::{BoxedElement, DynWidget, Element, StaticWidget, Widget, WidgetLoad}, widget::{BoxedElement, DynWidget, Element, StaticWidget, Widget, WidgetLoad},
}; };
@@ -158,8 +159,10 @@ 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());
for ext in self.extensions.lock().unwrap().iter() { for ext in self.extensions.lock().unwrap().iter() {
ext.lock().unwrap().init(self.clone()); ext.lock().unwrap().init(&ctx);
} }
utils::hide_cursor()?; utils::hide_cursor()?;
@@ -230,7 +233,7 @@ impl Screen {
utils::clear().unwrap(); utils::clear().unwrap();
for ext in self.extensions.lock().unwrap().iter() { for ext in self.extensions.lock().unwrap().iter() {
ext.lock().unwrap().on_close(self.clone()); ext.lock().unwrap().on_close();
} }
} }
} }