Couple layout & content to avoid desync

This commit is contained in:
Cory Forsstrom 2022-11-08 08:49:26 -08:00
parent 853ff4bcf4
commit 7de9d2475d
2 changed files with 55 additions and 68 deletions

View file

@ -100,8 +100,7 @@ where
Renderer: crate::Renderer, Renderer: crate::Renderer,
Renderer::Theme: StyleSheet + container::StyleSheet, Renderer::Theme: StyleSheet + container::StyleSheet,
{ {
state: state::Scoped<'a>, contents: Contents<'a, Content<'a, Message, Renderer>>,
contents: Contents<Content<'a, Message, Renderer>>,
width: Length, width: Length,
height: Length, height: Length,
spacing: u16, spacing: u16,
@ -124,32 +123,30 @@ where
state: &'a State<T>, state: &'a State<T>,
view: impl Fn(Pane, &'a T, bool) -> Content<'a, Message, Renderer>, view: impl Fn(Pane, &'a T, bool) -> Content<'a, Message, Renderer>,
) -> Self { ) -> Self {
let (contents, state) = if let Some((pane, pane_state)) = let contents = if let Some((pane, pane_state)) =
state.maximized.and_then(|pane| { state.maximized.and_then(|pane| {
state.panes.get(&pane).map(|pane_state| (pane, pane_state)) state.panes.get(&pane).map(|pane_state| (pane, pane_state))
}) { }) {
( Contents::Maximized(
Contents::Maximized(pane, view(pane, pane_state, true)), pane,
state::Scoped::Maximized(Node::Pane(pane)), view(pane, pane_state, true),
Node::Pane(pane),
) )
} else { } else {
( Contents::All(
Contents::All( state
state .panes
.panes .iter()
.iter() .map(|(pane, pane_state)| {
.map(|(pane, pane_state)| { (*pane, view(*pane, pane_state, false))
(*pane, view(*pane, pane_state, false)) })
}) .collect(),
.collect(), &state.internal,
),
state::Scoped::All(&state.internal),
) )
}; };
Self { Self {
contents, contents,
state,
width: Length::Fill, width: Length::Fill,
height: Length::Fill, height: Length::Fill,
spacing: 0, spacing: 0,
@ -254,12 +251,12 @@ where
fn diff(&self, tree: &mut Tree) { fn diff(&self, tree: &mut Tree) {
match &self.contents { match &self.contents {
Contents::All(contents) => tree.diff_children_custom( Contents::All(contents, _) => tree.diff_children_custom(
contents, contents,
|state, (_, content)| content.diff(state), |state, (_, content)| content.diff(state),
|(_, content)| content.state(), |(_, content)| content.state(),
), ),
Contents::Maximized(_, content) => tree.diff_children_custom( Contents::Maximized(_, content, _) => tree.diff_children_custom(
&[content], &[content],
|state, content| content.diff(state), |state, content| content.diff(state),
|content| content.state(), |content| content.state(),
@ -283,7 +280,7 @@ where
layout( layout(
renderer, renderer,
limits, limits,
&self.state, self.contents.layout(),
self.width, self.width,
self.height, self.height,
self.spacing, self.spacing,
@ -312,7 +309,7 @@ where
let event_status = update( let event_status = update(
action, action,
&self.state, self.contents.layout(),
&event, &event,
layout, layout,
cursor_position, cursor_position,
@ -357,7 +354,7 @@ where
) -> mouse::Interaction { ) -> mouse::Interaction {
mouse_interaction( mouse_interaction(
tree.state.downcast_ref(), tree.state.downcast_ref(),
&self.state, self.contents.layout(),
layout, layout,
cursor_position, cursor_position,
self.spacing, self.spacing,
@ -395,7 +392,7 @@ where
) { ) {
draw( draw(
tree.state.downcast_ref(), tree.state.downcast_ref(),
&self.state, self.contents.layout(),
layout, layout,
cursor_position, cursor_position,
renderer, renderer,
@ -460,10 +457,10 @@ where
} }
/// Calculates the [`Layout`] of a [`PaneGrid`]. /// Calculates the [`Layout`] of a [`PaneGrid`].
pub fn layout<'a, Renderer, T>( pub fn layout<Renderer, T>(
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
state: &state::Scoped<'a>, node: &Node,
width: Length, width: Length,
height: Length, height: Length,
spacing: u16, spacing: u16,
@ -473,7 +470,7 @@ pub fn layout<'a, Renderer, T>(
let limits = limits.width(width).height(height); let limits = limits.width(width).height(height);
let size = limits.resolve(Size::ZERO); let size = limits.resolve(Size::ZERO);
let regions = state.layout().pane_regions(f32::from(spacing), size); let regions = node.pane_regions(f32::from(spacing), size);
let children = contents let children = contents
.filter_map(|(pane, content)| { .filter_map(|(pane, content)| {
let region = regions.get(&pane)?; let region = regions.get(&pane)?;
@ -498,7 +495,7 @@ pub fn layout<'a, Renderer, T>(
/// accordingly. /// accordingly.
pub fn update<'a, Message, T: Draggable>( pub fn update<'a, Message, T: Draggable>(
action: &mut state::Action, action: &mut state::Action,
state: &state::Scoped<'a>, node: &Node,
event: &Event, event: &Event,
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
@ -526,7 +523,7 @@ pub fn update<'a, Message, T: Draggable>(
cursor_position.y - bounds.y, cursor_position.y - bounds.y,
); );
let splits = state.layout().split_regions( let splits = node.split_regions(
f32::from(spacing), f32::from(spacing),
Size::new(bounds.width, bounds.height), Size::new(bounds.width, bounds.height),
); );
@ -604,7 +601,7 @@ pub fn update<'a, Message, T: Draggable>(
if let Some((split, _)) = action.picked_split() { if let Some((split, _)) = action.picked_split() {
let bounds = layout.bounds(); let bounds = layout.bounds();
let splits = state.layout().split_regions( let splits = node.split_regions(
f32::from(spacing), f32::from(spacing),
Size::new(bounds.width, bounds.height), Size::new(bounds.width, bounds.height),
); );
@ -674,9 +671,9 @@ fn click_pane<'a, Message, T>(
} }
/// Returns the current [`mouse::Interaction`] of a [`PaneGrid`]. /// Returns the current [`mouse::Interaction`] of a [`PaneGrid`].
pub fn mouse_interaction<'a>( pub fn mouse_interaction(
action: &state::Action, action: &state::Action,
state: &state::Scoped<'a>, node: &Node,
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
spacing: u16, spacing: u16,
@ -691,9 +688,8 @@ pub fn mouse_interaction<'a>(
resize_leeway.and_then(|leeway| { resize_leeway.and_then(|leeway| {
let bounds = layout.bounds(); let bounds = layout.bounds();
let splits = state let splits =
.layout() node.split_regions(f32::from(spacing), bounds.size());
.split_regions(f32::from(spacing), bounds.size());
let relative_cursor = Point::new( let relative_cursor = Point::new(
cursor_position.x - bounds.x, cursor_position.x - bounds.x,
@ -720,9 +716,9 @@ pub fn mouse_interaction<'a>(
} }
/// Draws a [`PaneGrid`]. /// Draws a [`PaneGrid`].
pub fn draw<'a, Renderer, T>( pub fn draw<Renderer, T>(
action: &state::Action, action: &state::Action,
state: &state::Scoped<'a>, node: &Node,
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
renderer: &mut Renderer, renderer: &mut Renderer,
@ -752,9 +748,7 @@ pub fn draw<'a, Renderer, T>(
.and_then(|(split, axis)| { .and_then(|(split, axis)| {
let bounds = layout.bounds(); let bounds = layout.bounds();
let splits = state let splits = node.split_regions(f32::from(spacing), bounds.size());
.layout()
.split_regions(f32::from(spacing), bounds.size());
let (_axis, region, ratio) = splits.get(&split)?; let (_axis, region, ratio) = splits.get(&split)?;
@ -772,9 +766,8 @@ pub fn draw<'a, Renderer, T>(
cursor_position.y - bounds.y, cursor_position.y - bounds.y,
); );
let splits = state let splits =
.layout() node.split_regions(f32::from(spacing), bounds.size());
.split_regions(f32::from(spacing), bounds.size());
let (_split, axis, region) = hovered_split( let (_split, axis, region) = hovered_split(
splits.iter(), splits.iter(),
@ -938,21 +931,29 @@ fn hovered_split<'a>(
/// The visible contents of the [`PaneGrid`] /// The visible contents of the [`PaneGrid`]
#[derive(Debug)] #[derive(Debug)]
pub enum Contents<T> { pub enum Contents<'a, T> {
/// All panes are visible /// All panes are visible
All(Vec<(Pane, T)>), All(Vec<(Pane, T)>, &'a state::Internal),
/// A maximized pane is visible /// A maximized pane is visible
Maximized(Pane, T), Maximized(Pane, T, Node),
} }
impl<T> Contents<T> { 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`] /// Returns an iterator over the values of the [`Contents`]
pub fn iter(&self) -> Box<dyn Iterator<Item = (Pane, &T)> + '_> { pub fn iter(&self) -> Box<dyn Iterator<Item = (Pane, &T)> + '_> {
match self { match self {
Contents::All(contents) => Box::new( Contents::All(contents, _) => Box::new(
contents.iter().map(|(pane, content)| (*pane, content)), contents.iter().map(|(pane, content)| (*pane, content)),
), ),
Contents::Maximized(pane, content) => { Contents::Maximized(pane, content, _) => {
Box::new(std::iter::once((*pane, content))) Box::new(std::iter::once((*pane, content)))
} }
} }
@ -960,10 +961,10 @@ impl<T> Contents<T> {
fn iter_mut(&mut self) -> Box<dyn Iterator<Item = (Pane, &mut T)> + '_> { fn iter_mut(&mut self) -> Box<dyn Iterator<Item = (Pane, &mut T)> + '_> {
match self { match self {
Contents::All(contents) => Box::new( Contents::All(contents, _) => Box::new(
contents.iter_mut().map(|(pane, content)| (*pane, content)), contents.iter_mut().map(|(pane, content)| (*pane, content)),
), ),
Contents::Maximized(pane, content) => { Contents::Maximized(pane, content, _) => {
Box::new(std::iter::once((*pane, content))) Box::new(std::iter::once((*pane, content)))
} }
} }

View file

@ -293,17 +293,6 @@ impl Internal {
} }
} }
/// The scoped internal state of the [`PaneGrid`]
///
/// [`PaneGrid`]: crate::widget::PaneGrid
#[derive(Debug)]
pub enum Scoped<'a> {
/// The state when all panes are visible
All(&'a Internal),
/// The state when a pane is maximized
Maximized(Node),
}
/// The current action of a [`PaneGrid`]. /// The current action of a [`PaneGrid`].
/// ///
/// [`PaneGrid`]: crate::widget::PaneGrid /// [`PaneGrid`]: crate::widget::PaneGrid
@ -351,12 +340,9 @@ impl Action {
} }
} }
impl<'a> Scoped<'a> { impl Internal {
/// The layout [`Node`] of the [`Scoped`] state /// The layout [`Node`] of the [`Internal`] state
pub fn layout(&self) -> &Node { pub fn layout(&self) -> &Node {
match self { &self.layout
Scoped::All(Internal { layout, .. }) => layout,
Scoped::Maximized(layout) => layout,
}
} }
} }