Fix PaneGrid mouse interaction when clicking a pane
This commit is contained in:
parent
8bb1587a74
commit
c723c101d4
2 changed files with 60 additions and 100 deletions
|
|
@ -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),
|
||||
}
|
||||
_ => DragEvent::Canceled { pane },
|
||||
}
|
||||
};
|
||||
} else {
|
||||
let dropped_region = contents
|
||||
.zip(layout.children())
|
||||
.find_map(|(target, layout)| {
|
||||
layout_region(layout, cursor_position)
|
||||
.map(|region| (target, region))
|
||||
});
|
||||
|
||||
shell.publish(on_drag(event));
|
||||
match dropped_region {
|
||||
Some(((target, _), region))
|
||||
if pane != target =>
|
||||
{
|
||||
DragEvent::Dropped {
|
||||
pane,
|
||||
target: Target::Pane(
|
||||
target, region,
|
||||
),
|
||||
}
|
||||
}
|
||||
_ => DragEvent::Canceled { pane },
|
||||
}
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue