Merge pull request #2628 from tarkah/fix/pane-grid-continuity
Fix/pane grid continuity
This commit is contained in:
commit
17b35df160
3 changed files with 194 additions and 151 deletions
|
|
@ -83,7 +83,10 @@ where
|
||||||
new_size: Size,
|
new_size: Size,
|
||||||
view: &dyn Fn(Size) -> Element<'a, Message, Theme, Renderer>,
|
view: &dyn Fn(Size) -> Element<'a, Message, Theme, Renderer>,
|
||||||
) {
|
) {
|
||||||
if self.size == new_size {
|
let is_tree_empty =
|
||||||
|
tree.tag == tree::Tag::stateless() && tree.children.is_empty();
|
||||||
|
|
||||||
|
if !is_tree_empty && self.size == new_size {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,9 @@ pub struct PaneGrid<
|
||||||
Theme: Catalog,
|
Theme: Catalog,
|
||||||
Renderer: core::Renderer,
|
Renderer: core::Renderer,
|
||||||
{
|
{
|
||||||
contents: Contents<'a, Content<'a, Message, Theme, Renderer>>,
|
internal: &'a state::Internal,
|
||||||
|
panes: Vec<Pane>,
|
||||||
|
contents: Vec<Content<'a, Message, Theme, Renderer>>,
|
||||||
width: Length,
|
width: Length,
|
||||||
height: Length,
|
height: Length,
|
||||||
spacing: f32,
|
spacing: f32,
|
||||||
|
|
@ -180,29 +182,19 @@ where
|
||||||
state: &'a State<T>,
|
state: &'a State<T>,
|
||||||
view: impl Fn(Pane, &'a T, bool) -> Content<'a, Message, Theme, Renderer>,
|
view: impl Fn(Pane, &'a T, bool) -> Content<'a, Message, Theme, Renderer>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let contents = if let Some((pane, pane_state)) =
|
let panes = state.panes.keys().copied().collect();
|
||||||
state.maximized.and_then(|pane| {
|
let contents = state
|
||||||
state.panes.get(&pane).map(|pane_state| (pane, pane_state))
|
.panes
|
||||||
}) {
|
.iter()
|
||||||
Contents::Maximized(
|
.map(|(pane, pane_state)| match state.maximized() {
|
||||||
pane,
|
Some(p) if *pane == p => view(*pane, pane_state, true),
|
||||||
view(pane, pane_state, true),
|
_ => view(*pane, pane_state, false),
|
||||||
Node::Pane(pane),
|
})
|
||||||
)
|
.collect();
|
||||||
} else {
|
|
||||||
Contents::All(
|
|
||||||
state
|
|
||||||
.panes
|
|
||||||
.iter()
|
|
||||||
.map(|(pane, pane_state)| {
|
|
||||||
(*pane, view(*pane, pane_state, false))
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
&state.internal,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
internal: &state.internal,
|
||||||
|
panes,
|
||||||
contents,
|
contents,
|
||||||
width: Length::Fill,
|
width: Length::Fill,
|
||||||
height: Length::Fill,
|
height: Length::Fill,
|
||||||
|
|
@ -248,7 +240,9 @@ where
|
||||||
where
|
where
|
||||||
F: 'a + Fn(DragEvent) -> Message,
|
F: 'a + Fn(DragEvent) -> Message,
|
||||||
{
|
{
|
||||||
self.on_drag = Some(Box::new(f));
|
if self.internal.maximized().is_none() {
|
||||||
|
self.on_drag = Some(Box::new(f));
|
||||||
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,7 +259,9 @@ where
|
||||||
where
|
where
|
||||||
F: 'a + Fn(ResizeEvent) -> Message,
|
F: 'a + Fn(ResizeEvent) -> Message,
|
||||||
{
|
{
|
||||||
self.on_resize = Some((leeway.into().0, Box::new(f)));
|
if self.internal.maximized().is_none() {
|
||||||
|
self.on_resize = Some((leeway.into().0, Box::new(f)));
|
||||||
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -291,12 +287,20 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drag_enabled(&self) -> bool {
|
fn drag_enabled(&self) -> bool {
|
||||||
(!self.contents.is_maximized())
|
self.internal
|
||||||
|
.maximized()
|
||||||
|
.is_none()
|
||||||
.then(|| self.on_drag.is_some())
|
.then(|| self.on_drag.is_some())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Memory {
|
||||||
|
action: state::Action,
|
||||||
|
order: Vec<Pane>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
|
impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
|
||||||
for PaneGrid<'a, Message, Theme, Renderer>
|
for PaneGrid<'a, Message, Theme, Renderer>
|
||||||
where
|
where
|
||||||
|
|
@ -304,33 +308,47 @@ where
|
||||||
Renderer: core::Renderer,
|
Renderer: core::Renderer,
|
||||||
{
|
{
|
||||||
fn tag(&self) -> tree::Tag {
|
fn tag(&self) -> tree::Tag {
|
||||||
tree::Tag::of::<state::Action>()
|
tree::Tag::of::<Memory>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state(&self) -> tree::State {
|
fn state(&self) -> tree::State {
|
||||||
tree::State::new(state::Action::Idle)
|
tree::State::new(Memory::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children(&self) -> Vec<Tree> {
|
fn children(&self) -> Vec<Tree> {
|
||||||
self.contents
|
self.contents.iter().map(Content::state).collect()
|
||||||
.iter()
|
|
||||||
.map(|(_, content)| content.state())
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff(&self, tree: &mut Tree) {
|
fn diff(&self, tree: &mut Tree) {
|
||||||
match &self.contents {
|
let Memory { order, .. } = tree.state.downcast_ref();
|
||||||
Contents::All(contents, _) => tree.diff_children_custom(
|
|
||||||
contents,
|
// `Pane` always increments and is iterated by Ord so new
|
||||||
|state, (_, content)| content.diff(state),
|
// states are always added at the end. We can simply remove
|
||||||
|(_, content)| content.state(),
|
// states which no longer exist and `diff_children` will
|
||||||
),
|
// diff the remaining values in the correct order and
|
||||||
Contents::Maximized(_, content, _) => tree.diff_children_custom(
|
// add new states at the end
|
||||||
&[content],
|
|
||||||
|state, content| content.diff(state),
|
let mut i = 0;
|
||||||
|content| content.state(),
|
let mut j = 0;
|
||||||
),
|
tree.children.retain(|_| {
|
||||||
}
|
let retain = self.panes.get(i) == order.get(j);
|
||||||
|
|
||||||
|
if retain {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
j += 1;
|
||||||
|
|
||||||
|
retain
|
||||||
|
});
|
||||||
|
|
||||||
|
tree.diff_children_custom(
|
||||||
|
&self.contents,
|
||||||
|
|state, content| content.diff(state),
|
||||||
|
Content::state,
|
||||||
|
);
|
||||||
|
|
||||||
|
let Memory { order, .. } = tree.state.downcast_mut();
|
||||||
|
order.clone_from(&self.panes);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size(&self) -> Size<Length> {
|
fn size(&self) -> Size<Length> {
|
||||||
|
|
@ -347,14 +365,23 @@ where
|
||||||
limits: &layout::Limits,
|
limits: &layout::Limits,
|
||||||
) -> layout::Node {
|
) -> layout::Node {
|
||||||
let size = limits.resolve(self.width, self.height, Size::ZERO);
|
let size = limits.resolve(self.width, self.height, Size::ZERO);
|
||||||
let node = self.contents.layout();
|
let regions = self.internal.layout().pane_regions(self.spacing, size);
|
||||||
let regions = node.pane_regions(self.spacing, size);
|
|
||||||
|
|
||||||
let children = self
|
let children = self
|
||||||
.contents
|
.panes
|
||||||
.iter()
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip(&self.contents)
|
||||||
.zip(tree.children.iter_mut())
|
.zip(tree.children.iter_mut())
|
||||||
.filter_map(|((pane, content), tree)| {
|
.filter_map(|((pane, content), tree)| {
|
||||||
|
if self
|
||||||
|
.internal
|
||||||
|
.maximized()
|
||||||
|
.is_some_and(|maximized| maximized != pane)
|
||||||
|
{
|
||||||
|
return Some(layout::Node::new(Size::ZERO));
|
||||||
|
}
|
||||||
|
|
||||||
let region = regions.get(&pane)?;
|
let region = regions.get(&pane)?;
|
||||||
let size = Size::new(region.width, region.height);
|
let size = Size::new(region.width, region.height);
|
||||||
|
|
||||||
|
|
@ -379,11 +406,18 @@ where
|
||||||
operation: &mut dyn widget::Operation,
|
operation: &mut dyn widget::Operation,
|
||||||
) {
|
) {
|
||||||
operation.container(None, layout.bounds(), &mut |operation| {
|
operation.container(None, layout.bounds(), &mut |operation| {
|
||||||
self.contents
|
self.panes
|
||||||
.iter()
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip(&self.contents)
|
||||||
.zip(&mut tree.children)
|
.zip(&mut tree.children)
|
||||||
.zip(layout.children())
|
.zip(layout.children())
|
||||||
.for_each(|(((_pane, content), state), layout)| {
|
.filter(|(((pane, _), _), _)| {
|
||||||
|
self.internal
|
||||||
|
.maximized()
|
||||||
|
.map_or(true, |maximized| *pane == maximized)
|
||||||
|
})
|
||||||
|
.for_each(|(((_, content), state), layout)| {
|
||||||
content.operate(state, layout, renderer, operation);
|
content.operate(state, layout, renderer, operation);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -402,8 +436,8 @@ where
|
||||||
) -> event::Status {
|
) -> event::Status {
|
||||||
let mut event_status = event::Status::Ignored;
|
let mut event_status = event::Status::Ignored;
|
||||||
|
|
||||||
let action = tree.state.downcast_mut::<state::Action>();
|
let Memory { action, .. } = tree.state.downcast_mut();
|
||||||
let node = self.contents.layout();
|
let node = self.internal.layout();
|
||||||
|
|
||||||
let on_drag = if self.drag_enabled() {
|
let on_drag = if self.drag_enabled() {
|
||||||
&self.on_drag
|
&self.on_drag
|
||||||
|
|
@ -448,7 +482,10 @@ where
|
||||||
layout,
|
layout,
|
||||||
cursor_position,
|
cursor_position,
|
||||||
shell,
|
shell,
|
||||||
self.contents.iter(),
|
self.panes
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip(&self.contents),
|
||||||
&self.on_click,
|
&self.on_click,
|
||||||
on_drag,
|
on_drag,
|
||||||
);
|
);
|
||||||
|
|
@ -460,7 +497,7 @@ where
|
||||||
layout,
|
layout,
|
||||||
cursor_position,
|
cursor_position,
|
||||||
shell,
|
shell,
|
||||||
self.contents.iter(),
|
self.panes.iter().copied().zip(&self.contents),
|
||||||
&self.on_click,
|
&self.on_click,
|
||||||
on_drag,
|
on_drag,
|
||||||
);
|
);
|
||||||
|
|
@ -486,8 +523,10 @@ where
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let dropped_region = self
|
let dropped_region = self
|
||||||
.contents
|
.panes
|
||||||
.iter()
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip(&self.contents)
|
||||||
.zip(layout.children())
|
.zip(layout.children())
|
||||||
.find_map(|(target, layout)| {
|
.find_map(|(target, layout)| {
|
||||||
layout_region(
|
layout_region(
|
||||||
|
|
@ -572,10 +611,17 @@ where
|
||||||
|
|
||||||
let picked_pane = action.picked_pane().map(|(pane, _)| pane);
|
let picked_pane = action.picked_pane().map(|(pane, _)| pane);
|
||||||
|
|
||||||
self.contents
|
self.panes
|
||||||
.iter_mut()
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip(&mut self.contents)
|
||||||
.zip(&mut tree.children)
|
.zip(&mut tree.children)
|
||||||
.zip(layout.children())
|
.zip(layout.children())
|
||||||
|
.filter(|(((pane, _), _), _)| {
|
||||||
|
self.internal
|
||||||
|
.maximized()
|
||||||
|
.map_or(true, |maximized| *pane == maximized)
|
||||||
|
})
|
||||||
.map(|(((pane, content), tree), layout)| {
|
.map(|(((pane, content), tree), layout)| {
|
||||||
let is_picked = picked_pane == Some(pane);
|
let is_picked = picked_pane == Some(pane);
|
||||||
|
|
||||||
|
|
@ -602,14 +648,14 @@ where
|
||||||
viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
) -> mouse::Interaction {
|
) -> mouse::Interaction {
|
||||||
let action = tree.state.downcast_ref::<state::Action>();
|
let Memory { action, .. } = tree.state.downcast_ref();
|
||||||
|
|
||||||
if action.picked_pane().is_some() {
|
if action.picked_pane().is_some() {
|
||||||
return mouse::Interaction::Grabbing;
|
return mouse::Interaction::Grabbing;
|
||||||
}
|
}
|
||||||
|
|
||||||
let resize_leeway = self.on_resize.as_ref().map(|(leeway, _)| *leeway);
|
let resize_leeway = self.on_resize.as_ref().map(|(leeway, _)| *leeway);
|
||||||
let node = self.contents.layout();
|
let node = self.internal.layout();
|
||||||
|
|
||||||
let resize_axis =
|
let resize_axis =
|
||||||
action.picked_split().map(|(_, axis)| axis).or_else(|| {
|
action.picked_split().map(|(_, axis)| axis).or_else(|| {
|
||||||
|
|
@ -641,11 +687,18 @@ where
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
self.contents
|
self.panes
|
||||||
.iter()
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip(&self.contents)
|
||||||
.zip(&tree.children)
|
.zip(&tree.children)
|
||||||
.zip(layout.children())
|
.zip(layout.children())
|
||||||
.map(|(((_pane, content), tree), layout)| {
|
.filter(|(((pane, _), _), _)| {
|
||||||
|
self.internal
|
||||||
|
.maximized()
|
||||||
|
.map_or(true, |maximized| *pane == maximized)
|
||||||
|
})
|
||||||
|
.map(|(((_, content), tree), layout)| {
|
||||||
content.mouse_interaction(
|
content.mouse_interaction(
|
||||||
tree,
|
tree,
|
||||||
layout,
|
layout,
|
||||||
|
|
@ -669,16 +722,10 @@ where
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
) {
|
) {
|
||||||
let action = tree.state.downcast_ref::<state::Action>();
|
let Memory { action, .. } = tree.state.downcast_ref();
|
||||||
let node = self.contents.layout();
|
let node = self.internal.layout();
|
||||||
let resize_leeway = self.on_resize.as_ref().map(|(leeway, _)| *leeway);
|
let resize_leeway = self.on_resize.as_ref().map(|(leeway, _)| *leeway);
|
||||||
|
|
||||||
let contents = self
|
|
||||||
.contents
|
|
||||||
.iter()
|
|
||||||
.zip(&tree.children)
|
|
||||||
.map(|((pane, content), tree)| (pane, (content, tree)));
|
|
||||||
|
|
||||||
let picked_pane = action.picked_pane().filter(|(_, origin)| {
|
let picked_pane = action.picked_pane().filter(|(_, origin)| {
|
||||||
cursor
|
cursor
|
||||||
.position()
|
.position()
|
||||||
|
|
@ -747,8 +794,18 @@ where
|
||||||
|
|
||||||
let style = Catalog::style(theme, &self.class);
|
let style = Catalog::style(theme, &self.class);
|
||||||
|
|
||||||
for ((id, (content, tree)), pane_layout) in
|
for (((id, content), tree), pane_layout) in self
|
||||||
contents.zip(layout.children())
|
.panes
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip(&self.contents)
|
||||||
|
.zip(&tree.children)
|
||||||
|
.zip(layout.children())
|
||||||
|
.filter(|(((pane, _), _), _)| {
|
||||||
|
self.internal
|
||||||
|
.maximized()
|
||||||
|
.map_or(true, |maximized| maximized == *pane)
|
||||||
|
})
|
||||||
{
|
{
|
||||||
match picked_pane {
|
match picked_pane {
|
||||||
Some((dragging, origin)) if id == dragging => {
|
Some((dragging, origin)) if id == dragging => {
|
||||||
|
|
@ -883,11 +940,21 @@ where
|
||||||
translation: Vector,
|
translation: Vector,
|
||||||
) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
|
) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
|
||||||
let children = self
|
let children = self
|
||||||
.contents
|
.panes
|
||||||
.iter_mut()
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip(&mut self.contents)
|
||||||
.zip(&mut tree.children)
|
.zip(&mut tree.children)
|
||||||
.zip(layout.children())
|
.zip(layout.children())
|
||||||
.filter_map(|(((_, content), state), layout)| {
|
.filter_map(|(((pane, content), state), layout)| {
|
||||||
|
if self
|
||||||
|
.internal
|
||||||
|
.maximized()
|
||||||
|
.is_some_and(|maximized| maximized != pane)
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
content.overlay(state, layout, renderer, translation)
|
content.overlay(state, layout, renderer, translation)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
@ -1136,52 +1203,6 @@ fn hovered_split<'a>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The visible contents of the [`PaneGrid`]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Contents<'a, T> {
|
|
||||||
/// All panes are visible
|
|
||||||
All(Vec<(Pane, T)>, &'a state::Internal),
|
|
||||||
/// A maximized pane is visible
|
|
||||||
Maximized(Pane, T, Node),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> Contents<'a, T> {
|
|
||||||
/// Returns the layout [`Node`] of the [`Contents`]
|
|
||||||
pub fn layout(&self) -> &Node {
|
|
||||||
match self {
|
|
||||||
Contents::All(_, state) => state.layout(),
|
|
||||||
Contents::Maximized(_, _, layout) => layout,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an iterator over the values of the [`Contents`]
|
|
||||||
pub fn iter(&self) -> Box<dyn Iterator<Item = (Pane, &T)> + '_> {
|
|
||||||
match self {
|
|
||||||
Contents::All(contents, _) => Box::new(
|
|
||||||
contents.iter().map(|(pane, content)| (*pane, content)),
|
|
||||||
),
|
|
||||||
Contents::Maximized(pane, content, _) => {
|
|
||||||
Box::new(std::iter::once((*pane, content)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn iter_mut(&mut self) -> Box<dyn Iterator<Item = (Pane, &mut T)> + '_> {
|
|
||||||
match self {
|
|
||||||
Contents::All(contents, _) => Box::new(
|
|
||||||
contents.iter_mut().map(|(pane, content)| (*pane, content)),
|
|
||||||
),
|
|
||||||
Contents::Maximized(pane, content, _) => {
|
|
||||||
Box::new(std::iter::once((*pane, content)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_maximized(&self) -> bool {
|
|
||||||
matches!(self, Self::Maximized(..))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The appearance of a [`PaneGrid`].
|
/// The appearance of a [`PaneGrid`].
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct Style {
|
pub struct Style {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ use crate::pane_grid::{
|
||||||
Axis, Configuration, Direction, Edge, Node, Pane, Region, Split, Target,
|
Axis, Configuration, Direction, Edge, Node, Pane, Region, Split, Target,
|
||||||
};
|
};
|
||||||
|
|
||||||
use rustc_hash::FxHashMap;
|
use std::borrow::Cow;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
/// The state of a [`PaneGrid`].
|
/// The state of a [`PaneGrid`].
|
||||||
///
|
///
|
||||||
|
|
@ -25,17 +26,12 @@ pub struct State<T> {
|
||||||
/// The panes of the [`PaneGrid`].
|
/// The panes of the [`PaneGrid`].
|
||||||
///
|
///
|
||||||
/// [`PaneGrid`]: super::PaneGrid
|
/// [`PaneGrid`]: super::PaneGrid
|
||||||
pub panes: FxHashMap<Pane, T>,
|
pub panes: BTreeMap<Pane, T>,
|
||||||
|
|
||||||
/// The internal state of the [`PaneGrid`].
|
/// The internal state of the [`PaneGrid`].
|
||||||
///
|
///
|
||||||
/// [`PaneGrid`]: super::PaneGrid
|
/// [`PaneGrid`]: super::PaneGrid
|
||||||
pub internal: Internal,
|
pub internal: Internal,
|
||||||
|
|
||||||
/// The maximized [`Pane`] of the [`PaneGrid`].
|
|
||||||
///
|
|
||||||
/// [`PaneGrid`]: super::PaneGrid
|
|
||||||
pub(super) maximized: Option<Pane>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> State<T> {
|
impl<T> State<T> {
|
||||||
|
|
@ -52,16 +48,12 @@ impl<T> State<T> {
|
||||||
|
|
||||||
/// Creates a new [`State`] with the given [`Configuration`].
|
/// Creates a new [`State`] with the given [`Configuration`].
|
||||||
pub fn with_configuration(config: impl Into<Configuration<T>>) -> Self {
|
pub fn with_configuration(config: impl Into<Configuration<T>>) -> Self {
|
||||||
let mut panes = FxHashMap::default();
|
let mut panes = BTreeMap::default();
|
||||||
|
|
||||||
let internal =
|
let internal =
|
||||||
Internal::from_configuration(&mut panes, config.into(), 0);
|
Internal::from_configuration(&mut panes, config.into(), 0);
|
||||||
|
|
||||||
State {
|
State { panes, internal }
|
||||||
panes,
|
|
||||||
internal,
|
|
||||||
maximized: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the total amount of panes in the [`State`].
|
/// Returns the total amount of panes in the [`State`].
|
||||||
|
|
@ -214,7 +206,7 @@ impl<T> State<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = self.panes.insert(new_pane, state);
|
let _ = self.panes.insert(new_pane, state);
|
||||||
let _ = self.maximized.take();
|
let _ = self.internal.maximized.take();
|
||||||
|
|
||||||
Some((new_pane, new_split))
|
Some((new_pane, new_split))
|
||||||
}
|
}
|
||||||
|
|
@ -228,8 +220,11 @@ impl<T> State<T> {
|
||||||
) {
|
) {
|
||||||
if let Some((state, _)) = self.close(pane) {
|
if let Some((state, _)) = self.close(pane) {
|
||||||
if let Some((new_pane, _)) = self.split(axis, target, state) {
|
if let Some((new_pane, _)) = self.split(axis, target, state) {
|
||||||
|
// Ensure new node corresponds to original closed `Pane` for state continuity
|
||||||
|
self.relabel(new_pane, pane);
|
||||||
|
|
||||||
if swap {
|
if swap {
|
||||||
self.swap(target, new_pane);
|
self.swap(target, pane);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -259,13 +254,27 @@ impl<T> State<T> {
|
||||||
&mut self,
|
&mut self,
|
||||||
axis: Axis,
|
axis: Axis,
|
||||||
pane: Pane,
|
pane: Pane,
|
||||||
swap: bool,
|
inverse: bool,
|
||||||
) {
|
) {
|
||||||
if let Some((state, _)) = self.close(pane) {
|
if let Some((state, _)) = self.close(pane) {
|
||||||
let _ = self.split_node(axis, None, state, swap);
|
if let Some((new_pane, _)) =
|
||||||
|
self.split_node(axis, None, state, inverse)
|
||||||
|
{
|
||||||
|
// Ensure new node corresponds to original closed `Pane` for state continuity
|
||||||
|
self.relabel(new_pane, pane);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn relabel(&mut self, target: Pane, label: Pane) {
|
||||||
|
self.swap(target, label);
|
||||||
|
|
||||||
|
let _ = self
|
||||||
|
.panes
|
||||||
|
.remove(&target)
|
||||||
|
.and_then(|state| self.panes.insert(label, state));
|
||||||
|
}
|
||||||
|
|
||||||
/// Swaps the position of the provided panes in the [`State`].
|
/// Swaps the position of the provided panes in the [`State`].
|
||||||
///
|
///
|
||||||
/// If you want to swap panes on drag and drop in your [`PaneGrid`], you
|
/// If you want to swap panes on drag and drop in your [`PaneGrid`], you
|
||||||
|
|
@ -303,8 +312,8 @@ impl<T> State<T> {
|
||||||
/// Closes the given [`Pane`] and returns its internal state and its closest
|
/// Closes the given [`Pane`] and returns its internal state and its closest
|
||||||
/// sibling, if it exists.
|
/// sibling, if it exists.
|
||||||
pub fn close(&mut self, pane: Pane) -> Option<(T, Pane)> {
|
pub fn close(&mut self, pane: Pane) -> Option<(T, Pane)> {
|
||||||
if self.maximized == Some(pane) {
|
if self.internal.maximized == Some(pane) {
|
||||||
let _ = self.maximized.take();
|
let _ = self.internal.maximized.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(sibling) = self.internal.layout.remove(pane) {
|
if let Some(sibling) = self.internal.layout.remove(pane) {
|
||||||
|
|
@ -319,7 +328,7 @@ impl<T> State<T> {
|
||||||
///
|
///
|
||||||
/// [`PaneGrid`]: super::PaneGrid
|
/// [`PaneGrid`]: super::PaneGrid
|
||||||
pub fn maximize(&mut self, pane: Pane) {
|
pub fn maximize(&mut self, pane: Pane) {
|
||||||
self.maximized = Some(pane);
|
self.internal.maximized = Some(pane);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restore the currently maximized [`Pane`] to it's normal size. All panes
|
/// Restore the currently maximized [`Pane`] to it's normal size. All panes
|
||||||
|
|
@ -327,14 +336,14 @@ impl<T> State<T> {
|
||||||
///
|
///
|
||||||
/// [`PaneGrid`]: super::PaneGrid
|
/// [`PaneGrid`]: super::PaneGrid
|
||||||
pub fn restore(&mut self) {
|
pub fn restore(&mut self) {
|
||||||
let _ = self.maximized.take();
|
let _ = self.internal.maximized.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the maximized [`Pane`] of the [`PaneGrid`].
|
/// Returns the maximized [`Pane`] of the [`PaneGrid`].
|
||||||
///
|
///
|
||||||
/// [`PaneGrid`]: super::PaneGrid
|
/// [`PaneGrid`]: super::PaneGrid
|
||||||
pub fn maximized(&self) -> Option<Pane> {
|
pub fn maximized(&self) -> Option<Pane> {
|
||||||
self.maximized
|
self.internal.maximized
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -345,6 +354,7 @@ impl<T> State<T> {
|
||||||
pub struct Internal {
|
pub struct Internal {
|
||||||
layout: Node,
|
layout: Node,
|
||||||
last_id: usize,
|
last_id: usize,
|
||||||
|
maximized: Option<Pane>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Internal {
|
impl Internal {
|
||||||
|
|
@ -353,7 +363,7 @@ impl Internal {
|
||||||
///
|
///
|
||||||
/// [`PaneGrid`]: super::PaneGrid
|
/// [`PaneGrid`]: super::PaneGrid
|
||||||
pub fn from_configuration<T>(
|
pub fn from_configuration<T>(
|
||||||
panes: &mut FxHashMap<Pane, T>,
|
panes: &mut BTreeMap<Pane, T>,
|
||||||
content: Configuration<T>,
|
content: Configuration<T>,
|
||||||
next_id: usize,
|
next_id: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
@ -390,18 +400,34 @@ impl Internal {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Self { layout, last_id }
|
Self {
|
||||||
|
layout,
|
||||||
|
last_id,
|
||||||
|
maximized: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn layout(&self) -> Cow<'_, Node> {
|
||||||
|
match self.maximized {
|
||||||
|
Some(pane) => Cow::Owned(Node::Pane(pane)),
|
||||||
|
None => Cow::Borrowed(&self.layout),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn maximized(&self) -> Option<Pane> {
|
||||||
|
self.maximized
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The current action of a [`PaneGrid`].
|
/// The current action of a [`PaneGrid`].
|
||||||
///
|
///
|
||||||
/// [`PaneGrid`]: super::PaneGrid
|
/// [`PaneGrid`]: super::PaneGrid
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
/// The [`PaneGrid`] is idle.
|
/// The [`PaneGrid`] is idle.
|
||||||
///
|
///
|
||||||
/// [`PaneGrid`]: super::PaneGrid
|
/// [`PaneGrid`]: super::PaneGrid
|
||||||
|
#[default]
|
||||||
Idle,
|
Idle,
|
||||||
/// A [`Pane`] in the [`PaneGrid`] is being dragged.
|
/// A [`Pane`] in the [`PaneGrid`] is being dragged.
|
||||||
///
|
///
|
||||||
|
|
@ -440,10 +466,3 @@ impl Action {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Internal {
|
|
||||||
/// 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