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