From 52336040f2f470e0d62dde78ce279dbdf8b8a06f Mon Sep 17 00:00:00 2001
From: hodasemi <michaelh.95@t-online.de>
Date: Tue, 4 Mar 2025 18:18:08 +0100
Subject: [PATCH] Improve ecs ergonomics

---
 src/builder/builder.rs               |  27 ++++---
 src/builder/snippet.rs               |  21 +++--
 src/elements/button.rs               |  15 ++--
 src/elements/callback_builder.rs     |  18 +++--
 src/elements/multi_line_textfield.rs |   5 +-
 src/elements/textfield.rs            |   3 +-
 src/elements/traits.rs               |  21 +++--
 src/gui_handler/gui/executable.rs    |   5 +-
 src/gui_handler/gui/selectable.rs    |  14 +++-
 src/gui_handler/gui/topgui.rs        |   9 +--
 src/gui_handler/gui_handler.rs       |  29 ++++---
 src/keyboard/mod.rs                  |  80 +++++++++++-------
 src/lib.rs                           |   2 -
 src/prelude.rs                       |   2 -
 src/states.rs                        | 116 +++++++++++++++------------
 15 files changed, 216 insertions(+), 151 deletions(-)

diff --git a/src/builder/builder.rs b/src/builder/builder.rs
index 8cb20e4..3041e9a 100644
--- a/src/builder/builder.rs
+++ b/src/builder/builder.rs
@@ -2,6 +2,7 @@ use crate::prelude::*;
 use anyhow::{Context, Result, bail};
 
 use assetpath::AssetPath;
+use ecs::World;
 
 use super::validator::buttoninfo::{NeighbourDirection, NeighbourInfo};
 use super::validator::gridinfo::GridInfo;
