Dismiss pickers with Escape before cancelling outer drafts
This commit is contained in:
+49
@@ -1,6 +1,7 @@
|
||||
//! Build and show dropdown menus.
|
||||
use crate::core::alignment;
|
||||
use crate::core::border::{self, Border};
|
||||
use crate::core::keyboard;
|
||||
use crate::core::layout::{self, Layout};
|
||||
use crate::core::mouse;
|
||||
use crate::core::overlay;
|
||||
@@ -15,6 +16,7 @@ use crate::core::{
|
||||
};
|
||||
use crate::core::{Element, Shell, Widget};
|
||||
use crate::scrollable::{self, Scrollable};
|
||||
use std::cell::Cell;
|
||||
|
||||
/// A list of selectable options.
|
||||
pub struct Menu<
|
||||
@@ -34,6 +36,7 @@ pub struct Menu<
|
||||
hovered_option: &'a mut Option<usize>,
|
||||
on_selected: Box<dyn FnMut(T) -> Message + 'a>,
|
||||
on_option_hovered: Option<&'a dyn Fn(T) -> Message>,
|
||||
escape: Option<(&'a Cell<bool>, Option<Message>)>,
|
||||
width: f32,
|
||||
padding: Padding,
|
||||
text_size: Option<Pixels>,
|
||||
@@ -68,6 +71,7 @@ where
|
||||
hovered_option,
|
||||
on_selected: Box::new(on_selected),
|
||||
on_option_hovered,
|
||||
escape: None,
|
||||
width: 0.0,
|
||||
padding: Padding::ZERO,
|
||||
text_size: None,
|
||||
@@ -78,6 +82,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// PickList owns this flag. Other Menu consumers retain their existing
|
||||
// keyboard behavior unless they explicitly opt into this private bridge.
|
||||
pub(crate) fn close_on_escape(
|
||||
mut self,
|
||||
open: &'a Cell<bool>,
|
||||
on_close: Option<Message>,
|
||||
) -> Self {
|
||||
self.escape = Some((open, on_close));
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the width of the [`Menu`].
|
||||
pub fn width(mut self, width: f32) -> Self {
|
||||
self.width = width;
|
||||
@@ -170,6 +185,7 @@ where
|
||||
viewport: Rectangle,
|
||||
tree: &'a mut Tree,
|
||||
list: Scrollable<'a, Message, Theme, Renderer>,
|
||||
escape: Option<(&'a Cell<bool>, Option<Message>)>,
|
||||
width: f32,
|
||||
target_height: f32,
|
||||
class: &'a <Theme as Catalog>::Class<'b>,
|
||||
@@ -198,6 +214,7 @@ where
|
||||
hovered_option,
|
||||
on_selected,
|
||||
on_option_hovered,
|
||||
escape,
|
||||
width,
|
||||
padding,
|
||||
font,
|
||||
@@ -228,6 +245,7 @@ where
|
||||
viewport,
|
||||
tree: &mut state.tree,
|
||||
list,
|
||||
escape,
|
||||
width,
|
||||
target_height,
|
||||
class,
|
||||
@@ -278,6 +296,31 @@ where
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
) {
|
||||
// UserInterface may retain this overlay for the rest of an event batch.
|
||||
// A dismissed owner must not select an option on a queued later click.
|
||||
if self.escape.as_ref().is_some_and(|(open, _)| !open.get()) {
|
||||
return;
|
||||
}
|
||||
// Consume dismissal in the overlay so Iced never sends the same key
|
||||
// into focused controls or canvases beneath this picker. The shared
|
||||
// owner flag also prevents duplicate close notifications in one batch.
|
||||
if matches!(
|
||||
event,
|
||||
Event::Keyboard(keyboard::Event::KeyPressed {
|
||||
key: keyboard::Key::Named(keyboard::key::Named::Escape),
|
||||
..
|
||||
})
|
||||
) && let Some((open, on_close)) = &mut self.escape
|
||||
&& open.replace(false)
|
||||
{
|
||||
if let Some(message) = on_close.take() {
|
||||
shell.publish(message);
|
||||
}
|
||||
shell.capture_event();
|
||||
shell.request_redraw();
|
||||
return;
|
||||
}
|
||||
|
||||
let bounds = layout.bounds();
|
||||
|
||||
self.list.update(
|
||||
@@ -292,6 +335,9 @@ where
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &Renderer,
|
||||
) -> mouse::Interaction {
|
||||
if self.escape.as_ref().is_some_and(|(open, _)| !open.get()) {
|
||||
return mouse::Interaction::None;
|
||||
}
|
||||
self.list.mouse_interaction(
|
||||
self.tree,
|
||||
layout,
|
||||
@@ -309,6 +355,9 @@ where
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
) {
|
||||
if self.escape.as_ref().is_some_and(|(open, _)| !open.get()) {
|
||||
return;
|
||||
}
|
||||
let bounds = layout.bounds();
|
||||
|
||||
let style = Catalog::style(theme, self.class);
|
||||
|
||||
Reference in New Issue
Block a user