diff --git a/src/ui/app.rs b/src/ui/app.rs
index 199d195db146ae8c6c97c1b5b555385e69407996..801b580c3585203a1b8eadc74a277380cae24b74 100644
--- a/src/ui/app.rs
+++ b/src/ui/app.rs
@@ -49,11 +49,7 @@ impl eframe::App for App {
         let panes_tree = &mut self.state.panes_tree;
 
         // Get the id of the hovered pane, in order to apply actions to it
-        let hovered_pane = panes_tree
-            .tiles
-            .iter()
-            .find(|(_, tile)| matches!(tile, Tile::Pane(pane) if pane.contains_pointer()))
-            .map(|(id, _)| *id);
+        let hovered_pane = self.behavior.tile_id_hovered;
         trace!("Hovered pane: {:?}", hovered_pane);
 
         // Capture any pane action generated by pane children
@@ -400,6 +396,7 @@ impl AppState {
 #[derive(Default)]
 pub struct AppBehavior {
     pub action: Option<(TileId, PaneAction)>,
+    pub tile_id_hovered: Option<TileId>,
 }
 
 impl Behavior<Pane> for AppBehavior {
@@ -409,10 +406,17 @@ impl Behavior<Pane> for AppBehavior {
         tile_id: TileId,
         pane: &mut Pane,
     ) -> egui_tiles::UiResponse {
+        let res = ui.scope(|ui| pane.ui(ui));
         let PaneResponse {
             action_called,
             drag_response,
-        } = pane.ui(ui);
+        } = res.inner;
+
+        // Check if the pointer is hovering over the pane
+        if res.response.contains_pointer() {
+            self.tile_id_hovered = Some(tile_id);
+        }
+
         // Capture the action and store it to be consumed in the update function
         if let Some(action_called) = action_called {
             self.action = Some((tile_id, action_called));
diff --git a/src/ui/panes.rs b/src/ui/panes.rs
index 1bec4dfe618a45380e44fa8e140420804929ccb0..9e0ea2f10a89d5f26cfee111faf8934b5649ecb0 100644
--- a/src/ui/panes.rs
+++ b/src/ui/panes.rs
@@ -29,9 +29,6 @@ pub trait PaneBehavior {
     /// Renders the UI of the pane.
     fn ui(&mut self, ui: &mut Ui) -> PaneResponse;
 
-    /// Whether the pane contains the pointer.
-    fn contains_pointer(&self) -> bool;
-
     /// Updates the pane state. This method is called before `ui` to allow the
     /// pane to update its state based on the messages received.
     fn update(&mut self, _messages: &[&TimedMessage]) {}
@@ -57,10 +54,6 @@ impl PaneBehavior for Pane {
         self.pane.ui(ui)
     }
 
-    fn contains_pointer(&self) -> bool {
-        self.pane.contains_pointer()
-    }
-
     fn update(&mut self, messages: &[&TimedMessage]) {
         self.pane.update(messages)
     }
diff --git a/src/ui/panes/default.rs b/src/ui/panes/default.rs
index 63eb9d753929847dd2d65ba44e987efce058e618..e0419cae5aa3aef587fe6c8753e662db24b5ad97 100644
--- a/src/ui/panes/default.rs
+++ b/src/ui/panes/default.rs
@@ -60,10 +60,6 @@ impl PaneBehavior for DefaultPane {
         response
     }
 
-    fn contains_pointer(&self) -> bool {
-        self.contains_pointer
-    }
-
     fn update(&mut self, _messages: &[&TimedMessage]) {}
 
     fn get_message_subscriptions(&self) -> Box<dyn Iterator<Item = u32>> {
diff --git a/src/ui/panes/messages_viewer.rs b/src/ui/panes/messages_viewer.rs
index 628f2d12ec63ae8d73188d74df9a58b00606cd8f..3d85aef8ecefb2c54be85d088e1e52fd13327540 100644
--- a/src/ui/panes/messages_viewer.rs
+++ b/src/ui/panes/messages_viewer.rs
@@ -1,4 +1,4 @@
-use egui::Label;
+use egui::{Label, Ui};
 use serde::{Deserialize, Serialize};
 
 use crate::ui::app::PaneResponse;
@@ -19,7 +19,7 @@ impl PartialEq for MessagesViewerPane {
 
 impl PaneBehavior for MessagesViewerPane {
     #[profiling::function]
-    fn ui(&mut self, ui: &mut egui::Ui) -> PaneResponse {
+    fn ui(&mut self, ui: &mut Ui) -> PaneResponse {
         let mut response = PaneResponse::default();
         let label = ui.add_sized(ui.available_size(), Label::new("This is a label"));
         self.contains_pointer = label.contains_pointer();
@@ -28,8 +28,4 @@ impl PaneBehavior for MessagesViewerPane {
         }
         response
     }
-
-    fn contains_pointer(&self) -> bool {
-        self.contains_pointer
-    }
 }
diff --git a/src/ui/panes/pid_drawing_tool.rs b/src/ui/panes/pid_drawing_tool.rs
index 1a7ec73dc7a56f3c0e9da23be78a635afe921bf5..05160cc8a16e697f7d417667b7e4bb5839881741 100644
--- a/src/ui/panes/pid_drawing_tool.rs
+++ b/src/ui/panes/pid_drawing_tool.rs
@@ -52,8 +52,6 @@ pub struct PidPane {
     editable: bool,
     #[serde(skip)]
     is_subs_window_visible: bool,
-    #[serde(skip)]
-    contains_pointer: bool,
 }
 
 impl Default for PidPane {
@@ -67,7 +65,6 @@ impl Default for PidPane {
             action: None,
             editable: false,
             is_subs_window_visible: false,
-            contains_pointer: false,
         }
     }
 }
@@ -137,7 +134,6 @@ impl PaneBehavior for PidPane {
         }
 
         // Check if the user is draqging the pane
-        self.contains_pointer = response.contains_pointer();
         let ctrl_pressed = ui.input(|i| i.modifiers.ctrl);
         if response.dragged() && (ctrl_pressed || !self.editable) {
             pane_response.set_drag_started();
@@ -146,10 +142,6 @@ impl PaneBehavior for PidPane {
         pane_response
     }
 
-    fn contains_pointer(&self) -> bool {
-        self.contains_pointer
-    }
-
     fn update(&mut self, messages: &[&TimedMessage]) {
         if let Some(msg) = messages.last() {
             for element in &mut self.elements {
diff --git a/src/ui/panes/plot.rs b/src/ui/panes/plot.rs
index 0d67e3df3a0e3ec22dcd68e0e0d8f537441a4d7f..af835401f3ca7b9dda7e81a664b8bae940461818 100644
--- a/src/ui/panes/plot.rs
+++ b/src/ui/panes/plot.rs
@@ -31,8 +31,6 @@ pub struct Plot2DPane {
     state_valid: bool,
     #[serde(skip)]
     settings_visible: bool,
-    #[serde(skip)]
-    contains_pointer: bool,
 }
 
 impl PartialEq for Plot2DPane {
@@ -145,7 +143,6 @@ impl PaneBehavior for Plot2DPane {
         }
 
         plot.show(ui, |plot_ui| {
-            self.contains_pointer = plot_ui.response().contains_pointer();
             if plot_ui.response().dragged() && ctrl_pressed {
                 response.set_drag_started();
             }
@@ -180,10 +177,6 @@ impl PaneBehavior for Plot2DPane {
         response
     }
 
-    fn contains_pointer(&self) -> bool {
-        self.contains_pointer
-    }
-
     #[profiling::function]
     fn update(&mut self, messages: &[&TimedMessage]) {
         if !self.state_valid {
diff --git a/src/ui/panes/valve_control.rs b/src/ui/panes/valve_control.rs
index f2e83cc5b08c989aecaa3ddf76e29ecbf851a094..4fdf47d0f52a9a540e6c7c2534deec32a5f9f12f 100644
--- a/src/ui/panes/valve_control.rs
+++ b/src/ui/panes/valve_control.rs
@@ -1,3 +1,4 @@
+use egui::Ui;
 use serde::{Deserialize, Serialize};
 
 use crate::ui::app::PaneResponse;
@@ -7,18 +8,10 @@ use super::PaneBehavior;
 mod enums;
 
 #[derive(Clone, PartialEq, Default, Serialize, Deserialize, Debug)]
-pub struct ValveControlPane {
-    // Temporary Internal state
-    #[serde(skip)]
-    contains_pointer: bool,
-}
+pub struct ValveControlPane {}
 
 impl PaneBehavior for ValveControlPane {
-    fn ui(&mut self, ui: &mut egui::Ui) -> PaneResponse {
+    fn ui(&mut self, ui: &mut Ui) -> PaneResponse {
         todo!()
     }
-
-    fn contains_pointer(&self) -> bool {
-        self.contains_pointer
-    }
 }