@@ -178,10 +179,7 @@ impl GuiBuilder {
 impl Functionality for GuiBuilder {
     fn set_click_callbacks(
         &self,
-        functions: Vec<(
-            &str,
-            Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>,
-        )>,
+        functions: Vec<(&str, Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>)>,
     ) -> Result<()> {
         for (function_name, callback) in functions {
             let suffix_less_function_name = handle_function_suffix(function_name);
@@ -195,14 +193,20 @@ impl Functionality for GuiBuilder {
 
     fn set_vec_callbacks(
         &self,
-        _functions: Vec<(&str, Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>)>,
+        _functions: Vec<(
+            &str,
+            Box<dyn Fn(&mut World, &dyn Any) -> Result<()> + Send + Sync>,
+        )>,
     ) -> Result<()> {
         Ok(())
     }
 
     fn set_select_callbacks(
         &self,
-        callbacks: Vec<(&str, Box<CustomCallback<bool, ()>>)>,
+        callbacks: Vec<(
+            &str,
+            Box<dyn Fn(&mut World, bool) -> Result<()> + Send + Sync>,
+        )>,
     ) -> Result<()> {
         for (function_name, callback) in callbacks {
             let suffix_less_function_name = handle_function_suffix(function_name);
@@ -216,7 +220,10 @@ impl Functionality for GuiBuilder {
 
     fn set_custom_callbacks(
         &self,
-        callbacks: Vec<(&str, Box<CustomCallback<ControllerButton, bool>>)>,
+        callbacks: Vec<(
+            &str,
+            Box<dyn Fn(&mut World, ControllerButton) -> Result<bool> + Send + Sync>,
+        )>,
     ) -> Result<()> {
         for (function_name, callback) in callbacks {
             let suffix_less_function_name = handle_function_suffix(function_name);
@@ -262,7 +269,7 @@ impl GuiElementTraits for GuiBuilder {
 }
 
 impl TopGui for GuiBuilder {
-    fn decline(&self, _gui_handler: &mut GuiHandler) -> Result<()> {
+    fn decline(&self, _world: &mut World) -> Result<()> {
         if let Some(decline_callback) = self.decline_callback.read().unwrap().as_ref() {
             decline_callback()?;
         }
@@ -270,11 +277,11 @@ impl TopGui for GuiBuilder {
         Ok(())
     }
 
-    fn next_tab(&self, _gui_handler: &mut GuiHandler, _: bool) -> Result<()> {
+    fn next_tab(&self, _world: &mut World, _: bool) -> Result<()> {
         Ok(())
     }
 
-    fn previous_tab(&self, _gui_handler: &mut GuiHandler, _: bool) -> Result<()> {
+    fn previous_tab(&self, _world: &mut World, _: bool) -> Result<()> {
         Ok(())
     }
 }
diff --git a/src/builder/snippet.rs b/src/builder/snippet.rs
index 720f37c..d8436e3 100644
--- a/src/builder/snippet.rs
+++ b/src/builder/snippet.rs
@@ -1,6 +1,7 @@
 use std::{any::Any, collections::HashMap, sync::Arc};
 
 use assetpath::AssetPath;
+use ecs::World;
 
 use super::validator::{
     buttoninfo::NeighbourInfo,
@@ -147,10 +148,7 @@ impl Gridable for GuiSnippet {
 impl Functionality for GuiSnippet {
     fn set_click_callbacks(
         &self,
-        functions: Vec<(
-            &str,
-            Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>,
-        )>,
+        functions: Vec<(&str, Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>)>,
     ) -> Result<()> {
         for (function_name, callback) in functions {
             let suffix_less_function_name = handle_function_suffix(function_name);
@@ -164,14 +162,20 @@ impl Functionality for GuiSnippet {
 
     fn set_vec_callbacks(
         &self,
-        _functions: Vec<(&str, Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>)>,
+        _functions: Vec<(
+            &str,
+            Box<dyn Fn(&mut World, &dyn Any) -> Result<()> + Send + Sync>,
+        )>,
     ) -> Result<()> {
         Ok(())
     }
 
     fn set_select_callbacks(
         &self,
-        callbacks: Vec<(&str, Box<CustomCallback<bool, ()>>)>,
+        callbacks: Vec<(
+            &str,
+            Box<dyn Fn(&mut World, bool) -> Result<()> + Send + Sync>,
+        )>,
     ) -> Result<()> {
         for (function_name, callback) in callbacks {
             let suffix_less_function_name = handle_function_suffix(function_name);
@@ -185,7 +189,10 @@ impl Functionality for GuiSnippet {
 
     fn set_custom_callbacks(
         &self,
-        callbacks: Vec<(&str, Box<CustomCallback<ControllerButton, bool>>)>,
+        callbacks: Vec<(
+            &str,
+            Box<dyn Fn(&mut World, ControllerButton) -> Result<bool> + Send + Sync>,
+        )>,
     ) -> Result<()> {
         for (function_name, callback) in callbacks {
             let suffix_less_function_name = handle_function_suffix(function_name);
diff --git a/src/elements/button.rs b/src/elements/button.rs
index 1c315ff..156f87a 100644
--- a/src/elements/button.rs
+++ b/src/elements/button.rs
@@ -5,6 +5,7 @@ use crate::{
 
 use anyhow::{Result, anyhow};
 use assetpath::AssetPath;
+use ecs::World;
 use utilities::prelude::*;
 use vulkan_rs::prelude::*;
 
@@ -314,23 +315,23 @@ impl Button {
 
     pub fn set_callback<F>(&self, callback: F)
     where
-        F: Fn(&mut GuiHandler) -> Result<()> + Send + Sync + 'static,
+        F: Fn(&mut World) -> Result<()> + Send + Sync + 'static,
     {
         self.click_executable
-            .set_callback(move |gui_handler: &mut GuiHandler, _: ()| callback(gui_handler));
+            .set_callback(move |world: &mut World, _: ()| callback(world));
     }
 
     pub fn set_select_callback<F>(&self, callback: F)
     where
-        F: Fn(bool) -> Result<()> + Send + Sync + 'static,
+        F: Fn(&mut World, bool) -> Result<()> + Send + Sync + 'static,
     {
         self.on_select_executable
-            .set_callback(move |_: &mut GuiHandler, select: bool| callback(select));
+            .set_callback(move |world: &mut World, select: bool| callback(world, select));
     }
 
     pub fn set_custom_callback<F>(&self, callback: F)
     where
-        F: Fn(ControllerButton) -> Result<bool> + Send + Sync + 'static,
+        F: Fn(&mut World, ControllerButton) -> Result<bool> + Send + Sync + 'static,
     {
         self.selectable.set_custom_callback(callback);
     }
@@ -578,8 +579,10 @@ impl Button {
     fn create_selected_changed_callback(button: Arc<Button>) {
         let button_weak = Arc::downgrade(&button);
 
-        let selected_changed = move |gui_handler: &mut GuiHandler, selected: bool| {
+        let selected_changed = move |world: &mut World, selected: bool| {
             if let Some(button) = button_weak.upgrade() {
+                let gui_handler = world.resources.get_mut::<GuiHandler>();
+
                 if selected {
                     button.set_button_state(gui_handler, ButtonState::Selected)?;
                 } else {
diff --git a/src/elements/callback_builder.rs b/src/elements/callback_builder.rs
index ee68db0..45156d9 100644
--- a/src/elements/callback_builder.rs
+++ b/src/elements/callback_builder.rs
@@ -1,6 +1,7 @@
 use std::any::Any;
 
 use anyhow::Result;
+use ecs::World;
 
 use super::ControllerButton;
 use crate::prelude::*;
@@ -27,18 +28,21 @@ macro_rules! callbacks {
     };
 }
 
-callbacks!(ClickCallbacks, Fn(&mut GuiHandler) -> Result<()> + Send + Sync);
-callbacks!(SelectCallbacks, Fn(bool) -> anyhow::Result<()> + Send + Sync);
-callbacks!(CustomCallbacks, Fn(ControllerButton) -> anyhow::Result<bool> + Send + Sync);
-callbacks!(VecCallbacks, Fn(&dyn Any) -> Result<()> + Send + Sync);
+callbacks!(ClickCallbacks, Fn(&mut World, &mut GuiHandler) -> Result<()> + Send + Sync);
+callbacks!(SelectCallbacks, Fn(&mut World, &mut GuiHandler, bool) -> anyhow::Result<()> + Send + Sync);
+callbacks!(CustomCallbacks, Fn(&mut World, &mut GuiHandler, ControllerButton) -> anyhow::Result<bool> + Send + Sync);
+callbacks!(
+    VecCallbacks,
+    Fn(&mut World, &mut GuiHandler, &dyn Any) -> Result<()> + Send + Sync
+);
 
 #[cfg(test)]
 mod test {
     use super::*;
     use anyhow::Result;
 
-    fn normal_fn() -> impl Fn(&mut GuiHandler) -> Result<()> + Send + Sync {
-        |_| Ok(())
+    fn normal_fn() -> impl Fn(&mut World, &mut GuiHandler) -> Result<()> + Send + Sync {
+        |_, _| Ok(())
     }
 
     #[test]
@@ -50,7 +54,7 @@ mod test {
                 &self,
                 _callbacks: Vec<(
                     &str,
-                    Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>,
+                    Box<dyn Fn(&mut World, &mut GuiHandler) -> Result<()> + Send + Sync>,
                 )>,
             ) -> Result<()> {
                 Ok(())
diff --git a/src/elements/multi_line_textfield.rs b/src/elements/multi_line_textfield.rs
index 86cbc92..56988f7 100644
--- a/src/elements/multi_line_textfield.rs
+++ b/src/elements/multi_line_textfield.rs
@@ -10,6 +10,7 @@ use std::sync::{
 };
 
 use anyhow::{Context, Result};
+use ecs::World;
 use utilities::prelude::*;
 
 use super::fill_type::InnerFillType;
@@ -96,9 +97,9 @@ impl MultiLineTextFieldBuilder {
         multi_line_text_field.text_changed_exec.set_callback({
             let weak_tf = Arc::downgrade(&multi_line_text_field);
 
-            move |gui_handler: &mut GuiHandler, _text| {
+            move |world: &mut World, _text| {
                 if let Some(tf) = weak_tf.upgrade() {
-                    tf.update_text(gui_handler)?;
+                    tf.update_text(world.resources.get_mut::<GuiHandler>())?;
                 }
 
                 Ok(())
diff --git a/src/elements/textfield.rs b/src/elements/textfield.rs
index 283c685..3a987a4 100644
--- a/src/elements/textfield.rs
+++ b/src/elements/textfield.rs
@@ -1,5 +1,6 @@
 use crate::{builder::validator::textfieldinfo::TextFieldInfo, prelude::*};
 use anyhow::Result;
+use ecs::World;
 use utilities::prelude::*;
 
 use std::sync::{
@@ -169,7 +170,7 @@ impl TextField {
 
     pub fn set_text_changed_callback<F>(&self, f: F)
     where
-        F: Fn(&mut GuiHandler, Option<String>) -> Result<()> + Send + Sync + 'static,
+        F: Fn(&mut World, Option<String>) -> Result<()> + Send + Sync + 'static,
     {
         self.text_changed_executable.set_callback(f);
     }
diff --git a/src/elements/traits.rs b/src/elements/traits.rs
index 7f201f5..9a20c79 100644
--- a/src/elements/traits.rs
+++ b/src/elements/traits.rs
@@ -1,5 +1,6 @@
 use crate::prelude::*;
 use anyhow::Result;
+use ecs::World;
 
 use std::{any::Any, collections::HashMap, sync::Arc};
 
@@ -26,25 +27,31 @@ where
 pub trait Functionality {
     fn set_click_callbacks(
         &self,
-        callbacks: Vec<(
-            &str,
-            Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>,
-        )>,
+        callbacks: Vec<(&str, Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>)>,
     ) -> Result<()>;
 
     fn set_select_callbacks(
         &self,
-        callbacks: Vec<(&str, Box<CustomCallback<bool, ()>>)>,
+        callbacks: Vec<(
+            &str,
+            Box<dyn Fn(&mut World, bool) -> Result<()> + Send + Sync>,
+        )>,
     ) -> Result<()>;
 
     fn set_custom_callbacks(
         &self,
-        callbacks: Vec<(&str, Box<CustomCallback<ControllerButton, bool>>)>,
+        callbacks: Vec<(
+            &str,
+            Box<dyn Fn(&mut World, ControllerButton) -> Result<bool> + Send + Sync>,
+        )>,
     ) -> Result<()>;
 
     fn set_vec_callbacks(
         &self,
-        callbacks: Vec<(&str, Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>)>,
+        callbacks: Vec<(
+            &str,
+            Box<dyn Fn(&mut World, &dyn Any) -> Result<()> + Send + Sync>,
+        )>,
     ) -> Result<()>;
 }
 
diff --git a/src/gui_handler/gui/executable.rs b/src/gui_handler/gui/executable.rs
index ad8f231..a334b73 100644
--- a/src/gui_handler/gui/executable.rs
+++ b/src/gui_handler/gui/executable.rs
@@ -1,6 +1,7 @@
 //! `Executable` is a property to execute a closure
 
 use anyhow::Result;
+use ecs::World;
 
 use std::sync::{Arc, RwLock};
 
@@ -8,7 +9,7 @@ use crate::prelude::*;
 
 /// `Executable` holds a closure which can be executed
 pub struct Executable<I: Send + Sync> {
-    callback: RwLock<Option<Arc<dyn Fn(&mut GuiHandler, I) -> Result<()> + Send + Sync>>>,
+    callback: RwLock<Option<Arc<dyn Fn(&mut World, I) -> Result<()> + Send + Sync>>>,
 }
 
 impl<I: Send + Sync + 'static> Executable<I> {
@@ -26,7 +27,7 @@ impl<I: Send + Sync + 'static> Executable<I> {
     /// * `callback` is a `Option<Callback>` closure
     pub fn set_callback<F>(&self, callback: impl Into<Option<F>>)
     where
-        F: Fn(&mut GuiHandler, I) -> Result<()> + Send + Sync + 'static,
+        F: Fn(&mut World, I) -> Result<()> + Send + Sync + 'static,
     {
         let mut function = self.callback.write().unwrap();
 
diff --git a/src/gui_handler/gui/selectable.rs b/src/gui_handler/gui/selectable.rs
index a4bfa80..9fb49fa 100644
--- a/src/gui_handler/gui/selectable.rs
+++ b/src/gui_handler/gui/selectable.rs
@@ -3,6 +3,7 @@
 use super::executable::Executable;
 use crate::prelude::*;
 use anyhow::Result;
+use ecs::World;
 
 use std::sync::{
     Arc, RwLock, Weak,
@@ -39,7 +40,8 @@ pub struct Selectable {
     on_select_executable: Arc<Executable<bool>>,
 
     // used for custom buttons
-    custom_callback: RwLock<Option<Box<dyn Fn(ControllerButton) -> Result<bool> + Send + Sync>>>,
+    custom_callback:
+        RwLock<Option<Box<dyn Fn(&mut World, ControllerButton) -> Result<bool> + Send + Sync>>>,
 }
 
 impl Selectable {
@@ -115,7 +117,7 @@ impl Selectable {
 
     pub fn set_custom_callback<F>(&self, custom_callback: F)
     where
-        F: Fn(ControllerButton) -> Result<bool> + Send + Sync + 'static,
+        F: Fn(&mut World, ControllerButton) -> Result<bool> + Send + Sync + 'static,
     {
         *self.custom_callback.write().unwrap() = Some(Box::new(custom_callback));
     }
@@ -176,9 +178,13 @@ impl Selectable {
         Ok(())
     }
 
-    pub(crate) fn custom_click_event(&self, button: ControllerButton) -> Result<bool> {
+    pub(crate) fn custom_click_event(
+        &self,
+        world: &mut World,
+        button: ControllerButton,
+    ) -> Result<bool> {
         if let Some(custom_callback) = self.custom_callback.read().unwrap().as_ref() {
-            if custom_callback(button)? {
+            if custom_callback(world, button)? {
                 #[cfg(feature = "audio")]
                 {
                     if let Some(audible) = self.click_audible.read().unwrap().as_ref() {
diff --git a/src/gui_handler/gui/topgui.rs b/src/gui_handler/gui/topgui.rs
index 929d76e..c7532a9 100644
--- a/src/gui_handler/gui/topgui.rs
+++ b/src/gui_handler/gui/topgui.rs
@@ -1,21 +1,20 @@
 /// A trait that is used by the gui handler as the target for input
 use anyhow::Result;
-
-use crate::prelude::*;
+use ecs::World;
 
 pub trait TopGui: Send + Sync {
     /// Decline method which is executed on `InputMap::B` press
-    fn decline(&self, gui_handler: &mut GuiHandler) -> Result<()>;
+    fn decline(&self, world: &mut World) -> Result<()>;
 
     /// Method which is executed on `InputMap::RightButton` press
     ///
     /// # Arguments
     /// * `second_level` adds support for multiple tab layers, e.g. RB and RT press on controller
-    fn next_tab(&self, gui_handler: &mut GuiHandler, second_level: bool) -> Result<()>;
+    fn next_tab(&self, world: &mut World, second_level: bool) -> Result<()>;
 
     /// Method which is executed on `InputMap::LeftButton` press
     /// ///
     /// # Arguments
     /// * `second_level` adds support for multiple tab layers, e.g. RB and RT press on controller
-    fn previous_tab(&self, gui_handler: &mut GuiHandler, second_level: bool) -> Result<()>;
+    fn previous_tab(&self, world: &mut World, second_level: bool) -> Result<()>;
 }
diff --git a/src/gui_handler/gui_handler.rs b/src/gui_handler/gui_handler.rs
index 5fc7636..badd9fe 100644
--- a/src/gui_handler/gui_handler.rs
+++ b/src/gui_handler/gui_handler.rs
@@ -2,6 +2,7 @@ use crate::prelude::*;
 use anyhow::{Result, anyhow};
 use assetpath::AssetPath;
 
+use ecs::World;
 use serde::{Deserialize, Serialize};
 use utilities::{impl_reprc, prelude::*};
 use vulkan_rs::{prelude::*, render_target::sub_pass::InputAttachmentInfo};
@@ -243,7 +244,7 @@ pub struct GuiHandler {
 
     text_sample_count: VkSampleCountFlags,
 
-    callback_list: Vec<Box<dyn FnOnce(&mut Self) -> Result<()> + Send + Sync>>,
+    callback_list: Vec<Box<dyn FnOnce(&mut World) -> Result<()> + Send + Sync>>,
 }
 
 impl GuiHandler {
@@ -726,9 +727,13 @@ impl GuiHandler {
         Ok(false)
     }
 
-    pub fn accept_custom_selection(&self, button: ControllerButton) -> Result<bool> {
+    pub fn accept_custom_selection(
+        &self,
+        world: &mut World,
+        button: ControllerButton,
+    ) -> Result<bool> {
         if let Some(current_selectable) = &self.current_selectable {
-            if current_selectable.custom_click_event(button)? {
+            if current_selectable.custom_click_event(world, button)? {
                 return Ok(true);
             }
         }
@@ -736,36 +741,36 @@ impl GuiHandler {
         Ok(false)
     }
 
-    pub fn decline_topgui(&mut self) -> Result<bool> {
+    pub fn decline_topgui(&mut self, world: &mut World) -> Result<bool> {
         // workaround for unwanted borrowing behaviour inside decline function
         let opt_topgui = self.top_ui.as_ref().cloned();
 
         if let Some(topgui) = opt_topgui {
-            topgui.decline(self)?;
+            topgui.decline(world)?;
             return Ok(true);
         }
 
         Ok(false)
     }
 
-    pub fn next_tab_topgui(&mut self, 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
         let opt_topgui = self.top_ui.as_ref().cloned();
 
         if let Some(topgui) = opt_topgui {
-            topgui.next_tab(self, second_level)?;
+            topgui.next_tab(world, second_level)?;
             return Ok(true);
         }
 
         Ok(false)
     }
 
-    pub fn previous_tab_topgui(&mut self, 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
         let opt_topgui = self.top_ui.as_ref().cloned();
 
         if let Some(topgui) = opt_topgui {
-            topgui.previous_tab(self, second_level)?;
+            topgui.previous_tab(world, second_level)?;
             return Ok(true);
         }
 
@@ -860,19 +865,19 @@ impl GuiHandler {
         self.tooltip_ui = tooltip;
     }
 
-    pub(crate) fn add_callback<F: FnOnce(&mut Self) -> Result<()> + Send + Sync + 'static>(
+    pub(crate) fn add_callback<F: FnOnce(&mut World) -> Result<()> + Send + Sync + 'static>(
         &mut self,
         f: F,
     ) {
         self.callback_list.push(Box::new(f));
     }
 
-    pub fn process_callbacks(&mut self) -> Result<()> {
+    pub fn process_callbacks(&mut self, world: &mut World) -> Result<()> {
         let callbacks = mem::take(&mut self.callback_list);
 
         callbacks
             .into_iter()
-            .try_for_each(|callback| callback(self))
+            .try_for_each(|callback| callback(world))
     }
 
     fn render(
diff --git a/src/keyboard/mod.rs b/src/keyboard/mod.rs
index 39c6f18..c7131cd 100644
--- a/src/keyboard/mod.rs
+++ b/src/keyboard/mod.rs
@@ -1,5 +1,6 @@
 use crate::prelude::*;
 use anyhow::Result;
+use ecs::World;
 
 use std::any::Any;
 use std::collections::HashMap;
@@ -25,8 +26,9 @@ pub struct Keyboard {
 
     mode: Arc<RwLock<KeyboardMode>>,
 
-    decline_callback: Arc<RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>>>,
-    accept_callback: Arc<RwLock<Option<Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>>>>,
+    decline_callback: Arc<RwLock<Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>>>,
+    accept_callback:
+        Arc<RwLock<Option<Box<dyn Fn(&mut World, &dyn Any) -> Result<()> + Send + Sync>>>>,
 
     elements: HashMap<String, UiElement>,
 }
@@ -39,11 +41,11 @@ impl Keyboard {
         let text_field: Arc<TextField> = text_field_gui.element("field")?;
 
         let decline_callback: Arc<
-            RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>>,
+            RwLock<Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>>,
         > = Arc::new(RwLock::new(None));
 
         let accept_callback: Arc<
-            RwLock<Option<Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>>>,
+            RwLock<Option<Box<dyn Fn(&mut World, &dyn Any) -> Result<()> + Send + Sync>>>,
         > = Arc::new(RwLock::new(None));
 
         let mode = Arc::new(RwLock::new(KeyboardMode::UpperCase));
@@ -84,10 +86,10 @@ impl Keyboard {
         gui_handler: &mut GuiHandler,
         textfield: Arc<TextField>,
         mode: &Arc<RwLock<KeyboardMode>>,
-        decline_callback: Arc<
-            RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>>,
+        decline_callback: Arc<RwLock<Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>>>,
+        accept_callback: Arc<
+            RwLock<Option<Box<dyn Fn(&mut World, &dyn Any) -> Result<()> + Send + Sync>>>,
         >,
-        accept_callback: Arc<RwLock<Option<Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>>>>,
     ) -> Result<(Arc<GuiBuilder>, Arc<GuiBuilder>, Arc<GuiBuilder>)> {
         let lower_case = GuiBuilder::from_str(gui_handler, include_str!("lower_case.xml"))?;
         let upper_case = GuiBuilder::from_str(gui_handler, include_str!("upper_case.xml"))?;
@@ -193,9 +195,9 @@ impl Keyboard {
         Self::set_text_callback(&specials, ".", textfield.clone())?;
         Self::set_text_callback(&specials, "_", textfield.clone())?;
 
-        let back = Box::new(move |gui_handler: &mut GuiHandler| {
+        let back = Box::new(move |world: &mut World| {
             if let Some(callback) = decline_callback.read().unwrap().as_ref() {
-                (callback)(gui_handler)?;
+                (callback)(world)?;
             }
 
             Ok(())
@@ -205,12 +207,12 @@ impl Keyboard {
             let weak_textfield = Arc::downgrade(&textfield);
             let weak_accept = Arc::downgrade(&accept_callback);
 
-            Box::new(move |_: &mut GuiHandler| {
+            Box::new(move |world: &mut World| {
                 if let Some(textfield) = weak_textfield.upgrade() {
                     if let Some(accept_callback) = weak_accept.upgrade() {
                         if let Some(text) = textfield.text() {
                             if let Some(callback) = accept_callback.read().unwrap().as_ref() {
-                                (callback)(&text)?;
+                                (callback)(world, &text)?;
                             }
                         }
                     }
@@ -225,13 +227,16 @@ impl Keyboard {
             let weak_lower = Arc::downgrade(&lower_case);
             let weak_upper = Arc::downgrade(&upper_case);
 
-            Box::new(move |gui_handler: &mut GuiHandler| {
+            Box::new(move |world: &mut World| {
                 if let Some(lower) = weak_lower.upgrade() {
                     if let Some(upper) = weak_upper.upgrade() {
                         let mut mode = mode.write().unwrap();
 
                         if let KeyboardMode::LowerCase = mode.deref() {
                             *mode = KeyboardMode::UpperCase;
+
+                            let gui_handler = world.resources.get_mut::<GuiHandler>();
+
                             lower.disable(gui_handler)?;
                             upper.enable(gui_handler)?;
                         }
@@ -247,13 +252,16 @@ impl Keyboard {
             let weak_upper = Arc::downgrade(&upper_case);
             let weak_specials = Arc::downgrade(&specials);
 
-            Box::new(move |gui_handler: &mut GuiHandler| {
+            Box::new(move |world: &mut World| {
                 if let Some(specials) = weak_specials.upgrade() {
                     if let Some(upper) = weak_upper.upgrade() {
                         let mut mode = mode.write().unwrap();
 
                         if let KeyboardMode::UpperCase = mode.deref() {
                             *mode = KeyboardMode::Specials;
+
+                            let gui_handler = world.resources.get_mut::<GuiHandler>();
+
                             upper.disable(gui_handler)?;
                             specials.enable(gui_handler)?;
                         }
@@ -269,13 +277,16 @@ impl Keyboard {
             let weak_lower = Arc::downgrade(&lower_case);
             let weak_specials = Arc::downgrade(&specials);
 
-            Box::new(move |gui_handler: &mut GuiHandler| {
+            Box::new(move |world: &mut World| {
                 if let Some(lower) = weak_lower.upgrade() {
                     if let Some(specials) = weak_specials.upgrade() {
                         let mut mode = mode.write().unwrap();
 
                         if let KeyboardMode::Specials = mode.deref() {
                             *mode = KeyboardMode::LowerCase;
+
+                            let gui_handler = world.resources.get_mut::<GuiHandler>();
+
                             specials.disable(gui_handler)?;
                             lower.enable(gui_handler)?;
                         }
@@ -289,8 +300,9 @@ impl Keyboard {
         let space_bar = {
             let weak_textfield = Arc::downgrade(&textfield);
 
-            Box::new(move |gui_handler: &mut GuiHandler| {
+            Box::new(move |world: &mut World| {
                 if let Some(text_field) = weak_textfield.upgrade() {
+                    let gui_handler = world.resources.get_mut::<GuiHandler>();
                     text_field.add_letter(gui_handler, ' ')?;
                 }
 
@@ -330,10 +342,11 @@ impl Keyboard {
         let weak_textfield = Arc::downgrade(&textfield);
         let weak_button = Arc::downgrade(&button_ref);
 
-        button_ref.set_callback(Box::new(move |gui_handler: &mut GuiHandler| {
+        button_ref.set_callback(Box::new(move |world: &mut World| {
             if let Some(textfield) = weak_textfield.upgrade() {
                 if let Some(button) = weak_button.upgrade() {
                     if let Some(text) = button.text()? {
+                        let gui_handler = world.resources.get_mut::<GuiHandler>();
                         textfield.add_letter(gui_handler, text.as_bytes()[0] as char)?;
                     }
                 }
@@ -347,21 +360,22 @@ impl Keyboard {
 }
 
 impl TopGui for Keyboard {
-    fn decline(&self, gui_handler: &mut GuiHandler) -> Result<()> {
+    fn decline(&self, world: &mut World) -> Result<()> {
         if let Some(callback) = self.decline_callback.read().unwrap().as_ref() {
-            (callback)(gui_handler)?;
+            (callback)(world)?;
         }
 
         Ok(())
     }
 
-    fn next_tab(&self, _gui_handler: &mut GuiHandler, _: bool) -> Result<()> {
+    fn next_tab(&self, _world: &mut World, _: bool) -> Result<()> {
         Ok(())
     }
 
-    fn previous_tab(&self, gui_handler: &mut GuiHandler, second_level: bool) -> Result<()> {
+    fn previous_tab(&self, world: &mut World, second_level: bool) -> Result<()> {
         // abuse event
         if !second_level {
+            let gui_handler = world.resources.get_mut::<GuiHandler>();
             self.text_field.remove_last(gui_handler)?;
         }
 
@@ -449,21 +463,22 @@ impl TopLevelGui for Keyboard {
 impl Functionality for Keyboard {
     fn set_click_callbacks(
         &self,
-        callbacks: Vec<(
-            &str,
-            Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>,
-        )>,
+        callbacks: Vec<(&str, Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>)>,
     ) -> Result<()> {
-        for (name, callback) in callbacks {
-            if name == "decline" {
-                *self.decline_callback.write().unwrap() = Some(callback);
-            }
+        if let Some((_, callback)) = callbacks.into_iter().find(|(name, _)| *name == "decline") {
+            *self.decline_callback.write().unwrap() = Some(callback);
         }
 
         Ok(())
     }
 
-    fn set_select_callbacks(&self, _: Vec<(&str, Box<CustomCallback<bool, ()>>)>) -> Result<()> {
+    fn set_select_callbacks(
+        &self,
+        _: Vec<(
+            &str,
+            Box<dyn Fn(&mut World, bool) -> Result<()> + Send + Sync>,
+        )>,
+    ) -> Result<()> {
         Ok(())
     }
 
@@ -471,7 +486,7 @@ impl Functionality for Keyboard {
         &self,
         _: Vec<(
             &str,
-            Box<dyn Fn(ControllerButton) -> Result<bool> + Send + Sync>,
+            Box<dyn Fn(&mut World, ControllerButton) -> Result<bool> + Send + Sync>,
         )>,
     ) -> Result<()> {
         Ok(())
@@ -479,7 +494,10 @@ impl Functionality for Keyboard {
 
     fn set_vec_callbacks(
         &self,
-        callbacks: Vec<(&str, Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>)>,
+        callbacks: Vec<(
+            &str,
+            Box<dyn Fn(&mut World, &dyn Any) -> Result<()> + Send + Sync>,
+        )>,
     ) -> Result<()> {
         for (name, callback) in callbacks {
             if name == "accept" {
diff --git a/src/lib.rs b/src/lib.rs
index 72e4a27..f91f018 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -13,5 +13,3 @@ mod element_creator;
 mod gui_direction;
 mod mouse_button;
 pub mod prelude;
-
-pub type CustomCallback<I, O> = dyn Fn(I) -> anyhow::Result<O> + Send + Sync;
diff --git a/src/prelude.rs b/src/prelude.rs
index fcc0468..5ec1c36 100644
--- a/src/prelude.rs
+++ b/src/prelude.rs
@@ -9,5 +9,3 @@ pub use super::keyboard::Keyboard;
 pub use super::mouse_button::MouseButton;
 pub use super::states::*;
 pub use super::tab_control::TabControl;
-
-pub use super::CustomCallback;
diff --git a/src/states.rs b/src/states.rs
index 9762944..3b3ae0b 100644
--- a/src/states.rs
+++ b/src/states.rs
@@ -1,18 +1,20 @@
 use crate::prelude::*;
 use anyhow::Result;
 use assetpath::AssetPath;
+use ecs::World;
+use utilities::prelude::remove_life_time_mut;
 
 use std::any::Any;
 use std::collections::HashMap;
 
 use std::sync::{Arc, Mutex, RwLock, Weak};
 
-pub trait FutureStateChange: Fn(&mut GuiHandler) -> Result<()> + Send + Sync {
+pub trait FutureStateChange: Fn(&mut World) -> Result<()> + Send + Sync {
     fn clone_box<'a>(&self) -> Box<dyn 'a + FutureStateChange>
     where
         Self: 'a;
 
-    fn as_fn(&self) -> &(dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync)
+    fn as_fn(&self) -> &(dyn Fn(&mut World) -> Result<()> + Send + Sync)
     where
         Self: Sized,
     {
@@ -21,7 +23,7 @@ pub trait FutureStateChange: Fn(&mut GuiHandler) -> Result<()> + Send + Sync {
 
     fn as_static(
         &'static self,
-    ) -> &'static (dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync + 'static)
+    ) -> &'static (dyn Fn(&mut World) -> Result<()> + Send + Sync + 'static)
     where
         Self: Sized,
     {
@@ -29,7 +31,7 @@ pub trait FutureStateChange: Fn(&mut GuiHandler) -> Result<()> + Send + Sync {
     }
 }
 
-impl<F: Fn(&mut GuiHandler) -> Result<()> + Clone + Send + Sync> FutureStateChange for F {
+impl<F: Fn(&mut World) -> Result<()> + Clone + Send + Sync> FutureStateChange for F {
     fn clone_box<'a>(&self) -> Box<dyn 'a + FutureStateChange>
     where
         Self: 'a,
@@ -49,12 +51,12 @@ struct State {
 
     top_level_gui: Arc<dyn TopLevelGui>,
 
-    on_activate: RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>>,
-    on_deactivate: RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>>,
+    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 GuiHandler) -> Result<()> + Send + Sync>>>,
-    previous_tab: RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>>,
-    decline: RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> 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
@@ -150,36 +152,46 @@ impl GetElement<ProgressBar> for StateHandle {
 /// Update type
 pub enum StateUpdateType<'a> {
     /// Updates the callback which is executed on next tab event
-    NextTab(Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>),
+    NextTab(Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>),
 
     /// Updates the callback which is executed on previous tab event
-    PreviousTab(Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>),
+    PreviousTab(Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>),
 
     /// Updates the callback which is executed on decline event
-    Decline(Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>),
+    Decline(Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>),
 
     /// Updates callbacks by identifier
-    ClickCallbacks(
+    ClickCallbacks(Vec<(&'a str, Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>)>),
+
+    /// Updates callbacks by identifier
+    SelectCallbacks(
         Vec<(
             &'a str,
-            Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>,
+            Box<dyn Fn(&mut World, bool) -> Result<()> + Send + Sync>,
         )>,
     ),
 
     /// Updates callbacks by identifier
-    SelectCallbacks(Vec<(&'a str, Box<CustomCallback<bool, ()>>)>),
-
-    /// Updates callbacks by identifier
-    CustomClickCallbacks(Vec<(&'a str, Box<CustomCallback<ControllerButton, bool>>)>),
+    CustomClickCallbacks(
+        Vec<(
+            &'a str,
+            Box<dyn Fn(&mut World, ControllerButton) -> Result<bool> + Send + Sync>,
+        )>,
+    ),
 
     /// Updates callbacks by identifier with input parameters
-    VecCallbacks(Vec<(&'a str, Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>)>),
+    VecCallbacks(
+        Vec<(
+            &'a str,
+            Box<dyn Fn(&mut World, &dyn Any) -> Result<()> + Send + Sync>,
+        )>,
+    ),
 
     /// Updates the callback which is executed when this state gets activated on state change
-    OnActivate(Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>),
+    OnActivate(Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>),
 
     /// Updates the callback which is executed when this state gets deactivated on state change
-    OnDeactivate(Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>),
+    OnDeactivate(Option<Box<dyn Fn(&mut World) -> Result<()> + Send + Sync>>),
 }
 
 /// Type of the state to be created
@@ -274,14 +286,13 @@ impl States {
     /// # Arguments
     ///
     /// * `id` - Set state with the given identifier or None
-    pub fn set_state<'b>(
-        &self,
-        gui_handler: &mut GuiHandler,
-        id: impl Into<Option<&'b str>>,
-    ) -> Result<()> {
+    pub fn set_state<'b>(&self, world: &mut World, id: impl Into<Option<&'b str>>) -> Result<()> {
+        let gui_handler = unsafe { remove_life_time_mut(world.resources.get_mut::<GuiHandler>()) };
+
         Self::_set_state(
             id.into().map(|id| self.get_state(id)).transpose()?,
             &mut *self.current_state.lock().unwrap(),
+            world,
             gui_handler,
             self.log_state_change,
         )
@@ -290,6 +301,7 @@ impl States {
     fn _set_state(
         state: Option<Arc<State>>,
         current: &mut Option<Arc<State>>,
+        world: &mut World,
         gui_handler: &mut GuiHandler,
         logging: bool,
     ) -> Result<()> {
@@ -302,13 +314,13 @@ impl States {
             }
 
             // execute deactivate on old state
-            old_state.deactivate(gui_handler)?;
+            old_state.deactivate(world, gui_handler)?;
         }
 
         // set new state, either no state or requested state
         match state {
             Some(state) => {
-                state.activate(gui_handler)?;
+                state.activate(world, gui_handler)?;
                 gui_handler.set_top_gui(Some(state.clone()));
 
                 if logging {
@@ -354,11 +366,15 @@ impl States {
         let weak_current_state = Arc::downgrade(&self.current_state);
         let logging = self.log_state_change;
 
-        Ok(Box::new(move |gui_handler: &mut GuiHandler| {
+        Ok(Box::new(move |world: &mut World| {
             if let Some(current) = weak_current_state.upgrade() {
+                let gui_handler =
+                    unsafe { remove_life_time_mut(world.resources.get_mut::<GuiHandler>()) };
+
                 Self::_set_state(
                     weak_state.as_ref().map(|w| w.upgrade()).flatten(),
                     &mut *current.lock().unwrap(),
+                    world,
                     gui_handler,
                     logging,
                 )?;
@@ -429,21 +445,21 @@ impl State {
         }
     }
 
-    fn activate(&self, gui_handler: &mut GuiHandler) -> Result<()> {
+    fn activate(&self, world: &mut World, gui_handler: &mut GuiHandler) -> Result<()> {
         self.top_level_gui.enable(gui_handler)?;
 
         if let Some(activate) = self.on_activate.read().unwrap().as_ref() {
-            (activate)(gui_handler)?;
+            (activate)(world)?;
         }
 
         Ok(())
     }
 
-    fn deactivate(&self, gui_handler: &mut GuiHandler) -> Result<()> {
+    fn deactivate(&self, world: &mut World, gui_handler: &mut GuiHandler) -> Result<()> {
         self.top_level_gui.disable(gui_handler)?;
 
         if let Some(deactivate) = self.on_deactivate.read().unwrap().as_ref() {
-            (deactivate)(gui_handler)?;
+            (deactivate)(world)?;
         }
 
         Ok(())
@@ -451,49 +467,43 @@ impl State {
 
     fn set_on_activate(
         &self,
-        on_activate: Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>,
+        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 GuiHandler) -> Result<()> + Send + Sync>>,
+        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 GuiHandler) -> Result<()> + Send + Sync>>,
+        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 GuiHandler) -> Result<()> + Send + Sync>>,
-    ) {
+    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 GuiHandler) -> Result<()> + Send + Sync>>,
-    ) {
+    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, gui_handler: &mut GuiHandler) -> Result<()> {
+    fn decline(&self, world: &mut World) -> Result<()> {
         match self.decline.read().unwrap().as_ref() {
             Some(decline) => {
-                (decline)(gui_handler)?;
+                (decline)(world)?;
             }
             None => {
                 if let Some(top_gui) = self.top_level_gui.top_gui() {
-                    top_gui.decline(gui_handler)?;
+                    top_gui.decline(world)?;
                 }
             }
         }
@@ -501,14 +511,14 @@ impl TopGui for State {
         Ok(())
     }
 
-    fn next_tab(&self, gui_handler: &mut GuiHandler, second_level: bool) -> Result<()> {
+    fn next_tab(&self, world: &mut World, second_level: bool) -> Result<()> {
         match self.next_tab.read().unwrap().as_ref() {
             Some(next_tab) => {
-                (next_tab)(gui_handler)?;
+                (next_tab)(world)?;
             }
             None => {
                 if let Some(top_gui) = self.top_level_gui.top_gui() {
-                    top_gui.next_tab(gui_handler, second_level)?;
+                    top_gui.next_tab(world, second_level)?;
                 }
             }
         }
@@ -516,14 +526,14 @@ impl TopGui for State {
         Ok(())
     }
 
-    fn previous_tab(&self, gui_handler: &mut GuiHandler, second_level: bool) -> Result<()> {
+    fn previous_tab(&self, world: &mut World, second_level: bool) -> Result<()> {
         match self.previous_tab.read().unwrap().as_ref() {
             Some(previous_tab) => {
-                (previous_tab)(gui_handler)?;
+                (previous_tab)(world)?;
             }
             None => {
                 if let Some(top_gui) = self.top_level_gui.top_gui() {
-                    top_gui.previous_tab(gui_handler, second_level)?;
+                    top_gui.previous_tab(world, second_level)?;
                 }
             }
         }