diff --git a/examples/cosmic/src/window.rs b/examples/cosmic/src/window.rs index 18e90aae..5769b870 100644 --- a/examples/cosmic/src/window.rs +++ b/examples/cosmic/src/window.rs @@ -2,13 +2,10 @@ // SPDX-License-Identifier: MPL-2.0 use cosmic::{ iced::widget::{self, button, column, container, horizontal_space, row, text}, - iced::{ - self, - event::{self, Event}, - keyboard, Application, Command, Length, Subscription, - }, + iced::{self, Application, Command, Length, Subscription}, iced_native::{subscription, window}, iced_winit::window::{close, drag, minimize, toggle_maximize}, + keyboard_nav, theme::{self, Theme}, widget::{ header_bar, icon, list, nav_bar, nav_bar_toggle, scrollable, segmented_button, settings, @@ -172,11 +169,11 @@ pub enum Message { Desktop(desktop::Message), Drag, InputChanged, + KeyboardNav(keyboard_nav::Message), Maximize, Minimize, NavBar(segmented_button::Key), Page(Page), - TabNav(bool), ToggleNavBar, ToggleNavBarCondensed, } @@ -348,21 +345,9 @@ impl Application for Window { _ => None, }); - let tab_navagation = subscription::events_with(|event, status| match (event, status) { - ( - Event::Keyboard(keyboard::Event::KeyPressed { - key_code: keyboard::KeyCode::Tab, - modifiers, - .. - }), - event::Status::Ignored, - ) => Some(modifiers.shift()), - _ => None, - }); - Subscription::batch(vec![ window_break.map(|_| Message::CondensedViewToggle), - tab_navagation.map(Message::TabNav), + keyboard_nav::subscription().map(Message::KeyboardNav), ]) } @@ -400,13 +385,11 @@ impl Application for Window { Message::InputChanged => {} Message::CondensedViewToggle => {} - Message::TabNav(shift) => { - if shift { - ret = widget::focus_previous(); - } else { - ret = widget::focus_next(); - } - } + Message::KeyboardNav(message) => match message { + keyboard_nav::Message::Unfocus => ret = keyboard_nav::unfocus(), + keyboard_nav::Message::FocusNext => ret = widget::focus_next(), + keyboard_nav::Message::FocusPrevious => ret = widget::focus_previous(), + }, } ret } diff --git a/src/keyboard_nav.rs b/src/keyboard_nav.rs new file mode 100644 index 00000000..3b4fd729 --- /dev/null +++ b/src/keyboard_nav.rs @@ -0,0 +1,58 @@ +use iced::{event, keyboard, mouse, subscription, Command, Event, Subscription}; +use iced_native::widget::{operation, Id, Operation}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Message { + FocusNext, + FocusPrevious, + Unfocus, +} + +#[must_use] +pub fn subscription() -> Subscription { + subscription::events_with(|event, status| match (event, status) { + ( + Event::Keyboard(keyboard::Event::KeyPressed { + key_code: keyboard::KeyCode::Tab, + modifiers, + .. + }), + event::Status::Ignored, + ) => Some(if modifiers.shift() { + Message::FocusPrevious + } else { + Message::FocusNext + }), + (Event::Mouse(mouse::Event::ButtonReleased { .. }), _) => Some(Message::Unfocus), + _ => None, + }) +} + +/// Unfocuses any actively-focused widget. +#[must_use] +pub fn unfocus() -> Command { + Command::::widget(unfocus_operation()) +} + +#[must_use] +fn unfocus_operation() -> impl Operation { + struct Unfocus {} + + impl Operation for Unfocus { + fn focusable(&mut self, state: &mut dyn operation::Focusable, _id: Option<&Id>) { + if state.is_focused() { + state.unfocus(); + } + } + + fn container( + &mut self, + _id: Option<&Id>, + operate_on_children: &mut dyn FnMut(&mut dyn Operation), + ) { + operate_on_children(self); + } + } + + Unfocus {} +} diff --git a/src/lib.rs b/src/lib.rs index 35242e79..97b337f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ pub use iced_winit; #[cfg(feature = "applet")] pub mod applet; pub mod font; +pub mod keyboard_nav; pub mod theme; pub mod widget;