@@ -506,6 +506,10 @@ impl HitboxId {
///
/// See [`Hitbox::is_hovered`] for details.
pub fn is_hovered(self, window: &Window) -> bool {
+ // If this hitbox has captured the pointer, it's always considered hovered
+ if window.captured_hitbox == Some(self) {
+ return true;
+ }
let hit_test = &window.mouse_hit_test;
for id in hit_test.ids.iter().take(hit_test.hover_hitbox_count) {
if self == *id {
@@ -892,6 +896,9 @@ pub struct Window {
pub(crate) pending_input_observers: SubscriberSet<(), AnyObserver>,
prompt: Option<RenderablePromptHandle>,
pub(crate) client_inset: Option<Pixels>,
+ /// The hitbox that has captured the pointer, if any.
+ /// While captured, mouse events route to this hitbox regardless of hit testing.
+ captured_hitbox: Option<HitboxId>,
#[cfg(any(feature = "inspector", debug_assertions))]
inspector: Option<Entity<Inspector>>,
}
@@ -1316,6 +1323,7 @@ impl Window {
prompt: None,
client_inset: None,
image_cache_stack: Vec::new(),
+ captured_hitbox: None,
#[cfg(any(feature = "inspector", debug_assertions))]
inspector: None,
})
@@ -1999,6 +2007,26 @@ impl Window {
self.mouse_position
}
+ /// Captures the pointer for the given hitbox. While captured, all mouse move and mouse up
+ /// events will be routed to listeners that check this hitbox's `is_hovered` status,
+ /// regardless of actual hit testing. This enables drag operations that continue
+ /// even when the pointer moves outside the element's bounds.
+ ///
+ /// The capture is automatically released on mouse up.
+ pub fn capture_pointer(&mut self, hitbox_id: HitboxId) {
+ self.captured_hitbox = Some(hitbox_id);
+ }
+
+ /// Releases any active pointer capture.
+ pub fn release_pointer(&mut self) {
+ self.captured_hitbox = None;
+ }
+
+ /// Returns the hitbox that has captured the pointer, if any.
+ pub fn captured_hitbox(&self) -> Option<HitboxId> {
+ self.captured_hitbox
+ }
+
/// The current state of the keyboard's modifiers
pub fn modifiers(&self) -> Modifiers {
self.modifiers
@@ -3890,6 +3918,11 @@ impl Window {
self.refresh();
}
}
+
+ // Auto-release pointer capture on mouse up
+ if event.is::<MouseUpEvent>() && self.captured_hitbox.is_some() {
+ self.captured_hitbox = None;
+ }
}
fn dispatch_key_event(&mut self, event: &dyn Any, cx: &mut App) {