summaryrefslogtreecommitdiffstats
path: root/widget/src/pane_grid.rs
diff options
context:
space:
mode:
Diffstat (limited to 'widget/src/pane_grid.rs')
-rw-r--r--widget/src/pane_grid.rs261
1 files changed, 184 insertions, 77 deletions
diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs
index 67145e8e..040d6bb3 100644
--- a/widget/src/pane_grid.rs
+++ b/widget/src/pane_grid.rs
@@ -30,7 +30,7 @@ pub use split::Split;
pub use state::State;
pub use title_bar::TitleBar;
-pub use crate::style::pane_grid::{Line, StyleSheet};
+pub use crate::style::pane_grid::{Appearance, Line, StyleSheet};
use crate::container;
use crate::core::event::{self, Event};
@@ -313,7 +313,7 @@ where
tree: &mut Tree,
event: Event,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
@@ -331,7 +331,7 @@ where
self.contents.layout(),
&event,
layout,
- cursor_position,
+ cursor,
shell,
self.spacing,
self.contents.iter(),
@@ -353,7 +353,7 @@ where
tree,
event.clone(),
layout,
- cursor_position,
+ cursor,
renderer,
clipboard,
shell,
@@ -367,7 +367,7 @@ where
&self,
tree: &Tree,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
@@ -375,7 +375,7 @@ where
tree.state.downcast_ref(),
self.contents.layout(),
layout,
- cursor_position,
+ cursor,
self.spacing,
self.on_resize.as_ref().map(|(leeway, _)| *leeway),
)
@@ -388,7 +388,7 @@ where
content.mouse_interaction(
tree,
layout,
- cursor_position,
+ cursor,
viewport,
renderer,
self.drag_enabled(),
@@ -406,14 +406,14 @@ where
theme: &Renderer::Theme,
style: &renderer::Style,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
viewport: &Rectangle,
) {
draw(
tree.state.downcast_ref(),
self.contents.layout(),
layout,
- cursor_position,
+ cursor,
renderer,
theme,
style,
@@ -425,20 +425,9 @@ where
.iter()
.zip(&tree.children)
.map(|((pane, content), tree)| (pane, (content, tree))),
- |(content, tree),
- renderer,
- style,
- layout,
- cursor_position,
- rectangle| {
+ |(content, tree), renderer, style, layout, cursor, rectangle| {
content.draw(
- tree,
- renderer,
- theme,
- style,
- layout,
- cursor_position,
- rectangle,
+ tree, renderer, theme, style, layout, cursor, rectangle,
);
},
)
@@ -520,7 +509,7 @@ pub fn update<'a, Message, T: Draggable>(
node: &Node,
event: &Event,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
shell: &mut Shell<'_, Message>,
spacing: f32,
contents: impl Iterator<Item = (Pane, T)>,
@@ -535,7 +524,7 @@ pub fn update<'a, Message, T: Draggable>(
| Event::Touch(touch::Event::FingerPressed { .. }) => {
let bounds = layout.bounds();
- if bounds.contains(cursor_position) {
+ if let Some(cursor_position) = cursor.position_over(bounds) {
event_status = event::Status::Captured;
match on_resize {
@@ -592,15 +581,24 @@ pub fn update<'a, Message, T: Draggable>(
| Event::Touch(touch::Event::FingerLost { .. }) => {
if let Some((pane, _)) = action.picked_pane() {
if let Some(on_drag) = on_drag {
- let mut dropped_region = contents
- .zip(layout.children())
- .filter(|(_, layout)| {
- layout.bounds().contains(cursor_position)
+ let dropped_region =
+ cursor.position().and_then(|cursor_position| {
+ contents
+ .zip(layout.children())
+ .filter_map(|(target, layout)| {
+ layout_region(layout, cursor_position)
+ .map(|region| (target, region))
+ })
+ .next()
});
- let event = match dropped_region.next() {
- Some(((target, _), _)) if pane != target => {
- DragEvent::Dropped { pane, target }
+ let event = match dropped_region {
+ Some(((target, _), region)) if pane != target => {
+ DragEvent::Dropped {
+ pane,
+ target,
+ region,
+ }
}
_ => DragEvent::Canceled { pane },
};
@@ -629,24 +627,32 @@ pub fn update<'a, Message, T: Draggable>(
);
if let Some((axis, rectangle, _)) = splits.get(&split) {
- let ratio = match axis {
- Axis::Horizontal => {
- let position =
- cursor_position.y - bounds.y - rectangle.y;
-
- (position / rectangle.height).clamp(0.1, 0.9)
- }
- Axis::Vertical => {
- let position =
- cursor_position.x - bounds.x - rectangle.x;
-
- (position / rectangle.width).clamp(0.1, 0.9)
- }
- };
-
- shell.publish(on_resize(ResizeEvent { split, ratio }));
-
- event_status = event::Status::Captured;
+ if let Some(cursor_position) = cursor.position() {
+ let ratio = match axis {
+ Axis::Horizontal => {
+ let position = cursor_position.y
+ - bounds.y
+ - rectangle.y;
+
+ (position / rectangle.height)
+ .clamp(0.1, 0.9)
+ }
+ Axis::Vertical => {
+ let position = cursor_position.x
+ - bounds.x
+ - rectangle.x;
+
+ (position / rectangle.width).clamp(0.1, 0.9)
+ }
+ };
+
+ shell.publish(on_resize(ResizeEvent {
+ split,
+ ratio,
+ }));
+
+ event_status = event::Status::Captured;
+ }
}
}
}
@@ -657,6 +663,28 @@ pub fn update<'a, Message, T: Draggable>(
event_status
}
+fn layout_region(layout: Layout<'_>, cursor_position: Point) -> Option<Region> {
+ let bounds = layout.bounds();
+
+ if !bounds.contains(cursor_position) {
+ return None;
+ }
+
+ let region = if cursor_position.x < (bounds.x + bounds.width / 3.0) {
+ Region::Left
+ } else if cursor_position.x > (bounds.x + 2.0 * bounds.width / 3.0) {
+ Region::Right
+ } else if cursor_position.y < (bounds.y + bounds.height / 3.0) {
+ Region::Top
+ } else if cursor_position.y > (bounds.y + 2.0 * bounds.height / 3.0) {
+ Region::Bottom
+ } else {
+ Region::Center
+ };
+
+ Some(region)
+}
+
fn click_pane<'a, Message, T>(
action: &mut state::Action,
layout: Layout<'_>,
@@ -697,7 +725,7 @@ pub fn mouse_interaction(
action: &state::Action,
node: &Node,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
spacing: f32,
resize_leeway: Option<f32>,
) -> Option<mouse::Interaction> {
@@ -708,6 +736,7 @@ pub fn mouse_interaction(
let resize_axis =
action.picked_split().map(|(_, axis)| axis).or_else(|| {
resize_leeway.and_then(|leeway| {
+ let cursor_position = cursor.position()?;
let bounds = layout.bounds();
let splits = node.split_regions(spacing, bounds.size());
@@ -737,7 +766,7 @@ pub fn draw<Renderer, T>(
action: &state::Action,
node: &Node,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
renderer: &mut Renderer,
theme: &Renderer::Theme,
default_style: &renderer::Style,
@@ -751,7 +780,7 @@ pub fn draw<Renderer, T>(
&mut Renderer,
&renderer::Style,
Layout<'_>,
- Point,
+ mouse::Cursor,
&Rectangle,
),
) where
@@ -775,6 +804,7 @@ pub fn draw<Renderer, T>(
})
.or_else(|| match resize_leeway {
Some(leeway) => {
+ let cursor_position = cursor.position()?;
let bounds = layout.bounds();
let relative_cursor = Point::new(
@@ -795,12 +825,10 @@ pub fn draw<Renderer, T>(
None => None,
});
- let pane_cursor_position = if picked_pane.is_some() {
- // TODO: Remove once cursor availability is encoded in the type
- // system
- Point::new(-1.0, -1.0)
+ let pane_cursor = if picked_pane.is_some() {
+ mouse::Cursor::Unavailable
} else {
- cursor_position
+ cursor
};
let mut render_picked_pane = None;
@@ -810,13 +838,45 @@ pub fn draw<Renderer, T>(
Some((dragging, origin)) if id == dragging => {
render_picked_pane = Some((pane, origin, layout));
}
+ Some((dragging, _)) if id != dragging => {
+ draw_pane(
+ pane,
+ renderer,
+ default_style,
+ layout,
+ pane_cursor,
+ viewport,
+ );
+
+ if picked_pane.is_some() {
+ if let Some(region) =
+ cursor.position().and_then(|cursor_position| {
+ layout_region(layout, cursor_position)
+ })
+ {
+ let bounds = layout_region_bounds(layout, region);
+ let hovered_region_style = theme.hovered_region(style);
+
+ renderer.fill_quad(
+ renderer::Quad {
+ bounds,
+ border_radius: hovered_region_style
+ .border_radius,
+ border_width: hovered_region_style.border_width,
+ border_color: hovered_region_style.border_color,
+ },
+ theme.hovered_region(style).background,
+ );
+ }
+ }
+ }
_ => {
draw_pane(
pane,
renderer,
default_style,
layout,
- pane_cursor_position,
+ pane_cursor,
viewport,
);
}
@@ -825,25 +885,27 @@ pub fn draw<Renderer, T>(
// Render picked pane last
if let Some((pane, origin, layout)) = render_picked_pane {
- let bounds = layout.bounds();
-
- renderer.with_translation(
- cursor_position
- - Point::new(bounds.x + origin.x, bounds.y + origin.y),
- |renderer| {
- renderer.with_layer(bounds, |renderer| {
- draw_pane(
- pane,
- renderer,
- default_style,
- layout,
- pane_cursor_position,
- viewport,
- );
- });
- },
- );
- };
+ if let Some(cursor_position) = cursor.position() {
+ let bounds = layout.bounds();
+
+ renderer.with_translation(
+ cursor_position
+ - Point::new(bounds.x + origin.x, bounds.y + origin.y),
+ |renderer| {
+ renderer.with_layer(bounds, |renderer| {
+ draw_pane(
+ pane,
+ renderer,
+ default_style,
+ layout,
+ pane_cursor,
+ viewport,
+ );
+ });
+ },
+ );
+ }
+ }
if let Some((axis, split_region, is_picked)) = picked_split {
let highlight = if is_picked {
@@ -884,6 +946,32 @@ pub fn draw<Renderer, T>(
}
}
+fn layout_region_bounds(layout: Layout<'_>, region: Region) -> Rectangle {
+ let bounds = layout.bounds();
+
+ match region {
+ Region::Center => bounds,
+ Region::Top => Rectangle {
+ height: bounds.height / 2.0,
+ ..bounds
+ },
+ Region::Left => Rectangle {
+ width: bounds.width / 2.0,
+ ..bounds
+ },
+ Region::Right => Rectangle {
+ x: bounds.x + bounds.width / 2.0,
+ width: bounds.width / 2.0,
+ ..bounds
+ },
+ Region::Bottom => Rectangle {
+ y: bounds.y + bounds.height / 2.0,
+ height: bounds.height / 2.0,
+ ..bounds
+ },
+ }
+}
+
/// An event produced during a drag and drop interaction of a [`PaneGrid`].
#[derive(Debug, Clone, Copy)]
pub enum DragEvent {
@@ -900,6 +988,9 @@ pub enum DragEvent {
/// The [`Pane`] where the picked one was dropped on.
target: Pane,
+
+ /// The [`Region`] of the target [`Pane`] where the picked one was dropped on.
+ region: Region,
},
/// A [`Pane`] was picked and then dropped outside of other [`Pane`]
@@ -910,6 +1001,22 @@ pub enum DragEvent {
},
}
+/// The region of a [`Pane`].
+#[derive(Debug, Clone, Copy, Default)]
+pub enum Region {
+ /// Center region.
+ #[default]
+ Center,
+ /// Top region.
+ Top,
+ /// Left region.
+ Left,
+ /// Right region.
+ Right,
+ /// Bottom region.
+ Bottom,
+}
+
/// An event produced during a resize interaction of a [`PaneGrid`].
#[derive(Debug, Clone, Copy)]
pub struct ResizeEvent {