better state management
This commit is contained in:
+11
-2
@@ -4,7 +4,7 @@ use std::{
|
|||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::event;
|
use crate::{event, state::StateManager};
|
||||||
|
|
||||||
event!(Close);
|
event!(Close);
|
||||||
|
|
||||||
@@ -21,15 +21,16 @@ impl std::fmt::Debug for EventHandlerFn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct EventManager {
|
pub struct EventManager {
|
||||||
handlers: HashMap<TypeId, Vec<EventHandlerFn>>,
|
handlers: HashMap<TypeId, Vec<EventHandlerFn>>,
|
||||||
|
states: Option<Arc<StateManager>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventManager {
|
impl EventManager {
|
||||||
pub fn new() -> EventManager {
|
pub fn new() -> EventManager {
|
||||||
EventManager {
|
EventManager {
|
||||||
handlers: HashMap::new(),
|
handlers: HashMap::new(),
|
||||||
|
states: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,10 +38,14 @@ impl EventManager {
|
|||||||
&mut self,
|
&mut self,
|
||||||
mut f: F,
|
mut f: F,
|
||||||
) {
|
) {
|
||||||
|
let states = self.states.clone();
|
||||||
let wrapper = Arc::new(Mutex::new(
|
let wrapper = Arc::new(Mutex::new(
|
||||||
move |e: &mut EventManager, evt: Box<dyn Event>| {
|
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(e, concrete);
|
f(e, concrete);
|
||||||
|
if let Some(states) = &states {
|
||||||
|
states.clone().flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)) as Arc<Mutex<dyn FnMut(&mut EventManager, Box<dyn Event>)>>;
|
)) as Arc<Mutex<dyn FnMut(&mut EventManager, Box<dyn Event>)>>;
|
||||||
@@ -68,4 +73,8 @@ impl EventManager {
|
|||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_state_manager(&mut self, states: Arc<StateManager>) {
|
||||||
|
self.states = Some(states);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-29
@@ -1,10 +1,8 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crossterm::event::KeyEvent;
|
||||||
use osui::{
|
use osui::{
|
||||||
element::{
|
element::rect::Rect,
|
||||||
input::{Input, InputKeyPress},
|
|
||||||
rect::Rect,
|
|
||||||
},
|
|
||||||
events::{Close, EventManager},
|
events::{Close, EventManager},
|
||||||
extensions::{keypress::KeyPressExtension, tick_rate::TickRate, ExtensionManager},
|
extensions::{keypress::KeyPressExtension, tick_rate::TickRate, ExtensionManager},
|
||||||
state::StateManager,
|
state::StateManager,
|
||||||
@@ -18,42 +16,33 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn app(states: Arc<StateManager>) {
|
fn app(states: Arc<StateManager>) {
|
||||||
states.begin();
|
|
||||||
let mut screen = Screen::new();
|
let mut screen = Screen::new();
|
||||||
let mut extensions = ExtensionManager::new();
|
let mut extensions = ExtensionManager::new();
|
||||||
let mut events = EventManager::new();
|
let mut events = EventManager::new();
|
||||||
extensions.add(KeyPressExtension);
|
|
||||||
extensions.add(TickRate(255));
|
|
||||||
|
|
||||||
let my_state = states.use_state(String::new());
|
extensions.add(TickRate(50));
|
||||||
|
extensions.add(KeyPressExtension);
|
||||||
|
|
||||||
|
events.set_state_manager(states.clone());
|
||||||
|
|
||||||
|
let count = states.use_state(0);
|
||||||
|
|
||||||
screen
|
screen
|
||||||
.draw(Rect(0xffffff))
|
.draw(Rect(0xffffff))
|
||||||
.component(Transform::center().dimensions(30, 3));
|
.component(Transform::center().dimensions(30, 3));
|
||||||
|
|
||||||
screen
|
screen
|
||||||
.draw(format!(
|
.draw(format!("Count: {}", count.get()))
|
||||||
"Type exit to exit\nMy-State: {}",
|
.component(Transform::center());
|
||||||
my_state.get().trim()
|
|
||||||
))
|
|
||||||
.component(Transform::new().bottom().margin(0, -1));
|
|
||||||
|
|
||||||
screen
|
events.on(move |events, event: Box<KeyEvent>| match event.code {
|
||||||
.draw(Input::new())
|
crossterm::event::KeyCode::Enter => {
|
||||||
.component(Transform::new().bottom());
|
count.set(count.get() + 1);
|
||||||
|
}
|
||||||
events.on(
|
_ => {
|
||||||
move |events, event: Box<InputKeyPress>| match event.1.code {
|
events.dispatch(Close);
|
||||||
crossterm::event::KeyCode::Enter => {
|
}
|
||||||
my_state.set(my_state.get() + &format!("{}\n", event.0));
|
});
|
||||||
if event.0 == "exit" {
|
|
||||||
events.dispatch(Close);
|
|
||||||
}
|
|
||||||
my_state.update();
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
screen.run(&mut events, &mut extensions).unwrap();
|
screen.run(&mut events, &mut extensions).unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-9
@@ -11,6 +11,7 @@ pub struct StateManager {
|
|||||||
recall: fn(Arc<StateManager>),
|
recall: fn(Arc<StateManager>),
|
||||||
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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct State<S> {
|
pub struct State<S> {
|
||||||
@@ -25,14 +26,10 @@ impl StateManager {
|
|||||||
recall,
|
recall,
|
||||||
store: Mutex::new(HashMap::new()),
|
store: Mutex::new(HashMap::new()),
|
||||||
cursor: Mutex::new(0),
|
cursor: Mutex::new(0),
|
||||||
|
dirty: Mutex::new(false),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call this at the very top of every “render” before doing any `use_state` calls
|
|
||||||
pub fn begin(&self) {
|
|
||||||
*self.cursor.lock().unwrap() = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn use_state<S: 'static + Send + Sync>(self: &Arc<Self>, initial: S) -> State<S> {
|
pub fn use_state<S: 'static + Send + Sync>(self: &Arc<Self>, initial: S) -> State<S> {
|
||||||
// `slot` == position of this call in the render
|
// `slot` == position of this call in the render
|
||||||
let mut cur = self.cursor.lock().unwrap();
|
let mut cur = self.cursor.lock().unwrap();
|
||||||
@@ -51,9 +48,24 @@ impl StateManager {
|
|||||||
_pd: PhantomData,
|
_pd: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn flush(self: Arc<Self>) {
|
||||||
|
let mut d = self.dirty.lock().unwrap();
|
||||||
|
if *d {
|
||||||
|
*d = false;
|
||||||
|
drop(d);
|
||||||
|
|
||||||
|
*self.cursor.lock().unwrap() = 0;
|
||||||
|
(self.recall)(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static + Clone + Send + Sync> State<S> {
|
impl<S: 'static + Clone + Send + Sync> State<S> {
|
||||||
|
pub fn dirty(&self) {
|
||||||
|
*self.manager.dirty.lock().unwrap() = true;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get(&self) -> S {
|
pub fn get(&self) -> S {
|
||||||
let store = self.manager.store.lock().unwrap();
|
let store = self.manager.store.lock().unwrap();
|
||||||
let x = store[&self.id]
|
let x = store[&self.id]
|
||||||
@@ -74,9 +86,6 @@ impl<S: 'static + Clone + Send + Sync> State<S> {
|
|||||||
.lock()
|
.lock()
|
||||||
.unwrap() = val;
|
.unwrap() = val;
|
||||||
}
|
}
|
||||||
}
|
self.dirty();
|
||||||
|
|
||||||
pub fn update(&self) {
|
|
||||||
(self.manager.recall)(Arc::clone(&self.manager));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user