Restore hotkeys in `pane_grid` example

- Implement `subscription::events_with`
- Remove `pane_grid::KeyPressEvent`
- Return closest sibling in `pane_grid::State::close`
This commit is contained in:
Héctor Ramón Jiménez 2020-11-10 02:32:57 +01:00
parent c53022e8df
commit d6d5cf0294
9 changed files with 88 additions and 45 deletions

View File

@ -7,3 +7,4 @@ publish = false
[dependencies] [dependencies]
iced = { path = "../..", features = ["debug"] } iced = { path = "../..", features = ["debug"] }
iced_native = { path = "../../native" }

View File

@ -1,8 +1,9 @@
use iced::{ use iced::{
button, keyboard, pane_grid, scrollable, Align, Button, Column, Container, button, executor, keyboard, pane_grid, scrollable, Align, Application,
Element, HorizontalAlignment, Length, PaneGrid, Sandbox, Scrollable, Button, Column, Command, Container, Element, HorizontalAlignment, Length,
Settings, Text, PaneGrid, Scrollable, Settings, Subscription, Text,
}; };
use iced_native::{subscription, Event};
pub fn main() -> iced::Result { pub fn main() -> iced::Result {
Example::run(Settings::default()) Example::run(Settings::default())
@ -26,24 +27,29 @@ enum Message {
CloseFocused, CloseFocused,
} }
impl Sandbox for Example { impl Application for Example {
type Message = Message; type Message = Message;
type Executor = executor::Default;
type Flags = ();
fn new() -> Self { fn new(_flags: ()) -> (Self, Command<Message>) {
let (panes, _) = pane_grid::State::new(Content::new(0)); let (panes, _) = pane_grid::State::new(Content::new(0));
Example { (
panes, Example {
panes_created: 1, panes,
focus: None, panes_created: 1,
} focus: None,
},
Command::none(),
)
} }
fn title(&self) -> String { fn title(&self) -> String {
String::from("Pane grid - Iced") String::from("Pane grid - Iced")
} }
fn update(&mut self, message: Message) { fn update(&mut self, message: Message) -> Command<Message> {
match message { match message {
Message::Split(axis, pane) => { Message::Split(axis, pane) => {
let result = self.panes.split( let result = self.panes.split(
@ -96,14 +102,30 @@ impl Sandbox for Example {
} }
Message::Dragged(_) => {} Message::Dragged(_) => {}
Message::Close(pane) => { Message::Close(pane) => {
let _ = self.panes.close(&pane); if let Some((_, sibling)) = self.panes.close(&pane) {
self.focus = Some(sibling);
}
} }
Message::CloseFocused => { Message::CloseFocused => {
if let Some(pane) = self.focus { 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<Message> {
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<Message> { fn view(&mut self) -> Element<Message> {
@ -137,11 +159,11 @@ impl Sandbox for Example {
} }
} }
fn handle_hotkey(event: pane_grid::KeyPressEvent) -> Option<Message> { fn handle_hotkey(key_code: keyboard::KeyCode) -> Option<Message> {
use keyboard::KeyCode; use keyboard::KeyCode;
use pane_grid::{Axis, Direction}; use pane_grid::{Axis, Direction};
let direction = match event.key_code { let direction = match key_code {
KeyCode::Up => Some(Direction::Up), KeyCode::Up => Some(Direction::Up),
KeyCode::Down => Some(Direction::Down), KeyCode::Down => Some(Direction::Down),
KeyCode::Left => Some(Direction::Left), KeyCode::Left => Some(Direction::Left),
@ -149,7 +171,7 @@ fn handle_hotkey(event: pane_grid::KeyPressEvent) -> Option<Message> {
_ => None, _ => None,
}; };
match event.key_code { match key_code {
KeyCode::V => Some(Message::SplitFocused(Axis::Vertical)), KeyCode::V => Some(Message::SplitFocused(Axis::Vertical)),
KeyCode::H => Some(Message::SplitFocused(Axis::Horizontal)), KeyCode::H => Some(Message::SplitFocused(Axis::Horizontal)),
KeyCode::W => Some(Message::CloseFocused), KeyCode::W => Some(Message::CloseFocused),

View File

@ -11,8 +11,8 @@
use crate::Renderer; use crate::Renderer;
pub use iced_native::pane_grid::{ pub use iced_native::pane_grid::{
Axis, Configuration, Direction, DragEvent, Focus, KeyPressEvent, Node, Axis, Configuration, Direction, DragEvent, Focus, Node, Pane, ResizeEvent,
Pane, ResizeEvent, Split, State, Split, State,
}; };
/// A collection of panes distributed using either vertical or horizontal splits /// A collection of panes distributed using either vertical or horizontal splits

View File

@ -20,8 +20,8 @@ use iced_native::{
}; };
pub use iced_native::pane_grid::{ pub use iced_native::pane_grid::{
Axis, Configuration, Content, Direction, DragEvent, Focus, KeyPressEvent, Axis, Configuration, Content, Direction, DragEvent, Focus, Pane,
Pane, ResizeEvent, Split, State, TitleBar, ResizeEvent, Split, State, TitleBar,
}; };
/// A collection of panes distributed using either vertical or horizontal splits /// A collection of panes distributed using either vertical or horizontal splits

View File

@ -43,5 +43,25 @@ use events::Events;
/// [`Subscription`]: type.Subscription.html /// [`Subscription`]: type.Subscription.html
/// [`Event`]: ../enum.Event.html /// [`Event`]: ../enum.Event.html
pub fn events() -> Subscription<Event> { pub fn events() -> Subscription<Event> {
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<Message>(
f: fn(Event) -> Option<Message>,
) -> Subscription<Message>
where
Message: 'static + Send,
{
Subscription::from_recipe(Events { f })
} }

View File

@ -2,17 +2,26 @@ use crate::{
subscription::{EventStream, Recipe}, subscription::{EventStream, Recipe},
Event, Hasher, Event, Hasher,
}; };
use iced_futures::futures::future;
use iced_futures::futures::StreamExt;
use iced_futures::BoxStream; use iced_futures::BoxStream;
pub struct Events; pub struct Events<Message> {
pub(super) f: fn(Event) -> Option<Message>,
}
impl Recipe<Hasher, Event> for Events { impl<Message> Recipe<Hasher, Event> for Events<Message>
type Output = Event; where
Message: 'static + Send,
{
type Output = Message;
fn hash(&self, state: &mut Hasher) { fn hash(&self, state: &mut Hasher) {
use std::hash::Hash; use std::hash::Hash;
std::any::TypeId::of::<Self>().hash(state); struct Marker;
std::any::TypeId::of::<Marker>().hash(state);
self.f.hash(state);
} }
fn stream( fn stream(
@ -20,5 +29,7 @@ impl Recipe<Hasher, Event> for Events {
event_stream: EventStream, event_stream: EventStream,
) -> BoxStream<Self::Output> { ) -> BoxStream<Self::Output> {
event_stream event_stream
.filter_map(move |event| future::ready((self.f)(event)))
.boxed()
} }
} }

View File

@ -29,8 +29,8 @@ pub use state::{Focus, State};
pub use title_bar::TitleBar; pub use title_bar::TitleBar;
use crate::{ use crate::{
container, keyboard, layout, mouse, overlay, row, text, Clipboard, Element, container, layout, mouse, overlay, row, text, Clipboard, Element, Event,
Event, Hasher, Layout, Length, Point, Rectangle, Size, Vector, Widget, Hasher, Layout, Length, Point, Rectangle, Size, Vector, Widget,
}; };
/// A collection of panes distributed using either vertical or horizontal splits /// A collection of panes distributed using either vertical or horizontal splits
@ -336,18 +336,6 @@ pub struct ResizeEvent {
pub ratio: f32, 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<Message, Renderer> impl<'a, Message, Renderer> Widget<Message, Renderer>
for PaneGrid<'a, Message, Renderer> for PaneGrid<'a, Message, Renderer>
where where

View File

@ -227,12 +227,13 @@ impl<T> State<T> {
let _ = self.internal.layout.resize(split, ratio); 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 /// [`Pane`]: struct.Pane.html
pub fn close(&mut self, pane: &Pane) -> Option<T> { pub fn close(&mut self, pane: &Pane) -> Option<(T, Pane)> {
if let Some(_) = self.internal.layout.remove(pane) { if let Some(sibling) = self.internal.layout.remove(pane) {
self.panes.remove(pane) self.panes.remove(pane).map(|state| (state, sibling))
} else { } else {
None None
} }

View File

@ -11,8 +11,8 @@
use crate::Renderer; use crate::Renderer;
pub use iced_native::pane_grid::{ pub use iced_native::pane_grid::{
Axis, Configuration, Direction, DragEvent, Focus, KeyPressEvent, Node, Axis, Configuration, Direction, DragEvent, Focus, Node, Pane, ResizeEvent,
Pane, ResizeEvent, Split, State, Split, State,
}; };
/// A collection of panes distributed using either vertical or horizontal splits /// A collection of panes distributed using either vertical or horizontal splits