event handler on events

This commit is contained in:
2025-06-27 12:22:59 -05:00
parent 15b61d57c8
commit 3cacd42421
5 changed files with 38 additions and 54 deletions
+7 -25
View File
@@ -1,20 +1,14 @@
use std::sync::{Arc, Mutex};
use crossterm::event::KeyEvent; use crossterm::event::KeyEvent;
use crate::{ use crate::{
event, event_handler, events::EventManager, extensions::keypress::KeyPressEventHandler, Element, event, event_handler, events::EventManager, extensions::keypress::KeyPressEventHandler, Element,
}; };
pub struct Input(String, usize, Arc<Mutex<EventManager>>); pub struct Input(String, usize);
impl Input { impl Input {
pub fn new() -> Input { pub fn new() -> Input {
Input(String::new(), 0, Arc::new(Mutex::new(EventManager::new()))) Input(String::new(), 0)
}
pub fn get_event(&self) -> Arc<Mutex<EventManager>> {
self.2.clone()
} }
} }
@@ -45,42 +39,30 @@ impl Element for Input {
} }
impl KeyPressEventHandler for Input { impl KeyPressEventHandler for Input {
fn on_keypress(&mut self, event: Box<KeyEvent>) { fn on_keypress(&mut self, events: &mut EventManager, event: Box<KeyEvent>) {
match event.code { match event.code {
crossterm::event::KeyCode::Char(c) => { crossterm::event::KeyCode::Char(c) => {
self.0.insert(self.1, c); self.0.insert(self.1, c);
self.1 += 1; self.1 += 1;
self.2 events.dispatch(InputUpdateEvent(self.0.clone()));
.lock()
.unwrap()
.dispatch(InputUpdateEvent(self.0.clone()));
} }
crossterm::event::KeyCode::Backspace => { crossterm::event::KeyCode::Backspace => {
if self.1 > 0 { if self.1 > 0 {
self.0.remove(self.1 - 1); self.0.remove(self.1 - 1);
self.1 -= 1; self.1 -= 1;
self.2 events.dispatch(InputUpdateEvent(self.0.clone()));
.lock()
.unwrap()
.dispatch(InputUpdateEvent(self.0.clone()));
} }
} }
crossterm::event::KeyCode::Left => { crossterm::event::KeyCode::Left => {
if self.1 > 0 { if self.1 > 0 {
self.1 -= 1; self.1 -= 1;
self.2 events.dispatch(InputUpdateEvent(self.0.clone()));
.lock()
.unwrap()
.dispatch(InputUpdateEvent(self.0.clone()));
} }
} }
crossterm::event::KeyCode::Right => { crossterm::event::KeyCode::Right => {
if self.1 < self.0.len() { if self.1 < self.0.len() {
self.1 += 1; self.1 += 1;
self.2 events.dispatch(InputUpdateEvent(self.0.clone()));
.lock()
.unwrap()
.dispatch(InputUpdateEvent(self.0.clone()));
} }
} }
_ => {} _ => {}
+19 -7
View File
@@ -1,6 +1,7 @@
use std::{ use std::{
any::{Any, TypeId}, any::{Any, TypeId},
collections::HashMap, collections::HashMap,
sync::{Arc, Mutex},
}; };
use crate::event; use crate::event;
@@ -11,7 +12,8 @@ pub trait Event {
fn as_any(self: Box<Self>) -> Box<dyn Any>; fn as_any(self: Box<Self>) -> Box<dyn Any>;
} }
pub struct EventHandlerFn(pub Box<dyn FnMut(Box<dyn Event>)>); #[derive(Clone)]
pub struct EventHandlerFn(pub Arc<Mutex<dyn FnMut(&mut EventManager, Box<dyn Event>)>>);
impl std::fmt::Debug for EventHandlerFn { impl std::fmt::Debug for EventHandlerFn {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -31,12 +33,17 @@ impl EventManager {
} }
} }
pub fn on<E: Event + 'static, F: FnMut(Box<E>) + 'static>(&mut self, mut f: F) { pub fn on<E: Event + 'static, F: FnMut(&mut EventManager, Box<E>) + 'static>(
let wrapper = Box::new(move |evt: Box<dyn Event>| { &mut self,
mut f: F,
) {
let wrapper = Arc::new(Mutex::new(
move |e: &mut EventManager, evt: Box<dyn Event>| {
if let Ok(concrete) = evt.as_any().downcast::<E>() { if let Ok(concrete) = evt.as_any().downcast::<E>() {
f(concrete); f(e, concrete);
} }
}) as Box<dyn FnMut(Box<dyn Event>)>; },
)) as Arc<Mutex<dyn FnMut(&mut EventManager, Box<dyn Event>)>>;
self.handlers self.handlers
.entry(TypeId::of::<E>()) .entry(TypeId::of::<E>())
@@ -46,9 +53,14 @@ impl EventManager {
pub fn dispatch<E: Event + 'static + Clone>(&mut self, evt: E) { pub fn dispatch<E: Event + 'static + Clone>(&mut self, evt: E) {
let tid = evt.type_id(); let tid = evt.type_id();
if let Some(handlers) = self.handlers.get_mut(&tid) { if let Some(handlers) = self.handlers.get_mut(&tid) {
for h in handlers { // Clone handlers to avoid borrowing self during call
(h.0)(Box::new(evt.clone())); let handler_clones: Vec<_> = handlers.iter().cloned().collect();
for h in handler_clones {
let mut ha = h.0.lock().unwrap();
(ha)(self, Box::new(evt.clone()));
} }
} }
+2 -2
View File
@@ -13,7 +13,7 @@ impl Event for KeyEvent {
} }
pub trait KeyPressEventHandler { pub trait KeyPressEventHandler {
fn on_keypress(&mut self, event: Box<KeyEvent>); fn on_keypress(&mut self, events: &mut EventManager, event: Box<KeyEvent>);
} }
pub struct KeyPressExtension; pub struct KeyPressExtension;
@@ -24,7 +24,7 @@ impl Extension for KeyPressExtension {
crate::utils::clear().unwrap(); crate::utils::clear().unwrap();
crate::utils::hide_cursor().unwrap(); crate::utils::hide_cursor().unwrap();
events.on(|_: Box<Close>| { events.on(|_, _: Box<Close>| {
crossterm::terminal::disable_raw_mode().unwrap(); crossterm::terminal::disable_raw_mode().unwrap();
crate::utils::show_cursor().unwrap(); crate::utils::show_cursor().unwrap();
crate::utils::clear().unwrap(); crate::utils::clear().unwrap();
+1 -1
View File
@@ -119,6 +119,6 @@ macro_rules! component {
macro_rules! event_handler { macro_rules! event_handler {
($self_ty:ty, $self:ident, $events:ident, $method:ident) => {{ ($self_ty:ty, $self:ident, $events:ident, $method:ident) => {{
let self_ref = $self as *mut $self_ty; let self_ref = $self as *mut $self_ty;
$events.on(move |e| unsafe { (*self_ref).$method(e) }); $events.on(move |es, e| unsafe { (*self_ref).$method(es, e) });
}}; }};
} }
+4 -14
View File
@@ -1,6 +1,6 @@
use osui::{ use osui::{
element::input::{Input, InputUpdateEvent}, element::input::{Input, InputUpdateEvent},
events::EventManager, events::{Close, EventManager},
extensions::{keypress::KeyPressExtension, ExtensionManager}, extensions::{keypress::KeyPressExtension, ExtensionManager},
style::Transform, style::Transform,
Screen, Screen,
@@ -12,21 +12,11 @@ fn main() {
let mut events = EventManager::new(); let mut events = EventManager::new();
extensions.add(KeyPressExtension); extensions.add(KeyPressExtension);
let widget = screen.draw(Input::new()).component(Transform::center()); screen.draw(Input::new()).component(Transform::center());
let input_event = widget events.on(|events, event: Box<InputUpdateEvent>| {
.0
.as_any()
.downcast_ref::<Input>()
.unwrap()
.get_event();
input_event
.lock()
.unwrap()
.on(|event: Box<InputUpdateEvent>| {
if event.0 == "quit" { if event.0 == "quit" {
std::process::exit(0) events.dispatch(Close);
} }
}); });