diff --git a/examples/pane_grid/src/main.rs b/examples/pane_grid/src/main.rs index c4946645..42184114 100644 --- a/examples/pane_grid/src/main.rs +++ b/examples/pane_grid/src/main.rs @@ -11,6 +11,7 @@ pub fn main() -> iced::Result { struct Example { panes: pane_grid::State, panes_created: usize, + focus: Option, } #[derive(Debug, Clone, Copy)] @@ -33,6 +34,7 @@ impl Sandbox for Example { Example { panes, panes_created: 1, + focus: None, } } @@ -52,7 +54,7 @@ impl Sandbox for Example { self.panes_created += 1; } Message::SplitFocused(axis) => { - if let Some(pane) = self.panes.active() { + if let Some(pane) = self.focus { let _ = self.panes.split( axis, &pane, @@ -63,11 +65,11 @@ impl Sandbox for Example { } } Message::FocusAdjacent(direction) => { - if let Some(pane) = self.panes.active() { + if let Some(pane) = self.focus { if let Some(adjacent) = self.panes.adjacent(&pane, direction) { - self.panes.focus(&adjacent); + self.focus = Some(adjacent); } } } @@ -85,7 +87,7 @@ impl Sandbox for Example { let _ = self.panes.close(&pane); } Message::CloseFocused => { - if let Some(pane) = self.panes.active() { + if let Some(pane) = self.focus { let _ = self.panes.close(&pane); } } @@ -93,26 +95,26 @@ impl Sandbox for Example { } fn view(&mut self) -> Element { + let focus = self.focus; let total_panes = self.panes.len(); - let pane_grid = - PaneGrid::new(&mut self.panes, |pane, content, focus| { - let is_focused = focus.is_some(); - let title_bar = - pane_grid::TitleBar::new(format!("Pane {}", content.id)) - .padding(10) - .style(style::TitleBar { is_focused }); + let pane_grid = PaneGrid::new(&mut self.panes, |pane, content| { + let is_focused = focus == Some(pane); - pane_grid::Content::new(content.view(pane, total_panes)) - .title_bar(title_bar) - .style(style::Pane { is_focused }) - }) - .width(Length::Fill) - .height(Length::Fill) - .spacing(10) - .on_drag(Message::Dragged) - .on_resize(10, Message::Resized) - .on_key_press(handle_hotkey); + let title_bar = + pane_grid::TitleBar::new(format!("Pane {}", content.id)) + .padding(10) + .style(style::TitleBar { is_focused }); + + pane_grid::Content::new(content.view(pane, total_panes)) + .title_bar(title_bar) + .style(style::Pane { is_focused }) + }) + .width(Length::Fill) + .height(Length::Fill) + .spacing(10) + .on_drag(Message::Dragged) + .on_resize(10, Message::Resized); Container::new(pane_grid) .width(Length::Fill) diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index 276bfae3..43d57e19 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -73,7 +73,7 @@ use crate::{ /// let (mut state, _) = pane_grid::State::new(PaneState::SomePane); /// /// let pane_grid = -/// PaneGrid::new(&mut state, |pane, state, focus| { +/// PaneGrid::new(&mut state, |pane, state| { /// pane_grid::Content::new(match state { /// PaneState::SomePane => Text::new("This is some pane"), /// PaneState::AnotherKindOfPane => Text::new("This is another kind of pane"), @@ -92,10 +92,8 @@ pub struct PaneGrid<'a, Message, Renderer: self::Renderer> { width: Length, height: Length, spacing: u16, - modifier_keys: keyboard::ModifiersState, on_drag: Option Message + 'a>>, on_resize: Option<(u16, Box Message + 'a>)>, - on_key_press: Option Option + 'a>>, } impl<'a, Message, Renderer> PaneGrid<'a, Message, Renderer> @@ -112,31 +110,13 @@ where /// [`Pane`]: struct.Pane.html pub fn new( state: &'a mut State, - view: impl Fn( - Pane, - &'a mut T, - Option, - ) -> Content<'a, Message, Renderer>, + view: impl Fn(Pane, &'a mut T) -> Content<'a, Message, Renderer>, ) -> Self { let elements = { - let action = state.internal.action(); - let current_focus = action.focus(); - state .panes .iter_mut() - .map(move |(pane, pane_state)| { - let focus = match current_focus { - Some((focused_pane, focus)) - if *pane == focused_pane => - { - Some(focus) - } - _ => None, - }; - - (*pane, view(*pane, pane_state, focus)) - }) + .map(move |(pane, pane_state)| (*pane, view(*pane, pane_state))) .collect() }; @@ -146,13 +126,8 @@ where width: Length::Fill, height: Length::Fill, spacing: 0, - modifier_keys: keyboard::ModifiersState { - control: true, - ..Default::default() - }, on_drag: None, on_resize: None, - on_key_press: None, } } @@ -180,21 +155,6 @@ where self } - /// Sets the modifier keys of the [`PaneGrid`]. - /// - /// The modifier keys will need to be pressed to trigger key events. - /// - /// The default modifier key is `Ctrl`. - /// - /// [`PaneGrid`]: struct.PaneGrid.html - pub fn modifier_keys( - mut self, - modifier_keys: keyboard::ModifiersState, - ) -> Self { - self.modifier_keys = modifier_keys; - self - } - /// Enables the drag and drop interactions of the [`PaneGrid`], which will /// use the provided function to produce messages. /// @@ -225,31 +185,6 @@ where self.on_resize = Some((leeway, Box::new(f))); self } - - /// Captures hotkey interactions with the [`PaneGrid`], using the provided - /// function to produce messages. - /// - /// The function will be called when: - /// - a [`Pane`] is focused - /// - a key is pressed - /// - all the modifier keys are pressed - /// - /// If the function returns `None`, the key press event will be discarded - /// without producing any message. - /// - /// This method is particularly useful to implement hotkey interactions. - /// For instance, you can use it to enable splitting, swapping, or resizing - /// panes by pressing combinations of keys. - /// - /// [`PaneGrid`]: struct.PaneGrid.html - /// [`Pane`]: struct.Pane.html - pub fn on_key_press(mut self, f: F) -> Self - where - F: 'a + Fn(KeyPressEvent) -> Option, - { - self.on_key_press = Some(Box::new(f)); - self - } } impl<'a, Message, Renderer> PaneGrid<'a, Message, Renderer> @@ -280,13 +215,9 @@ where messages .push(on_drag(DragEvent::Picked { pane: *pane })); - } else { - self.state.focus(pane); } } - None => { - self.state.focus(pane); - } + None => {} } } } @@ -495,17 +426,10 @@ where ); } } - } else { - // TODO: Encode cursor availability in the type system - if cursor_position.x > 0.0 && cursor_position.y > 0.0 { - self.state.unfocus(); - } } } mouse::Event::ButtonReleased(mouse::Button::Left) => { if let Some((pane, _)) = self.state.picked_pane() { - self.state.focus(&pane); - if let Some(on_drag) = &self.on_drag { let mut dropped_region = self .elements @@ -527,8 +451,10 @@ where messages.push(on_drag(event)); } + + self.state.idle(); } else if self.state.picked_split().is_some() { - self.state.drop_split(); + self.state.idle(); } } mouse::Event::CursorMoved { .. } => { @@ -536,31 +462,6 @@ where } _ => {} }, - Event::Keyboard(keyboard_event) => { - match keyboard_event { - keyboard::Event::KeyPressed { - modifiers, - key_code, - } => { - if let Some(on_key_press) = &self.on_key_press { - // TODO: Discard when event is captured - if let Some(_) = self.state.active_pane() { - if modifiers.matches(self.modifier_keys) { - if let Some(message) = - on_key_press(KeyPressEvent { - key_code, - modifiers, - }) - { - messages.push(message); - } - } - } - } - } - _ => {} - } - } _ => {} } diff --git a/native/src/widget/pane_grid/state.rs b/native/src/widget/pane_grid/state.rs index fb59c846..e2793641 100644 --- a/native/src/widget/pane_grid/state.rs +++ b/native/src/widget/pane_grid/state.rs @@ -72,7 +72,7 @@ impl State { internal: Internal { layout, last_id, - action: Action::Idle { focus: None }, + action: Action::Idle, }, } } @@ -122,45 +122,10 @@ impl State { &self.internal.layout } - /// Returns the focused [`Pane`] of the [`State`], if there is one. - /// - /// [`Pane`]: struct.Pane.html - /// [`State`]: struct.State.html - pub fn focused(&self) -> Option { - self.internal.focused_pane() - } - - /// Returns the active [`Pane`] of the [`State`], if there is one. - /// - /// A [`Pane`] is active if it is focused and is __not__ being dragged. - /// - /// [`Pane`]: struct.Pane.html - /// [`State`]: struct.State.html - pub fn active(&self) -> Option { - self.internal.active_pane() - } - /// Returns the adjacent [`Pane`] of another [`Pane`] in the given /// direction, if there is one. /// - /// ## Example - /// You can combine this with [`State::active`] to find the pane that is - /// adjacent to the current active one, and then swap them. For instance: - /// - /// ``` - /// # use iced_native::pane_grid; - /// # - /// # let (mut state, _) = pane_grid::State::new(()); - /// # - /// if let Some(active) = state.active() { - /// if let Some(adjacent) = state.adjacent(&active, pane_grid::Direction::Right) { - /// state.swap(&active, &adjacent); - /// } - /// } - /// ``` - /// /// [`Pane`]: struct.Pane.html - /// [`State::active`]: struct.State.html#method.active pub fn adjacent(&self, pane: &Pane, direction: Direction) -> Option { let regions = self .internal @@ -194,20 +159,6 @@ impl State { Some(*pane) } - /// Focuses the given [`Pane`]. - /// - /// [`Pane`]: struct.Pane.html - pub fn focus(&mut self, pane: &Pane) { - self.internal.focus(pane); - } - - /// Unfocuses the current focused [`Pane`]. - /// - /// [`Pane`]: struct.Pane.html - pub fn unfocus(&mut self) { - self.internal.unfocus(); - } - /// Splits the given [`Pane`] into two in the given [`Axis`] and /// initializing the new [`Pane`] with the provided internal state. /// @@ -236,7 +187,6 @@ impl State { node.split(new_split, axis, new_pane); let _ = self.panes.insert(new_pane, state); - self.focus(&new_pane); Some((new_pane, new_split)) } @@ -281,8 +231,7 @@ impl State { /// /// [`Pane`]: struct.Pane.html pub fn close(&mut self, pane: &Pane) -> Option { - if let Some(sibling) = self.internal.layout.remove(pane) { - self.focus(&sibling); + if let Some(_) = self.internal.layout.remove(pane) { self.panes.remove(pane) } else { None @@ -329,52 +278,12 @@ pub struct Internal { #[derive(Debug, Clone, Copy, PartialEq)] pub enum Action { - Idle { - focus: Option, - }, - Dragging { - pane: Pane, - origin: Point, - focus: Option, - }, - Resizing { - split: Split, - axis: Axis, - focus: Option, - }, -} - -impl Action { - pub fn focus(&self) -> Option<(Pane, Focus)> { - match self { - Action::Idle { focus } | Action::Resizing { focus, .. } => { - focus.map(|pane| (pane, Focus::Idle)) - } - Action::Dragging { pane, .. } => Some((*pane, Focus::Dragging)), - } - } + Idle, + Dragging { pane: Pane, origin: Point }, + Resizing { split: Split, axis: Axis }, } impl Internal { - pub fn action(&self) -> Action { - self.action - } - - pub fn focused_pane(&self) -> Option { - match self.action { - Action::Idle { focus } => focus, - Action::Dragging { focus, .. } => focus, - Action::Resizing { focus, .. } => focus, - } - } - - pub fn active_pane(&self) -> Option { - match self.action { - Action::Idle { focus } => focus, - _ => None, - } - } - pub fn picked_pane(&self) -> Option<(Pane, Point)> { match self.action { Action::Dragging { pane, origin, .. } => Some((pane, origin)), @@ -405,17 +314,10 @@ impl Internal { self.layout.split_regions(spacing, size) } - pub fn focus(&mut self, pane: &Pane) { - self.action = Action::Idle { focus: Some(*pane) }; - } - pub fn pick_pane(&mut self, pane: &Pane, origin: Point) { - let focus = self.focused_pane(); - self.action = Action::Dragging { pane: *pane, origin, - focus, }; } @@ -426,26 +328,14 @@ impl Internal { return; } - let focus = self.action.focus().map(|(pane, _)| pane); - self.action = Action::Resizing { split: *split, axis, - focus, }; } - pub fn drop_split(&mut self) { - match self.action { - Action::Resizing { focus, .. } => { - self.action = Action::Idle { focus }; - } - _ => {} - } - } - - pub fn unfocus(&mut self) { - self.action = Action::Idle { focus: None }; + pub fn idle(&mut self) { + self.action = Action::Idle; } pub fn hash_layout(&self, hasher: &mut Hasher) {