diff options
| author | 2020-03-14 05:26:59 +0100 | |
|---|---|---|
| committer | 2020-03-14 05:27:27 +0100 | |
| commit | 5c8ec4504b6541cdc588b91a6b2c7100b4a7cc77 (patch) | |
| tree | 7d780613c258c02078813f5c7d8163d07acd1341 /native/src | |
| parent | 460565056e6787d5cc7cb0d1d49c9e8ff1f77850 (diff) | |
| download | iced-5c8ec4504b6541cdc588b91a6b2c7100b4a7cc77.tar.gz iced-5c8ec4504b6541cdc588b91a6b2c7100b4a7cc77.tar.bz2 iced-5c8ec4504b6541cdc588b91a6b2c7100b4a7cc77.zip  | |
Create module boundaries for `pane_grid` logic
Diffstat (limited to '')
| -rw-r--r-- | native/src/widget/pane_grid.rs | 442 | ||||
| -rw-r--r-- | native/src/widget/pane_grid/direction.rs | 7 | ||||
| -rw-r--r-- | native/src/widget/pane_grid/node.rs | 128 | ||||
| -rw-r--r-- | native/src/widget/pane_grid/pane.rs | 2 | ||||
| -rw-r--r-- | native/src/widget/pane_grid/split.rs | 54 | ||||
| -rw-r--r-- | native/src/widget/pane_grid/state.rs | 227 | 
6 files changed, 448 insertions, 412 deletions
diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index 32dc4236..2272d32c 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -1,14 +1,24 @@ +mod direction; +mod node; +mod pane; +mod split; +mod state; + +pub use direction::Direction; +pub use pane::Pane; +pub use split::Split; +pub use state::{Focus, State}; +  use crate::{      input::{keyboard, mouse, ButtonState}, -    layout, Clipboard, Element, Event, Hasher, Layout, Length, Point, -    Rectangle, Size, Widget, +    layout, Clipboard, Element, Event, Hasher, Layout, Length, Point, Size, +    Widget,  }; -use std::collections::HashMap; -  #[allow(missing_debug_implementations)]  pub struct PaneGrid<'a, Message, Renderer> { -    state: &'a mut Internal, +    state: &'a mut state::Internal, +    modifiers: &'a mut keyboard::ModifiersState,      elements: Vec<(Pane, Element<'a, Message, Renderer>)>,      width: Length,      height: Length, @@ -26,14 +36,14 @@ impl<'a, Message, Renderer> PaneGrid<'a, Message, Renderer> {          ) -> Element<'a, Message, Renderer>,      ) -> Self {          let elements = { -            let focused_pane = state.internal.focused_pane; +            let focused_pane = state.internal.focused();              state                  .panes                  .iter_mut()                  .map(move |(pane, pane_state)| {                      let focus = match focused_pane { -                        FocusedPane::Some { +                        state::FocusedPane::Some {                              pane: focused_pane,                              focus,                          } if *pane == focused_pane => Some(focus), @@ -47,6 +57,7 @@ impl<'a, Message, Renderer> PaneGrid<'a, Message, Renderer> {          Self {              state: &mut state.internal, +            modifiers: &mut state.modifiers,              elements,              width: Length::Fill,              height: Length::Fill, @@ -117,7 +128,7 @@ where          let limits = limits.width(self.width).height(self.height);          let size = limits.resolve(Size::ZERO); -        let regions = self.state.layout.regions(f32::from(self.spacing), size); +        let regions = self.state.regions(f32::from(self.spacing), size);          let children = self              .elements @@ -162,37 +173,24 @@ where                      if let Some(((pane, _), _)) = clicked_region.next() {                          match &self.on_drag { -                            Some(on_drag) if self.state.modifiers.alt => { -                                self.state.focused_pane = FocusedPane::Some { -                                    pane: *pane, -                                    focus: Focus::Dragging, -                                }; +                            Some(on_drag) if self.modifiers.alt => { +                                self.state.drag(pane);                                  messages.push(on_drag(DragEvent::Picked {                                      pane: *pane,                                  }));                              }                              _ => { -                                self.state.focused_pane = FocusedPane::Some { -                                    pane: *pane, -                                    focus: Focus::Idle, -                                }; +                                self.state.focus(pane);                              }                          }                      } else { -                        self.state.focused_pane = FocusedPane::None; +                        self.state.unfocus();                      }                  }                  ButtonState::Released => { -                    if let FocusedPane::Some { -                        pane, -                        focus: Focus::Dragging, -                    } = self.state.focused_pane -                    { -                        self.state.focused_pane = FocusedPane::Some { -                            pane, -                            focus: Focus::Idle, -                        }; +                    if let Some(pane) = self.state.dragged() { +                        self.state.focus(&pane);                          if let Some(on_drag) = &self.on_drag {                              let mut dropped_region = self @@ -219,17 +217,13 @@ where                  }              },              Event::Keyboard(keyboard::Event::Input { modifiers, .. }) => { -                self.state.modifiers = modifiers; +                *self.modifiers = modifiers;              }              _ => {}          } -        match self.state.focused_pane { -            FocusedPane::Some { -                focus: Focus::Dragging, -                .. -            } => {} -            _ => { +        if self.state.dragged().is_none() { +            {                  self.elements.iter_mut().zip(layout.children()).for_each(                      |((_, pane), layout)| {                          pane.widget.on_event( @@ -253,18 +247,10 @@ where          layout: Layout<'_>,          cursor_position: Point,      ) -> Renderer::Output { -        let dragging = match self.state.focused_pane { -            FocusedPane::Some { -                pane, -                focus: Focus::Dragging, -            } => Some(pane), -            _ => None, -        }; -          renderer.draw(              defaults,              &self.elements, -            dragging, +            self.state.dragged(),              layout,              cursor_position,          ) @@ -276,7 +262,7 @@ where          std::any::TypeId::of::<PaneGrid<'_, Message, Renderer>>().hash(state);          self.width.hash(state);          self.height.hash(state); -        self.state.layout.hash(state); +        self.state.hash_layout(state);          for (_, element) in &self.elements {              element.hash_layout(state); @@ -284,374 +270,6 @@ where      }  } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Pane(usize); - -impl Pane { -    pub fn index(&self) -> usize { -        self.0 -    } -} - -#[derive(Debug)] -pub struct State<T> { -    panes: HashMap<Pane, T>, -    internal: Internal, -} - -#[derive(Debug)] -struct Internal { -    layout: Node, -    last_pane: usize, -    focused_pane: FocusedPane, -    modifiers: keyboard::ModifiersState, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Focus { -    Idle, -    Dragging, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum FocusedPane { -    None, -    Some { pane: Pane, focus: Focus }, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Direction { -    Up, -    Down, -    Left, -    Right, -} - -impl<T> State<T> { -    pub fn new(first_pane_state: T) -> (Self, Pane) { -        let first_pane = Pane(0); - -        let mut panes = HashMap::new(); -        let _ = panes.insert(first_pane, first_pane_state); - -        ( -            State { -                panes, -                internal: Internal { -                    layout: Node::Pane(first_pane), -                    last_pane: 0, -                    focused_pane: FocusedPane::None, -                    modifiers: keyboard::ModifiersState::default(), -                }, -            }, -            first_pane, -        ) -    } - -    pub fn len(&self) -> usize { -        self.panes.len() -    } - -    pub fn get_mut(&mut self, pane: &Pane) -> Option<&mut T> { -        self.panes.get_mut(pane) -    } - -    pub fn iter(&self) -> impl Iterator<Item = (&Pane, &T)> { -        self.panes.iter() -    } - -    pub fn iter_mut(&mut self) -> impl Iterator<Item = (&Pane, &mut T)> { -        self.panes.iter_mut() -    } - -    pub fn focused_pane(&self) -> Option<Pane> { -        match self.internal.focused_pane { -            FocusedPane::Some { -                pane, -                focus: Focus::Idle, -            } => Some(pane), -            FocusedPane::Some { -                focus: Focus::Dragging, -                .. -            } => None, -            FocusedPane::None => None, -        } -    } - -    pub fn adjacent_pane( -        &self, -        pane: &Pane, -        direction: Direction, -    ) -> Option<Pane> { -        let regions = -            self.internal.layout.regions(0.0, Size::new(4096.0, 4096.0)); - -        let current_region = regions.get(pane)?; - -        let target = match direction { -            Direction::Left => { -                Point::new(current_region.x - 1.0, current_region.y + 1.0) -            } -            Direction::Right => Point::new( -                current_region.x + current_region.width + 1.0, -                current_region.y + 1.0, -            ), -            Direction::Up => { -                Point::new(current_region.x + 1.0, current_region.y - 1.0) -            } -            Direction::Down => Point::new( -                current_region.x + 1.0, -                current_region.y + current_region.height + 1.0, -            ), -        }; - -        let mut colliding_regions = -            regions.iter().filter(|(_, region)| region.contains(target)); - -        let (pane, _) = colliding_regions.next()?; - -        Some(*pane) -    } - -    pub fn focus(&mut self, pane: &Pane) { -        self.internal.focused_pane = FocusedPane::Some { -            pane: *pane, -            focus: Focus::Idle, -        }; -    } - -    pub fn split_vertically(&mut self, pane: &Pane, state: T) -> Option<Pane> { -        self.split(Split::Vertical, pane, state) -    } - -    pub fn split_horizontally( -        &mut self, -        pane: &Pane, -        state: T, -    ) -> Option<Pane> { -        self.split(Split::Horizontal, pane, state) -    } - -    pub fn split( -        &mut self, -        kind: Split, -        pane: &Pane, -        state: T, -    ) -> Option<Pane> { -        let node = self.internal.layout.find(pane)?; - -        let new_pane = { -            self.internal.last_pane = self.internal.last_pane.checked_add(1)?; - -            Pane(self.internal.last_pane) -        }; - -        node.split(kind, new_pane); - -        let _ = self.panes.insert(new_pane, state); -        self.focus(&new_pane); - -        Some(new_pane) -    } - -    pub fn swap(&mut self, a: &Pane, b: &Pane) { -        self.internal.layout.update(&|node| match node { -            Node::Split { .. } => {} -            Node::Pane(pane) => { -                if pane == a { -                    *node = Node::Pane(*b); -                } else if pane == b { -                    *node = Node::Pane(*a); -                } -            } -        }); -    } - -    pub fn close(&mut self, pane: &Pane) -> Option<T> { -        if let Some(sibling) = self.internal.layout.remove(pane) { -            self.focus(&sibling); -            self.panes.remove(pane) -        } else { -            None -        } -    } -} - -#[derive(Debug, Clone, Hash)] -enum Node { -    Split { -        kind: Split, -        ratio: u32, -        a: Box<Node>, -        b: Box<Node>, -    }, -    Pane(Pane), -} - -impl Node { -    fn find(&mut self, pane: &Pane) -> Option<&mut Node> { -        match self { -            Node::Split { a, b, .. } => { -                a.find(pane).or_else(move || b.find(pane)) -            } -            Node::Pane(p) => { -                if p == pane { -                    Some(self) -                } else { -                    None -                } -            } -        } -    } - -    fn split(&mut self, kind: Split, new_pane: Pane) { -        *self = Node::Split { -            kind, -            ratio: 500_000, -            a: Box::new(self.clone()), -            b: Box::new(Node::Pane(new_pane)), -        }; -    } - -    fn update(&mut self, f: &impl Fn(&mut Node)) { -        match self { -            Node::Split { a, b, .. } => { -                a.update(f); -                b.update(f); -            } -            _ => {} -        } - -        f(self); -    } - -    fn remove(&mut self, pane: &Pane) -> Option<Pane> { -        match self { -            Node::Split { a, b, .. } => { -                if a.pane() == Some(*pane) { -                    *self = *b.clone(); -                    Some(self.first_pane()) -                } else if b.pane() == Some(*pane) { -                    *self = *a.clone(); -                    Some(self.first_pane()) -                } else { -                    a.remove(pane).or_else(|| b.remove(pane)) -                } -            } -            Node::Pane(_) => None, -        } -    } - -    pub fn regions( -        &self, -        spacing: f32, -        size: Size, -    ) -> HashMap<Pane, Rectangle> { -        let mut regions = HashMap::new(); - -        self.compute_regions( -            spacing / 2.0, -            &Rectangle { -                x: 0.0, -                y: 0.0, -                width: size.width, -                height: size.height, -            }, -            &mut regions, -        ); - -        regions -    } - -    fn pane(&self) -> Option<Pane> { -        match self { -            Node::Split { .. } => None, -            Node::Pane(pane) => Some(*pane), -        } -    } - -    fn first_pane(&self) -> Pane { -        match self { -            Node::Split { a, .. } => a.first_pane(), -            Node::Pane(pane) => *pane, -        } -    } - -    fn compute_regions( -        &self, -        halved_spacing: f32, -        current: &Rectangle, -        regions: &mut HashMap<Pane, Rectangle>, -    ) { -        match self { -            Node::Split { kind, ratio, a, b } => { -                let ratio = *ratio as f32 / 1_000_000.0; -                let (region_a, region_b) = -                    kind.apply(current, ratio, halved_spacing); - -                a.compute_regions(halved_spacing, ®ion_a, regions); -                b.compute_regions(halved_spacing, ®ion_b, regions); -            } -            Node::Pane(pane) => { -                let _ = regions.insert(*pane, *current); -            } -        } -    } -} - -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] -pub enum Split { -    Horizontal, -    Vertical, -} - -impl Split { -    fn apply( -        &self, -        rectangle: &Rectangle, -        ratio: f32, -        halved_spacing: f32, -    ) -> (Rectangle, Rectangle) { -        match self { -            Split::Horizontal => { -                let width_left = -                    (rectangle.width * ratio).round() - halved_spacing; -                let width_right = rectangle.width - width_left - halved_spacing; - -                ( -                    Rectangle { -                        width: width_left, -                        ..*rectangle -                    }, -                    Rectangle { -                        x: rectangle.x + width_left + halved_spacing, -                        width: width_right, -                        ..*rectangle -                    }, -                ) -            } -            Split::Vertical => { -                let height_top = -                    (rectangle.height * ratio).round() - halved_spacing; -                let height_bottom = -                    rectangle.height - height_top - halved_spacing; - -                ( -                    Rectangle { -                        height: height_top, -                        ..*rectangle -                    }, -                    Rectangle { -                        y: rectangle.y + height_top + halved_spacing, -                        height: height_bottom, -                        ..*rectangle -                    }, -                ) -            } -        } -    } -} -  /// The renderer of a [`PaneGrid`].  ///  /// Your [renderer] will need to implement this trait before being diff --git a/native/src/widget/pane_grid/direction.rs b/native/src/widget/pane_grid/direction.rs new file mode 100644 index 00000000..0ee90557 --- /dev/null +++ b/native/src/widget/pane_grid/direction.rs @@ -0,0 +1,7 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Direction { +    Up, +    Down, +    Left, +    Right, +} diff --git a/native/src/widget/pane_grid/node.rs b/native/src/widget/pane_grid/node.rs new file mode 100644 index 00000000..a9aa7fdc --- /dev/null +++ b/native/src/widget/pane_grid/node.rs @@ -0,0 +1,128 @@ +use crate::{ +    pane_grid::{Pane, Split}, +    Rectangle, Size, +}; + +use std::collections::HashMap; + +#[derive(Debug, Clone, Hash)] +pub enum Node { +    Split { +        kind: Split, +        ratio: u32, +        a: Box<Node>, +        b: Box<Node>, +    }, +    Pane(Pane), +} + +impl Node { +    pub fn find(&mut self, pane: &Pane) -> Option<&mut Node> { +        match self { +            Node::Split { a, b, .. } => { +                a.find(pane).or_else(move || b.find(pane)) +            } +            Node::Pane(p) => { +                if p == pane { +                    Some(self) +                } else { +                    None +                } +            } +        } +    } + +    pub fn split(&mut self, kind: Split, new_pane: Pane) { +        *self = Node::Split { +            kind, +            ratio: 500_000, +            a: Box::new(self.clone()), +            b: Box::new(Node::Pane(new_pane)), +        }; +    } + +    pub fn update(&mut self, f: &impl Fn(&mut Node)) { +        match self { +            Node::Split { a, b, .. } => { +                a.update(f); +                b.update(f); +            } +            _ => {} +        } + +        f(self); +    } + +    pub fn remove(&mut self, pane: &Pane) -> Option<Pane> { +        match self { +            Node::Split { a, b, .. } => { +                if a.pane() == Some(*pane) { +                    *self = *b.clone(); +                    Some(self.first_pane()) +                } else if b.pane() == Some(*pane) { +                    *self = *a.clone(); +                    Some(self.first_pane()) +                } else { +                    a.remove(pane).or_else(|| b.remove(pane)) +                } +            } +            Node::Pane(_) => None, +        } +    } + +    pub fn regions( +        &self, +        spacing: f32, +        size: Size, +    ) -> HashMap<Pane, Rectangle> { +        let mut regions = HashMap::new(); + +        self.compute_regions( +            spacing / 2.0, +            &Rectangle { +                x: 0.0, +                y: 0.0, +                width: size.width, +                height: size.height, +            }, +            &mut regions, +        ); + +        regions +    } + +    pub fn pane(&self) -> Option<Pane> { +        match self { +            Node::Split { .. } => None, +            Node::Pane(pane) => Some(*pane), +        } +    } + +    pub fn first_pane(&self) -> Pane { +        match self { +            Node::Split { a, .. } => a.first_pane(), +            Node::Pane(pane) => *pane, +        } +    } + +    fn compute_regions( +        &self, +        halved_spacing: f32, +        current: &Rectangle, +        regions: &mut HashMap<Pane, Rectangle>, +    ) { +        match self { +            Node::Split { kind, ratio, a, b } => { +                let ratio = *ratio as f32 / 1_000_000.0; +                let (region_a, region_b) = +                    kind.apply(current, ratio, halved_spacing); + +                a.compute_regions(halved_spacing, ®ion_a, regions); +                b.compute_regions(halved_spacing, ®ion_b, regions); +            } +            Node::Pane(pane) => { +                let _ = regions.insert(*pane, *current); +            } +        } +    } +} diff --git a/native/src/widget/pane_grid/pane.rs b/native/src/widget/pane_grid/pane.rs new file mode 100644 index 00000000..cfca3b03 --- /dev/null +++ b/native/src/widget/pane_grid/pane.rs @@ -0,0 +1,2 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Pane(pub(super) usize); diff --git a/native/src/widget/pane_grid/split.rs b/native/src/widget/pane_grid/split.rs new file mode 100644 index 00000000..ca9ed5e1 --- /dev/null +++ b/native/src/widget/pane_grid/split.rs @@ -0,0 +1,54 @@ +use crate::Rectangle; + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub enum Split { +    Horizontal, +    Vertical, +} + +impl Split { +    pub(super) fn apply( +        &self, +        rectangle: &Rectangle, +        ratio: f32, +        halved_spacing: f32, +    ) -> (Rectangle, Rectangle) { +        match self { +            Split::Horizontal => { +                let width_left = +                    (rectangle.width * ratio).round() - halved_spacing; +                let width_right = rectangle.width - width_left - halved_spacing; + +                ( +                    Rectangle { +                        width: width_left, +                        ..*rectangle +                    }, +                    Rectangle { +                        x: rectangle.x + width_left + halved_spacing, +                        width: width_right, +                        ..*rectangle +                    }, +                ) +            } +            Split::Vertical => { +                let height_top = +                    (rectangle.height * ratio).round() - halved_spacing; +                let height_bottom = +                    rectangle.height - height_top - halved_spacing; + +                ( +                    Rectangle { +                        height: height_top, +                        ..*rectangle +                    }, +                    Rectangle { +                        y: rectangle.y + height_top + halved_spacing, +                        height: height_bottom, +                        ..*rectangle +                    }, +                ) +            } +        } +    } +} diff --git a/native/src/widget/pane_grid/state.rs b/native/src/widget/pane_grid/state.rs new file mode 100644 index 00000000..130c7e34 --- /dev/null +++ b/native/src/widget/pane_grid/state.rs @@ -0,0 +1,227 @@ +use crate::{ +    input::keyboard, +    pane_grid::{node::Node, Direction, Pane, Split}, +    Hasher, Point, Rectangle, Size, +}; + +use std::collections::HashMap; + +#[derive(Debug)] +pub struct State<T> { +    pub(super) panes: HashMap<Pane, T>, +    pub(super) internal: Internal, +    pub(super) modifiers: keyboard::ModifiersState, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Focus { +    Idle, +    Dragging, +} + +impl<T> State<T> { +    pub fn new(first_pane_state: T) -> (Self, Pane) { +        let first_pane = Pane(0); + +        let mut panes = HashMap::new(); +        let _ = panes.insert(first_pane, first_pane_state); + +        ( +            State { +                panes, +                internal: Internal { +                    layout: Node::Pane(first_pane), +                    last_pane: 0, +                    focused_pane: FocusedPane::None, +                }, +                modifiers: keyboard::ModifiersState::default(), +            }, +            first_pane, +        ) +    } + +    pub fn len(&self) -> usize { +        self.panes.len() +    } + +    pub fn get_mut(&mut self, pane: &Pane) -> Option<&mut T> { +        self.panes.get_mut(pane) +    } + +    pub fn iter(&self) -> impl Iterator<Item = (&Pane, &T)> { +        self.panes.iter() +    } + +    pub fn iter_mut(&mut self) -> impl Iterator<Item = (&Pane, &mut T)> { +        self.panes.iter_mut() +    } + +    pub fn focused_pane(&self) -> Option<Pane> { +        match self.internal.focused_pane { +            FocusedPane::Some { +                pane, +                focus: Focus::Idle, +            } => Some(pane), +            FocusedPane::Some { +                focus: Focus::Dragging, +                .. +            } => None, +            FocusedPane::None => None, +        } +    } + +    pub fn adjacent_pane( +        &self, +        pane: &Pane, +        direction: Direction, +    ) -> Option<Pane> { +        let regions = +            self.internal.layout.regions(0.0, Size::new(4096.0, 4096.0)); + +        let current_region = regions.get(pane)?; + +        let target = match direction { +            Direction::Left => { +                Point::new(current_region.x - 1.0, current_region.y + 1.0) +            } +            Direction::Right => Point::new( +                current_region.x + current_region.width + 1.0, +                current_region.y + 1.0, +            ), +            Direction::Up => { +                Point::new(current_region.x + 1.0, current_region.y - 1.0) +            } +            Direction::Down => Point::new( +                current_region.x + 1.0, +                current_region.y + current_region.height + 1.0, +            ), +        }; + +        let mut colliding_regions = +            regions.iter().filter(|(_, region)| region.contains(target)); + +        let (pane, _) = colliding_regions.next()?; + +        Some(*pane) +    } + +    pub fn focus(&mut self, pane: &Pane) { +        self.internal.focus(pane); +    } + +    pub fn split_vertically(&mut self, pane: &Pane, state: T) -> Option<Pane> { +        self.split(Split::Vertical, pane, state) +    } + +    pub fn split_horizontally( +        &mut self, +        pane: &Pane, +        state: T, +    ) -> Option<Pane> { +        self.split(Split::Horizontal, pane, state) +    } + +    pub fn split( +        &mut self, +        kind: Split, +        pane: &Pane, +        state: T, +    ) -> Option<Pane> { +        let node = self.internal.layout.find(pane)?; + +        let new_pane = { +            self.internal.last_pane = self.internal.last_pane.checked_add(1)?; + +            Pane(self.internal.last_pane) +        }; + +        node.split(kind, new_pane); + +        let _ = self.panes.insert(new_pane, state); +        self.focus(&new_pane); + +        Some(new_pane) +    } + +    pub fn swap(&mut self, a: &Pane, b: &Pane) { +        self.internal.layout.update(&|node| match node { +            Node::Split { .. } => {} +            Node::Pane(pane) => { +                if pane == a { +                    *node = Node::Pane(*b); +                } else if pane == b { +                    *node = Node::Pane(*a); +                } +            } +        }); +    } + +    pub fn close(&mut self, pane: &Pane) -> Option<T> { +        if let Some(sibling) = self.internal.layout.remove(pane) { +            self.focus(&sibling); +            self.panes.remove(pane) +        } else { +            None +        } +    } +} + +#[derive(Debug)] +pub struct Internal { +    layout: Node, +    last_pane: usize, +    focused_pane: FocusedPane, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum FocusedPane { +    None, +    Some { pane: Pane, focus: Focus }, +} + +impl Internal { +    pub fn focused(&self) -> FocusedPane { +        self.focused_pane +    } +    pub fn dragged(&self) -> Option<Pane> { +        match self.focused_pane { +            FocusedPane::Some { +                pane, +                focus: Focus::Dragging, +            } => Some(pane), +            _ => None, +        } +    } + +    pub fn regions( +        &self, +        spacing: f32, +        size: Size, +    ) -> HashMap<Pane, Rectangle> { +        self.layout.regions(spacing, size) +    } + +    pub fn focus(&mut self, pane: &Pane) { +        self.focused_pane = FocusedPane::Some { +            pane: *pane, +            focus: Focus::Idle, +        }; +    } + +    pub fn drag(&mut self, pane: &Pane) { +        self.focused_pane = FocusedPane::Some { +            pane: *pane, +            focus: Focus::Dragging, +        }; +    } + +    pub fn unfocus(&mut self) { +        self.focused_pane = FocusedPane::None; +    } + +    pub fn hash_layout(&self, hasher: &mut Hasher) { +        use std::hash::Hash; + +        self.layout.hash(hasher); +    } +}  | 
