Add compact variant for pane grid controls
This commit is contained in:
parent
9b99b932bc
commit
3a434c9505
4 changed files with 324 additions and 72 deletions
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
59
widget/src/pane_grid/controls.rs
Normal file
59
widget/src/pane_grid/controls.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue