summaryrefslogtreecommitdiffstats
path: root/native/src/widget/pane_grid.rs
diff options
context:
space:
mode:
Diffstat (limited to 'native/src/widget/pane_grid.rs')
-rw-r--r--native/src/widget/pane_grid.rs215
1 files changed, 124 insertions, 91 deletions
diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs
index ff19cbc2..b72172cc 100644
--- a/native/src/widget/pane_grid.rs
+++ b/native/src/widget/pane_grid.rs
@@ -6,7 +6,7 @@
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
//! drag and drop, and hotkey support.
//!
-//! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.2/examples/pane_grid
+//! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.3/examples/pane_grid
mod axis;
mod configuration;
mod content;
@@ -33,7 +33,7 @@ use crate::layout;
use crate::mouse;
use crate::overlay;
use crate::row;
-use crate::text;
+use crate::touch;
use crate::{
Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Size, Vector,
Widget,
@@ -98,6 +98,7 @@ pub struct PaneGrid<'a, Message, Renderer: self::Renderer> {
on_click: Option<Box<dyn Fn(Pane) -> Message + 'a>>,
on_drag: Option<Box<dyn Fn(DragEvent) -> Message + 'a>>,
on_resize: Option<(u16, Box<dyn Fn(ResizeEvent) -> Message + 'a>)>,
+ style: <Renderer as self::Renderer>::Style,
}
impl<'a, Message, Renderer> PaneGrid<'a, Message, Renderer>
@@ -129,6 +130,7 @@ where
on_click: None,
on_drag: None,
on_resize: None,
+ style: Default::default(),
}
}
@@ -186,6 +188,15 @@ where
self.on_resize = Some((leeway, Box::new(f)));
self
}
+
+ /// Sets the style of the [`PaneGrid`].
+ pub fn style(
+ mut self,
+ style: impl Into<<Renderer as self::Renderer>::Style>,
+ ) -> Self {
+ self.style = style.into();
+ self
+ }
}
impl<'a, Message, Renderer> PaneGrid<'a, Message, Renderer>
@@ -351,49 +362,41 @@ where
event: Event,
layout: Layout<'_>,
cursor_position: Point,
- messages: &mut Vec<Message>,
renderer: &Renderer,
- clipboard: Option<&dyn Clipboard>,
+ clipboard: &mut dyn Clipboard,
+ messages: &mut Vec<Message>,
) -> event::Status {
let mut event_status = event::Status::Ignored;
match event {
- Event::Mouse(mouse_event) => match mouse_event {
- mouse::Event::ButtonPressed(mouse::Button::Left) => {
- let bounds = layout.bounds();
-
- if bounds.contains(cursor_position) {
- event_status = event::Status::Captured;
-
- match self.on_resize {
- Some((leeway, _)) => {
- let relative_cursor = Point::new(
- cursor_position.x - bounds.x,
- cursor_position.y - bounds.y,
- );
-
- let splits = self.state.split_regions(
- f32::from(self.spacing),
- Size::new(bounds.width, bounds.height),
- );
-
- let clicked_split = hovered_split(
- splits.iter(),
- f32::from(self.spacing + leeway),
- relative_cursor,
- );
+ Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))
+ | Event::Touch(touch::Event::FingerPressed { .. }) => {
+ let bounds = layout.bounds();
- if let Some((split, axis)) = clicked_split {
- self.state.pick_split(&split, axis);
- } else {
- self.click_pane(
- layout,
- cursor_position,
- messages,
- );
- }
- }
- None => {
+ if bounds.contains(cursor_position) {
+ event_status = event::Status::Captured;
+
+ match self.on_resize {
+ Some((leeway, _)) => {
+ let relative_cursor = Point::new(
+ cursor_position.x - bounds.x,
+ cursor_position.y - bounds.y,
+ );
+
+ let splits = self.state.split_regions(
+ f32::from(self.spacing),
+ Size::new(bounds.width, bounds.height),
+ );
+
+ let clicked_split = hovered_split(
+ splits.iter(),
+ f32::from(self.spacing + leeway),
+ relative_cursor,
+ );
+
+ if let Some((split, axis, _)) = clicked_split {
+ self.state.pick_split(&split, axis);
+ } else {
self.click_pane(
layout,
cursor_position,
@@ -401,47 +404,51 @@ where
);
}
}
+ None => {
+ self.click_pane(layout, cursor_position, messages);
+ }
}
}
- mouse::Event::ButtonReleased(mouse::Button::Left) => {
- if let Some((pane, _)) = self.state.picked_pane() {
- if let Some(on_drag) = &self.on_drag {
- let mut dropped_region = self
- .elements
- .iter()
- .zip(layout.children())
- .filter(|(_, layout)| {
+ }
+ Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))
+ | Event::Touch(touch::Event::FingerLifted { .. })
+ | Event::Touch(touch::Event::FingerLost { .. }) => {
+ if let Some((pane, _)) = self.state.picked_pane() {
+ if let Some(on_drag) = &self.on_drag {
+ let mut dropped_region =
+ self.elements.iter().zip(layout.children()).filter(
+ |(_, layout)| {
layout.bounds().contains(cursor_position)
- });
-
- let event = match dropped_region.next() {
- Some(((target, _), _)) if pane != *target => {
- DragEvent::Dropped {
- pane,
- target: *target,
- }
+ },
+ );
+
+ let event = match dropped_region.next() {
+ Some(((target, _), _)) if pane != *target => {
+ DragEvent::Dropped {
+ pane,
+ target: *target,
}
- _ => DragEvent::Canceled { pane },
- };
+ }
+ _ => DragEvent::Canceled { pane },
+ };
- messages.push(on_drag(event));
- }
+ messages.push(on_drag(event));
+ }
- self.state.idle();
+ self.state.idle();
- event_status = event::Status::Captured;
- } else if self.state.picked_split().is_some() {
- self.state.idle();
+ event_status = event::Status::Captured;
+ } else if self.state.picked_split().is_some() {
+ self.state.idle();
- event_status = event::Status::Captured;
- }
- }
- mouse::Event::CursorMoved { .. } => {
- event_status =
- self.trigger_resize(layout, cursor_position, messages);
+ event_status = event::Status::Captured;
}
- _ => {}
- },
+ }
+ Event::Mouse(mouse::Event::CursorMoved { .. })
+ | Event::Touch(touch::Event::FingerMoved { .. }) => {
+ event_status =
+ self.trigger_resize(layout, cursor_position, messages);
+ }
_ => {}
}
@@ -454,9 +461,9 @@ where
event.clone(),
layout,
cursor_position,
- messages,
renderer,
clipboard,
+ messages,
)
})
.fold(event_status, event::Status::merge)
@@ -471,11 +478,28 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
- _viewport: &Rectangle,
+ viewport: &Rectangle,
) -> Renderer::Output {
let picked_split = self
.state
.picked_split()
+ .and_then(|(split, axis)| {
+ let bounds = layout.bounds();
+
+ let splits = self
+ .state
+ .split_regions(f32::from(self.spacing), bounds.size());
+
+ let (_axis, region, ratio) = splits.get(&split)?;
+
+ let region = axis.split_line_bounds(
+ *region,
+ *ratio,
+ f32::from(self.spacing),
+ );
+
+ Some((axis, region + Vector::new(bounds.x, bounds.y), true))
+ })
.or_else(|| match self.on_resize {
Some((leeway, _)) => {
let bounds = layout.bounds();
@@ -489,15 +513,20 @@ where
.state
.split_regions(f32::from(self.spacing), bounds.size());
- hovered_split(
+ let (_split, axis, region) = hovered_split(
splits.iter(),
f32::from(self.spacing + leeway),
relative_cursor,
- )
+ )?;
+
+ Some((
+ axis,
+ region + Vector::new(bounds.x, bounds.y),
+ false,
+ ))
}
None => None,
- })
- .map(|(_, axis)| axis);
+ });
self::Renderer::draw(
renderer,
@@ -506,7 +535,9 @@ where
self.state.picked_pane(),
picked_split,
layout,
+ &self.style,
cursor_position,
+ viewport,
)
}
@@ -543,9 +574,10 @@ where
/// able to use a [`PaneGrid`] in your user interface.
///
/// [renderer]: crate::renderer
-pub trait Renderer:
- crate::Renderer + container::Renderer + text::Renderer + Sized
-{
+pub trait Renderer: crate::Renderer + container::Renderer + Sized {
+ /// The style supported by this renderer.
+ type Style: Default;
+
/// Draws a [`PaneGrid`].
///
/// It receives:
@@ -559,9 +591,11 @@ pub trait Renderer:
defaults: &Self::Defaults,
content: &[(Pane, Content<'_, Message, Self>)],
dragging: Option<(Pane, Point)>,
- resizing: Option<Axis>,
+ resizing: Option<(Axis, Rectangle, bool)>,
layout: Layout<'_>,
+ style: &<Self as self::Renderer>::Style,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Self::Output;
/// Draws a [`Pane`].
@@ -575,10 +609,11 @@ pub trait Renderer:
&mut self,
defaults: &Self::Defaults,
bounds: Rectangle,
- style: &Self::Style,
+ style: &<Self as container::Renderer>::Style,
title_bar: Option<(&TitleBar<'_, Message, Self>, Layout<'_>)>,
body: (&Element<'_, Message, Self>, Layout<'_>),
cursor_position: Point,
+ viewport: &Rectangle,
) -> Self::Output;
/// Draws a [`TitleBar`].
@@ -586,20 +621,18 @@ pub trait Renderer:
/// It receives:
/// - the bounds, style of the [`TitleBar`]
/// - the style of the [`TitleBar`]
- /// - the title of the [`TitleBar`] with its size, font, and bounds
- /// - the controls of the [`TitleBar`] with their [`Layout`+, if any
+ /// - the content of the [`TitleBar`] with its layout
+ /// - the controls of the [`TitleBar`] with their [`Layout`], if any
/// - the cursor position
fn draw_title_bar<Message>(
&mut self,
defaults: &Self::Defaults,
bounds: Rectangle,
- style: &Self::Style,
- title: &str,
- title_size: u16,
- title_font: Self::Font,
- title_bounds: Rectangle,
+ style: &<Self as container::Renderer>::Style,
+ content: (&Element<'_, Message, Self>, Layout<'_>),
controls: Option<(&Element<'_, Message, Self>, Layout<'_>)>,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Self::Output;
}
@@ -623,14 +656,14 @@ fn hovered_split<'a>(
splits: impl Iterator<Item = (&'a Split, &'a (Axis, Rectangle, f32))>,
spacing: f32,
cursor_position: Point,
-) -> Option<(Split, Axis)> {
+) -> Option<(Split, Axis, Rectangle)> {
splits
.filter_map(|(split, (axis, region, ratio))| {
let bounds =
axis.split_line_bounds(*region, *ratio, f32::from(spacing));
if bounds.contains(cursor_position) {
- Some((*split, *axis))
+ Some((*split, *axis, bounds))
} else {
None
}