diff --git a/examples/pane_grid/Cargo.toml b/examples/pane_grid/Cargo.toml index 3d1631f1..e489f210 100644 --- a/examples/pane_grid/Cargo.toml +++ b/examples/pane_grid/Cargo.toml @@ -7,3 +7,4 @@ publish = false [dependencies] iced = { path = "../..", features = ["debug"] } +iced_native = { path = "../../native" } diff --git a/examples/pane_grid/src/main.rs b/examples/pane_grid/src/main.rs index 36485e9a..d149f9c6 100644 --- a/examples/pane_grid/src/main.rs +++ b/examples/pane_grid/src/main.rs @@ -1,8 +1,9 @@ use iced::{ - button, keyboard, pane_grid, scrollable, Align, Button, Column, Container, - Element, HorizontalAlignment, Length, PaneGrid, Sandbox, Scrollable, - Settings, Text, + button, executor, keyboard, pane_grid, scrollable, Align, Application, + Button, Column, Command, Container, Element, HorizontalAlignment, Length, + PaneGrid, Scrollable, Settings, Subscription, Text, }; +use iced_native::{subscription, Event}; pub fn main() -> iced::Result { Example::run(Settings::default()) @@ -26,24 +27,29 @@ enum Message { CloseFocused, } -impl Sandbox for Example { +impl Application for Example { type Message = Message; + type Executor = executor::Default; + type Flags = (); - fn new() -> Self { + fn new(_flags: ()) -> (Self, Command) { let (panes, _) = pane_grid::State::new(Content::new(0)); - Example { - panes, - panes_created: 1, - focus: None, - } + ( + Example { + panes, + panes_created: 1, + focus: None, + }, + Command::none(), + ) } fn title(&self) -> String { String::from("Pane grid - Iced") } - fn update(&mut self, message: Message) { + fn update(&mut self, message: Message) -> Command { match message { Message::Split(axis, pane) => { let result = self.panes.split( @@ -96,14 +102,30 @@ impl Sandbox for Example { } Message::Dragged(_) => {} Message::Close(pane) => { - let _ = self.panes.close(&pane); + if let Some((_, sibling)) = self.panes.close(&pane) { + self.focus = Some(sibling); + } } Message::CloseFocused => { if let Some(pane) = self.focus { - let _ = self.panes.close(&pane); + if let Some((_, sibling)) = self.panes.close(&pane) { + self.focus = Some(sibling); + } } } } + + Command::none() + } + + fn subscription(&self) -> Subscription { + subscription::events_with(|event| match event { + Event::Keyboard(keyboard::Event::KeyPressed { + modifiers, + key_code, + }) if modifiers.control => handle_hotkey(key_code), + _ => None, + }) } fn view(&mut self) -> Element { @@ -137,11 +159,11 @@ impl Sandbox for Example { } } -fn handle_hotkey(event: pane_grid::KeyPressEvent) -> Option { +fn handle_hotkey(key_code: keyboard::KeyCode) -> Option { use keyboard::KeyCode; use pane_grid::{Axis, Direction}; - let direction = match event.key_code { + let direction = match key_code { KeyCode::Up => Some(Direction::Up), KeyCode::Down => Some(Direction::Down), KeyCode::Left => Some(Direction::Left), @@ -149,7 +171,7 @@ fn handle_hotkey(event: pane_grid::KeyPressEvent) -> Option { _ => None, }; - match event.key_code { + match key_code { KeyCode::V => Some(Message::SplitFocused(Axis::Vertical)), KeyCode::H => Some(Message::SplitFocused(Axis::Horizontal)), KeyCode::W => Some(Message::CloseFocused), diff --git a/glow/src/widget/pane_grid.rs b/glow/src/widget/pane_grid.rs index 3c47b562..9e6d27d0 100644 --- a/glow/src/widget/pane_grid.rs +++ b/glow/src/widget/pane_grid.rs @@ -11,8 +11,8 @@ use crate::Renderer; pub use iced_native::pane_grid::{ - Axis, Configuration, Direction, DragEvent, Focus, KeyPressEvent, Node, - Pane, ResizeEvent, Split, State, + Axis, Configuration, Direction, DragEvent, Focus, Node, Pane, ResizeEvent, + Split, State, }; /// A collection of panes distributed using either vertical or horizontal splits diff --git a/graphics/src/widget/pane_grid.rs b/graphics/src/widget/pane_grid.rs index 5b0eb391..1bc01c03 100644 --- a/graphics/src/widget/pane_grid.rs +++ b/graphics/src/widget/pane_grid.rs @@ -20,8 +20,8 @@ use iced_native::{ }; pub use iced_native::pane_grid::{ - Axis, Configuration, Content, Direction, DragEvent, Focus, KeyPressEvent, - Pane, ResizeEvent, Split, State, TitleBar, + Axis, Configuration, Content, Direction, DragEvent, Focus, Pane, + ResizeEvent, Split, State, TitleBar, }; /// A collection of panes distributed using either vertical or horizontal splits diff --git a/native/src/subscription.rs b/native/src/subscription.rs index 0d002c6c..18750abf 100644 --- a/native/src/subscription.rs +++ b/native/src/subscription.rs @@ -43,5 +43,25 @@ use events::Events; /// [`Subscription`]: type.Subscription.html /// [`Event`]: ../enum.Event.html pub fn events() -> Subscription { - Subscription::from_recipe(Events) + Subscription::from_recipe(Events { f: Some }) +} + +/// Returns a [`Subscription`] that filters all the runtime events with the +/// provided function, producing messages accordingly. +/// +/// This subscription will call the provided function for every [`Event`] +/// handled by the runtime. If the function: +/// +/// - Returns `None`, the [`Event`] will be discarded. +/// - Returns `Some` message, the `Message` will be produced. +/// +/// [`Subscription`]: type.Subscription.html +/// [`Event`]: ../enum.Event.html +pub fn events_with( + f: fn(Event) -> Option, +) -> Subscription +where + Message: 'static + Send, +{ + Subscription::from_recipe(Events { f }) } diff --git a/native/src/subscription/events.rs b/native/src/subscription/events.rs index ceae467d..a1ae6051 100644 --- a/native/src/subscription/events.rs +++ b/native/src/subscription/events.rs @@ -2,17 +2,26 @@ use crate::{ subscription::{EventStream, Recipe}, Event, Hasher, }; +use iced_futures::futures::future; +use iced_futures::futures::StreamExt; use iced_futures::BoxStream; -pub struct Events; +pub struct Events { + pub(super) f: fn(Event) -> Option, +} -impl Recipe for Events { - type Output = Event; +impl Recipe for Events +where + Message: 'static + Send, +{ + type Output = Message; fn hash(&self, state: &mut Hasher) { use std::hash::Hash; - std::any::TypeId::of::().hash(state); + struct Marker; + std::any::TypeId::of::().hash(state); + self.f.hash(state); } fn stream( @@ -20,5 +29,7 @@ impl Recipe for Events { event_stream: EventStream, ) -> BoxStream { event_stream + .filter_map(move |event| future::ready((self.f)(event))) + .boxed() } } diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index 584b2ba4..7d9659e9 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -29,8 +29,8 @@ pub use state::{Focus, State}; pub use title_bar::TitleBar; use crate::{ - container, keyboard, layout, mouse, overlay, row, text, Clipboard, Element, - Event, Hasher, Layout, Length, Point, Rectangle, Size, Vector, Widget, + container, layout, mouse, overlay, row, text, Clipboard, Element, Event, + Hasher, Layout, Length, Point, Rectangle, Size, Vector, Widget, }; /// A collection of panes distributed using either vertical or horizontal splits @@ -336,18 +336,6 @@ pub struct ResizeEvent { pub ratio: f32, } -/// An event produced during a key press interaction of a [`PaneGrid`]. -/// -/// [`PaneGrid`]: struct.PaneGrid.html -#[derive(Debug, Clone, Copy)] -pub struct KeyPressEvent { - /// The key that was pressed. - pub key_code: keyboard::KeyCode, - - /// The state of the modifier keys when the key was pressed. - pub modifiers: keyboard::ModifiersState, -} - impl<'a, Message, Renderer> Widget for PaneGrid<'a, Message, Renderer> where diff --git a/native/src/widget/pane_grid/state.rs b/native/src/widget/pane_grid/state.rs index e2793641..be36b070 100644 --- a/native/src/widget/pane_grid/state.rs +++ b/native/src/widget/pane_grid/state.rs @@ -227,12 +227,13 @@ impl State { let _ = self.internal.layout.resize(split, ratio); } - /// Closes the given [`Pane`] and returns its internal state, if it exists. + /// Closes the given [`Pane`] and returns its internal state and its closest + /// sibling, if it exists. /// /// [`Pane`]: struct.Pane.html - pub fn close(&mut self, pane: &Pane) -> Option { - if let Some(_) = self.internal.layout.remove(pane) { - self.panes.remove(pane) + pub fn close(&mut self, pane: &Pane) -> Option<(T, Pane)> { + if let Some(sibling) = self.internal.layout.remove(pane) { + self.panes.remove(pane).map(|state| (state, sibling)) } else { None } diff --git a/wgpu/src/widget/pane_grid.rs b/wgpu/src/widget/pane_grid.rs index 3c47b562..9e6d27d0 100644 --- a/wgpu/src/widget/pane_grid.rs +++ b/wgpu/src/widget/pane_grid.rs @@ -11,8 +11,8 @@ use crate::Renderer; pub use iced_native::pane_grid::{ - Axis, Configuration, Direction, DragEvent, Focus, KeyPressEvent, Node, - Pane, ResizeEvent, Split, State, + Axis, Configuration, Direction, DragEvent, Focus, Node, Pane, ResizeEvent, + Split, State, }; /// A collection of panes distributed using either vertical or horizontal splits