Add maximize / restore to PaneGrid
This commit is contained in:
parent
1c00adad61
commit
b761ab5e1d
2 changed files with 128 additions and 55 deletions
|
|
@ -101,7 +101,7 @@ where
|
|||
Renderer::Theme: StyleSheet + container::StyleSheet,
|
||||
{
|
||||
state: &'a state::Internal,
|
||||
elements: Vec<(Pane, Content<'a, Message, Renderer>)>,
|
||||
elements: Elements<Content<'a, Message, Renderer>>,
|
||||
width: Length,
|
||||
height: Length,
|
||||
spacing: u16,
|
||||
|
|
@ -119,17 +119,30 @@ where
|
|||
/// Creates a [`PaneGrid`] with the given [`State`] and view function.
|
||||
///
|
||||
/// The view function will be called to display each [`Pane`] present in the
|
||||
/// [`State`].
|
||||
/// [`State`]. [`bool`] is set if the pane is maximized.
|
||||
pub fn new<T>(
|
||||
state: &'a State<T>,
|
||||
view: impl Fn(Pane, &'a T) -> Content<'a, Message, Renderer>,
|
||||
view: impl Fn(Pane, &'a T, bool) -> Content<'a, Message, Renderer>,
|
||||
) -> Self {
|
||||
let elements = {
|
||||
state
|
||||
.panes
|
||||
.iter()
|
||||
.map(|(pane, pane_state)| (*pane, view(*pane, pane_state)))
|
||||
.collect()
|
||||
let elements = if let Some((pane, pane_state)) =
|
||||
state.maximized.and_then(|pane| {
|
||||
state.panes.get(&pane).map(|pane_state| (pane, pane_state))
|
||||
}) {
|
||||
Elements::Maximized(
|
||||
pane,
|
||||
view(pane, pane_state, true),
|
||||
Node::Pane(pane),
|
||||
)
|
||||
} else {
|
||||
Elements::Normal(
|
||||
state
|
||||
.panes
|
||||
.iter()
|
||||
.map(|(pane, pane_state)| {
|
||||
(*pane, view(*pane, pane_state, false))
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
};
|
||||
|
||||
Self {
|
||||
|
|
@ -232,11 +245,18 @@ where
|
|||
}
|
||||
|
||||
fn diff(&self, tree: &mut Tree) {
|
||||
tree.diff_children_custom(
|
||||
&self.elements,
|
||||
|state, (_, content)| content.diff(state),
|
||||
|(_, content)| content.state(),
|
||||
)
|
||||
match &self.elements {
|
||||
Elements::Normal(elements) => tree.diff_children_custom(
|
||||
elements,
|
||||
|state, (_, content)| content.diff(state),
|
||||
|(_, content)| content.state(),
|
||||
),
|
||||
Elements::Maximized(_, content, _) => tree.diff_children_custom(
|
||||
&[content],
|
||||
|state, content| content.diff(state),
|
||||
|content| content.state(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn width(&self) -> Length {
|
||||
|
|
@ -255,11 +275,11 @@ where
|
|||
layout(
|
||||
renderer,
|
||||
limits,
|
||||
self.state,
|
||||
self.elements.node(self.state),
|
||||
self.width,
|
||||
self.height,
|
||||
self.spacing,
|
||||
self.elements.iter().map(|(pane, content)| (*pane, content)),
|
||||
self.elements.iter(),
|
||||
|element, renderer, limits| element.layout(renderer, limits),
|
||||
)
|
||||
}
|
||||
|
|
@ -278,13 +298,13 @@ where
|
|||
|
||||
let event_status = update(
|
||||
action,
|
||||
self.state,
|
||||
self.elements.node(self.state),
|
||||
&event,
|
||||
layout,
|
||||
cursor_position,
|
||||
shell,
|
||||
self.spacing,
|
||||
self.elements.iter().map(|(pane, content)| (*pane, content)),
|
||||
self.elements.iter(),
|
||||
&self.on_click,
|
||||
&self.on_drag,
|
||||
&self.on_resize,
|
||||
|
|
@ -297,7 +317,7 @@ where
|
|||
.zip(&mut tree.children)
|
||||
.zip(layout.children())
|
||||
.map(|(((pane, content), tree), layout)| {
|
||||
let is_picked = picked_pane == Some(*pane);
|
||||
let is_picked = picked_pane == Some(pane);
|
||||
|
||||
content.on_event(
|
||||
tree,
|
||||
|
|
@ -323,7 +343,7 @@ where
|
|||
) -> mouse::Interaction {
|
||||
mouse_interaction(
|
||||
tree.state.downcast_ref(),
|
||||
self.state,
|
||||
self.elements.node(self.state),
|
||||
layout,
|
||||
cursor_position,
|
||||
self.spacing,
|
||||
|
|
@ -361,7 +381,7 @@ where
|
|||
) {
|
||||
draw(
|
||||
tree.state.downcast_ref(),
|
||||
self.state,
|
||||
self.elements.node(self.state),
|
||||
layout,
|
||||
cursor_position,
|
||||
renderer,
|
||||
|
|
@ -374,7 +394,7 @@ where
|
|||
self.elements
|
||||
.iter()
|
||||
.zip(&tree.children)
|
||||
.map(|((pane, content), tree)| (*pane, (content, tree))),
|
||||
.map(|((pane, content), tree)| (pane, (content, tree))),
|
||||
|(content, tree),
|
||||
renderer,
|
||||
style,
|
||||
|
|
@ -429,7 +449,7 @@ where
|
|||
pub fn layout<Renderer, T>(
|
||||
renderer: &Renderer,
|
||||
limits: &layout::Limits,
|
||||
state: &state::Internal,
|
||||
node: &Node,
|
||||
width: Length,
|
||||
height: Length,
|
||||
spacing: u16,
|
||||
|
|
@ -439,7 +459,7 @@ pub fn layout<Renderer, T>(
|
|||
let limits = limits.width(width).height(height);
|
||||
let size = limits.resolve(Size::ZERO);
|
||||
|
||||
let regions = state.pane_regions(f32::from(spacing), size);
|
||||
let regions = node.pane_regions(f32::from(spacing), size);
|
||||
let children = elements
|
||||
.filter_map(|(pane, element)| {
|
||||
let region = regions.get(&pane)?;
|
||||
|
|
@ -464,7 +484,7 @@ pub fn layout<Renderer, T>(
|
|||
/// accordingly.
|
||||
pub fn update<'a, Message, T: Draggable>(
|
||||
action: &mut state::Action,
|
||||
state: &state::Internal,
|
||||
node: &Node,
|
||||
event: &Event,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
|
|
@ -492,7 +512,7 @@ pub fn update<'a, Message, T: Draggable>(
|
|||
cursor_position.y - bounds.y,
|
||||
);
|
||||
|
||||
let splits = state.split_regions(
|
||||
let splits = node.split_regions(
|
||||
f32::from(spacing),
|
||||
Size::new(bounds.width, bounds.height),
|
||||
);
|
||||
|
|
@ -570,7 +590,7 @@ pub fn update<'a, Message, T: Draggable>(
|
|||
if let Some((split, _)) = action.picked_split() {
|
||||
let bounds = layout.bounds();
|
||||
|
||||
let splits = state.split_regions(
|
||||
let splits = node.split_regions(
|
||||
f32::from(spacing),
|
||||
Size::new(bounds.width, bounds.height),
|
||||
);
|
||||
|
|
@ -642,7 +662,7 @@ fn click_pane<'a, Message, T>(
|
|||
/// Returns the current [`mouse::Interaction`] of a [`PaneGrid`].
|
||||
pub fn mouse_interaction(
|
||||
action: &state::Action,
|
||||
state: &state::Internal,
|
||||
node: &Node,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
spacing: u16,
|
||||
|
|
@ -658,7 +678,7 @@ pub fn mouse_interaction(
|
|||
let bounds = layout.bounds();
|
||||
|
||||
let splits =
|
||||
state.split_regions(f32::from(spacing), bounds.size());
|
||||
node.split_regions(f32::from(spacing), bounds.size());
|
||||
|
||||
let relative_cursor = Point::new(
|
||||
cursor_position.x - bounds.x,
|
||||
|
|
@ -687,7 +707,7 @@ pub fn mouse_interaction(
|
|||
/// Draws a [`PaneGrid`].
|
||||
pub fn draw<Renderer, T>(
|
||||
action: &state::Action,
|
||||
state: &state::Internal,
|
||||
node: &Node,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
renderer: &mut Renderer,
|
||||
|
|
@ -717,7 +737,7 @@ pub fn draw<Renderer, T>(
|
|||
.and_then(|(split, axis)| {
|
||||
let bounds = layout.bounds();
|
||||
|
||||
let splits = state.split_regions(f32::from(spacing), bounds.size());
|
||||
let splits = node.split_regions(f32::from(spacing), bounds.size());
|
||||
|
||||
let (_axis, region, ratio) = splits.get(&split)?;
|
||||
|
||||
|
|
@ -736,7 +756,7 @@ pub fn draw<Renderer, T>(
|
|||
);
|
||||
|
||||
let splits =
|
||||
state.split_regions(f32::from(spacing), bounds.size());
|
||||
node.split_regions(f32::from(spacing), bounds.size());
|
||||
|
||||
let (_split, axis, region) = hovered_split(
|
||||
splits.iter(),
|
||||
|
|
@ -897,3 +917,48 @@ fn hovered_split<'a>(
|
|||
})
|
||||
.next()
|
||||
}
|
||||
|
||||
/// TODO
|
||||
#[derive(Debug)]
|
||||
pub enum Elements<T> {
|
||||
/// TODO
|
||||
Normal(Vec<(Pane, T)>),
|
||||
/// TODO
|
||||
Maximized(Pane, T, Node),
|
||||
}
|
||||
|
||||
impl<T> Elements<T> {
|
||||
/// TODO
|
||||
pub fn iter(&self) -> Box<dyn Iterator<Item = (Pane, &T)> + '_> {
|
||||
match self {
|
||||
Elements::Normal(elements) => Box::new(
|
||||
elements.iter().map(|(pane, content)| (*pane, content)),
|
||||
),
|
||||
Elements::Maximized(pane, content, _) => {
|
||||
Box::new(std::iter::once((*pane, content)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn iter_mut(
|
||||
&mut self,
|
||||
) -> Box<dyn Iterator<Item = (Pane, &mut T)> + '_> {
|
||||
match self {
|
||||
Elements::Normal(elements) => Box::new(
|
||||
elements.iter_mut().map(|(pane, content)| (*pane, content)),
|
||||
),
|
||||
Elements::Maximized(pane, content, _) => {
|
||||
Box::new(std::iter::once((*pane, content)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn node<'a>(&'a self, state: &'a state::Internal) -> &'a Node {
|
||||
match self {
|
||||
Elements::Normal(_) => state.layout(),
|
||||
Elements::Maximized(_, _, node) => node,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
use crate::widget::pane_grid::{
|
||||
Axis, Configuration, Direction, Node, Pane, Split,
|
||||
};
|
||||
use crate::{Point, Rectangle, Size};
|
||||
use crate::{Point, Size};
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// The state of a [`PaneGrid`].
|
||||
///
|
||||
|
|
@ -31,6 +31,9 @@ pub struct State<T> {
|
|||
///
|
||||
/// [`PaneGrid`]: crate::widget::PaneGrid
|
||||
pub internal: Internal,
|
||||
|
||||
/// The maximized [`Pane`] of the [`PaneGrid`]
|
||||
pub(super) maximized: Option<Pane>,
|
||||
}
|
||||
|
||||
impl<T> State<T> {
|
||||
|
|
@ -52,7 +55,11 @@ impl<T> State<T> {
|
|||
let internal =
|
||||
Internal::from_configuration(&mut panes, config.into(), 0);
|
||||
|
||||
State { panes, internal }
|
||||
State {
|
||||
panes,
|
||||
internal,
|
||||
maximized: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the total amount of panes in the [`State`].
|
||||
|
|
@ -194,12 +201,28 @@ impl<T> State<T> {
|
|||
/// Closes the given [`Pane`] and returns its internal state and its closest
|
||||
/// sibling, if it exists.
|
||||
pub fn close(&mut self, pane: &Pane) -> Option<(T, Pane)> {
|
||||
if self.maximized == Some(*pane) {
|
||||
let _ = self.maximized.take();
|
||||
}
|
||||
|
||||
if let Some(sibling) = self.internal.layout.remove(pane) {
|
||||
self.panes.remove(pane).map(|state| (state, sibling))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Maximize the given [`Pane`]. Only this pane will be rendered by the
|
||||
/// [`PaneGrid`] until [`Self::restore()`] is called.
|
||||
pub fn maximize(&mut self, pane: &Pane) {
|
||||
self.maximized = Some(*pane);
|
||||
}
|
||||
|
||||
/// Restore the currently maximized [`Pane`] to it's normal size. All panes
|
||||
/// will be rendered by the [`PaneGrid`]
|
||||
pub fn restore(&mut self) {
|
||||
let _ = self.maximized.take();
|
||||
}
|
||||
}
|
||||
|
||||
/// The internal state of a [`PaneGrid`].
|
||||
|
|
@ -226,11 +249,13 @@ impl Internal {
|
|||
let Internal {
|
||||
layout: a,
|
||||
last_id: next_id,
|
||||
..
|
||||
} = Self::from_configuration(panes, *a, next_id);
|
||||
|
||||
let Internal {
|
||||
layout: b,
|
||||
last_id: next_id,
|
||||
..
|
||||
} = Self::from_configuration(panes, *b, next_id);
|
||||
|
||||
(
|
||||
|
|
@ -304,25 +329,8 @@ impl Action {
|
|||
}
|
||||
|
||||
impl Internal {
|
||||
/// Calculates the current [`Pane`] regions from the [`PaneGrid`] layout.
|
||||
///
|
||||
/// [`PaneGrid`]: crate::widget::PaneGrid
|
||||
pub fn pane_regions(
|
||||
&self,
|
||||
spacing: f32,
|
||||
size: Size,
|
||||
) -> BTreeMap<Pane, Rectangle> {
|
||||
self.layout.pane_regions(spacing, size)
|
||||
}
|
||||
|
||||
/// Calculates the current [`Split`] regions from the [`PaneGrid`] layout.
|
||||
///
|
||||
/// [`PaneGrid`]: crate::widget::PaneGrid
|
||||
pub fn split_regions(
|
||||
&self,
|
||||
spacing: f32,
|
||||
size: Size,
|
||||
) -> BTreeMap<Split, (Axis, Rectangle, f32)> {
|
||||
self.layout.split_regions(spacing, size)
|
||||
/// The layout [`Node`] of the [`Internal`] state
|
||||
pub fn layout(&self) -> &Node {
|
||||
&self.layout
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue