Add state::Scoped & rename Elements as Contents

This commit is contained in:
tarkah 2022-11-02 19:25:27 -07:00
parent 923878c7b7
commit 988515d57f
2 changed files with 100 additions and 94 deletions

View file

@ -100,8 +100,8 @@ where
Renderer: crate::Renderer, Renderer: crate::Renderer,
Renderer::Theme: StyleSheet + container::StyleSheet, Renderer::Theme: StyleSheet + container::StyleSheet,
{ {
state: &'a state::Internal, state: state::Scoped<'a>,
elements: Elements<Content<'a, Message, Renderer>>, contents: Contents<Content<'a, Message, Renderer>>,
width: Length, width: Length,
height: Length, height: Length,
spacing: u16, spacing: u16,
@ -124,30 +124,32 @@ 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 elements = if let Some((pane, pane_state)) = let (contents, state) = 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))
}) { }) {
Elements::Maximized( (
pane, Contents::Maximized(pane, view(pane, pane_state, true)),
view(pane, pane_state, true), state::Scoped::Maximized(Node::Pane(pane)),
Node::Pane(pane),
) )
} else { } else {
Elements::Normal( (
state Contents::All(
.panes state
.iter() .panes
.map(|(pane, pane_state)| { .iter()
(*pane, view(*pane, pane_state, false)) .map(|(pane, pane_state)| {
}) (*pane, view(*pane, pane_state, false))
.collect(), })
.collect(),
),
state::Scoped::All(&state.internal),
) )
}; };
Self { Self {
elements, contents,
state: &state.internal, state,
width: Length::Fill, width: Length::Fill,
height: Length::Fill, height: Length::Fill,
spacing: 0, spacing: 0,
@ -223,7 +225,7 @@ where
} }
fn drag_enabled(&self) -> bool { fn drag_enabled(&self) -> bool {
(!self.elements.is_maximized()) (!self.contents.is_maximized())
.then(|| self.on_drag.is_some()) .then(|| self.on_drag.is_some())
.unwrap_or_default() .unwrap_or_default()
} }
@ -244,20 +246,20 @@ where
} }
fn children(&self) -> Vec<Tree> { fn children(&self) -> Vec<Tree> {
self.elements self.contents
.iter() .iter()
.map(|(_, content)| content.state()) .map(|(_, content)| content.state())
.collect() .collect()
} }
fn diff(&self, tree: &mut Tree) { fn diff(&self, tree: &mut Tree) {
match &self.elements { match &self.contents {
Elements::Normal(elements) => tree.diff_children_custom( Contents::All(contents) => tree.diff_children_custom(
elements, contents,
|state, (_, content)| content.diff(state), |state, (_, content)| content.diff(state),
|(_, content)| content.state(), |(_, content)| content.state(),
), ),
Elements::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(),
@ -281,12 +283,12 @@ where
layout( layout(
renderer, renderer,
limits, limits,
self.elements.node(self.state), &self.state,
self.width, self.width,
self.height, self.height,
self.spacing, self.spacing,
self.elements.iter(), self.contents.iter(),
|element, renderer, limits| element.layout(renderer, limits), |content, renderer, limits| content.layout(renderer, limits),
) )
} }
@ -310,13 +312,13 @@ where
let event_status = update( let event_status = update(
action, action,
self.elements.node(self.state), &self.state,
&event, &event,
layout, layout,
cursor_position, cursor_position,
shell, shell,
self.spacing, self.spacing,
self.elements.iter(), self.contents.iter(),
&self.on_click, &self.on_click,
on_drag, on_drag,
&self.on_resize, &self.on_resize,
@ -324,7 +326,7 @@ where
let picked_pane = action.picked_pane().map(|(pane, _)| pane); let picked_pane = action.picked_pane().map(|(pane, _)| pane);
self.elements self.contents
.iter_mut() .iter_mut()
.zip(&mut tree.children) .zip(&mut tree.children)
.zip(layout.children()) .zip(layout.children())
@ -355,14 +357,14 @@ where
) -> mouse::Interaction { ) -> mouse::Interaction {
mouse_interaction( mouse_interaction(
tree.state.downcast_ref(), tree.state.downcast_ref(),
self.elements.node(self.state), &self.state,
layout, layout,
cursor_position, cursor_position,
self.spacing, self.spacing,
self.on_resize.as_ref().map(|(leeway, _)| *leeway), self.on_resize.as_ref().map(|(leeway, _)| *leeway),
) )
.unwrap_or_else(|| { .unwrap_or_else(|| {
self.elements self.contents
.iter() .iter()
.zip(&tree.children) .zip(&tree.children)
.zip(layout.children()) .zip(layout.children())
@ -393,7 +395,7 @@ where
) { ) {
draw( draw(
tree.state.downcast_ref(), tree.state.downcast_ref(),
self.elements.node(self.state), &self.state,
layout, layout,
cursor_position, cursor_position,
renderer, renderer,
@ -403,7 +405,7 @@ where
self.spacing, self.spacing,
self.on_resize.as_ref().map(|(leeway, _)| *leeway), self.on_resize.as_ref().map(|(leeway, _)| *leeway),
self.style, self.style,
self.elements self.contents
.iter() .iter()
.zip(&tree.children) .zip(&tree.children)
.map(|((pane, content), tree)| (pane, (content, tree))), .map(|((pane, content), tree)| (pane, (content, tree))),
@ -432,7 +434,7 @@ where
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
) -> Option<overlay::Element<'_, Message, Renderer>> { ) -> Option<overlay::Element<'_, Message, Renderer>> {
self.elements self.contents
.iter() .iter()
.zip(&mut tree.children) .zip(&mut tree.children)
.zip(layout.children()) .zip(layout.children())
@ -458,27 +460,27 @@ where
} }
/// Calculates the [`Layout`] of a [`PaneGrid`]. /// Calculates the [`Layout`] of a [`PaneGrid`].
pub fn layout<Renderer, T>( pub fn layout<'a, Renderer, T>(
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
node: &Node, state: &state::Scoped<'a>,
width: Length, width: Length,
height: Length, height: Length,
spacing: u16, spacing: u16,
elements: impl Iterator<Item = (Pane, T)>, contents: impl Iterator<Item = (Pane, T)>,
layout_element: impl Fn(T, &Renderer, &layout::Limits) -> layout::Node, layout_content: impl Fn(T, &Renderer, &layout::Limits) -> layout::Node,
) -> layout::Node { ) -> layout::Node {
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 = node.pane_regions(f32::from(spacing), size); let regions = state.layout().pane_regions(f32::from(spacing), size);
let children = elements let children = contents
.filter_map(|(pane, element)| { .filter_map(|(pane, content)| {
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);
let mut node = layout_element( let mut node = layout_content(
element, content,
renderer, renderer,
&layout::Limits::new(size, size), &layout::Limits::new(size, size),
); );
@ -496,13 +498,13 @@ pub fn layout<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,
node: &Node, state: &state::Scoped<'a>,
event: &Event, event: &Event,
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
shell: &mut Shell<'_, Message>, shell: &mut Shell<'_, Message>,
spacing: u16, spacing: u16,
elements: impl Iterator<Item = (Pane, T)>, contents: impl Iterator<Item = (Pane, T)>,
on_click: &Option<Box<dyn Fn(Pane) -> Message + 'a>>, on_click: &Option<Box<dyn Fn(Pane) -> Message + 'a>>,
on_drag: &Option<Box<dyn Fn(DragEvent) -> Message + 'a>>, on_drag: &Option<Box<dyn Fn(DragEvent) -> Message + 'a>>,
on_resize: &Option<(u16, Box<dyn Fn(ResizeEvent) -> Message + 'a>)>, on_resize: &Option<(u16, Box<dyn Fn(ResizeEvent) -> Message + 'a>)>,
@ -524,7 +526,7 @@ pub fn update<'a, Message, T: Draggable>(
cursor_position.y - bounds.y, cursor_position.y - bounds.y,
); );
let splits = node.split_regions( let splits = state.layout().split_regions(
f32::from(spacing), f32::from(spacing),
Size::new(bounds.width, bounds.height), Size::new(bounds.width, bounds.height),
); );
@ -546,7 +548,7 @@ pub fn update<'a, Message, T: Draggable>(
layout, layout,
cursor_position, cursor_position,
shell, shell,
elements, contents,
on_click, on_click,
on_drag, on_drag,
); );
@ -558,7 +560,7 @@ pub fn update<'a, Message, T: Draggable>(
layout, layout,
cursor_position, cursor_position,
shell, shell,
elements, contents,
on_click, on_click,
on_drag, on_drag,
); );
@ -571,7 +573,7 @@ pub fn update<'a, Message, T: Draggable>(
| Event::Touch(touch::Event::FingerLost { .. }) => { | Event::Touch(touch::Event::FingerLost { .. }) => {
if let Some((pane, _)) = action.picked_pane() { if let Some((pane, _)) = action.picked_pane() {
if let Some(on_drag) = on_drag { if let Some(on_drag) = on_drag {
let mut dropped_region = elements let mut dropped_region = contents
.zip(layout.children()) .zip(layout.children())
.filter(|(_, layout)| { .filter(|(_, layout)| {
layout.bounds().contains(cursor_position) layout.bounds().contains(cursor_position)
@ -602,7 +604,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 = node.split_regions( let splits = state.layout().split_regions(
f32::from(spacing), f32::from(spacing),
Size::new(bounds.width, bounds.height), Size::new(bounds.width, bounds.height),
); );
@ -641,13 +643,13 @@ fn click_pane<'a, Message, T>(
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
shell: &mut Shell<'_, Message>, shell: &mut Shell<'_, Message>,
elements: impl Iterator<Item = (Pane, T)>, contents: impl Iterator<Item = (Pane, T)>,
on_click: &Option<Box<dyn Fn(Pane) -> Message + 'a>>, on_click: &Option<Box<dyn Fn(Pane) -> Message + 'a>>,
on_drag: &Option<Box<dyn Fn(DragEvent) -> Message + 'a>>, on_drag: &Option<Box<dyn Fn(DragEvent) -> Message + 'a>>,
) where ) where
T: Draggable, T: Draggable,
{ {
let mut clicked_region = elements let mut clicked_region = contents
.zip(layout.children()) .zip(layout.children())
.filter(|(_, layout)| layout.bounds().contains(cursor_position)); .filter(|(_, layout)| layout.bounds().contains(cursor_position));
@ -672,9 +674,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( pub fn mouse_interaction<'a>(
action: &state::Action, action: &state::Action,
node: &Node, state: &state::Scoped<'a>,
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
spacing: u16, spacing: u16,
@ -689,8 +691,9 @@ pub fn mouse_interaction(
resize_leeway.and_then(|leeway| { resize_leeway.and_then(|leeway| {
let bounds = layout.bounds(); let bounds = layout.bounds();
let splits = let splits = state
node.split_regions(f32::from(spacing), bounds.size()); .layout()
.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,
@ -717,9 +720,9 @@ pub fn mouse_interaction(
} }
/// Draws a [`PaneGrid`]. /// Draws a [`PaneGrid`].
pub fn draw<Renderer, T>( pub fn draw<'a, Renderer, T>(
action: &state::Action, action: &state::Action,
node: &Node, state: &state::Scoped<'a>,
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
renderer: &mut Renderer, renderer: &mut Renderer,
@ -729,7 +732,7 @@ pub fn draw<Renderer, T>(
spacing: u16, spacing: u16,
resize_leeway: Option<u16>, resize_leeway: Option<u16>,
style: <Renderer::Theme as StyleSheet>::Style, style: <Renderer::Theme as StyleSheet>::Style,
elements: impl Iterator<Item = (Pane, T)>, contents: impl Iterator<Item = (Pane, T)>,
draw_pane: impl Fn( draw_pane: impl Fn(
T, T,
&mut Renderer, &mut Renderer,
@ -749,7 +752,9 @@ pub fn draw<Renderer, T>(
.and_then(|(split, axis)| { .and_then(|(split, axis)| {
let bounds = layout.bounds(); let bounds = layout.bounds();
let splits = node.split_regions(f32::from(spacing), bounds.size()); let splits = state
.layout()
.split_regions(f32::from(spacing), bounds.size());
let (_axis, region, ratio) = splits.get(&split)?; let (_axis, region, ratio) = splits.get(&split)?;
@ -767,8 +772,9 @@ pub fn draw<Renderer, T>(
cursor_position.y - bounds.y, cursor_position.y - bounds.y,
); );
let splits = let splits = state
node.split_regions(f32::from(spacing), bounds.size()); .layout()
.split_regions(f32::from(spacing), bounds.size());
let (_split, axis, region) = hovered_split( let (_split, axis, region) = hovered_split(
splits.iter(), splits.iter(),
@ -791,7 +797,7 @@ pub fn draw<Renderer, T>(
let mut render_picked_pane = None; let mut render_picked_pane = None;
for ((id, pane), layout) in elements.zip(layout.children()) { for ((id, pane), layout) in contents.zip(layout.children()) {
match picked_pane { match picked_pane {
Some((dragging, origin)) if id == dragging => { Some((dragging, origin)) if id == dragging => {
render_picked_pane = Some((pane, origin, layout)); render_picked_pane = Some((pane, origin, layout));
@ -930,52 +936,40 @@ fn hovered_split<'a>(
.next() .next()
} }
/// TODO /// The visible contents of the [`PaneGrid`]
#[derive(Debug)] #[derive(Debug)]
pub enum Elements<T> { pub enum Contents<T> {
/// TODO /// All panes are visible
Normal(Vec<(Pane, T)>), All(Vec<(Pane, T)>),
/// TODO /// A maximized pane is visible
Maximized(Pane, T, Node), Maximized(Pane, T),
} }
impl<T> Elements<T> { impl<T> Contents<T> {
/// TODO /// 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 {
Elements::Normal(elements) => Box::new( Contents::All(contents) => Box::new(
elements.iter().map(|(pane, content)| (*pane, content)), contents.iter().map(|(pane, content)| (*pane, content)),
), ),
Elements::Maximized(pane, content, _) => { Contents::Maximized(pane, content) => {
Box::new(std::iter::once((*pane, content))) Box::new(std::iter::once((*pane, content)))
} }
} }
} }
/// TODO fn iter_mut(&mut self) -> Box<dyn Iterator<Item = (Pane, &mut T)> + '_> {
pub fn iter_mut(
&mut self,
) -> Box<dyn Iterator<Item = (Pane, &mut T)> + '_> {
match self { match self {
Elements::Normal(elements) => Box::new( Contents::All(contents) => Box::new(
elements.iter_mut().map(|(pane, content)| (*pane, content)), contents.iter_mut().map(|(pane, content)| (*pane, content)),
), ),
Elements::Maximized(pane, content, _) => { Contents::Maximized(pane, content) => {
Box::new(std::iter::once((*pane, content))) Box::new(std::iter::once((*pane, content)))
} }
} }
} }
/// TODO fn is_maximized(&self) -> bool {
pub fn node<'a>(&'a self, state: &'a state::Internal) -> &'a Node {
match self {
Elements::Normal(_) => state.layout(),
Elements::Maximized(_, _, node) => node,
}
}
/// TODO
pub fn is_maximized(&self) -> bool {
matches!(self, Self::Maximized(..)) matches!(self, Self::Maximized(..))
} }
} }

View file

@ -281,6 +281,15 @@ impl Internal {
} }
} }
/// The scoped internal state of the [`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
@ -328,9 +337,12 @@ impl Action {
} }
} }
impl Internal { impl<'a> Scoped<'a> {
/// The layout [`Node`] of the [`Internal`] state /// The layout [`Node`] of the [`Scope`] state
pub fn layout(&self) -> &Node { pub fn layout(&self) -> &Node {
&self.layout match self {
Scoped::All(Internal { layout, .. }) => layout,
Scoped::Maximized(layout) => layout,
}
} }
} }