diff --git a/widget/src/lib.rs b/widget/src/lib.rs index d9bdf1f3..526f3576 100644 --- a/widget/src/lib.rs +++ b/widget/src/lib.rs @@ -9,6 +9,8 @@ pub use iced_renderer::graphics; pub use core::widget::Id; +pub(crate) const DRAG_DEADBAND_DISTANCE: f32 = 10.0; + mod action; mod mouse_area; mod pin; diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs index d43c69bd..9358c0ad 100644 --- a/widget/src/pane_grid.rs +++ b/widget/src/pane_grid.rs @@ -92,7 +92,8 @@ use crate::core::{ }; use log::trace; -const DRAG_DEADBAND_DISTANCE: f32 = 10.0; +use crate::DRAG_DEADBAND_DISTANCE; + const THICKNESS_RATIO: f32 = 25.0; /// A collection of panes distributed using either vertical or horizontal splits diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index e005a7b8..61a18bd5 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -961,6 +961,16 @@ where y: y + translation.y as f64, }, )), + Event::Touch(touch::Event::FingerLifted { + id, + position, + }) if matches!( + state.interaction, + Interaction::TouchScrolling(_) + ) => + { + Event::Touch(touch::Event::FingerLost { id, position }) + } e => e, }; self.content.as_widget_mut().update( @@ -988,6 +998,14 @@ where } }; + if matches!( + event, + Event::Mouse(mouse::Event::CursorMoved { .. }) + | Event::Touch(touch::Event::FingerPressed { .. }) + ) { + state.suppress_touch_hover = false; + } + if matches!( event, Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) @@ -996,10 +1014,18 @@ where | touch::Event::FingerLost { .. } ) ) { + if matches!(state.interaction, Interaction::TouchScrolling(_)) { + state.suppress_touch_hover = true; + } state.interaction = Interaction::None; + state.touch_press_start = None; return; } + if let Event::Touch(touch::Event::FingerPressed { .. }) = event { + state.touch_press_start = cursor_over_scrollable; + } + if shell.is_event_captured() { return; } @@ -1093,14 +1119,31 @@ where Interaction::TouchScrolling(position); } touch::Event::FingerMoved { .. } => { - let Interaction::TouchScrolling( - scroll_box_touched_at, - ) = state.interaction + let Some(cursor_position) = cursor.position() else { return; }; - let Some(cursor_position) = cursor.position() + if !matches!( + state.interaction, + Interaction::TouchScrolling(_) + ) { + let Some(start) = state.touch_press_start + else { + return; + }; + if start.distance(cursor_position) + < crate::DRAG_DEADBAND_DISTANCE + { + return; + } + state.interaction = + Interaction::TouchScrolling(start); + } + + let Interaction::TouchScrolling( + scroll_box_touched_at, + ) = state.interaction else { return; }; @@ -1322,6 +1365,14 @@ where state.translation(self.direction, bounds, content_bounds); let cursor = match cursor_over_scrollable { + _ if state.suppress_touch_hover + || matches!( + state.interaction, + Interaction::TouchScrolling(_) + ) => + { + mouse::Cursor::Unavailable + } Some(cursor_position) if !(mouse_over_x_scrollbar || mouse_over_y_scrollbar) => { @@ -1497,6 +1548,14 @@ where state.translation(self.direction, bounds, content_bounds); let cursor = match cursor_over_scrollable { + _ if state.suppress_touch_hover + || matches!( + state.interaction, + Interaction::TouchScrolling(_) + ) => + { + cursor.levitate() + translation + } Some(cursor_position) if !(mouse_over_x_scrollbar || mouse_over_y_scrollbar) => { @@ -2022,6 +2081,8 @@ struct State { last_notified: Option, last_scrolled: Option, is_scrollbar_visible: bool, + touch_press_start: Option, + suppress_touch_hover: bool, } #[derive(Debug, Clone, Copy)] @@ -2047,6 +2108,8 @@ impl Default for State { last_notified: None, last_scrolled: None, is_scrollbar_visible: true, + touch_press_start: None, + suppress_touch_hover: false, } } }