better structure

This commit is contained in:
2025-06-28 03:51:13 +02:00
parent 551a062021
commit f401d4a995
9 changed files with 93 additions and 85 deletions
+4 -2
View File
@@ -1,3 +1,5 @@
use std::sync::Arc;
use crossterm::event::KeyEvent; use crossterm::event::KeyEvent;
use crate::{ use crate::{
@@ -13,7 +15,7 @@ impl Input {
} }
impl Element for Input { impl Element for Input {
fn init(&mut self, events: &mut crate::events::EventManager) { fn init(&mut self, events: &Arc<EventManager>) {
event_handler!(Self, self, events, on_keypress); event_handler!(Self, self, events, on_keypress);
} }
@@ -39,7 +41,7 @@ impl Element for Input {
} }
impl KeyPressEventHandler for Input { impl KeyPressEventHandler for Input {
fn on_keypress(&mut self, events: &mut EventManager, event: Box<KeyEvent>) { fn on_keypress(&mut self, events: &Arc<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);
+25 -33
View File
@@ -12,59 +12,51 @@ pub trait Event {
fn as_any(self: Box<Self>) -> Box<dyn Any>; fn as_any(self: Box<Self>) -> Box<dyn Any>;
} }
#[derive(Clone)]
pub struct EventHandlerFn(pub Arc<Mutex<dyn FnMut(&mut EventManager, Box<dyn Event>)>>);
impl std::fmt::Debug for EventHandlerFn {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "FnMut()")
}
}
pub struct EventManager { pub struct EventManager {
handlers: HashMap<TypeId, Vec<EventHandlerFn>>, handlers:
states: Option<Arc<StateManager>>, Mutex<HashMap<TypeId, Vec<Arc<Mutex<dyn FnMut(&Arc<EventManager>, Box<dyn Event>)>>>>>,
states: Mutex<Option<Arc<StateManager>>>,
} }
impl EventManager { impl EventManager {
pub fn new() -> EventManager { pub fn new() -> Arc<EventManager> {
EventManager { Arc::new(EventManager {
handlers: HashMap::new(), handlers: Mutex::new(HashMap::new()),
states: None, states: Mutex::new(None),
} })
} }
pub fn on<E: Event + 'static, F: FnMut(&mut EventManager, Box<E>) + 'static>( pub fn on<E: Event + 'static, F: FnMut(&Arc<EventManager>, Box<E>) + 'static>(
&mut self, self: &Arc<Self>,
mut f: F, mut f: F,
) { ) {
let states = self.states.clone(); let states = self.states.lock().unwrap().clone();
let wrapper = Arc::new(Mutex::new( self.handlers
move |e: &mut EventManager, evt: Box<dyn Event>| { .lock()
.unwrap()
.entry(TypeId::of::<E>())
.or_insert_with(Vec::new)
.push(Arc::new(Mutex::new(
move |e: &Arc<EventManager>, evt: Box<dyn Event>| {
if let Ok(concrete) = evt.as_any().downcast::<E>() { if let Ok(concrete) = evt.as_any().downcast::<E>() {
f(e, concrete); f(&e, concrete);
if let Some(states) = &states { if let Some(states) = &states {
states.clone().flush(); states.clone().flush();
} }
} }
}, },
)) as Arc<Mutex<dyn FnMut(&mut EventManager, Box<dyn Event>)>>; )));
self.handlers
.entry(TypeId::of::<E>())
.or_insert_with(Vec::new)
.push(EventHandlerFn(wrapper));
} }
pub fn dispatch<E: Event + 'static + Clone>(&mut self, evt: E) { pub fn dispatch<E: Event + 'static + Clone>(self: &Arc<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.lock().unwrap().get_mut(&tid) {
// Clone handlers to avoid borrowing self during call // Clone handlers to avoid borrowing self during call
let handler_clones: Vec<_> = handlers.iter().cloned().collect(); let handler_clones: Vec<_> = handlers.iter().cloned().collect();
for h in handler_clones { for h in handler_clones {
let mut ha = h.0.lock().unwrap(); let mut ha = h.lock().unwrap();
(ha)(self, Box::new(evt.clone())); (ha)(self, Box::new(evt.clone()));
} }
} }
@@ -74,7 +66,7 @@ impl EventManager {
} }
} }
pub fn set_state_manager(&mut self, states: Arc<StateManager>) { pub fn set_state_manager(self: &Arc<Self>, states: Arc<StateManager>) {
self.states = Some(states); *self.states.lock().unwrap() = Some(states);
} }
} }
+6 -4
View File
@@ -1,3 +1,5 @@
use std::sync::Arc;
use crossterm::event::KeyEvent; use crossterm::event::KeyEvent;
use crate::{ use crate::{
@@ -13,13 +15,13 @@ impl Event for KeyEvent {
} }
pub trait KeyPressEventHandler { pub trait KeyPressEventHandler {
fn on_keypress(&mut self, events: &mut EventManager, event: Box<KeyEvent>); fn on_keypress(&mut self, events: &Arc<EventManager>, event: Box<KeyEvent>);
} }
pub struct KeyPressExtension; pub struct KeyPressExtension;
impl Extension for KeyPressExtension { impl Extension for KeyPressExtension {
fn init(&mut self, _: &mut Screen, events: &mut EventManager) { fn init(&mut self, _: &mut Screen, events: &Arc<EventManager>) {
crossterm::terminal::enable_raw_mode().unwrap(); crossterm::terminal::enable_raw_mode().unwrap();
crate::utils::clear().unwrap(); crate::utils::clear().unwrap();
crate::utils::hide_cursor().unwrap(); crate::utils::hide_cursor().unwrap();
@@ -31,9 +33,9 @@ impl Extension for KeyPressExtension {
}); });
} }
fn tick_start(&mut self, _: &mut Screen, _: &mut EventManager) {} fn tick_start(&mut self, _: &mut Screen, _: &Arc<EventManager>) {}
fn tick_end(&mut self, _: &mut Screen, events: &mut EventManager) { fn tick_end(&mut self, _: &mut Screen, events: &Arc<EventManager>) {
if crossterm::event::poll(std::time::Duration::from_millis(13)).unwrap() { if crossterm::event::poll(std::time::Duration::from_millis(13)).unwrap() {
match crossterm::event::read().unwrap() { match crossterm::event::read().unwrap() {
crossterm::event::Event::Key(e) => { crossterm::event::Event::Key(e) => {
+8 -6
View File
@@ -1,30 +1,32 @@
pub mod keypress; pub mod keypress;
pub mod tick_rate; pub mod tick_rate;
use std::sync::Arc;
use crate::{events::EventManager, Screen}; use crate::{events::EventManager, Screen};
pub trait Extension { pub trait Extension {
fn init(&mut self, screen: &mut Screen, events: &mut EventManager); fn init(&mut self, screen: &mut Screen, events: &Arc<EventManager>);
fn tick_start(&mut self, screen: &mut Screen, events: &mut EventManager); fn tick_start(&mut self, screen: &mut Screen, events: &Arc<EventManager>);
fn tick_end(&mut self, screen: &mut Screen, events: &mut EventManager); fn tick_end(&mut self, screen: &mut Screen, events: &Arc<EventManager>);
} }
pub struct ExtensionManager(Vec<Box<dyn Extension>>); pub struct ExtensionManager(Vec<Box<dyn Extension>>);
impl Extension for ExtensionManager { impl Extension for ExtensionManager {
fn init(&mut self, screen: &mut Screen, events: &mut EventManager) { fn init(&mut self, screen: &mut Screen, events: &Arc<EventManager>) {
for ext in &mut self.0 { for ext in &mut self.0 {
ext.init(screen, events); ext.init(screen, events);
} }
} }
fn tick_start(&mut self, screen: &mut Screen, events: &mut EventManager) { fn tick_start(&mut self, screen: &mut Screen, events: &Arc<EventManager>) {
for ext in &mut self.0 { for ext in &mut self.0 {
ext.tick_start(screen, events); ext.tick_start(screen, events);
} }
} }
fn tick_end(&mut self, screen: &mut Screen, events: &mut EventManager) { fn tick_end(&mut self, screen: &mut Screen, events: &Arc<EventManager>) {
for ext in &mut self.0 { for ext in &mut self.0 {
ext.tick_end(screen, events); ext.tick_end(screen, events);
} }
+6 -4
View File
@@ -1,13 +1,15 @@
use crate::extensions::Extension; use std::sync::Arc;
use crate::{events::EventManager, extensions::Extension};
pub struct TickRate(pub u8); pub struct TickRate(pub u8);
impl Extension for TickRate { impl Extension for TickRate {
fn init(&mut self, _: &mut crate::Screen, _: &mut crate::events::EventManager) {} fn init(&mut self, _: &mut crate::Screen, _: &Arc<EventManager>) {}
fn tick_end(&mut self, _: &mut crate::Screen, _: &mut crate::events::EventManager) { fn tick_end(&mut self, _: &mut crate::Screen, _: &Arc<EventManager>) {
std::thread::sleep(std::time::Duration::from_millis(1000 / self.0 as u64)); std::thread::sleep(std::time::Duration::from_millis(1000 / self.0 as u64));
} }
fn tick_start(&mut self, _: &mut crate::Screen, _: &mut crate::events::EventManager) {} fn tick_start(&mut self, _: &mut crate::Screen, _: &Arc<EventManager>) {}
} }
+9 -10
View File
@@ -1,6 +1,7 @@
use std::{ use std::{
any::{Any, TypeId}, any::{Any, TypeId},
collections::HashMap, collections::HashMap,
sync::Arc,
}; };
use crate::{ use crate::{
@@ -23,7 +24,7 @@ pub trait Element {
#[allow(unused)] #[allow(unused)]
fn render(&mut self, scope: &mut RenderScope) {} fn render(&mut self, scope: &mut RenderScope) {}
#[allow(unused)] #[allow(unused)]
fn init(&mut self, events: &mut EventManager) {} fn init(&mut self, events: &Arc<EventManager>) {}
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any;
} }
@@ -61,12 +62,14 @@ impl Widget {
pub struct Screen { pub struct Screen {
pub elements: Vec<Widget>, pub elements: Vec<Widget>,
pub events: Arc<EventManager>,
} }
impl Screen { impl Screen {
pub fn new() -> Screen { pub fn new() -> Screen {
Screen { Screen {
elements: Vec::new(), elements: Vec::new(),
events: EventManager::new(),
} }
} }
@@ -76,22 +79,18 @@ impl Screen {
self.elements.last_mut().unwrap() self.elements.last_mut().unwrap()
} }
pub fn run( pub fn run(&mut self, extensions: &mut ExtensionManager) -> std::io::Result<()> {
&mut self,
events: &mut EventManager,
extensions: &mut ExtensionManager,
) -> std::io::Result<()> {
let mut scope = RenderScope::new(); let mut scope = RenderScope::new();
for elem in &mut self.elements { for elem in &mut self.elements {
elem.component(Transform::new()); elem.component(Transform::new());
elem.0.init(events); elem.0.init(&self.events);
} }
extensions.init(self, events); extensions.init(self, &self.events.clone());
loop { loop {
extensions.tick_start(self, events); extensions.tick_start(self, &self.events.clone());
utils::clear().unwrap(); utils::clear().unwrap();
for elem in &mut self.elements { for elem in &mut self.elements {
@@ -108,7 +107,7 @@ impl Screen {
scope.draw(); scope.draw();
} }
extensions.tick_end(self, events); extensions.tick_end(self, &self.events.clone());
} }
} }
} }
+5
View File
@@ -122,3 +122,8 @@ macro_rules! event_handler {
$events.on(move |es, e| unsafe { (*self_ref).$method(es, e) }); $events.on(move |es, e| unsafe { (*self_ref).$method(es, e) });
}}; }};
} }
#[macro_export]
macro_rules! rsx {
() => {};
}
+16 -12
View File
@@ -3,27 +3,31 @@ use std::sync::Arc;
use crossterm::event::KeyEvent; use crossterm::event::KeyEvent;
use osui::{ use osui::{
element::rect::Rect, element::rect::Rect,
events::{Close, EventManager}, events::Close,
extensions::{keypress::KeyPressExtension, tick_rate::TickRate, ExtensionManager}, extensions::{keypress::KeyPressExtension, ExtensionManager},
state::StateManager, state::StateManager,
style::Transform, style::Transform,
Screen, Screen,
}; };
fn main() { fn main() {
let states = StateManager::new(app); init(&StateManager::new(init));
app(states);
} }
fn app(states: Arc<StateManager>) { fn init(states: &Arc<StateManager>) {
let mut screen = Screen::new(); let mut screen = Screen::new();
let mut extensions = ExtensionManager::new(); screen.events.set_state_manager(states.clone());
let mut events = EventManager::new();
extensions.add(TickRate(50)); let mut extensions = ExtensionManager::new();
extensions.add(KeyPressExtension); extensions.add(KeyPressExtension);
events.set_state_manager(states.clone()); app(states, &mut screen);
screen.run(&mut extensions).unwrap();
}
fn app(states: &Arc<StateManager>, screen: &mut Screen) {
screen.events.set_state_manager(states.clone());
let count = states.use_state(0); let count = states.use_state(0);
@@ -35,7 +39,9 @@ fn app(states: Arc<StateManager>) {
.draw(format!("Count: {}", count.get())) .draw(format!("Count: {}", count.get()))
.component(Transform::center()); .component(Transform::center());
events.on(move |events, event: Box<KeyEvent>| match event.code { screen
.events
.on(move |events, event: Box<KeyEvent>| match event.code {
crossterm::event::KeyCode::Enter => { crossterm::event::KeyCode::Enter => {
count.set(count.get() + 1); count.set(count.get() + 1);
} }
@@ -43,6 +49,4 @@ fn app(states: Arc<StateManager>) {
events.dispatch(Close); events.dispatch(Close);
} }
}); });
screen.run(&mut events, &mut extensions).unwrap();
} }
+4 -4
View File
@@ -8,7 +8,7 @@ use std::{
/// ---------- public API ---------- /// ---------- public API ----------
pub struct StateManager { pub struct StateManager {
recall: fn(Arc<StateManager>), recall: Box<dyn Fn(&Arc<Self>)>,
store: Mutex<HashMap<usize, Box<dyn Any + Send + Sync>>>, store: Mutex<HashMap<usize, Box<dyn Any + Send + Sync>>>,
cursor: Mutex<usize>, cursor: Mutex<usize>,
dirty: Mutex<bool>, dirty: Mutex<bool>,
@@ -21,9 +21,9 @@ pub struct State<S> {
} }
impl StateManager { impl StateManager {
pub fn new(recall: fn(Arc<StateManager>)) -> Arc<Self> { pub fn new<F: Fn(&Arc<Self>) + 'static>(recall: F) -> Arc<Self> {
Arc::new(Self { Arc::new(Self {
recall, recall: Box::new(recall),
store: Mutex::new(HashMap::new()), store: Mutex::new(HashMap::new()),
cursor: Mutex::new(0), cursor: Mutex::new(0),
dirty: Mutex::new(false), dirty: Mutex::new(false),
@@ -49,7 +49,7 @@ impl StateManager {
} }
} }
pub fn flush(self: Arc<Self>) { pub fn flush(self: &Arc<Self>) {
let mut d = self.dirty.lock().unwrap(); let mut d = self.dirty.lock().unwrap();
if *d { if *d {
*d = false; *d = false;