better structure
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
+28
-36
@@ -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(
|
|
||||||
move |e: &mut EventManager, evt: Box<dyn Event>| {
|
|
||||||
if let Ok(concrete) = evt.as_any().downcast::<E>() {
|
|
||||||
f(e, concrete);
|
|
||||||
if let Some(states) = &states {
|
|
||||||
states.clone().flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)) as Arc<Mutex<dyn FnMut(&mut EventManager, Box<dyn Event>)>>;
|
|
||||||
|
|
||||||
self.handlers
|
self.handlers
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.entry(TypeId::of::<E>())
|
.entry(TypeId::of::<E>())
|
||||||
.or_insert_with(Vec::new)
|
.or_insert_with(Vec::new)
|
||||||
.push(EventHandlerFn(wrapper));
|
.push(Arc::new(Mutex::new(
|
||||||
|
move |e: &Arc<EventManager>, evt: Box<dyn Event>| {
|
||||||
|
if let Ok(concrete) = evt.as_any().downcast::<E>() {
|
||||||
|
f(&e, concrete);
|
||||||
|
if let Some(states) = &states {
|
||||||
|
states.clone().flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
() => {};
|
||||||
|
}
|
||||||
|
|||||||
+23
-19
@@ -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,14 +39,14 @@ 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
|
||||||
crossterm::event::KeyCode::Enter => {
|
.events
|
||||||
count.set(count.get() + 1);
|
.on(move |events, event: Box<KeyEvent>| match event.code {
|
||||||
}
|
crossterm::event::KeyCode::Enter => {
|
||||||
_ => {
|
count.set(count.get() + 1);
|
||||||
events.dispatch(Close);
|
}
|
||||||
}
|
_ => {
|
||||||
});
|
events.dispatch(Close);
|
||||||
|
}
|
||||||
screen.run(&mut events, &mut extensions).unwrap();
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user