Compare commits
3 commits
2f1b4688af
...
9265d66418
Author | SHA1 | Date | |
---|---|---|---|
9265d66418 | |||
68b564fa18 | |||
1383cd5c4d |
6 changed files with 376 additions and 285 deletions
|
@ -5,7 +5,7 @@ authors = ["hodasemi <michaelh.95@t-online.de>"]
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
quick-xml = "0.31.0"
|
quick-xml = "0.37.0"
|
||||||
serde = { version = "1.0.203", features = ["derive"] }
|
serde = { version = "1.0.203", features = ["derive"] }
|
||||||
serde_json = { version = "1.0.120" }
|
serde_json = { version = "1.0.120" }
|
||||||
paste = "1.0.15"
|
paste = "1.0.15"
|
||||||
|
|
|
@ -190,8 +190,8 @@ pub struct GuiHandler {
|
||||||
|
|
||||||
resource_base_path: Option<AssetPath>,
|
resource_base_path: Option<AssetPath>,
|
||||||
|
|
||||||
top_ui: Option<Arc<dyn TopGui>>,
|
top_ui: Option<Arc<dyn TopLevelGui>>,
|
||||||
tooltip_ui: Option<Arc<dyn TopGui>>,
|
tooltip_ui: Option<Arc<dyn TopLevelGui>>,
|
||||||
|
|
||||||
render_targets: TargetMode<RenderTarget>,
|
render_targets: TargetMode<RenderTarget>,
|
||||||
command_buffers: TargetMode<Vec<CommandBufferState>>,
|
command_buffers: TargetMode<Vec<CommandBufferState>>,
|
||||||
|
@ -743,11 +743,13 @@ impl GuiHandler {
|
||||||
|
|
||||||
pub fn decline_topgui(&mut self, world: &mut World) -> Result<bool> {
|
pub fn decline_topgui(&mut self, world: &mut World) -> Result<bool> {
|
||||||
// workaround for unwanted borrowing behaviour inside decline function
|
// workaround for unwanted borrowing behaviour inside decline function
|
||||||
let opt_topgui = self.top_ui.as_ref().cloned();
|
let opt_top_level_gui = self.top_ui.as_ref().cloned();
|
||||||
|
|
||||||
if let Some(topgui) = opt_topgui {
|
if let Some(top_level_gui) = opt_top_level_gui {
|
||||||
topgui.decline(world)?;
|
if let Some(top_gui) = top_level_gui.top_gui() {
|
||||||
return Ok(true);
|
top_gui.decline(world)?;
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(false)
|
Ok(false)
|
||||||
|
@ -755,11 +757,13 @@ impl GuiHandler {
|
||||||
|
|
||||||
pub fn next_tab_topgui(&mut self, world: &mut World, second_level: bool) -> Result<bool> {
|
pub fn next_tab_topgui(&mut self, world: &mut World, second_level: bool) -> Result<bool> {
|
||||||
// workaround for unwanted borrowing behaviour inside decline function
|
// workaround for unwanted borrowing behaviour inside decline function
|
||||||
let opt_topgui = self.top_ui.as_ref().cloned();
|
let opt_top_level_gui = self.top_ui.as_ref().cloned();
|
||||||
|
|
||||||
if let Some(topgui) = opt_topgui {
|
if let Some(top_level_gui) = opt_top_level_gui {
|
||||||
topgui.next_tab(world, second_level)?;
|
if let Some(top_gui) = top_level_gui.top_gui() {
|
||||||
return Ok(true);
|
top_gui.next_tab(world, second_level)?;
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(false)
|
Ok(false)
|
||||||
|
@ -767,11 +771,13 @@ impl GuiHandler {
|
||||||
|
|
||||||
pub fn previous_tab_topgui(&mut self, world: &mut World, second_level: bool) -> Result<bool> {
|
pub fn previous_tab_topgui(&mut self, world: &mut World, second_level: bool) -> Result<bool> {
|
||||||
// workaround for unwanted borrowing behaviour inside decline function
|
// workaround for unwanted borrowing behaviour inside decline function
|
||||||
let opt_topgui = self.top_ui.as_ref().cloned();
|
let opt_top_level_gui = self.top_ui.as_ref().cloned();
|
||||||
|
|
||||||
if let Some(topgui) = opt_topgui {
|
if let Some(top_level_gui) = opt_top_level_gui {
|
||||||
topgui.previous_tab(world, second_level)?;
|
if let Some(top_gui) = top_level_gui.top_gui() {
|
||||||
return Ok(true);
|
top_gui.previous_tab(world, second_level)?;
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(false)
|
Ok(false)
|
||||||
|
@ -857,12 +863,50 @@ impl GuiHandler {
|
||||||
self.needs_update = true;
|
self.needs_update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_top_gui(&mut self, top_gui: Option<Arc<dyn TopGui>>) {
|
pub fn set_top_gui(
|
||||||
|
&mut self,
|
||||||
|
world: &mut World,
|
||||||
|
top_gui: Option<Arc<dyn TopLevelGui>>,
|
||||||
|
) -> Result<()> {
|
||||||
|
match (&self.top_ui, &top_gui) {
|
||||||
|
(Some(current), Some(incoming)) => {
|
||||||
|
if !Arc::ptr_eq(current, incoming) {
|
||||||
|
current.disable(world)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Some(current), None) => {
|
||||||
|
current.disable(world)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
self.top_ui = top_gui;
|
self.top_ui = top_gui;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_tooltip(&mut self, tooltip: Option<Arc<dyn TopGui>>) {
|
pub fn set_tooltip(
|
||||||
|
&mut self,
|
||||||
|
world: &mut World,
|
||||||
|
tooltip: Option<Arc<dyn TopLevelGui>>,
|
||||||
|
) -> Result<()> {
|
||||||
|
match (&self.tooltip_ui, &tooltip) {
|
||||||
|
(Some(current), Some(incoming)) => {
|
||||||
|
if !Arc::ptr_eq(current, incoming) {
|
||||||
|
current.disable(world)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Some(current), None) => {
|
||||||
|
current.disable(world)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
self.tooltip_ui = tooltip;
|
self.tooltip_ui = tooltip;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_callback<F: FnOnce(&mut World) -> Result<()> + Send + Sync + 'static>(
|
pub(crate) fn add_callback<F: FnOnce(&mut World) -> Result<()> + Send + Sync + 'static>(
|
||||||
|
|
|
@ -13,3 +13,4 @@ mod element_creator;
|
||||||
mod gui_direction;
|
mod gui_direction;
|
||||||
mod mouse_button;
|
mod mouse_button;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
pub mod state;
|
||||||
|
|
|
@ -7,5 +7,6 @@ pub use super::gui_direction::GuiDirection;
|
||||||
pub use super::gui_handler::prelude::*;
|
pub use super::gui_handler::prelude::*;
|
||||||
pub use super::keyboard::Keyboard;
|
pub use super::keyboard::Keyboard;
|
||||||
pub use super::mouse_button::MouseButton;
|
pub use super::mouse_button::MouseButton;
|
||||||
|
pub use super::state::*;
|
||||||
pub use super::states::*;
|
pub use super::states::*;
|
||||||
pub use super::tab_control::TabControl;
|
pub use super::tab_control::TabControl;
|
||||||
|
|
307
src/state.rs
Normal file
307
src/state.rs
Normal file
|
@ -0,0 +1,307 @@
|
||||||
|
use crate::prelude::*;
|
||||||
|
use anyhow::{Result, anyhow};
|
||||||
|
use ecs::World;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::{Arc, RwLock, Weak};
|
||||||
|
|
||||||
|
/// Opaque handle for a State
|
||||||
|
/// only used for updating callbacks
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct StateHandle {
|
||||||
|
state: Weak<State>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StateHandle {
|
||||||
|
pub fn update<'a>(&self, update_type: StateUpdateType<'a>) -> Result<()> {
|
||||||
|
self.state.upgrade().unwrap().update(update_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetElement<Button> for StateHandle {
|
||||||
|
fn element(&self, id: &str) -> Result<Arc<Button>> {
|
||||||
|
let state = self.state.upgrade().unwrap();
|
||||||
|
|
||||||
|
match state.top_level_gui.elements() {
|
||||||
|
Some(elements) => elements.element(id),
|
||||||
|
None => panic!("state ({}) has no elements", state.name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetElement<Grid> for StateHandle {
|
||||||
|
fn element(&self, id: &str) -> Result<Arc<Grid>> {
|
||||||
|
let state = self.state.upgrade().unwrap();
|
||||||
|
|
||||||
|
match state.top_level_gui.elements() {
|
||||||
|
Some(elements) => elements.element(id),
|
||||||
|
None => panic!("state ({}) has no elements", state.name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetElement<Label> for StateHandle {
|
||||||
|
fn element(&self, id: &str) -> Result<Arc<Label>> {
|
||||||
|
let state = self.state.upgrade().unwrap();
|
||||||
|
|
||||||
|
match state.top_level_gui.elements() {
|
||||||
|
Some(elements) => elements.element(id),
|
||||||
|
None => panic!("state ({}) has no elements", state.name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetElement<TextField> for StateHandle {
|
||||||
|
fn element(&self, id: &str) -> Result<Arc<TextField>> {
|
||||||
|
let state = self.state.upgrade().unwrap();
|
||||||
|
|
||||||
|
match state.top_level_gui.elements() {
|
||||||
|
Some(elements) => elements.element(id),
|
||||||
|
None => panic!("state ({}) has no elements", state.name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetElement<MultiLineTextField> for StateHandle {
|
||||||
|
fn element(&self, id: &str) -> Result<Arc<MultiLineTextField>> {
|
||||||
|
let state = self.state.upgrade().unwrap();
|
||||||
|
|
||||||
|
match state.top_level_gui.elements() {
|
||||||
|
Some(elements) => elements.element(id),
|
||||||
|
None => panic!("state ({}) has no elements", state.name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetElement<Icon> for StateHandle {
|
||||||
|
fn element(&self, id: &str) -> Result<Arc<Icon>> {
|
||||||
|
let state = self.state.upgrade().unwrap();
|
||||||
|
|
||||||
|
match state.top_level_gui.elements() {
|
||||||
|
Some(elements) => elements.element(id),
|
||||||
|
None => panic!("state ({}) has no elements", state.name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetElement<ProgressBar> for StateHandle {
|
||||||
|
fn element(&self, id: &str) -> Result<Arc<ProgressBar>> {
|
||||||
|
let state = self.state.upgrade().unwrap();
|
||||||
|
|
||||||
|
match state.top_level_gui.elements() {
|
||||||
|
Some(elements) => elements.element(id),
|
||||||
|
None => panic!("state ({}) has no elements", state.name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct State {
|
||||||
|
pub(crate) name: String,
|
||||||
|
|
||||||
|
pub(crate) top_level_gui: Arc<dyn TopLevelGui>,
|
||||||
|
|
||||||
|
pub(crate) on_activate: RwLock<Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>>,
|
||||||
|
pub(crate) on_deactivate: RwLock<Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>>,
|
||||||
|
|
||||||
|
pub(crate) next_tab: RwLock<Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>>,
|
||||||
|
pub(crate) previous_tab: RwLock<Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>>,
|
||||||
|
pub(crate) decline: RwLock<Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub(crate) fn new<'a>(
|
||||||
|
world: &mut World,
|
||||||
|
name: &str,
|
||||||
|
creation_type: CreationType<'a>,
|
||||||
|
) -> Result<Arc<Self>> {
|
||||||
|
let gui = match creation_type {
|
||||||
|
CreationType::File(path) => GuiBuilder::new(world, path)?,
|
||||||
|
CreationType::TopGui(top_gui) => top_gui,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Arc::new(State {
|
||||||
|
name: name.to_string(),
|
||||||
|
|
||||||
|
top_level_gui: gui,
|
||||||
|
|
||||||
|
on_activate: RwLock::new(None),
|
||||||
|
on_deactivate: RwLock::new(None),
|
||||||
|
|
||||||
|
next_tab: RwLock::new(None),
|
||||||
|
previous_tab: RwLock::new(None),
|
||||||
|
decline: RwLock::new(None),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn update<'a>(&self, update_type: StateUpdateType<'a>) -> Result<()> {
|
||||||
|
match update_type {
|
||||||
|
StateUpdateType::NextTab(next_tab) => self.set_next_tab(next_tab),
|
||||||
|
StateUpdateType::PreviousTab(previous_tab) => self.set_previous_tab(previous_tab),
|
||||||
|
StateUpdateType::Decline(decline) => self.set_decline(decline),
|
||||||
|
StateUpdateType::OnActivate(oa) => self.set_on_activate(oa),
|
||||||
|
StateUpdateType::OnDeactivate(oda) => self.set_on_deactivate(oda),
|
||||||
|
StateUpdateType::ClickCallbacks(cbs) => {
|
||||||
|
let functionality = self.functionality().ok_or(anyhow!(
|
||||||
|
"State ({}) has no functionality implementation",
|
||||||
|
self.name
|
||||||
|
))?;
|
||||||
|
|
||||||
|
functionality.set_click_callbacks(cbs)?;
|
||||||
|
}
|
||||||
|
StateUpdateType::SelectCallbacks(cbs) => {
|
||||||
|
let functionality = self.functionality().ok_or(anyhow!(
|
||||||
|
"State ({}) has no functionality implementation",
|
||||||
|
self.name
|
||||||
|
))?;
|
||||||
|
|
||||||
|
functionality.set_select_callbacks(cbs)?;
|
||||||
|
}
|
||||||
|
StateUpdateType::CustomClickCallbacks(cbs) => {
|
||||||
|
let functionality = self.functionality().ok_or(anyhow!(
|
||||||
|
"State ({}) has no functionality implementation",
|
||||||
|
self.name
|
||||||
|
))?;
|
||||||
|
|
||||||
|
functionality.set_custom_callbacks(cbs)?;
|
||||||
|
}
|
||||||
|
StateUpdateType::VecCallbacks(vcbs) => {
|
||||||
|
let functionality = self.functionality().ok_or(anyhow!(
|
||||||
|
"State ({}) has no functionality implementation",
|
||||||
|
self.name
|
||||||
|
))?;
|
||||||
|
|
||||||
|
functionality.set_vec_callbacks(vcbs)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_on_activate(
|
||||||
|
&self,
|
||||||
|
on_activate: Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>,
|
||||||
|
) {
|
||||||
|
*self.on_activate.write().unwrap() = on_activate;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_on_deactivate(
|
||||||
|
&self,
|
||||||
|
on_deactivate: Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>,
|
||||||
|
) {
|
||||||
|
*self.on_deactivate.write().unwrap() = on_deactivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_previous_tab(
|
||||||
|
&self,
|
||||||
|
previous_tab: Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>,
|
||||||
|
) {
|
||||||
|
*self.previous_tab.write().unwrap() = previous_tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_next_tab(
|
||||||
|
&self,
|
||||||
|
next_tab: Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>,
|
||||||
|
) {
|
||||||
|
*self.next_tab.write().unwrap() = next_tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_decline(
|
||||||
|
&self,
|
||||||
|
decline: Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>,
|
||||||
|
) {
|
||||||
|
*self.decline.write().unwrap() = decline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TopGui for State {
|
||||||
|
fn decline(&self, world: &mut World) -> Result<()> {
|
||||||
|
match self.decline.read().unwrap().as_ref() {
|
||||||
|
Some(decline) => {
|
||||||
|
(decline)(world)?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if let Some(top_gui) = self.top_level_gui.top_gui() {
|
||||||
|
top_gui.decline(world)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_tab(&self, world: &mut World, second_level: bool) -> Result<()> {
|
||||||
|
match self.next_tab.read().unwrap().as_ref() {
|
||||||
|
Some(next_tab) => {
|
||||||
|
(next_tab)(world)?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if let Some(top_gui) = self.top_level_gui.top_gui() {
|
||||||
|
top_gui.next_tab(world, second_level)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn previous_tab(&self, world: &mut World, second_level: bool) -> Result<()> {
|
||||||
|
match self.previous_tab.read().unwrap().as_ref() {
|
||||||
|
Some(previous_tab) => {
|
||||||
|
(previous_tab)(world)?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if let Some(top_gui) = self.top_level_gui.top_gui() {
|
||||||
|
top_gui.previous_tab(world, second_level)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TopLevelGui for State {
|
||||||
|
fn gui_traits(&self) -> &dyn GuiElementTraits {
|
||||||
|
self.top_level_gui.gui_traits()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn top_gui(&self) -> Option<&dyn TopGui> {
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn elements(&self) -> Option<&HashMap<String, UiElement>> {
|
||||||
|
self.top_level_gui.elements()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn functionality(&self) -> Option<&dyn Functionality> {
|
||||||
|
self.top_level_gui.functionality()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enable(&self, world: &mut World) -> Result<()> {
|
||||||
|
self.top_level_gui.enable(world)?;
|
||||||
|
|
||||||
|
if let Some(activate) = self.on_activate.read().unwrap().as_ref() {
|
||||||
|
(activate)(world)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disable(&self, world: &mut World) -> Result<()> {
|
||||||
|
self.top_level_gui.disable(world)?;
|
||||||
|
|
||||||
|
if let Some(deactivate) = self.on_deactivate.read().unwrap().as_ref() {
|
||||||
|
(deactivate)(world)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<StateHandle> for Arc<State> {
|
||||||
|
fn into(self) -> StateHandle {
|
||||||
|
StateHandle {
|
||||||
|
state: Arc::downgrade(&self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
274
src/states.rs
274
src/states.rs
|
@ -7,7 +7,7 @@ use utilities::prelude::remove_life_time_mut;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex, RwLock, Weak};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
pub trait FutureStateChange: Fn(&mut World) -> Result<()> + Send + Sync {
|
pub trait FutureStateChange: Fn(&mut World) -> Result<()> + Send + Sync {
|
||||||
fn clone_box<'a>(&self) -> Box<dyn 'a + FutureStateChange>
|
fn clone_box<'a>(&self) -> Box<dyn 'a + FutureStateChange>
|
||||||
|
@ -46,109 +46,6 @@ impl<'a> Clone for Box<dyn 'a + FutureStateChange> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct State {
|
|
||||||
name: String,
|
|
||||||
|
|
||||||
top_level_gui: Arc<dyn TopLevelGui>,
|
|
||||||
|
|
||||||
on_activate: RwLock<Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>>,
|
|
||||||
on_deactivate: RwLock<Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>>,
|
|
||||||
|
|
||||||
next_tab: RwLock<Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>>,
|
|
||||||
previous_tab: RwLock<Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>>,
|
|
||||||
decline: RwLock<Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Opaque handle for a State
|
|
||||||
/// only used for updating callbacks
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct StateHandle {
|
|
||||||
state: Weak<State>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StateHandle {
|
|
||||||
pub fn update<'a>(&self, update_type: StateUpdateType<'a>) -> Result<()> {
|
|
||||||
self.state.upgrade().unwrap().update(update_type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetElement<Button> for StateHandle {
|
|
||||||
fn element(&self, id: &str) -> Result<Arc<Button>> {
|
|
||||||
let state = self.state.upgrade().unwrap();
|
|
||||||
|
|
||||||
match state.top_level_gui.elements() {
|
|
||||||
Some(elements) => elements.element(id),
|
|
||||||
None => panic!("state ({}) has no elements", state.name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetElement<Grid> for StateHandle {
|
|
||||||
fn element(&self, id: &str) -> Result<Arc<Grid>> {
|
|
||||||
let state = self.state.upgrade().unwrap();
|
|
||||||
|
|
||||||
match state.top_level_gui.elements() {
|
|
||||||
Some(elements) => elements.element(id),
|
|
||||||
None => panic!("state ({}) has no elements", state.name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetElement<Label> for StateHandle {
|
|
||||||
fn element(&self, id: &str) -> Result<Arc<Label>> {
|
|
||||||
let state = self.state.upgrade().unwrap();
|
|
||||||
|
|
||||||
match state.top_level_gui.elements() {
|
|
||||||
Some(elements) => elements.element(id),
|
|
||||||
None => panic!("state ({}) has no elements", state.name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetElement<TextField> for StateHandle {
|
|
||||||
fn element(&self, id: &str) -> Result<Arc<TextField>> {
|
|
||||||
let state = self.state.upgrade().unwrap();
|
|
||||||
|
|
||||||
match state.top_level_gui.elements() {
|
|
||||||
Some(elements) => elements.element(id),
|
|
||||||
None => panic!("state ({}) has no elements", state.name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetElement<MultiLineTextField> for StateHandle {
|
|
||||||
fn element(&self, id: &str) -> Result<Arc<MultiLineTextField>> {
|
|
||||||
let state = self.state.upgrade().unwrap();
|
|
||||||
|
|
||||||
match state.top_level_gui.elements() {
|
|
||||||
Some(elements) => elements.element(id),
|
|
||||||
None => panic!("state ({}) has no elements", state.name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetElement<Icon> for StateHandle {
|
|
||||||
fn element(&self, id: &str) -> Result<Arc<Icon>> {
|
|
||||||
let state = self.state.upgrade().unwrap();
|
|
||||||
|
|
||||||
match state.top_level_gui.elements() {
|
|
||||||
Some(elements) => elements.element(id),
|
|
||||||
None => panic!("state ({}) has no elements", state.name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetElement<ProgressBar> for StateHandle {
|
|
||||||
fn element(&self, id: &str) -> Result<Arc<ProgressBar>> {
|
|
||||||
let state = self.state.upgrade().unwrap();
|
|
||||||
|
|
||||||
match state.top_level_gui.elements() {
|
|
||||||
Some(elements) => elements.element(id),
|
|
||||||
None => panic!("state ({}) has no elements", state.name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Update type
|
/// Update type
|
||||||
pub enum StateUpdateType<'a> {
|
pub enum StateUpdateType<'a> {
|
||||||
/// Updates the callback which is executed on next tab event
|
/// Updates the callback which is executed on next tab event
|
||||||
|
@ -312,14 +209,14 @@ impl States {
|
||||||
}
|
}
|
||||||
|
|
||||||
// execute deactivate on old state
|
// execute deactivate on old state
|
||||||
old_state.deactivate(world)?;
|
old_state.disable(world)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set new state, either no state or requested state
|
// set new state, either no state or requested state
|
||||||
match state {
|
match state {
|
||||||
Some(state) => {
|
Some(state) => {
|
||||||
state.activate(world)?;
|
state.enable(world)?;
|
||||||
gui_handler.set_top_gui(Some(state.clone()));
|
gui_handler.set_top_gui(world, Some(state.clone()))?;
|
||||||
|
|
||||||
if logging {
|
if logging {
|
||||||
println!("Change UI State to {}", state.name);
|
println!("Change UI State to {}", state.name);
|
||||||
|
@ -328,7 +225,7 @@ impl States {
|
||||||
*current = Some(state);
|
*current = Some(state);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
gui_handler.set_top_gui(None);
|
gui_handler.set_top_gui(world, None)?;
|
||||||
|
|
||||||
if logging {
|
if logging {
|
||||||
println!("Change UI State to None");
|
println!("Change UI State to None");
|
||||||
|
@ -343,9 +240,7 @@ impl States {
|
||||||
|
|
||||||
/// Retrieve a StateHandle
|
/// Retrieve a StateHandle
|
||||||
pub fn state_handle(&self, id: &str) -> Result<StateHandle> {
|
pub fn state_handle(&self, id: &str) -> Result<StateHandle> {
|
||||||
Ok(StateHandle {
|
Ok(self.get_state(id)?.into())
|
||||||
state: Arc::downgrade(&self.get_state(id)?),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_state(&self, id: &str) -> Result<Arc<State>> {
|
fn get_state(&self, id: &str) -> Result<Arc<State>> {
|
||||||
|
@ -382,160 +277,3 @@ impl States {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
|
||||||
fn new<'a>(
|
|
||||||
world: &mut World,
|
|
||||||
name: &str,
|
|
||||||
creation_type: CreationType<'a>,
|
|
||||||
) -> Result<Arc<Self>> {
|
|
||||||
let gui = match creation_type {
|
|
||||||
CreationType::File(path) => GuiBuilder::new(world, path)?,
|
|
||||||
CreationType::TopGui(top_gui) => top_gui,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Arc::new(State {
|
|
||||||
name: name.to_string(),
|
|
||||||
|
|
||||||
top_level_gui: gui,
|
|
||||||
|
|
||||||
on_activate: RwLock::new(None),
|
|
||||||
on_deactivate: RwLock::new(None),
|
|
||||||
|
|
||||||
next_tab: RwLock::new(None),
|
|
||||||
previous_tab: RwLock::new(None),
|
|
||||||
decline: RwLock::new(None),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update<'a>(&self, update_type: StateUpdateType<'a>) -> Result<()> {
|
|
||||||
match update_type {
|
|
||||||
StateUpdateType::NextTab(next_tab) => self.set_next_tab(next_tab),
|
|
||||||
StateUpdateType::PreviousTab(previous_tab) => self.set_previous_tab(previous_tab),
|
|
||||||
StateUpdateType::Decline(decline) => self.set_decline(decline),
|
|
||||||
StateUpdateType::OnActivate(oa) => self.set_on_activate(oa),
|
|
||||||
StateUpdateType::OnDeactivate(oda) => self.set_on_deactivate(oda),
|
|
||||||
StateUpdateType::ClickCallbacks(cbs) => {
|
|
||||||
let functionality = self.functionality()?;
|
|
||||||
functionality.set_click_callbacks(cbs)?;
|
|
||||||
}
|
|
||||||
StateUpdateType::SelectCallbacks(cbs) => {
|
|
||||||
let functionality = self.functionality()?;
|
|
||||||
functionality.set_select_callbacks(cbs)?;
|
|
||||||
}
|
|
||||||
StateUpdateType::CustomClickCallbacks(cbs) => {
|
|
||||||
let functionality = self.functionality()?;
|
|
||||||
functionality.set_custom_callbacks(cbs)?;
|
|
||||||
}
|
|
||||||
StateUpdateType::VecCallbacks(vcbs) => {
|
|
||||||
let functionality = self.functionality()?;
|
|
||||||
functionality.set_vec_callbacks(vcbs)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn functionality(&self) -> Result<&dyn Functionality> {
|
|
||||||
match self.top_level_gui.functionality() {
|
|
||||||
Some(functionality) => Ok(functionality),
|
|
||||||
None => panic!("state ’{}' does not implement Functionality", &self.name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn activate(&self, world: &mut World) -> Result<()> {
|
|
||||||
self.top_level_gui.enable(world)?;
|
|
||||||
|
|
||||||
if let Some(activate) = self.on_activate.read().unwrap().as_ref() {
|
|
||||||
(activate)(world)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deactivate(&self, world: &mut World) -> Result<()> {
|
|
||||||
self.top_level_gui.disable(world)?;
|
|
||||||
|
|
||||||
if let Some(deactivate) = self.on_deactivate.read().unwrap().as_ref() {
|
|
||||||
(deactivate)(world)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_on_activate(
|
|
||||||
&self,
|
|
||||||
on_activate: Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>,
|
|
||||||
) {
|
|
||||||
*self.on_activate.write().unwrap() = on_activate;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_on_deactivate(
|
|
||||||
&self,
|
|
||||||
on_deactivate: Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>,
|
|
||||||
) {
|
|
||||||
*self.on_deactivate.write().unwrap() = on_deactivate;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_previous_tab(
|
|
||||||
&self,
|
|
||||||
previous_tab: Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>,
|
|
||||||
) {
|
|
||||||
*self.previous_tab.write().unwrap() = previous_tab;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_next_tab(&self, next_tab: Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>) {
|
|
||||||
*self.next_tab.write().unwrap() = next_tab;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_decline(&self, decline: Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>) {
|
|
||||||
*self.decline.write().unwrap() = decline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TopGui for State {
|
|
||||||
fn decline(&self, world: &mut World) -> Result<()> {
|
|
||||||
match self.decline.read().unwrap().as_ref() {
|
|
||||||
Some(decline) => {
|
|
||||||
(decline)(world)?;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if let Some(top_gui) = self.top_level_gui.top_gui() {
|
|
||||||
top_gui.decline(world)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_tab(&self, world: &mut World, second_level: bool) -> Result<()> {
|
|
||||||
match self.next_tab.read().unwrap().as_ref() {
|
|
||||||
Some(next_tab) => {
|
|
||||||
(next_tab)(world)?;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if let Some(top_gui) = self.top_level_gui.top_gui() {
|
|
||||||
top_gui.next_tab(world, second_level)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn previous_tab(&self, world: &mut World, second_level: bool) -> Result<()> {
|
|
||||||
match self.previous_tab.read().unwrap().as_ref() {
|
|
||||||
Some(previous_tab) => {
|
|
||||||
(previous_tab)(world)?;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if let Some(top_gui) = self.top_level_gui.top_gui() {
|
|
||||||
top_gui.previous_tab(world, second_level)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue