diff options
| author | 2024-02-27 02:31:09 +0100 | |
|---|---|---|
| committer | 2024-02-27 02:31:09 +0100 | |
| commit | 13e399ccba0ad75f9cb922a5d5f3a24fbbc03fe0 (patch) | |
| tree | eaa466526366b912e15c7ea4c64996f906b9a96d /widget/src | |
| parent | 8bb1587a748f2c579ce8ea7f5c584cf4a6361e83 (diff) | |
| parent | c723c101d4e5be45ad6dbe49d92cd7980b954a58 (diff) | |
| download | iced-13e399ccba0ad75f9cb922a5d5f3a24fbbc03fe0.tar.gz iced-13e399ccba0ad75f9cb922a5d5f3a24fbbc03fe0.tar.bz2 iced-13e399ccba0ad75f9cb922a5d5f3a24fbbc03fe0.zip | |
Merge pull request #2300 from iced-rs/fix/pane-grid-drag
Fix `PaneGrid` mouse interaction when clicking a pane
Diffstat (limited to '')
| -rw-r--r-- | widget/src/pane_grid.rs | 141 | ||||
| -rw-r--r-- | widget/src/pane_grid/state.rs | 17 | 
2 files changed, 59 insertions, 99 deletions
| diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs index 37562504..478a7024 100644 --- a/widget/src/pane_grid.rs +++ b/widget/src/pane_grid.rs @@ -46,6 +46,9 @@ use crate::core::{      Vector, Widget,  }; +const DRAG_DEADBAND_DISTANCE: f32 = 10.0; +const THICKNESS_RATIO: f32 = 25.0; +  /// A collection of panes distributed using either vertical or horizontal splits  /// to completely fill the space available.  /// @@ -532,8 +535,6 @@ pub fn update<'a, Message, T: Draggable>(      on_drag: &Option<Box<dyn Fn(DragEvent) -> Message + 'a>>,      on_resize: &Option<(f32, Box<dyn Fn(ResizeEvent) -> Message + 'a>)>,  ) -> event::Status { -    const DRAG_DEADBAND_DISTANCE: f32 = 10.0; -      let mut event_status = event::Status::Ignored;      match event { @@ -575,6 +576,7 @@ pub fn update<'a, Message, T: Draggable>(                                  shell,                                  contents,                                  on_click, +                                on_drag,                              );                          }                      } @@ -586,6 +588,7 @@ pub fn update<'a, Message, T: Draggable>(                              shell,                              contents,                              on_click, +                            on_drag,                          );                      }                  } @@ -594,38 +597,44 @@ pub fn update<'a, Message, T: Draggable>(          Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))          | Event::Touch(touch::Event::FingerLifted { .. })          | Event::Touch(touch::Event::FingerLost { .. }) => { -            if let Some((pane, _)) = action.picked_pane() { +            if let Some((pane, origin)) = action.picked_pane() {                  if let Some(on_drag) = on_drag {                      if let Some(cursor_position) = cursor.position() { -                        let event = if let Some(edge) = -                            in_edge(layout, cursor_position) +                        if cursor_position.distance(origin) +                            > DRAG_DEADBAND_DISTANCE                          { -                            DragEvent::Dropped { -                                pane, -                                target: Target::Edge(edge), -                            } -                        } else { -                            let dropped_region = contents -                                .zip(layout.children()) -                                .find_map(|(target, layout)| { -                                    layout_region(layout, cursor_position) -                                        .map(|region| (target, region)) -                                }); - -                            match dropped_region { -                                Some(((target, _), region)) -                                    if pane != target => -                                { -                                    DragEvent::Dropped { -                                        pane, -                                        target: Target::Pane(target, region), +                            let event = if let Some(edge) = +                                in_edge(layout, cursor_position) +                            { +                                DragEvent::Dropped { +                                    pane, +                                    target: Target::Edge(edge), +                                } +                            } else { +                                let dropped_region = contents +                                    .zip(layout.children()) +                                    .find_map(|(target, layout)| { +                                        layout_region(layout, cursor_position) +                                            .map(|region| (target, region)) +                                    }); + +                                match dropped_region { +                                    Some(((target, _), region)) +                                        if pane != target => +                                    { +                                        DragEvent::Dropped { +                                            pane, +                                            target: Target::Pane( +                                                target, region, +                                            ), +                                        }                                      } +                                    _ => DragEvent::Canceled { pane },                                  } -                                _ => DragEvent::Canceled { pane }, -                            } -                        }; +                            }; -                        shell.publish(on_drag(event)); +                            shell.publish(on_drag(event)); +                        }                      }                  } @@ -638,49 +647,7 @@ pub fn update<'a, Message, T: Draggable>(          }          Event::Mouse(mouse::Event::CursorMoved { .. })          | Event::Touch(touch::Event::FingerMoved { .. }) => { -            if let Some((_, origin)) = action.clicked_pane() { -                if let Some(on_drag) = &on_drag { -                    let bounds = layout.bounds(); - -                    if let Some(cursor_position) = cursor.position_over(bounds) -                    { -                        let mut clicked_region = contents -                            .zip(layout.children()) -                            .filter(|(_, layout)| { -                                layout.bounds().contains(cursor_position) -                            }); - -                        if let Some(((pane, content), layout)) = -                            clicked_region.next() -                        { -                            if content -                                .can_be_dragged_at(layout, cursor_position) -                            { -                                let pane_position = layout.position(); - -                                let new_origin = cursor_position -                                    - Vector::new( -                                        pane_position.x, -                                        pane_position.y, -                                    ); - -                                if new_origin.distance(origin) -                                    > DRAG_DEADBAND_DISTANCE -                                { -                                    *action = state::Action::Dragging { -                                        pane, -                                        origin, -                                    }; - -                                    shell.publish(on_drag(DragEvent::Picked { -                                        pane, -                                    })); -                                } -                            } -                        } -                    } -                } -            } else if let Some((_, on_resize)) = on_resize { +            if let Some((_, on_resize)) = on_resize {                  if let Some((split, _)) = action.picked_split() {                      let bounds = layout.bounds(); @@ -755,6 +722,7 @@ fn click_pane<'a, Message, T>(      shell: &mut Shell<'_, Message>,      contents: impl Iterator<Item = (Pane, T)>,      on_click: &Option<Box<dyn Fn(Pane) -> Message + 'a>>, +    on_drag: &Option<Box<dyn Fn(DragEvent) -> Message + 'a>>,  ) where      T: Draggable,  { @@ -762,15 +730,21 @@ fn click_pane<'a, Message, T>(          .zip(layout.children())          .filter(|(_, layout)| layout.bounds().contains(cursor_position)); -    if let Some(((pane, _), layout)) = clicked_region.next() { +    if let Some(((pane, content), layout)) = clicked_region.next() {          if let Some(on_click) = &on_click {              shell.publish(on_click(pane));          } -        let pane_position = layout.position(); -        let origin = -            cursor_position - Vector::new(pane_position.x, pane_position.y); -        *action = state::Action::Clicking { pane, origin }; +        if let Some(on_drag) = &on_drag { +            if content.can_be_dragged_at(layout, cursor_position) { +                *action = state::Action::Dragging { +                    pane, +                    origin: cursor_position, +                }; + +                shell.publish(on_drag(DragEvent::Picked { pane })); +            } +        }      }  } @@ -783,7 +757,7 @@ pub fn mouse_interaction(      spacing: f32,      resize_leeway: Option<f32>,  ) -> Option<mouse::Interaction> { -    if action.clicked_pane().is_some() || action.picked_pane().is_some() { +    if action.picked_pane().is_some() {          return Some(mouse::Interaction::Grabbing);      } @@ -841,7 +815,13 @@ pub fn draw<Theme, Renderer, T>(      Theme: StyleSheet,      Renderer: crate::core::Renderer,  { -    let picked_pane = action.picked_pane(); +    let picked_pane = action.picked_pane().filter(|(_, origin)| { +        cursor +            .position() +            .map(|position| position.distance(*origin)) +            .unwrap_or_default() +            > DRAG_DEADBAND_DISTANCE +    });      let picked_split = action          .picked_split() @@ -962,8 +942,7 @@ pub fn draw<Theme, Renderer, T>(          if let Some(cursor_position) = cursor.position() {              let bounds = layout.bounds(); -            let translation = cursor_position -                - Point::new(bounds.x + origin.x, bounds.y + origin.y); +            let translation = cursor_position - Point::new(origin.x, origin.y);              renderer.with_translation(translation, |renderer| {                  renderer.with_layer(bounds, |renderer| { @@ -1020,8 +999,6 @@ pub fn draw<Theme, Renderer, T>(      }  } -const THICKNESS_RATIO: f32 = 25.0; -  fn in_edge(layout: Layout<'_>, cursor: Point) -> Option<Edge> {      let bounds = layout.bounds(); diff --git a/widget/src/pane_grid/state.rs b/widget/src/pane_grid/state.rs index 5d1fe254..481cd770 100644 --- a/widget/src/pane_grid/state.rs +++ b/widget/src/pane_grid/state.rs @@ -403,15 +403,6 @@ pub enum Action {      ///      /// [`PaneGrid`]: super::PaneGrid      Idle, -    /// A [`Pane`] in the [`PaneGrid`] is being clicked. -    /// -    /// [`PaneGrid`]: super::PaneGrid -    Clicking { -        /// The [`Pane`] being clicked. -        pane: Pane, -        /// The starting [`Point`] of the click interaction. -        origin: Point, -    },      /// A [`Pane`] in the [`PaneGrid`] is being dragged.      ///      /// [`PaneGrid`]: super::PaneGrid @@ -441,14 +432,6 @@ impl Action {          }      } -    /// Returns the current [`Pane`] that is being clicked, if any. -    pub fn clicked_pane(&self) -> Option<(Pane, Point)> { -        match *self { -            Action::Clicking { pane, origin, .. } => Some((pane, origin)), -            _ => None, -        } -    } -      /// Returns the current [`Split`] that is being dragged, if any.      pub fn picked_split(&self) -> Option<(Split, Axis)> {          match *self { | 
