Add compact variant for pane grid controls

This commit is contained in:
mtkennerly 2024-08-22 09:32:35 -04:00
parent 9b99b932bc
commit 3a434c9505
No known key found for this signature in database
GPG key ID: E764BE00BE6E6408
4 changed files with 324 additions and 72 deletions

View file

@ -154,11 +154,23 @@ impl Example {
.spacing(5); .spacing(5);
let title_bar = pane_grid::TitleBar::new(title) let title_bar = pane_grid::TitleBar::new(title)
.controls(view_controls( .controls(pane_grid::Controls::dynamic(
id, view_controls(
total_panes, id,
pane.is_pinned, total_panes,
is_maximized, 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) .padding(10)
.style(if is_focused { .style(if is_focused {

View file

@ -10,6 +10,7 @@
mod axis; mod axis;
mod configuration; mod configuration;
mod content; mod content;
mod controls;
mod direction; mod direction;
mod draggable; mod draggable;
mod node; mod node;
@ -22,6 +23,7 @@ pub mod state;
pub use axis::Axis; pub use axis::Axis;
pub use configuration::Configuration; pub use configuration::Configuration;
pub use content::Content; pub use content::Content;
pub use controls::Controls;
pub use direction::Direction; pub use direction::Direction;
pub use draggable::Draggable; pub use draggable::Draggable;
pub use node::Node; pub use node::Node;

View file

@ -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)
}
}

View file

@ -9,6 +9,7 @@ use crate::core::{
self, Clipboard, Element, Layout, Padding, Point, Rectangle, Shell, Size, self, Clipboard, Element, Layout, Padding, Point, Rectangle, Shell, Size,
Vector, Vector,
}; };
use crate::pane_grid::controls::Controls;
/// The title bar of a [`Pane`]. /// The title bar of a [`Pane`].
/// ///
@ -24,7 +25,7 @@ pub struct TitleBar<
Renderer: core::Renderer, Renderer: core::Renderer,
{ {
content: Element<'a, Message, Theme, Renderer>, content: Element<'a, Message, Theme, Renderer>,
controls: Option<Element<'a, Message, Theme, Renderer>>, controls: Option<Controls<'a, Message, Theme, Renderer>>,
padding: Padding, padding: Padding,
always_show_controls: bool, always_show_controls: bool,
class: Theme::Class<'a>, class: Theme::Class<'a>,
@ -51,7 +52,7 @@ where
/// Sets the controls of the [`TitleBar`]. /// Sets the controls of the [`TitleBar`].
pub fn controls( pub fn controls(
mut self, mut self,
controls: impl Into<Element<'a, Message, Theme, Renderer>>, controls: impl Into<Controls<'a, Message, Theme, Renderer>>,
) -> Self { ) -> Self {
self.controls = Some(controls.into()); self.controls = Some(controls.into());
self self
@ -104,10 +105,22 @@ where
Renderer: core::Renderer, Renderer: core::Renderer,
{ {
pub(super) fn state(&self) -> Tree { pub(super) fn state(&self) -> Tree {
let children = if let Some(controls) = self.controls.as_ref() { let children = match self.controls.as_ref() {
vec![Tree::new(&self.content), Tree::new(controls)] Some(controls) => match controls.compact.as_ref() {
} else { Some(compact) => vec![
vec![Tree::new(&self.content), Tree::empty()] 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 { Tree {
@ -117,9 +130,13 @@ where
} }
pub(super) fn diff(&self, tree: &mut Tree) { 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() { 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); tree.children[0].diff(&self.content);
@ -164,18 +181,42 @@ where
if title_layout.bounds().width + controls_layout.bounds().width if title_layout.bounds().width + controls_layout.bounds().width
> padded.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().draw( compact.as_widget().draw(
&tree.children[1], &tree.children[2],
renderer, renderer,
theme, theme,
&inherited_style, &inherited_style,
controls_layout, compact_layout,
cursor, cursor,
viewport, 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,
);
}
} }
} }
@ -207,13 +248,20 @@ where
let mut children = padded.children(); let mut children = padded.children();
let title_layout = children.next().unwrap(); 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(); let controls_layout = children.next().unwrap();
if title_layout.bounds().width + controls_layout.bounds().width if title_layout.bounds().width + controls_layout.bounds().width
> padded.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 { } else {
!controls_layout.bounds().contains(cursor_position) !controls_layout.bounds().contains(cursor_position)
&& !title_layout.bounds().contains(cursor_position) && !title_layout.bounds().contains(cursor_position)
@ -244,25 +292,73 @@ where
let title_size = title_layout.size(); let title_size = title_layout.size();
let node = if let Some(controls) = &self.controls { 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], &mut tree.children[1],
renderer, renderer,
&layout::Limits::new(Size::ZERO, max_size), &layout::Limits::new(Size::ZERO, max_size),
); );
let controls_size = controls_layout.size(); if title_layout.bounds().width + controls_layout.bounds().width
let space_before_controls = max_size.width - controls_size.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 height = title_size.height.max(controls_size.height); let compact_size = compact_layout.size();
let space_before_controls =
max_size.width - compact_size.width;
layout::Node::with_children( let height = title_size.height.max(compact_size.height);
Size::new(max_size.width, height),
vec![ layout::Node::with_children(
title_layout, Size::new(max_size.width, height),
controls_layout vec![
.move_to(Point::new(space_before_controls, 0.0)), 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 { } else {
layout::Node::with_children( layout::Node::with_children(
Size::new(max_size.width, title_size.height), Size::new(max_size.width, title_size.height),
@ -293,15 +389,33 @@ where
if title_layout.bounds().width + controls_layout.bounds().width if title_layout.bounds().width + controls_layout.bounds().width
> padded.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( compact.as_widget().operate(
&mut tree.children[1], &mut tree.children[2],
controls_layout, compact_layout,
renderer, renderer,
operation, 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 { if show_title {
@ -337,19 +451,45 @@ where
if title_layout.bounds().width + controls_layout.bounds().width if title_layout.bounds().width + controls_layout.bounds().width
> padded.bounds().width > padded.bounds().width
{ {
show_title = false; if let Some(compact) = controls.compact.as_mut() {
} let compact_layout = children.next().unwrap();
controls.as_widget_mut().on_event( compact.as_widget_mut().on_event(
&mut tree.children[1], &mut tree.children[2],
event.clone(), event.clone(),
controls_layout, compact_layout,
cursor, cursor,
renderer, renderer,
clipboard, clipboard,
shell, shell,
viewport, viewport,
) )
} else {
show_title = false;
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 { } else {
event::Status::Ignored event::Status::Ignored
}; };
@ -396,18 +536,33 @@ where
if let Some(controls) = &self.controls { if let Some(controls) = &self.controls {
let controls_layout = children.next().unwrap(); let controls_layout = children.next().unwrap();
let controls_interaction = controls.as_widget().mouse_interaction( let controls_interaction =
&tree.children[1], controls.full.as_widget().mouse_interaction(
controls_layout, &tree.children[1],
cursor, controls_layout,
viewport, cursor,
renderer, viewport,
); renderer,
);
if title_layout.bounds().width + controls_layout.bounds().width if title_layout.bounds().width + controls_layout.bounds().width
> padded.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 { } else {
controls_interaction.max(title_interaction) controls_interaction.max(title_interaction)
} }
@ -444,12 +599,36 @@ where
controls.as_mut().and_then(|controls| { controls.as_mut().and_then(|controls| {
let controls_layout = children.next()?; let controls_layout = children.next()?;
controls.as_widget_mut().overlay( if title_layout.bounds().width
controls_state, + controls_layout.bounds().width
controls_layout, > padded.bounds().width
renderer, {
translation, 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,
)
}
}) })
}) })
} }