Implement future state change
This commit is contained in:
parent
47163b097b
commit
ff076d016a
1 changed files with 69 additions and 35 deletions
104
src/states.rs
104
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<GuiHandler>,
|
||||
|
||||
states: HashMap<String, Arc<State>>,
|
||||
current_state: Mutex<Option<Arc<State>>>,
|
||||
current_state: Arc<Mutex<Option<Arc<State>>>>,
|
||||
|
||||
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<Option<&'b str>>) -> 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<Arc<State>>,
|
||||
current: &mut Option<Arc<State>>,
|
||||
gui_handler: Option<Arc<GuiHandler>>,
|
||||
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<State> = 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<Option<&'b str>>,
|
||||
) -> Result<impl Fn() -> 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 {
|
||||
|
|
Loading…
Reference in a new issue