Implement future state change

This commit is contained in:
hodasemi 2024-03-27 13:49:22 +01:00
parent 47163b097b
commit ff076d016a

View file

@ -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 {