refactor: more ergonomic dropdown popups
This commit is contained in:
parent
3ee5c0372d
commit
c916c89b03
6 changed files with 149 additions and 160 deletions
|
|
@ -1,29 +1,19 @@
|
|||
use cosmic::app::{Core, Task};
|
||||
use cosmic::cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity;
|
||||
use cosmic::iced::event::listen_with;
|
||||
|
||||
use cosmic::iced::window::Id;
|
||||
use cosmic::iced::{self, Length, Limits};
|
||||
use cosmic::iced::Length;
|
||||
use cosmic::iced_runtime::core::window;
|
||||
use cosmic::iced_runtime::platform_specific::wayland::popup::SctkPopupSettings;
|
||||
use cosmic::iced_runtime::platform_specific::wayland::subsurface;
|
||||
use cosmic::surface::action::{app_popup, destroy_popup};
|
||||
use cosmic::widget::dropdown::DropdownView;
|
||||
use cosmic::widget::{autosize, dropdown, layer_container, list_column, settings, toggler};
|
||||
use cosmic::{iced_core, Element};
|
||||
use once_cell::sync::Lazy;
|
||||
use cosmic::widget::{dropdown::popup_dropdown, list_column, settings, toggler};
|
||||
use cosmic::Element;
|
||||
|
||||
const ID: &str = "com.system76.CosmicAppletExample";
|
||||
|
||||
static SUBSURFACE_ID: Lazy<cosmic::widget::Id> =
|
||||
Lazy::new(|| cosmic::widget::Id::new("subsurface"));
|
||||
|
||||
pub struct Window {
|
||||
core: Core,
|
||||
popup: Option<Id>,
|
||||
example_row: bool,
|
||||
selected: Option<usize>,
|
||||
subsurface_id: Id,
|
||||
dropdown_id: Id,
|
||||
}
|
||||
|
||||
impl Default for Window {
|
||||
|
|
@ -33,52 +23,18 @@ impl Default for Window {
|
|||
popup: None,
|
||||
example_row: false,
|
||||
selected: None,
|
||||
subsurface_id: Id::unique(),
|
||||
dropdown_id: Id::unique(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Message {
|
||||
PopupClosed(Id),
|
||||
PopupCloseRequested(Id),
|
||||
ToggleExampleRow(bool),
|
||||
Selected(usize),
|
||||
Surface(cosmic::surface::Action),
|
||||
OpenDropdown(SctkPopupSettings, DropdownView<Message>),
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Message {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::PopupClosed(arg0) => f.debug_tuple("PopupClosed").field(arg0).finish(),
|
||||
Self::PopupCloseRequested(arg0) => {
|
||||
f.debug_tuple("PopupCloseRequested").field(arg0).finish()
|
||||
}
|
||||
Self::ToggleExampleRow(arg0) => f.debug_tuple("ToggleExampleRow").field(arg0).finish(),
|
||||
Self::Selected(arg0) => f.debug_tuple("Selected").field(arg0).finish(),
|
||||
Self::Surface(arg0) => f.debug_tuple("Surface").field(arg0).finish(),
|
||||
Self::OpenDropdown(arg0, _) => f.debug_tuple("OpenDropdown").field(arg0).finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl From<Message> for MessageWrapper<Message> {
|
||||
// fn from(value: Message) -> Self {
|
||||
// match value {
|
||||
// Message::Surface(s) => MessageWrapper::Surface(s),
|
||||
// m => MessageWrapper::Message(m),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl From<SurfaceMessage> for Message {
|
||||
// fn from(value: SurfaceMessage) -> Self {
|
||||
// Message::Surface(value)
|
||||
// }
|
||||
// }
|
||||
|
||||
impl cosmic::Application for Window {
|
||||
type Executor = cosmic::SingleThreadExecutor;
|
||||
type Flags = ();
|
||||
|
|
@ -123,25 +79,6 @@ impl cosmic::Application for Window {
|
|||
}
|
||||
Message::Selected(i) => {
|
||||
self.selected = Some(i);
|
||||
return cosmic::task::message(cosmic::Action::Cosmic(
|
||||
cosmic::app::Action::Surface(cosmic::surface::action::destroy_popup(
|
||||
self.dropdown_id,
|
||||
)),
|
||||
));
|
||||
}
|
||||
Message::OpenDropdown(sctk_popup_settings, view) => {
|
||||
self.dropdown_id = sctk_popup_settings.id;
|
||||
return cosmic::task::message(cosmic::Action::Cosmic(
|
||||
cosmic::app::Action::Surface(cosmic::surface::action::app_popup(
|
||||
move |_: &mut Window| sctk_popup_settings.clone(),
|
||||
Some(Box::new(move |_: &Window| view().map(cosmic::Action::App))),
|
||||
)),
|
||||
));
|
||||
}
|
||||
Message::PopupCloseRequested(id) => {
|
||||
return cosmic::task::message(cosmic::Action::Cosmic(
|
||||
cosmic::app::Action::Surface(cosmic::surface::action::destroy_popup(id)),
|
||||
));
|
||||
}
|
||||
};
|
||||
Task::none()
|
||||
|
|
@ -178,15 +115,14 @@ impl cosmic::Application for Window {
|
|||
)
|
||||
.height(Length::Fixed(50.)),
|
||||
))
|
||||
.add(
|
||||
dropdown(
|
||||
&["1", "asdf", "hello", "test"],
|
||||
state.selected,
|
||||
Message::Selected,
|
||||
)
|
||||
.with_popup(state.popup.unwrap_or(Id::NONE), Message::OpenDropdown)
|
||||
.on_close_popup(Message::PopupCloseRequested),
|
||||
);
|
||||
.add(popup_dropdown(
|
||||
&["1", "asdf", "hello", "test"],
|
||||
state.selected,
|
||||
Message::Selected,
|
||||
state.popup.unwrap_or(Id::NONE),
|
||||
Message::Surface,
|
||||
|m| m,
|
||||
));
|
||||
Element::from(state.core.applet.popup_container(content_list))
|
||||
.map(cosmic::Action::App)
|
||||
})),
|
||||
|
|
|
|||
2
iced
2
iced
|
|
@ -1 +1 @@
|
|||
Subproject commit fd229ebf90e0873f0f40a3906f6d92bceae56ba2
|
||||
Subproject commit ea5570fdd756f599637a60c7fed4b8a4f03f049e
|
||||
|
|
@ -43,7 +43,6 @@ pub async fn spawn(mut command: Command) -> Option<u32> {
|
|||
return None;
|
||||
};
|
||||
|
||||
|
||||
match unsafe { libc::fork() } {
|
||||
// Parent process
|
||||
1.. => {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use std::sync::{Arc, Mutex};
|
|||
|
||||
pub use appearance::{Appearance, StyleSheet};
|
||||
|
||||
use crate::surface;
|
||||
use crate::widget::{icon, Container, RcWrapper};
|
||||
use iced_core::event::{self, Event};
|
||||
use iced_core::layout::{self, Layout};
|
||||
|
|
@ -32,6 +33,7 @@ where
|
|||
hovered_option: Arc<Mutex<Option<usize>>>,
|
||||
selected_option: Option<usize>,
|
||||
on_selected: Box<dyn FnMut(usize) -> Message + 'a>,
|
||||
close_on_selected: Option<Message>,
|
||||
on_option_hovered: Option<&'a dyn Fn(usize) -> Message>,
|
||||
width: f32,
|
||||
padding: Padding,
|
||||
|
|
@ -54,6 +56,7 @@ where
|
|||
selected_option: Option<usize>,
|
||||
on_selected: impl FnMut(usize) -> Message + 'a,
|
||||
on_option_hovered: Option<&'a dyn Fn(usize) -> Message>,
|
||||
close_on_selected: Option<Message>,
|
||||
) -> Self {
|
||||
Menu {
|
||||
state,
|
||||
|
|
@ -68,6 +71,7 @@ where
|
|||
text_size: None,
|
||||
text_line_height: text::LineHeight::default(),
|
||||
style: Default::default(),
|
||||
close_on_selected,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -153,7 +157,7 @@ struct Overlay<'a, Message> {
|
|||
position: Point,
|
||||
}
|
||||
|
||||
impl<'a, Message: 'a> Overlay<'a, Message> {
|
||||
impl<'a, Message: Clone + 'a> Overlay<'a, Message> {
|
||||
pub fn new<S: AsRef<str>>(
|
||||
menu: Menu<'a, S, Message>,
|
||||
target_height: f32,
|
||||
|
|
@ -175,6 +179,7 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
|
|||
text_size,
|
||||
text_line_height,
|
||||
style,
|
||||
close_on_selected,
|
||||
} = menu;
|
||||
|
||||
let mut container = Container::new(Scrollable::new(
|
||||
|
|
@ -184,6 +189,7 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
|
|||
hovered_option,
|
||||
selected_option,
|
||||
on_selected,
|
||||
close_on_selected,
|
||||
on_option_hovered,
|
||||
text_size,
|
||||
text_line_height,
|
||||
|
|
@ -297,7 +303,7 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, Message: 'a> iced_core::Overlay<Message, crate::Theme, crate::Renderer>
|
||||
impl<'a, Message: Clone + 'a> iced_core::Overlay<Message, crate::Theme, crate::Renderer>
|
||||
for Overlay<'a, Message>
|
||||
{
|
||||
fn layout(&mut self, renderer: &crate::Renderer, bounds: Size) -> layout::Node {
|
||||
|
|
@ -338,7 +344,7 @@ impl<'a, Message: 'a> iced_core::Overlay<Message, crate::Theme, crate::Renderer>
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, Message: 'a> crate::widget::Widget<Message, crate::Theme, crate::Renderer>
|
||||
impl<'a, Message: Clone + 'a> crate::widget::Widget<Message, crate::Theme, crate::Renderer>
|
||||
for Overlay<'a, Message>
|
||||
{
|
||||
fn size(&self) -> Size<Length> {
|
||||
|
|
@ -411,6 +417,7 @@ where
|
|||
hovered_option: Arc<Mutex<Option<usize>>>,
|
||||
selected_option: Option<usize>,
|
||||
on_selected: Box<dyn FnMut(usize) -> Message + 'a>,
|
||||
close_on_selected: Option<Message>,
|
||||
on_option_hovered: Option<&'a dyn Fn(usize) -> Message>,
|
||||
padding: Padding,
|
||||
text_size: Option<f32>,
|
||||
|
|
@ -420,6 +427,7 @@ where
|
|||
impl<S: AsRef<str>, Message> Widget<Message, crate::Theme, crate::Renderer> for List<'_, S, Message>
|
||||
where
|
||||
[S]: std::borrow::ToOwned,
|
||||
Message: Clone,
|
||||
{
|
||||
fn size(&self) -> Size<Length> {
|
||||
Size::new(Length::Fill, Length::Shrink)
|
||||
|
|
@ -469,6 +477,9 @@ where
|
|||
if cursor.is_over(layout.bounds()) {
|
||||
if let Some(index) = *hovered_guard {
|
||||
shell.publish((self.on_selected)(index));
|
||||
if let Some(close_on_selected) = self.close_on_selected.clone() {
|
||||
shell.publish(close_on_selected);
|
||||
}
|
||||
return event::Status::Captured;
|
||||
}
|
||||
}
|
||||
|
|
@ -510,6 +521,9 @@ where
|
|||
|
||||
if let Some(index) = *hovered_guard {
|
||||
shell.publish((self.on_selected)(index));
|
||||
if let Some(close_on_selected) = self.close_on_selected.clone() {
|
||||
shell.publish(close_on_selected);
|
||||
}
|
||||
return event::Status::Captured;
|
||||
}
|
||||
}
|
||||
|
|
@ -680,6 +694,7 @@ impl<'a, S: AsRef<str>, Message: 'a> From<List<'a, S, Message>>
|
|||
for Element<'a, Message, crate::Theme, crate::Renderer>
|
||||
where
|
||||
[S]: std::borrow::ToOwned,
|
||||
Message: Clone,
|
||||
{
|
||||
fn from(list: List<'a, S, Message>) -> Self {
|
||||
Element::new(list)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
//! Displays a list of options in a popover menu on select.
|
||||
|
||||
pub mod menu;
|
||||
use iced_core::window;
|
||||
pub use menu::Menu;
|
||||
|
||||
pub mod multi;
|
||||
|
|
@ -12,6 +13,8 @@ pub mod multi;
|
|||
mod widget;
|
||||
pub use widget::*;
|
||||
|
||||
use crate::surface;
|
||||
|
||||
/// Displays a list of options in a popover menu on select.
|
||||
pub fn dropdown<
|
||||
S: AsRef<str> + std::clone::Clone + Send + Sync + 'static,
|
||||
|
|
@ -20,6 +23,29 @@ pub fn dropdown<
|
|||
selections: &[S],
|
||||
selected: Option<usize>,
|
||||
on_selected: impl Fn(usize) -> Message + Send + Sync + 'static,
|
||||
) -> Dropdown<'_, S, Message> {
|
||||
) -> Dropdown<'_, S, Message, Message> {
|
||||
Dropdown::new(selections, selected, on_selected)
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "winit", feature = "wayland"))]
|
||||
/// Displays a list of options in a popover menu on select.
|
||||
/// AppMessage must be the App's toplevel message.
|
||||
pub fn popup_dropdown<
|
||||
'a,
|
||||
S: AsRef<str> + std::clone::Clone + Send + Sync + 'static,
|
||||
Message: 'static + Clone,
|
||||
AppMessage: 'static + Clone,
|
||||
>(
|
||||
selections: &'a [S],
|
||||
selected: Option<usize>,
|
||||
on_selected: impl Fn(usize) -> Message + Send + Sync + 'static,
|
||||
parent_id: window::Id,
|
||||
on_surface_action: impl Fn(surface::Action) -> Message + Send + Sync + 'static,
|
||||
map_action: impl Fn(Message) -> AppMessage + Send + Sync + 'static,
|
||||
) -> Dropdown<'a, S, Message, AppMessage> {
|
||||
Dropdown::new(selections, selected, on_selected).with_popup(
|
||||
parent_id,
|
||||
on_surface_action,
|
||||
map_action,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use super::menu::{self, Menu};
|
||||
use crate::widget::icon::{self, Handle};
|
||||
use crate::Element;
|
||||
use crate::{surface, Element};
|
||||
use derive_setters::Setters;
|
||||
use iced::window;
|
||||
use iced_core::event::{self, Event};
|
||||
|
|
@ -18,6 +18,7 @@ use iced_widget::pick_list::{self, Catalog};
|
|||
use std::borrow::Cow;
|
||||
use std::ffi::OsStr;
|
||||
use std::hash::{DefaultHasher, Hash, Hasher};
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, LazyLock, Mutex};
|
||||
|
||||
|
|
@ -26,7 +27,7 @@ static AUTOSIZE_ID: LazyLock<crate::widget::Id> =
|
|||
LazyLock::new(|| crate::widget::Id::new("cosmic-applet-autosize"));
|
||||
/// A widget for selecting a single value from a list of selections.
|
||||
#[derive(Setters)]
|
||||
pub struct Dropdown<'a, S: AsRef<str> + Send + Sync + Clone + 'static, Message>
|
||||
pub struct Dropdown<'a, S: AsRef<str> + Send + Sync + Clone + 'static, Message, AppMessage>
|
||||
where
|
||||
[S]: std::borrow::ToOwned,
|
||||
{
|
||||
|
|
@ -48,26 +49,18 @@ where
|
|||
text_line_height: text::LineHeight,
|
||||
#[setters(strip_option)]
|
||||
font: Option<crate::font::Font>,
|
||||
#[cfg(feature = "wayland")]
|
||||
#[setters(skip)]
|
||||
on_open: Option<
|
||||
Arc<
|
||||
dyn Fn(
|
||||
iced_runtime::platform_specific::wayland::popup::SctkPopupSettings,
|
||||
DropdownView<Message>,
|
||||
) -> Message
|
||||
+ 'a,
|
||||
>,
|
||||
>,
|
||||
on_surface_action: Option<Arc<dyn Fn(surface::Action) -> Message + Send + Sync + 'static>>,
|
||||
#[setters(skip)]
|
||||
on_close_popup: Option<Box<dyn Fn(window::Id) -> Message + 'a>>,
|
||||
action_map: Option<Arc<dyn Fn(Message) -> AppMessage + 'static + Send + Sync>>,
|
||||
#[setters(strip_option)]
|
||||
window_id: Option<window::Id>,
|
||||
#[cfg(feature = "wayland")]
|
||||
#[cfg(all(feature = "winit", feature = "wayland"))]
|
||||
positioner: iced_runtime::platform_specific::wayland::popup::SctkPositioner,
|
||||
}
|
||||
|
||||
impl<'a, S: AsRef<str> + Send + Sync + Clone + 'static, Message: 'static> Dropdown<'a, S, Message>
|
||||
impl<'a, S: AsRef<str> + Send + Sync + Clone + 'static, Message: 'static, AppMessage: 'static>
|
||||
Dropdown<'a, S, Message, AppMessage>
|
||||
where
|
||||
[S]: std::borrow::ToOwned,
|
||||
{
|
||||
|
|
@ -95,33 +88,30 @@ where
|
|||
text_size: None,
|
||||
text_line_height: text::LineHeight::Relative(1.2),
|
||||
font: None,
|
||||
#[cfg(feature = "wayland")]
|
||||
on_open: None,
|
||||
window_id: None,
|
||||
#[cfg(feature = "wayland")]
|
||||
#[cfg(all(feature = "winit", feature = "wayland"))]
|
||||
positioner: iced_runtime::platform_specific::wayland::popup::SctkPositioner::default(),
|
||||
on_close_popup: None,
|
||||
on_surface_action: None,
|
||||
action_map: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
#[cfg(all(feature = "winit", feature = "wayland"))]
|
||||
/// Handle dropdown requests for popup creation.
|
||||
/// Intended to be used with [`crate::app::message::get_popup`]
|
||||
pub fn with_popup(
|
||||
mut self,
|
||||
parent_id: window::Id,
|
||||
on_open: impl Fn(
|
||||
iced_runtime::platform_specific::wayland::popup::SctkPopupSettings,
|
||||
DropdownView<Message>,
|
||||
) -> Message
|
||||
+ 'a,
|
||||
on_surface_action: impl Fn(surface::Action) -> Message + Send + Sync + 'static,
|
||||
action_map: impl Fn(Message) -> AppMessage + Send + Sync + 'static,
|
||||
) -> Self {
|
||||
self.window_id = Some(parent_id);
|
||||
self.on_open = Some(Arc::new(on_open));
|
||||
self.on_surface_action = Some(Arc::new(on_surface_action));
|
||||
self.action_map = Some(Arc::new(action_map));
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
#[cfg(all(feature = "winit", feature = "wayland"))]
|
||||
pub fn with_positioner(
|
||||
mut self,
|
||||
positioner: iced_runtime::platform_specific::wayland::popup::SctkPositioner,
|
||||
|
|
@ -129,18 +119,13 @@ where
|
|||
self.positioner = positioner;
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
/// Handle dropdown requests for popup removal.
|
||||
/// Intended to be used with [`crate::app::message::destroy_popup`]
|
||||
pub fn on_close_popup(mut self, on_close: impl Fn(window::Id) -> Message + 'a) -> Self {
|
||||
self.on_close_popup = Some(Box::new(on_close));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: AsRef<str> + Send + Sync + Clone + 'static, Message: 'static + std::clone::Clone>
|
||||
Widget<Message, crate::Theme, crate::Renderer> for Dropdown<'_, S, Message>
|
||||
impl<
|
||||
S: AsRef<str> + Send + Sync + Clone + 'static,
|
||||
Message: 'static + Clone,
|
||||
AppMessage: 'static + Clone,
|
||||
> Widget<Message, crate::Theme, crate::Renderer> for Dropdown<'_, S, Message, AppMessage>
|
||||
where
|
||||
[S]: std::borrow::ToOwned,
|
||||
{
|
||||
|
|
@ -225,21 +210,20 @@ where
|
|||
shell: &mut Shell<'_, Message>,
|
||||
_viewport: &Rectangle,
|
||||
) -> event::Status {
|
||||
update(
|
||||
update::<S, Message, AppMessage>(
|
||||
&event,
|
||||
layout,
|
||||
cursor,
|
||||
shell,
|
||||
#[cfg(feature = "wayland")]
|
||||
self.on_open.clone(),
|
||||
#[cfg(feature = "wayland")]
|
||||
#[cfg(all(feature = "winit", feature = "wayland"))]
|
||||
self.positioner.clone(),
|
||||
self.on_selected.clone(),
|
||||
self.selected,
|
||||
self.selections,
|
||||
|| tree.state.downcast_mut::<State>(),
|
||||
self.window_id,
|
||||
self.on_close_popup.as_deref(),
|
||||
self.on_surface_action.clone(),
|
||||
self.action_map.clone(),
|
||||
self.icons,
|
||||
self.gap,
|
||||
self.padding,
|
||||
|
|
@ -295,8 +279,8 @@ where
|
|||
renderer: &crate::Renderer,
|
||||
translation: Vector,
|
||||
) -> Option<overlay::Element<'b, Message, crate::Theme, crate::Renderer>> {
|
||||
#[cfg(feature = "wayland")]
|
||||
if self.on_open.is_some() || self.window_id.is_some() || self.on_close_popup.is_some() {
|
||||
#[cfg(all(feature = "winit", feature = "wayland"))]
|
||||
if self.window_id.is_some() || self.on_surface_action.is_some() {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
@ -316,6 +300,7 @@ where
|
|||
self.selected,
|
||||
self.on_selected.as_ref(),
|
||||
translation,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -331,12 +316,16 @@ where
|
|||
// }
|
||||
}
|
||||
|
||||
impl<'a, S: AsRef<str> + Send + Sync + Clone + 'static, Message: 'static + std::clone::Clone>
|
||||
From<Dropdown<'a, S, Message>> for crate::Element<'a, Message>
|
||||
impl<
|
||||
'a,
|
||||
S: AsRef<str> + Send + Sync + Clone + 'static,
|
||||
Message: 'static + std::clone::Clone,
|
||||
AppMessage: 'static + std::clone::Clone,
|
||||
> From<Dropdown<'a, S, Message, AppMessage>> for crate::Element<'a, Message>
|
||||
where
|
||||
[S]: std::borrow::ToOwned,
|
||||
{
|
||||
fn from(pick_list: Dropdown<'a, S, Message>) -> Self {
|
||||
fn from(pick_list: Dropdown<'a, S, Message, AppMessage>) -> Self {
|
||||
Self::new(pick_list)
|
||||
}
|
||||
}
|
||||
|
|
@ -441,33 +430,26 @@ pub fn layout(
|
|||
|
||||
/// Processes an [`Event`] and updates the [`State`] of a [`Dropdown`]
|
||||
/// accordingly.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[allow(clippy::too_many_arguments, clippy::too_many_lines)]
|
||||
pub fn update<
|
||||
'a,
|
||||
S: AsRef<str> + Send + Sync + std::clone::Clone + 'static,
|
||||
S: AsRef<str> + Send + Sync + Clone + 'static,
|
||||
Message: Clone + 'static,
|
||||
AppMessage: Clone + 'static,
|
||||
>(
|
||||
event: &Event,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
#[cfg(feature = "wayland")] on_open: Option<
|
||||
Arc<
|
||||
dyn Fn(
|
||||
iced_runtime::platform_specific::wayland::popup::SctkPopupSettings,
|
||||
DropdownView<Message>,
|
||||
) -> Message
|
||||
+ 'a,
|
||||
>,
|
||||
>,
|
||||
#[cfg(feature = "wayland")]
|
||||
#[cfg(all(feature = "winit", feature = "wayland"))]
|
||||
positioner: iced_runtime::platform_specific::wayland::popup::SctkPositioner,
|
||||
on_selected: Arc<dyn Fn(usize) -> Message + Send + Sync + 'static>,
|
||||
selected: Option<usize>,
|
||||
selections: &[S],
|
||||
state: impl FnOnce() -> &'a mut State,
|
||||
window_id: Option<window::Id>,
|
||||
on_close: Option<&'a dyn Fn(window::Id) -> Message>,
|
||||
_window_id: Option<window::Id>,
|
||||
on_surface_action: Option<Arc<dyn Fn(surface::Action) -> Message + Send + Sync + 'static>>,
|
||||
action_map: Option<Arc<dyn Fn(Message) -> AppMessage + Send + Sync + 'static>>,
|
||||
icons: &[icon::Handle],
|
||||
gap: f32,
|
||||
padding: Padding,
|
||||
|
|
@ -484,8 +466,9 @@ pub fn update<
|
|||
// Event wasn't processed by overlay, so cursor was clicked either outside it's
|
||||
// bounds or on the drop-down, either way we close the overlay.
|
||||
state.is_open.store(false, Ordering::Relaxed);
|
||||
if let Some(on_close) = on_close {
|
||||
shell.publish(on_close(state.popup_id));
|
||||
#[cfg(all(feature = "winit", feature = "wayland"))]
|
||||
if let Some(on_close) = on_surface_action {
|
||||
shell.publish(on_close(surface::action::destroy_popup(state.popup_id)));
|
||||
}
|
||||
event::Status::Captured
|
||||
} else if cursor.is_over(layout.bounds()) {
|
||||
|
|
@ -494,8 +477,10 @@ pub fn update<
|
|||
*hovered_guard = selected;
|
||||
let id = window::Id::unique();
|
||||
state.popup_id = id;
|
||||
#[cfg(feature = "wayland")]
|
||||
if let Some((on_open, parent)) = on_open.zip(window_id) {
|
||||
#[cfg(all(feature = "winit", feature = "wayland"))]
|
||||
if let Some(((on_surface_action, parent), action_map)) =
|
||||
on_surface_action.zip(_window_id).zip(action_map)
|
||||
{
|
||||
use iced_runtime::platform_specific::wayland::popup::{
|
||||
SctkPopupSettings, SctkPositioner,
|
||||
};
|
||||
|
|
@ -521,9 +506,19 @@ pub fn update<
|
|||
let icons: Cow<'static, [Handle]> = Cow::Owned(icons.to_vec());
|
||||
let selections: Cow<'static, [S]> = Cow::Owned(selections.to_vec());
|
||||
let state = state.clone();
|
||||
|
||||
shell.publish(on_open(
|
||||
SctkPopupSettings {
|
||||
let on_close = surface::action::destroy_popup(id);
|
||||
let on_surface_action_clone = on_surface_action.clone();
|
||||
let get_popup_action = surface::action::simple_popup::<
|
||||
AppMessage,
|
||||
Box<
|
||||
dyn Fn() -> Element<'static, crate::Action<AppMessage>>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>,
|
||||
>(
|
||||
move || {
|
||||
SctkPopupSettings {
|
||||
parent,
|
||||
id,
|
||||
input_zone: None,
|
||||
|
|
@ -538,15 +533,29 @@ pub fn update<
|
|||
parent_size: None,
|
||||
grab: true,
|
||||
close_with_children: true,
|
||||
}
|
||||
},
|
||||
Arc::new(move || {
|
||||
Element::from(
|
||||
menu_widget(
|
||||
bounds, &state, gap, padding,text_size.unwrap_or(14.0), selections.clone(), icons.clone(), selected_option, on_selected.clone()
|
||||
)
|
||||
)
|
||||
}),
|
||||
));
|
||||
Some(Box::new(move || {
|
||||
let action_map = action_map.clone();
|
||||
let on_selected = on_selected.clone();
|
||||
let e: Element<'static, crate::Action<AppMessage>> =
|
||||
Element::from(menu_widget(
|
||||
bounds,
|
||||
&state,
|
||||
gap,
|
||||
padding,
|
||||
text_size.unwrap_or(14.0),
|
||||
selections.clone(),
|
||||
icons.clone(),
|
||||
selected_option,
|
||||
Arc::new(move |i| on_selected.clone()(i)),
|
||||
Some(on_surface_action_clone(on_close.clone())),
|
||||
))
|
||||
.map(move |m| crate::Action::App(action_map.clone()(m)));
|
||||
e
|
||||
})),
|
||||
);
|
||||
shell.publish(on_surface_action(get_popup_action));
|
||||
}
|
||||
event::Status::Captured
|
||||
} else {
|
||||
|
|
@ -595,7 +604,7 @@ pub fn mouse_interaction(layout: Layout<'_>, cursor: mouse::Cursor) -> mouse::In
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
#[cfg(all(feature = "winit", feature = "wayland"))]
|
||||
/// Returns the current menu widget of a [`Dropdown`].
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn menu_widget<
|
||||
|
|
@ -611,6 +620,7 @@ pub fn menu_widget<
|
|||
icons: Cow<'static, [icon::Handle]>,
|
||||
selected_option: Option<usize>,
|
||||
on_selected: Arc<dyn Fn(usize) -> Message + Send + Sync + 'static>,
|
||||
close_on_selected: Option<Message>,
|
||||
) -> crate::Element<'static, Message>
|
||||
where
|
||||
[S]: std::borrow::ToOwned,
|
||||
|
|
@ -640,6 +650,7 @@ where
|
|||
(on_selected)(option)
|
||||
},
|
||||
None,
|
||||
close_on_selected,
|
||||
)
|
||||
.width(width)
|
||||
.padding(padding)
|
||||
|
|
@ -672,6 +683,7 @@ pub fn overlay<'a, S: AsRef<str> + Send + Sync + Clone + 'static, Message: std::
|
|||
selected_option: Option<usize>,
|
||||
on_selected: &'a dyn Fn(usize) -> Message,
|
||||
translation: Vector,
|
||||
close_on_selected: Option<Message>,
|
||||
) -> Option<overlay::Element<'a, Message, crate::Theme, crate::Renderer>>
|
||||
where
|
||||
[S]: std::borrow::ToOwned,
|
||||
|
|
@ -691,6 +703,7 @@ where
|
|||
(on_selected)(option)
|
||||
},
|
||||
None,
|
||||
close_on_selected,
|
||||
)
|
||||
.width({
|
||||
let measure = |_label: &str, selection_paragraph: &crate::Paragraph| -> f32 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue