summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar mtkennerly <mtkennerly@gmail.com>2024-08-22 09:32:35 -0400
committerLibravatar mtkennerly <mtkennerly@gmail.com>2024-08-22 12:43:48 -0400
commit3a434c9505bcc1a9ce71db1d69f77c3374b076cb (patch)
tree30d60f48a4812991eb31acd742c061da3f5696a0
parent9b99b932bced46047ec2e18c2b6ec5a6c5b3636f (diff)
downloadiced-3a434c9505bcc1a9ce71db1d69f77c3374b076cb.tar.gz
iced-3a434c9505bcc1a9ce71db1d69f77c3374b076cb.tar.bz2
iced-3a434c9505bcc1a9ce71db1d69f77c3374b076cb.zip
Add compact variant for pane grid controls
-rw-r--r--examples/pane_grid/src/main.rs22
-rw-r--r--widget/src/pane_grid.rs2
-rw-r--r--widget/src/pane_grid/controls.rs59
-rw-r--r--widget/src/pane_grid/title_bar.rs317
4 files changed, 326 insertions, 74 deletions
diff --git a/examples/pane_grid/src/main.rs b/examples/pane_grid/src/main.rs
index f18fc5f3..67f4d27f 100644
--- a/examples/pane_grid/src/main.rs
+++ b/examples/pane_grid/src/main.rs
@@ -154,11 +154,23 @@ impl Example {
.spacing(5);
let title_bar = pane_grid::TitleBar::new(title)
- .controls(view_controls(
- id,
- total_panes,
- pane.is_pinned,
- is_maximized,
+ .controls(pane_grid::Controls::dynamic(
+ view_controls(
+ id,
+ total_panes,
+ pane.is_pinned,
+ is_maximized,
+ ),
+ button(text("X").size(14))
+ .style(button::danger)
+ .padding(3)
+ .on_press_maybe(
+ if total_panes > 1 && !pane.is_pinned {
+ Some(Message::Close(id))
+ } else {
+ None
+ },
+ ),
))
.padding(10)
.style(if is_focused {
diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs
index 0aab1ab5..710a5443 100644
--- a/widget/src/pane_grid.rs
+++ b/widget/src/pane_grid.rs
@@ -10,6 +10,7 @@
mod axis;
mod configuration;
mod content;
+mod controls;
mod direction;
mod draggable;
mod node;
@@ -22,6 +23,7 @@ pub mod state;
pub use axis::Axis;
pub use configuration::Configuration;
pub use content::Content;
+pub use controls::Controls;
pub use direction::Direction;
pub use draggable::Draggable;
pub use node::Node;
diff --git a/widget/src/pane_grid/controls.rs b/widget/src/pane_grid/controls.rs
new file mode 100644
index 00000000..13b57acb
--- /dev/null
+++ b/widget/src/pane_grid/controls.rs
@@ -0,0 +1,59 @@
+use crate::container;
+use crate::core::{self, Element};
+
+/// The controls of a [`Pane`].
+///
+/// [`Pane`]: super::Pane
+#[allow(missing_debug_implementations)]
+pub struct Controls<
+ 'a,
+ Message,
+ Theme = crate::Theme,
+ Renderer = crate::Renderer,
+> where
+ Theme: container::Catalog,
+ Renderer: core::Renderer,
+{
+ pub(super) full: Element<'a, Message, Theme, Renderer>,
+ pub(super) compact: Option<Element<'a, Message, Theme, Renderer>>,
+}
+
+impl<'a, Message, Theme, Renderer> Controls<'a, Message, Theme, Renderer>
+where
+ Theme: container::Catalog,
+ Renderer: core::Renderer,
+{
+ /// Creates a new [`Controls`] with the given content.
+ pub fn new(
+ content: impl Into<Element<'a, Message, Theme, Renderer>>,
+ ) -> Self {
+ Self {
+ full: content.into(),
+ compact: None,
+ }
+ }
+
+ /// Creates a new [`Controls`] with a full and compact variant.
+ /// If there is not enough room to show the full variant without overlap,
+ /// then the compact variant will be shown instead.
+ pub fn dynamic(
+ full: impl Into<Element<'a, Message, Theme, Renderer>>,
+ compact: impl Into<Element<'a, Message, Theme, Renderer>>,
+ ) -> Self {
+ Self {
+ full: full.into(),
+ compact: Some(compact.into()),
+ }
+ }
+}
+
+impl<'a, Message, Theme, Renderer> From<Element<'a, Message, Theme, Renderer>>
+ for Controls<'a, Message, Theme, Renderer>
+where
+ Theme: container::Catalog,
+ Renderer: core::Renderer,
+{
+ fn from(value: Element<'a, Message, Theme, Renderer>) -> Self {
+ Self::new(value)
+ }
+}
diff --git a/widget/src/pane_grid/title_bar.rs b/widget/src/pane_grid/title_bar.rs
index 791fab4a..5002b4f7 100644
--- a/widget/src/pane_grid/title_bar.rs
+++ b/widget/src/pane_grid/title_bar.rs
@@ -9,6 +9,7 @@ use crate::core::{
self, Clipboard, Element, Layout, Padding, Point, Rectangle, Shell, Size,
Vector,
};
+use crate::pane_grid::controls::Controls;
/// The title bar of a [`Pane`].
///
@@ -24,7 +25,7 @@ pub struct TitleBar<
Renderer: core::Renderer,
{
content: Element<'a, Message, Theme, Renderer>,
- controls: Option<Element<'a, Message, Theme, Renderer>>,
+ controls: Option<Controls<'a, Message, Theme, Renderer>>,
padding: Padding,
always_show_controls: bool,
class: Theme::Class<'a>,
@@ -51,7 +52,7 @@ where
/// Sets the controls of the [`TitleBar`].
pub fn controls(
mut self,
- controls: impl Into<Element<'a, Message, Theme, Renderer>>,
+ controls: impl Into<Controls<'a, Message, Theme, Renderer>>,
) -> Self {
self.controls = Some(controls.into());
self
@@ -104,10 +105,22 @@ where
Renderer: core::Renderer,
{
pub(super) fn state(&self) -> Tree {
- let children = if let Some(controls) = self.controls.as_ref() {
- vec![Tree::new(&self.content), Tree::new(controls)]
- } else {
- vec![Tree::new(&self.content), Tree::empty()]
+ let children = match self.controls.as_ref() {
+ Some(controls) => match controls.compact.as_ref() {
+ Some(compact) => vec![
+ Tree::new(&self.content),
+ Tree::new(&controls.full),
+ Tree::new(compact),
+ ],
+ None => vec![
+ Tree::new(&self.content),
+ Tree::new(&controls.full),
+ Tree::empty(),
+ ],
+ },
+ None => {
+ vec![Tree::new(&self.content), Tree::empty(), Tree::empty()]
+ }
};
Tree {
@@ -117,9 +130,13 @@ where
}
pub(super) fn diff(&self, tree: &mut Tree) {
- if tree.children.len() == 2 {
+ if tree.children.len() == 3 {
if let Some(controls) = self.controls.as_ref() {
- tree.children[1].diff(controls);
+ if let Some(compact) = controls.compact.as_ref() {
+ tree.children[2].diff(compact);
+ }
+
+ tree.children[1].diff(&controls.full);
}
tree.children[0].diff(&self.content);
@@ -164,18 +181,42 @@ where
if title_layout.bounds().width + controls_layout.bounds().width
> padded.bounds().width
{
- show_title = false;
+ if let Some(compact) = controls.compact.as_ref() {
+ let compact_layout = children.next().unwrap();
+
+ compact.as_widget().draw(
+ &tree.children[2],
+ renderer,
+ theme,
+ &inherited_style,
+ compact_layout,
+ cursor,
+ viewport,
+ );
+ } else {
+ show_title = false;
+
+ controls.full.as_widget().draw(
+ &tree.children[1],
+ renderer,
+ theme,
+ &inherited_style,
+ controls_layout,
+ cursor,
+ viewport,
+ );
+ }
+ } else {
+ controls.full.as_widget().draw(
+ &tree.children[1],
+ renderer,
+ theme,
+ &inherited_style,
+ controls_layout,
+ cursor,
+ viewport,
+ );
}
-
- controls.as_widget().draw(
- &tree.children[1],
- renderer,
- theme,
- &inherited_style,
- controls_layout,
- cursor,
- viewport,
- );
}
}
@@ -207,13 +248,20 @@ where
let mut children = padded.children();
let title_layout = children.next().unwrap();
- if self.controls.is_some() {
+ if let Some(controls) = self.controls.as_ref() {
let controls_layout = children.next().unwrap();
if title_layout.bounds().width + controls_layout.bounds().width
> padded.bounds().width
{
- !controls_layout.bounds().contains(cursor_position)
+ if controls.compact.is_some() {
+ let compact_layout = children.next().unwrap();
+
+ !compact_layout.bounds().contains(cursor_position)
+ && !title_layout.bounds().contains(cursor_position)
+ } else {
+ !controls_layout.bounds().contains(cursor_position)
+ }
} else {
!controls_layout.bounds().contains(cursor_position)
&& !title_layout.bounds().contains(cursor_position)
@@ -244,25 +292,73 @@ where
let title_size = title_layout.size();
let node = if let Some(controls) = &self.controls {
- let controls_layout = controls.as_widget().layout(
+ let controls_layout = controls.full.as_widget().layout(
&mut tree.children[1],
renderer,
&layout::Limits::new(Size::ZERO, max_size),
);
- let controls_size = controls_layout.size();
- let space_before_controls = max_size.width - controls_size.width;
-
- let height = title_size.height.max(controls_size.height);
-
- layout::Node::with_children(
- Size::new(max_size.width, height),
- vec![
- title_layout,
- controls_layout
- .move_to(Point::new(space_before_controls, 0.0)),
- ],
- )
+ if title_layout.bounds().width + controls_layout.bounds().width
+ > max_size.width
+ {
+ if let Some(compact) = controls.compact.as_ref() {
+ let compact_layout = compact.as_widget().layout(
+ &mut tree.children[2],
+ renderer,
+ &layout::Limits::new(Size::ZERO, max_size),
+ );
+
+ let compact_size = compact_layout.size();
+ let space_before_controls =
+ max_size.width - compact_size.width;
+
+ let height = title_size.height.max(compact_size.height);
+
+ layout::Node::with_children(
+ Size::new(max_size.width, height),
+ vec![
+ title_layout,
+ controls_layout,
+ compact_layout.move_to(Point::new(
+ space_before_controls,
+ 0.0,
+ )),
+ ],
+ )
+ } else {
+ let controls_size = controls_layout.size();
+ let space_before_controls =
+ max_size.width - controls_size.width;
+
+ let height = title_size.height.max(controls_size.height);
+
+ layout::Node::with_children(
+ Size::new(max_size.width, height),
+ vec![
+ title_layout,
+ controls_layout.move_to(Point::new(
+ space_before_controls,
+ 0.0,
+ )),
+ ],
+ )
+ }
+ } else {
+ let controls_size = controls_layout.size();
+ let space_before_controls =
+ max_size.width - controls_size.width;
+
+ let height = title_size.height.max(controls_size.height);
+
+ layout::Node::with_children(
+ Size::new(max_size.width, height),
+ vec![
+ title_layout,
+ controls_layout
+ .move_to(Point::new(space_before_controls, 0.0)),
+ ],
+ )
+ }
} else {
layout::Node::with_children(
Size::new(max_size.width, title_size.height),
@@ -293,15 +389,33 @@ where
if title_layout.bounds().width + controls_layout.bounds().width
> padded.bounds().width
{
- show_title = false;
- }
+ if let Some(compact) = controls.compact.as_ref() {
+ let compact_layout = children.next().unwrap();
- controls.as_widget().operate(
- &mut tree.children[1],
- controls_layout,
- renderer,
- operation,
- );
+ compact.as_widget().operate(
+ &mut tree.children[2],
+ compact_layout,
+ renderer,
+ operation,
+ );
+ } else {
+ show_title = false;
+
+ controls.full.as_widget().operate(
+ &mut tree.children[1],
+ controls_layout,
+ renderer,
+ operation,
+ );
+ }
+ } else {
+ controls.full.as_widget().operate(
+ &mut tree.children[1],
+ controls_layout,
+ renderer,
+ operation,
+ );
+ }
};
if show_title {
@@ -337,19 +451,45 @@ where
if title_layout.bounds().width + controls_layout.bounds().width
> padded.bounds().width
{
- show_title = false;
- }
+ if let Some(compact) = controls.compact.as_mut() {
+ let compact_layout = children.next().unwrap();
+
+ compact.as_widget_mut().on_event(
+ &mut tree.children[2],
+ event.clone(),
+ compact_layout,
+ cursor,
+ renderer,
+ clipboard,
+ shell,
+ viewport,
+ )
+ } else {
+ show_title = false;
- controls.as_widget_mut().on_event(
- &mut tree.children[1],
- event.clone(),
- controls_layout,
- cursor,
- renderer,
- clipboard,
- shell,
- viewport,
- )
+ controls.full.as_widget_mut().on_event(
+ &mut tree.children[1],
+ event.clone(),
+ controls_layout,
+ cursor,
+ renderer,
+ clipboard,
+ shell,
+ viewport,
+ )
+ }
+ } else {
+ controls.full.as_widget_mut().on_event(
+ &mut tree.children[1],
+ event.clone(),
+ controls_layout,
+ cursor,
+ renderer,
+ clipboard,
+ shell,
+ viewport,
+ )
+ }
} else {
event::Status::Ignored
};
@@ -396,18 +536,33 @@ where
if let Some(controls) = &self.controls {
let controls_layout = children.next().unwrap();
- let controls_interaction = controls.as_widget().mouse_interaction(
- &tree.children[1],
- controls_layout,
- cursor,
- viewport,
- renderer,
- );
+ let controls_interaction =
+ controls.full.as_widget().mouse_interaction(
+ &tree.children[1],
+ controls_layout,
+ cursor,
+ viewport,
+ renderer,
+ );
if title_layout.bounds().width + controls_layout.bounds().width
> padded.bounds().width
{
- controls_interaction
+ if let Some(compact) = controls.compact.as_ref() {
+ let compact_layout = children.next().unwrap();
+ let compact_interaction =
+ compact.as_widget().mouse_interaction(
+ &tree.children[2],
+ compact_layout,
+ cursor,
+ viewport,
+ renderer,
+ );
+
+ compact_interaction.max(title_interaction)
+ } else {
+ controls_interaction
+ }
} else {
controls_interaction.max(title_interaction)
}
@@ -444,12 +599,36 @@ where
controls.as_mut().and_then(|controls| {
let controls_layout = children.next()?;
- controls.as_widget_mut().overlay(
- controls_state,
- controls_layout,
- renderer,
- translation,
- )
+ if title_layout.bounds().width
+ + controls_layout.bounds().width
+ > padded.bounds().width
+ {
+ if let Some(compact) = controls.compact.as_mut() {
+ let compact_state = states.next().unwrap();
+ let compact_layout = children.next()?;
+
+ compact.as_widget_mut().overlay(
+ compact_state,
+ compact_layout,
+ renderer,
+ translation,
+ )
+ } else {
+ controls.full.as_widget_mut().overlay(
+ controls_state,
+ controls_layout,
+ renderer,
+ translation,
+ )
+ }
+ } else {
+ controls.full.as_widget_mut().overlay(
+ controls_state,
+ controls_layout,
+ renderer,
+ translation,
+ )
+ }
})
})
}