diff --git a/src/states.rs b/src/states.rs index 37c6171..d53d92f 100644 --- a/src/states.rs +++ b/src/states.rs @@ -5,10 +5,7 @@ use assetpath::AssetPath; use std::any::Any; use std::collections::HashMap; -use std::sync::{ - atomic::{AtomicBool, Ordering::SeqCst}, - Arc, Mutex, RwLock, -}; +use std::sync::{Arc, Mutex, RwLock}; struct State { name: String, @@ -160,11 +157,10 @@ pub struct States { gui_handler: Arc, states: HashMap>, - current_state: Mutex>>, + current_state: Arc>>>, - control_top_gui: AtomicBool, - - log_state_change: AtomicBool, + control_top_gui: bool, + log_state_change: bool, } impl States { @@ -174,21 +170,22 @@ impl States { gui_handler, states: HashMap::new(), - current_state: Mutex::new(None), + current_state: Arc::new(Mutex::new(None)), - control_top_gui: AtomicBool::new(true), - - log_state_change: AtomicBool::new(false), + control_top_gui: true, + log_state_change: false, }) } - pub fn change_logging(&self, logging: bool) { - self.log_state_change.store(logging, SeqCst); + pub fn change_logging(mut self, logging: bool) -> Self { + self.log_state_change = logging; + self } /// Sets a flag if states should set and unset top gui of the gui handler - pub fn set_control_top_gui(&self, control_top_gui: bool) { - self.control_top_gui.store(control_top_gui, SeqCst); + pub fn set_control_top_gui(mut self, control_top_gui: bool) -> Self { + self.control_top_gui = control_top_gui; + self } /// Adds a single state @@ -219,12 +216,28 @@ impl States { /// /// * `id` - Set state with the given identifier or None pub fn set_state<'b>(&self, id: impl Into>) -> Result<()> { - let id = id.into(); + Self::_set_state( + id.into().map(|id| self.get_state(id)).transpose()?, + &mut *self.current_state.lock().unwrap(), + if self.control_top_gui { + Some(self.gui_handler.clone()) + } else { + None + }, + self.log_state_change, + ) + } - if let Some(old_state) = self.current_state.lock().unwrap().as_ref() { + fn _set_state( + state: Option>, + current: &mut Option>, + gui_handler: Option>, + logging: bool, + ) -> Result<()> { + if let Some(old_state) = current { // check if requested state is already in use - if let Some(name) = id { - if name == old_state.name { + if let Some(new_state) = &state { + if new_state.name == old_state.name { return Ok(()); } } @@ -234,32 +247,30 @@ impl States { } // set new state, either no state or requested state - match id { - Some(name) => { - let state: Arc = self.get_state(name)?; - + match state { + Some(state) => { state.activate()?; - if self.control_top_gui.load(SeqCst) { - self.gui_handler.set_top_gui(Some(state.clone())); + if let Some(gui_handler) = gui_handler { + gui_handler.set_top_gui(Some(state.clone())); } - *self.current_state.lock().unwrap() = Some(state); - - if self.log_state_change.load(SeqCst) { - println!("Change UI State to {}", name); + if logging { + println!("Change UI State to {}", state.name); } + + *current = Some(state); } None => { - if self.control_top_gui.load(SeqCst) { - self.gui_handler.set_top_gui(None); + if let Some(gui_handler) = gui_handler { + gui_handler.set_top_gui(None); } - *self.current_state.lock().unwrap() = None; - - if self.log_state_change.load(SeqCst) { + if logging { println!("Change UI State to None"); } + + *current = None; } } @@ -279,6 +290,29 @@ impl States { None => Err(anyhow::Error::msg(format!("UiState not found: {}", id))), } } + + pub fn future_state_change<'b>( + &self, + id: impl Into>, + ) -> Result Result<()>> { + let state = id.into().map(|id| self.get_state(id)).transpose()?; + let current_state = self.current_state.clone(); + let gui_handler = if self.control_top_gui { + Some(self.gui_handler.clone()) + } else { + None + }; + let logging = self.log_state_change; + + Ok(move || { + Self::_set_state( + state.clone(), + &mut *current_state.lock().unwrap(), + gui_handler.clone(), + logging, + ) + }) + } } impl State {