refactor dnd
This commit is contained in:
parent
de179d06f3
commit
35717797b7
3 changed files with 296 additions and 502 deletions
|
|
@ -669,12 +669,6 @@ impl cosmic::Application for SettingsApp {
|
||||||
|
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
fn view_window(&self, id: window::Id) -> Element<Message> {
|
fn view_window(&self, id: window::Id) -> Element<Message> {
|
||||||
if let Some(Some(page)) =
|
|
||||||
(id == *APPLET_DND_ICON_ID).then(|| self.pages.page::<applets_inner::Page>())
|
|
||||||
{
|
|
||||||
return page.dnd_icon();
|
|
||||||
}
|
|
||||||
|
|
||||||
panic!("unknown window ID: {id:?}");
|
panic!("unknown window ID: {id:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ impl Default for Page {
|
||||||
.collect(),
|
.collect(),
|
||||||
config_helper,
|
config_helper,
|
||||||
current_config,
|
current_config,
|
||||||
reorder_widget_state: ReorderWidgetState::default(),
|
reorder_widget_state: None,
|
||||||
search: String::new(),
|
search: String::new(),
|
||||||
context: None,
|
context: None,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,43 +1,33 @@
|
||||||
use button::Catalog as ButtonStyleSheet;
|
use button::Catalog as ButtonStyleSheet;
|
||||||
|
use cosmic::iced::clipboard::dnd::{
|
||||||
|
DndAction, DndDestinationRectangle, DndEvent, OfferEvent, SourceEvent,
|
||||||
|
};
|
||||||
|
use cosmic::iced::clipboard::mime::AsMimeTypes;
|
||||||
|
use cosmic::iced::id::Internal;
|
||||||
use cosmic::iced::{alignment, Vector};
|
use cosmic::iced::{alignment, Vector};
|
||||||
|
|
||||||
use cosmic::widget::{
|
use cosmic::iced_core;
|
||||||
button, column, container, horizontal_space, icon, list_column, row, text, text_input, Column,
|
use cosmic::widget::{button, column, container, icon, list_column, row, text, text_input, Column};
|
||||||
};
|
|
||||||
|
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
cctk::sctk::reexports::client::protocol::wl_data_device_manager::DndAction,
|
|
||||||
cosmic_config::{Config, CosmicConfigEntry},
|
cosmic_config::{Config, CosmicConfigEntry},
|
||||||
iced::{
|
iced::{
|
||||||
alignment::{Horizontal, Vertical},
|
alignment::{Horizontal, Vertical},
|
||||||
core::window,
|
core::window,
|
||||||
event::{
|
event, mouse, overlay, touch, Alignment, Color, Length, Point, Rectangle, Size,
|
||||||
self,
|
|
||||||
wayland::{self},
|
|
||||||
PlatformSpecific,
|
|
||||||
},
|
|
||||||
mouse, overlay, touch, Alignment, Color, Length, Point, Rectangle, Size,
|
|
||||||
},
|
},
|
||||||
iced_runtime::{core::id::Id, Task},
|
iced_runtime::{core::id::Id, Task},
|
||||||
iced_widget::{
|
iced_widget::core::{
|
||||||
core::{
|
layout, renderer,
|
||||||
layout, renderer,
|
widget::{tree, Operation, Tree},
|
||||||
widget::{tree, Operation, Tree},
|
Clipboard, Shell, Widget,
|
||||||
Clipboard, Shell, Widget,
|
|
||||||
},
|
|
||||||
graphics::image::image_rs::EncodableLayout,
|
|
||||||
},
|
},
|
||||||
theme, Apply, Element,
|
theme, Apply, Element,
|
||||||
};
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use std::{
|
use std::path::PathBuf;
|
||||||
borrow::{Borrow, Cow},
|
use std::{borrow::Cow, fmt::Debug, mem, path::Path};
|
||||||
fmt::Debug,
|
|
||||||
mem,
|
|
||||||
path::Path,
|
|
||||||
str::FromStr,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{app, pages};
|
use crate::{app, pages};
|
||||||
use cosmic_panel_config::CosmicPanelConfig;
|
use cosmic_panel_config::CosmicPanelConfig;
|
||||||
|
|
@ -64,7 +54,7 @@ pub struct Page {
|
||||||
pub(crate) available_entries: Vec<Applet<'static>>,
|
pub(crate) available_entries: Vec<Applet<'static>>,
|
||||||
pub(crate) config_helper: Option<Config>,
|
pub(crate) config_helper: Option<Config>,
|
||||||
pub(crate) current_config: Option<CosmicPanelConfig>,
|
pub(crate) current_config: Option<CosmicPanelConfig>,
|
||||||
pub(crate) reorder_widget_state: ReorderWidgetState,
|
pub(crate) reorder_widget_state: Option<(Applet<'static>, CosmicPanelConfig)>,
|
||||||
pub(crate) search: String,
|
pub(crate) search: String,
|
||||||
pub(crate) context: Option<ContextDrawer>,
|
pub(crate) context: Option<ContextDrawer>,
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +75,7 @@ impl Default for Page {
|
||||||
.collect(),
|
.collect(),
|
||||||
config_helper,
|
config_helper,
|
||||||
current_config,
|
current_config,
|
||||||
reorder_widget_state: ReorderWidgetState::default(),
|
reorder_widget_state: None,
|
||||||
search: String::new(),
|
search: String::new(),
|
||||||
context: None,
|
context: None,
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +154,7 @@ pub enum Message {
|
||||||
ReorderEnd(Vec<Applet<'static>>),
|
ReorderEnd(Vec<Applet<'static>>),
|
||||||
Applets(Vec<Applet<'static>>),
|
Applets(Vec<Applet<'static>>),
|
||||||
PanelConfig(CosmicPanelConfig),
|
PanelConfig(CosmicPanelConfig),
|
||||||
StartDnd(ReorderWidgetState),
|
StartDnd(Applet<'static>),
|
||||||
// DnDTask(Arc<Box<dyn Send + Sync + Fn() -> ActionInner>>),
|
// DnDTask(Arc<Box<dyn Send + Sync + Fn() -> ActionInner>>),
|
||||||
Search(String),
|
Search(String),
|
||||||
AddApplet(Applet<'static>),
|
AddApplet(Applet<'static>),
|
||||||
|
|
@ -217,11 +207,6 @@ impl Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn dnd_icon(&self) -> Element<app::Message> {
|
|
||||||
Element::from(AppletReorderList::dnd_icon(&self.reorder_widget_state))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
pub fn add_applet_view<T: Fn(Message) -> crate::pages::Message + Copy + 'static>(
|
pub fn add_applet_view<T: Fn(Message) -> crate::pages::Message + Copy + 'static>(
|
||||||
|
|
@ -373,15 +358,13 @@ impl Page {
|
||||||
Message::Applets(applets) => {
|
Message::Applets(applets) => {
|
||||||
self.available_entries = applets;
|
self.available_entries = applets;
|
||||||
}
|
}
|
||||||
Message::StartDnd(state) => {
|
Message::StartDnd(applet) => {
|
||||||
self.reorder_widget_state = state;
|
self.reorder_widget_state =
|
||||||
|
Some((applet, self.current_config.clone().unwrap_or_default()));
|
||||||
return Task::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
// Message::DnDTask(action) => {
|
|
||||||
// return data_device_action(action());
|
|
||||||
// }
|
|
||||||
Message::Save => {
|
Message::Save => {
|
||||||
self.reorder_widget_state = ReorderWidgetState::default();
|
self.reorder_widget_state = None;
|
||||||
self.save();
|
self.save();
|
||||||
}
|
}
|
||||||
Message::RemoveStart(to_remove) => {
|
Message::RemoveStart(to_remove) => {
|
||||||
|
|
@ -418,14 +401,9 @@ impl Page {
|
||||||
// TODO ask design team
|
// TODO ask design team
|
||||||
}
|
}
|
||||||
Message::Cancel => {
|
Message::Cancel => {
|
||||||
self.reorder_widget_state = ReorderWidgetState::default();
|
if let Some((_, config)) = self.reorder_widget_state.take() {
|
||||||
let current_config = self.config_helper.as_ref().and_then(|config_helper| {
|
self.current_config = Some(config);
|
||||||
// TODO error handling...
|
}
|
||||||
let panel_config = CosmicPanelConfig::get_entry(config_helper).ok()?;
|
|
||||||
// If the config is not present, it will be created with the default values and the name will not match
|
|
||||||
(panel_config.name == "Panel").then_some(panel_config)
|
|
||||||
});
|
|
||||||
self.current_config = current_config;
|
|
||||||
}
|
}
|
||||||
Message::Search(text) => {
|
Message::Search(text) => {
|
||||||
self.search = text;
|
self.search = text;
|
||||||
|
|
@ -489,7 +467,6 @@ pub fn lists<
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
Some((window::Id::NONE, *APPLET_DND_ICON_ID)),
|
|
||||||
Message::StartDnd,
|
Message::StartDnd,
|
||||||
// |a| Message::DnDTask(Arc::new(a)),
|
// |a| Message::DnDTask(Arc::new(a)),
|
||||||
Message::RemoveStart,
|
Message::RemoveStart,
|
||||||
|
|
@ -497,7 +474,7 @@ pub fn lists<
|
||||||
Message::ReorderStart,
|
Message::ReorderStart,
|
||||||
Message::Save,
|
Message::Save,
|
||||||
Message::Cancel,
|
Message::Cancel,
|
||||||
page.reorder_widget_state.dragged_applet().as_ref(),
|
page.reorder_widget_state.as_ref().map(|(a, _)| a.clone()),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
|
|
@ -520,7 +497,6 @@ pub fn lists<
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
Some((window::Id::NONE, *APPLET_DND_ICON_ID)),
|
|
||||||
Message::StartDnd,
|
Message::StartDnd,
|
||||||
// |a| Message::DnDTask(Arc::new(a)),
|
// |a| Message::DnDTask(Arc::new(a)),
|
||||||
Message::RemoveCenter,
|
Message::RemoveCenter,
|
||||||
|
|
@ -528,7 +504,7 @@ pub fn lists<
|
||||||
Message::ReorderCenter,
|
Message::ReorderCenter,
|
||||||
Message::Save,
|
Message::Save,
|
||||||
Message::Cancel,
|
Message::Cancel,
|
||||||
page.reorder_widget_state.dragged_applet().as_ref(),
|
page.reorder_widget_state.as_ref().map(|(a, _)| a.clone()),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
|
|
@ -552,7 +528,6 @@ pub fn lists<
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
Some((window::Id::NONE, *APPLET_DND_ICON_ID)),
|
|
||||||
Message::StartDnd,
|
Message::StartDnd,
|
||||||
// |a| Message::DnDTask(Arc::new(a)),
|
// |a| Message::DnDTask(Arc::new(a)),
|
||||||
Message::RemoveEnd,
|
Message::RemoveEnd,
|
||||||
|
|
@ -560,7 +535,7 @@ pub fn lists<
|
||||||
Message::ReorderEnd,
|
Message::ReorderEnd,
|
||||||
Message::Save,
|
Message::Save,
|
||||||
Message::Cancel,
|
Message::Cancel,
|
||||||
page.reorder_widget_state.dragged_applet().as_ref(),
|
page.reorder_widget_state.as_ref().map(|(a, _)| a.clone()),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
|
|
@ -639,13 +614,13 @@ impl<'a> Applet<'a> {
|
||||||
pub struct AppletReorderList<'a, Message> {
|
pub struct AppletReorderList<'a, Message> {
|
||||||
id: Id,
|
id: Id,
|
||||||
info: Vec<Applet<'a>>,
|
info: Vec<Applet<'a>>,
|
||||||
on_create_dnd_source: Box<dyn Fn(ReorderWidgetState) -> Message + 'a>,
|
on_create_dnd_source: Box<dyn Fn(Applet<'static>) -> Message + 'a>,
|
||||||
// on_dnd_task_produced: OnDndTask<'a, Message>,
|
// on_dnd_task_produced: OnDndTask<'a, Message>,
|
||||||
on_reorder: Box<dyn Fn(Vec<Applet<'static>>) -> Message + 'a>,
|
on_reorder: Box<dyn Fn(Vec<Applet<'static>>) -> Message + 'a>,
|
||||||
on_finish: Option<Message>,
|
on_finish: Option<Message>,
|
||||||
on_cancel: Option<Message>,
|
on_cancel: Option<Message>,
|
||||||
surface_ids: Option<(window::Id, window::Id)>,
|
|
||||||
inner: Element<'a, Message>,
|
inner: Element<'a, Message>,
|
||||||
|
active_applet_offer: Option<Applet<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message: 'static + Clone> AppletReorderList<'a, Message> {
|
impl<'a, Message: 'static + Clone> AppletReorderList<'a, Message> {
|
||||||
|
|
@ -654,18 +629,13 @@ impl<'a, Message: 'static + Clone> AppletReorderList<'a, Message> {
|
||||||
/// new applet list which can be reordered and dragged
|
/// new applet list which can be reordered and dragged
|
||||||
pub fn new(
|
pub fn new(
|
||||||
info: Vec<Applet<'a>>,
|
info: Vec<Applet<'a>>,
|
||||||
surface_ids: Option<(window::Id, window::Id)>,
|
on_create_dnd_source: impl Fn(Applet<'static>) -> Message + 'a,
|
||||||
on_create_dnd_source: impl Fn(ReorderWidgetState) -> Message + 'a,
|
|
||||||
// on_dnd_task_produced: impl Fn(
|
|
||||||
// Box<dyn Send + Sync + Fn() -> platform_specific::wayland::data_device::ActionInner>,
|
|
||||||
// ) -> Message
|
|
||||||
// + 'a,
|
|
||||||
on_remove: impl Fn(String) -> Message + 'a,
|
on_remove: impl Fn(String) -> Message + 'a,
|
||||||
on_details: impl Fn(String) -> Message + 'a,
|
on_details: impl Fn(String) -> Message + 'a,
|
||||||
on_reorder: impl Fn(Vec<Applet<'static>>) -> Message + 'a,
|
on_reorder: impl Fn(Vec<Applet<'static>>) -> Message + 'a,
|
||||||
on_apply_reorder: Message,
|
on_apply_reorder: Message,
|
||||||
on_cancel: Message,
|
on_cancel: Message,
|
||||||
active_dnd: Option<&Applet<'a>>,
|
active_dnd: Option<Applet<'a>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let spacing = cosmic::theme::active().cosmic().spacing;
|
let spacing = cosmic::theme::active().cosmic().spacing;
|
||||||
let applet_buttons = info
|
let applet_buttons = info
|
||||||
|
|
@ -722,7 +692,6 @@ impl<'a, Message: 'static + Clone> AppletReorderList<'a, Message> {
|
||||||
on_reorder: Box::new(on_reorder),
|
on_reorder: Box::new(on_reorder),
|
||||||
on_finish: Some(on_apply_reorder),
|
on_finish: Some(on_apply_reorder),
|
||||||
on_cancel: Some(on_cancel),
|
on_cancel: Some(on_cancel),
|
||||||
surface_ids,
|
|
||||||
inner: if active_dnd.is_some() && applet_buttons.is_empty() {
|
inner: if active_dnd.is_some() && applet_buttons.is_empty() {
|
||||||
container(
|
container(
|
||||||
text::body(fl!("drop-here"))
|
text::body(fl!("drop-here"))
|
||||||
|
|
@ -748,53 +717,7 @@ impl<'a, Message: 'static + Clone> AppletReorderList<'a, Message> {
|
||||||
.spacing(spacing.space_xxs)
|
.spacing(spacing.space_xxs)
|
||||||
.into()
|
.into()
|
||||||
},
|
},
|
||||||
}
|
active_applet_offer: active_dnd,
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
/// mark this as a dnd icon
|
|
||||||
pub fn dnd_icon(state: &'a ReorderWidgetState) -> Self {
|
|
||||||
Self {
|
|
||||||
id: Id::unique(),
|
|
||||||
info: Vec::new(),
|
|
||||||
on_create_dnd_source: Box::new(|_| unimplemented!()),
|
|
||||||
// on_dnd_task_produced: Box::new(|_| unimplemented!()),
|
|
||||||
on_reorder: Box::new(|_| unimplemented!()),
|
|
||||||
on_finish: None,
|
|
||||||
surface_ids: None,
|
|
||||||
inner: if let Some(info) = state.dragged_applet() {
|
|
||||||
container(
|
|
||||||
row::with_children(vec![
|
|
||||||
icon::from_name("grip-lines-symbolic")
|
|
||||||
.size(16)
|
|
||||||
.symbolic(true)
|
|
||||||
.into(),
|
|
||||||
icon::from_name(info.icon.into_owned()).size(32).into(),
|
|
||||||
column::with_capacity(2)
|
|
||||||
.spacing(4.0)
|
|
||||||
.width(Length::Fill)
|
|
||||||
.push(text::body(info.name))
|
|
||||||
.push(text::caption(info.description))
|
|
||||||
.into(),
|
|
||||||
button::icon(icon::from_name("edit-delete-symbolic"))
|
|
||||||
.extra_small()
|
|
||||||
.into(),
|
|
||||||
])
|
|
||||||
.spacing(12)
|
|
||||||
.align_y(Alignment::Center),
|
|
||||||
)
|
|
||||||
.width(Length::Fixed(state.layout.map_or(400.0, |l| l.width)))
|
|
||||||
.padding(8)
|
|
||||||
.class(theme::Container::Custom(Box::new(move |theme| {
|
|
||||||
let mut style = container::Catalog::style(theme, &theme::Container::Primary);
|
|
||||||
style.border.radius = 8.0.into();
|
|
||||||
style
|
|
||||||
})))
|
|
||||||
.into()
|
|
||||||
} else {
|
|
||||||
horizontal_space().width(1).into()
|
|
||||||
},
|
|
||||||
on_cancel: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -863,6 +786,61 @@ impl<'a, Message: 'static + Clone> AppletReorderList<'a, Message> {
|
||||||
|
|
||||||
reordered
|
reordered
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the drag id of the destination.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// Panics if the destination has been assigned a Set id, which is invalid.
|
||||||
|
#[must_use]
|
||||||
|
pub fn get_drag_id(&self) -> u128 {
|
||||||
|
match &self.id.0 {
|
||||||
|
Internal::Unique(id) | Internal::Custom(id, _) => *id as u128,
|
||||||
|
Internal::Set(_) => panic!("Invalid Id assigned to dnd destination."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
/// mark this as a dnd icon
|
||||||
|
pub fn dnd_icon(info: Applet<'static>, layout: &layout::Layout) -> AppletReorderList<'static, ()> {
|
||||||
|
AppletReorderList::<'static, ()> {
|
||||||
|
id: Id::unique(),
|
||||||
|
info: Vec::new(),
|
||||||
|
on_create_dnd_source: Box::new(|_| unimplemented!()),
|
||||||
|
// on_dnd_task_produced: Box::new(|_| unimplemented!()),
|
||||||
|
on_reorder: Box::new(|_| unimplemented!()),
|
||||||
|
on_finish: None,
|
||||||
|
inner: container(
|
||||||
|
row::with_children(vec![
|
||||||
|
icon::from_name("grip-lines-symbolic")
|
||||||
|
.size(16)
|
||||||
|
.symbolic(true)
|
||||||
|
.into(),
|
||||||
|
icon::from_name(info.icon.into_owned()).size(32).into(),
|
||||||
|
column::with_capacity(2)
|
||||||
|
.spacing(4.0)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.push(text::body(info.name))
|
||||||
|
.push(text::caption(info.description))
|
||||||
|
.into(),
|
||||||
|
button::icon(icon::from_name("edit-delete-symbolic"))
|
||||||
|
.extra_small()
|
||||||
|
.into(),
|
||||||
|
])
|
||||||
|
.spacing(12)
|
||||||
|
.align_y(Alignment::Center),
|
||||||
|
)
|
||||||
|
.width(Length::Fixed(layout.bounds().width))
|
||||||
|
.padding(8)
|
||||||
|
.class(theme::Container::Custom(Box::new(move |theme| {
|
||||||
|
let mut style = container::Catalog::style(theme, &theme::Container::Primary);
|
||||||
|
style.border.radius = 8.0.into();
|
||||||
|
style
|
||||||
|
})))
|
||||||
|
.into(),
|
||||||
|
on_cancel: None,
|
||||||
|
active_applet_offer: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message: 'static> Widget<Message, cosmic::Theme, cosmic::Renderer>
|
impl<'a, Message: 'static> Widget<Message, cosmic::Theme, cosmic::Renderer>
|
||||||
|
|
@ -910,6 +888,10 @@ where
|
||||||
renderer: &cosmic::Renderer,
|
renderer: &cosmic::Renderer,
|
||||||
operation: &mut dyn Operation<()>,
|
operation: &mut dyn Operation<()>,
|
||||||
) {
|
) {
|
||||||
|
let state = tree.state.downcast_mut::<ReorderWidgetState>();
|
||||||
|
|
||||||
|
operation.custom(state, Some(&self.id));
|
||||||
|
|
||||||
self.inner.as_widget().operate(
|
self.inner.as_widget().operate(
|
||||||
&mut tree.children[0],
|
&mut tree.children[0],
|
||||||
layout.children().next().unwrap(),
|
layout.children().next().unwrap(),
|
||||||
|
|
@ -950,286 +932,124 @@ where
|
||||||
/ self.info.len() as f32;
|
/ self.info.len() as f32;
|
||||||
let state = tree.state.downcast_mut::<ReorderWidgetState>();
|
let state = tree.state.downcast_mut::<ReorderWidgetState>();
|
||||||
|
|
||||||
state.dragging_state = match mem::take(&mut state.dragging_state) {
|
state.dragging_state = {
|
||||||
DraggingState::None => {
|
match mem::take(&mut state.dragging_state) {
|
||||||
// if no dragging state, listen for press events
|
DraggingState::Dragging(applet) => match &event {
|
||||||
match &event {
|
event::Event::Dnd(DndEvent::Source(source_event)) => match source_event {
|
||||||
event::Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))
|
SourceEvent::Cancelled => {
|
||||||
| event::Event::Touch(touch::Event::FingerPressed { .. })
|
ret = event::Status::Captured;
|
||||||
if cursor_position.is_over(layout.bounds()) =>
|
if let Some(on_cancel) = self.on_cancel.clone() {
|
||||||
{
|
shell.publish(on_cancel);
|
||||||
ret = event::Status::Captured;
|
}
|
||||||
|
DraggingState::None
|
||||||
|
}
|
||||||
|
SourceEvent::Finished => {
|
||||||
|
ret = event::Status::Captured;
|
||||||
|
|
||||||
DraggingState::Pressed(cursor_position.position().unwrap_or_default())
|
DraggingState::None
|
||||||
|
}
|
||||||
|
_ => DraggingState::Dragging(applet),
|
||||||
|
},
|
||||||
|
_ => DraggingState::Dragging(applet),
|
||||||
|
},
|
||||||
|
DraggingState::None => {
|
||||||
|
// if no dragging state, listen for press events
|
||||||
|
match &event {
|
||||||
|
event::Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))
|
||||||
|
| event::Event::Touch(touch::Event::FingerPressed { .. })
|
||||||
|
if cursor_position.is_over(layout.bounds()) =>
|
||||||
|
{
|
||||||
|
ret = event::Status::Captured;
|
||||||
|
|
||||||
|
DraggingState::Pressed(cursor_position.position().unwrap_or_default())
|
||||||
|
}
|
||||||
|
_ => DraggingState::None,
|
||||||
}
|
}
|
||||||
_ => DraggingState::None,
|
|
||||||
}
|
}
|
||||||
}
|
DraggingState::Pressed(start) => {
|
||||||
DraggingState::Dragging(applet) => match &event {
|
// if dragging state is pressed, listen for motion events or release events
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
match &event {
|
||||||
wayland::Event::DataSource(wayland::DataSourceEvent::DndFinished),
|
event::Event::Mouse(mouse::Event::CursorMoved { .. })
|
||||||
)) => {
|
| event::Event::Touch(touch::Event::FingerMoved { .. }) => {
|
||||||
ret = event::Status::Captured;
|
let pos = cursor_position.position().unwrap_or_default();
|
||||||
DraggingState::None
|
let d_y = pos.y - start.y;
|
||||||
}
|
let d_x = pos.x - start.x;
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
let distance_squared = d_y * d_y + d_x * d_x;
|
||||||
wayland::Event::DataSource(wayland::DataSourceEvent::Cancelled),
|
|
||||||
)) => {
|
|
||||||
ret = event::Status::Captured;
|
|
||||||
if let Some(on_cancel) = self.on_cancel.clone() {
|
|
||||||
shell.publish(on_cancel);
|
|
||||||
}
|
|
||||||
DraggingState::None
|
|
||||||
}
|
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
|
||||||
wayland::Event::DataSource(wayland::DataSourceEvent::DndDropPerformed),
|
|
||||||
)) => {
|
|
||||||
ret = event::Status::Captured;
|
|
||||||
|
|
||||||
DraggingState::None
|
if distance_squared > DRAG_START_DISTANCE_SQUARED {
|
||||||
}
|
if let Some((_, applet)) =
|
||||||
_ => DraggingState::Dragging(applet),
|
self.info.iter().enumerate().find(|(i, _)| {
|
||||||
},
|
start.y
|
||||||
DraggingState::Pressed(start) => {
|
< layout.bounds().y
|
||||||
// if dragging state is pressed, listen for motion events or release events
|
+ (*i + 1) as f32
|
||||||
match &event {
|
* (height + spacing.space_xxs as f32)
|
||||||
event::Event::Mouse(mouse::Event::CursorMoved { .. })
|
})
|
||||||
| event::Event::Touch(touch::Event::FingerMoved { .. }) => {
|
{
|
||||||
let pos = cursor_position.position().unwrap_or_default();
|
let applet = applet.clone().into_owned();
|
||||||
let d_y = pos.y - start.y;
|
state.dragging_state = DraggingState::Dragging(applet.clone());
|
||||||
let d_x = pos.x - start.x;
|
|
||||||
let distance_squared = d_y * d_y + d_x * d_x;
|
|
||||||
|
|
||||||
if distance_squared > DRAG_START_DISTANCE_SQUARED {
|
state.layout = Some(layout.bounds().size());
|
||||||
if let Some((_, applet)) =
|
shell.publish((self.on_create_dnd_source.as_ref())(
|
||||||
self.info.iter().enumerate().find(|(i, _)| {
|
applet.clone(),
|
||||||
start.y
|
));
|
||||||
< layout.bounds().y
|
|
||||||
+ (*i + 1) as f32 * (height + spacing.space_xxs as f32)
|
|
||||||
})
|
|
||||||
{
|
|
||||||
let (window_id, icon_id) = self.surface_ids.unwrap();
|
|
||||||
state.dragging_state =
|
|
||||||
DraggingState::Dragging(applet.clone().into_owned());
|
|
||||||
|
|
||||||
// TODO emit a dnd Task
|
let p = applet.path.to_path_buf();
|
||||||
state.layout = Some(layout.bounds().size());
|
iced_core::clipboard::start_dnd::<
|
||||||
let state_clone = state.clone();
|
cosmic::Theme,
|
||||||
shell.publish((self.on_create_dnd_source.as_ref())(
|
cosmic::Renderer,
|
||||||
state_clone.clone(),
|
(),
|
||||||
));
|
>(
|
||||||
|
clipboard,
|
||||||
let p = applet.path.to_path_buf();
|
false,
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(move || {
|
Some(iced_core::clipboard::DndSource::Widget(
|
||||||
// platform_specific::wayland::data_device::ActionInner::StartDnd {
|
self.id.clone(),
|
||||||
// mime_types: vec![MIME_TYPE.to_string()],
|
)),
|
||||||
// actions: DndAction::Move,
|
Some((
|
||||||
// origin_id: window_id,
|
dnd_icon(applet.clone(), &layout).into(),
|
||||||
// icon_id: Some((
|
iced_core::widget::tree::State::new(state.clone()),
|
||||||
// DndIcon::Widget(
|
)),
|
||||||
// icon_id,
|
Box::new(AppletString(p.clone())),
|
||||||
// Box::new(state_clone.clone()),
|
DndAction::Move,
|
||||||
// ),
|
);
|
||||||
// cosmic::iced::Vector::ZERO
|
ret = event::Status::Captured;
|
||||||
// )),
|
let reordered = self
|
||||||
// data: Box::new(AppletString(p.clone())),
|
.info
|
||||||
// }
|
.iter()
|
||||||
// })));
|
.filter(|a| {
|
||||||
ret = event::Status::Captured;
|
applet != **a
|
||||||
DraggingState::Dragging(applet.clone().into_owned())
|
})
|
||||||
|
.cloned()
|
||||||
|
.map(pages::desktop::panel::applets_inner::Applet::into_owned)
|
||||||
|
.collect();
|
||||||
|
shell.publish((self.on_reorder.as_ref())(reordered));
|
||||||
|
DraggingState::Dragging(applet.clone().into_owned())
|
||||||
|
} else {
|
||||||
|
DraggingState::Pressed(start)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
DraggingState::Pressed(start)
|
DraggingState::Pressed(start)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
DraggingState::Pressed(start)
|
|
||||||
}
|
}
|
||||||
|
event::Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))
|
||||||
|
| event::Event::Touch(
|
||||||
|
touch::Event::FingerLifted { .. } | touch::Event::FingerLost { .. },
|
||||||
|
) => {
|
||||||
|
ret = event::Status::Captured;
|
||||||
|
DraggingState::None
|
||||||
|
}
|
||||||
|
_ => DraggingState::Pressed(start),
|
||||||
}
|
}
|
||||||
event::Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))
|
|
||||||
| event::Event::Touch(
|
|
||||||
touch::Event::FingerLifted { .. } | touch::Event::FingerLost { .. },
|
|
||||||
) => {
|
|
||||||
ret = event::Status::Captured;
|
|
||||||
DraggingState::None
|
|
||||||
}
|
|
||||||
_ => DraggingState::Pressed(start),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
state.dnd_offer = match mem::take(&mut state.dnd_offer) {
|
state.dnd_offer = match mem::take(&mut state.dnd_offer) {
|
||||||
DndOfferState::None => match &event {
|
DndOfferState::None => match &event {
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
event::Event::Dnd(dnd_event) => match dnd_event {
|
||||||
wayland::Event::DndOffer(wayland::DndOfferEvent::SourceActions(actions)),
|
DndEvent::Offer(rectangle, OfferEvent::Enter { x, y, .. })
|
||||||
)) => DndOfferState::OutsideWidget(Vec::new(), *actions, None),
|
if *rectangle == Some(self.get_drag_id()) =>
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
{
|
||||||
wayland::Event::DndOffer(wayland::DndOfferEvent::Enter { x, y, mime_types }),
|
if let Some(data) = self.active_applet_offer.clone() {
|
||||||
)) => {
|
|
||||||
if mime_types.iter().any(|m| m.as_str() == MIME_TYPE) {
|
|
||||||
let point = Point::new(*x as f32, *y as f32);
|
|
||||||
|
|
||||||
if layout.bounds().contains(point) {
|
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(
|
|
||||||
// move || {
|
|
||||||
// platform_specific::wayland::data_device::ActionInner::SetActions {
|
|
||||||
// preferred: DndAction::Move,
|
|
||||||
// accepted: DndAction::Move,
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// )));
|
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(
|
|
||||||
// move || {
|
|
||||||
// platform_specific::wayland::data_device::ActionInner::Accept(
|
|
||||||
// Some(MIME_TYPE.to_string()),
|
|
||||||
// )
|
|
||||||
// },
|
|
||||||
// )));
|
|
||||||
let data = if let DraggingState::Dragging(a) = &state.dragging_state {
|
|
||||||
Some(a.clone())
|
|
||||||
} else {
|
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(
|
|
||||||
// move || {
|
|
||||||
// platform_specific::wayland::data_device::ActionInner::RequestDndData(
|
|
||||||
// MIME_TYPE.to_string(),
|
|
||||||
// )
|
|
||||||
// },
|
|
||||||
// )));
|
|
||||||
None
|
|
||||||
};
|
|
||||||
DndOfferState::HandlingOffer(
|
|
||||||
mime_types.clone(),
|
|
||||||
DndAction::empty(),
|
|
||||||
data,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
let data = match &state.dragging_state {
|
|
||||||
DraggingState::Dragging(data) => {
|
|
||||||
let filtered: Vec<_> = self
|
|
||||||
.info
|
|
||||||
.clone()
|
|
||||||
.into_iter()
|
|
||||||
.filter(|a| a != data)
|
|
||||||
.collect();
|
|
||||||
if filtered != self.info {
|
|
||||||
shell.publish((self.on_reorder.as_ref())(
|
|
||||||
filtered
|
|
||||||
.into_iter()
|
|
||||||
.map(pages::desktop::panel::applets_inner::Applet::into_owned)
|
|
||||||
.collect(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Some(data.clone())
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
DndOfferState::OutsideWidget(
|
|
||||||
mime_types.clone(),
|
|
||||||
DndAction::empty(),
|
|
||||||
data,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DndOfferState::None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => DndOfferState::None,
|
|
||||||
},
|
|
||||||
DndOfferState::OutsideWidget(mime_types, action, data) => match &event {
|
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
|
||||||
wayland::Event::DndOffer(wayland::DndOfferEvent::SourceActions(actions)),
|
|
||||||
)) => DndOfferState::OutsideWidget(mime_types, *actions, data),
|
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
|
||||||
wayland::Event::DndOffer(wayland::DndOfferEvent::Motion { x, y }),
|
|
||||||
)) => {
|
|
||||||
let point = Point::new(*x as f32, *y as f32);
|
|
||||||
|
|
||||||
if layout.bounds().contains(point) {
|
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(move || {
|
|
||||||
// platform_specific::wayland::data_device::ActionInner::SetActions {
|
|
||||||
// preferred: DndAction::Move,
|
|
||||||
// accepted: DndAction::Move,
|
|
||||||
// }
|
|
||||||
// })));
|
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(move || {
|
|
||||||
// platform_specific::wayland::data_device::ActionInner::Accept(Some(
|
|
||||||
// MIME_TYPE.to_string(),
|
|
||||||
// ))
|
|
||||||
// })));
|
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(move || {
|
|
||||||
// platform_specific::wayland::data_device::ActionInner::SetActions {
|
|
||||||
// preferred: action.intersection(DndAction::Move),
|
|
||||||
// accepted: action
|
|
||||||
// .intersection(DndAction::Move.union(DndAction::Copy)),
|
|
||||||
// }
|
|
||||||
// })));
|
|
||||||
// TODO maybe keep track of data and request here if we don't have it
|
|
||||||
// also maybe just refactor DND Targets to allow easier handling...
|
|
||||||
|
|
||||||
if data.is_none() {
|
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(
|
|
||||||
// move || {
|
|
||||||
// platform_specific::wayland::data_device::ActionInner::RequestDndData(
|
|
||||||
// MIME_TYPE.to_string(),
|
|
||||||
// )
|
|
||||||
// },
|
|
||||||
// )));
|
|
||||||
}
|
|
||||||
if let Some(applet) = data.clone() {
|
|
||||||
let reordered_list: Vec<_> = self.get_reordered(
|
|
||||||
&layout,
|
|
||||||
Point {
|
|
||||||
x: *x as f32,
|
|
||||||
y: *y as f32,
|
|
||||||
},
|
|
||||||
applet,
|
|
||||||
);
|
|
||||||
if reordered_list != self.info {
|
|
||||||
// shell.publish((self.on_reorder.as_ref())(
|
|
||||||
// reordered_list.into_iter().map(Applet::into_owned).collect(),
|
|
||||||
// ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DndOfferState::HandlingOffer(mime_types, DndAction::empty(), data)
|
|
||||||
} else {
|
|
||||||
DndOfferState::OutsideWidget(mime_types, DndAction::empty(), data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
|
||||||
wayland::Event::DndOffer(wayland::DndOfferEvent::DndData {
|
|
||||||
data: new_data,
|
|
||||||
mime_type,
|
|
||||||
}),
|
|
||||||
)) => {
|
|
||||||
if mime_type.as_str() == MIME_TYPE {
|
|
||||||
let data = std::str::from_utf8(new_data.as_bytes())
|
|
||||||
.ok()
|
|
||||||
.and_then(|s| url::Url::from_str(s).ok())
|
|
||||||
.and_then(|url| url.to_file_path().ok())
|
|
||||||
.and_then(|p| Applet::try_from(Cow::from(p)).ok());
|
|
||||||
DndOfferState::OutsideWidget(mime_types, action, data)
|
|
||||||
} else {
|
|
||||||
DndOfferState::OutsideWidget(mime_types, action, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
|
||||||
wayland::Event::DndOffer(
|
|
||||||
wayland::DndOfferEvent::DropPerformed | wayland::DndOfferEvent::Leave,
|
|
||||||
),
|
|
||||||
)) => DndOfferState::None,
|
|
||||||
_ => DndOfferState::OutsideWidget(mime_types, action, data),
|
|
||||||
},
|
|
||||||
DndOfferState::HandlingOffer(mime_types, action, data) => match &event {
|
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
|
||||||
wayland::Event::DndOffer(wayland::DndOfferEvent::Motion { x, y }),
|
|
||||||
)) => {
|
|
||||||
let point = Point::new(*x as f32, *y as f32);
|
|
||||||
if layout.bounds().contains(point) {
|
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(move || {
|
|
||||||
// platform_specific::wayland::data_device::ActionInner::SetActions {
|
|
||||||
// preferred: DndAction::Move,
|
|
||||||
// accepted: DndAction::Move,
|
|
||||||
// }
|
|
||||||
// })));
|
|
||||||
if let Some(data) = data.clone() {
|
|
||||||
let reordered_list = self.get_reordered(
|
let reordered_list = self.get_reordered(
|
||||||
&layout,
|
&layout,
|
||||||
Point {
|
Point {
|
||||||
|
|
@ -1247,124 +1067,69 @@ where
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DndOfferState::HandlingOffer(mime_types, DndAction::empty(), data)
|
DndOfferState::HandlingOffer
|
||||||
} else {
|
}
|
||||||
if let Some(applet) = data.clone() {
|
_ => DndOfferState::None,
|
||||||
let reordered_list: Vec<_> = self.get_reordered(
|
},
|
||||||
|
_ => DndOfferState::None,
|
||||||
|
},
|
||||||
|
DndOfferState::HandlingOffer => match &event {
|
||||||
|
event::Event::Dnd(dnd_event) => match dnd_event {
|
||||||
|
DndEvent::Offer(rectangle, OfferEvent::Motion { x, y })
|
||||||
|
if *rectangle == Some(self.get_drag_id()) =>
|
||||||
|
{
|
||||||
|
if let Some(data) = self.active_applet_offer.clone() {
|
||||||
|
let reordered_list = self.get_reordered(
|
||||||
&layout,
|
&layout,
|
||||||
Point {
|
Point {
|
||||||
x: *x as f32,
|
x: *x as f32,
|
||||||
y: *y as f32,
|
y: *y as f32,
|
||||||
},
|
},
|
||||||
applet,
|
data,
|
||||||
);
|
);
|
||||||
if reordered_list != self.info {
|
if reordered_list != self.info {
|
||||||
shell.publish((self.on_reorder.as_ref())(
|
shell.publish((self.on_reorder.as_ref())(
|
||||||
reordered_list.into_iter().map(Applet::into_owned).collect(),
|
reordered_list
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(move || {
|
|
||||||
// platform_specific::wayland::data_device::ActionInner::Accept(None)
|
|
||||||
// })));
|
|
||||||
DndOfferState::OutsideWidget(mime_types, DndAction::empty(), data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
|
||||||
wayland::Event::DndOffer(wayland::DndOfferEvent::Leave),
|
|
||||||
)) => DndOfferState::None,
|
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
|
||||||
wayland::Event::DndOffer(wayland::DndOfferEvent::SourceActions(actions)),
|
|
||||||
)) => {
|
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(move || {
|
|
||||||
// platform_specific::wayland::data_device::ActionInner::SetActions {
|
|
||||||
// preferred: DndAction::Move,
|
|
||||||
// accepted: DndAction::Move,
|
|
||||||
// }
|
|
||||||
// })));
|
|
||||||
DndOfferState::HandlingOffer(mime_types, *actions, data)
|
|
||||||
}
|
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
|
||||||
wayland::Event::DndOffer(wayland::DndOfferEvent::DndData {
|
|
||||||
data: new_data,
|
|
||||||
mime_type,
|
|
||||||
}),
|
|
||||||
)) => {
|
|
||||||
if mime_type.as_str() == MIME_TYPE {
|
|
||||||
let data = std::str::from_utf8(new_data.as_bytes())
|
|
||||||
.ok()
|
|
||||||
.and_then(|s| url::Url::from_str(s).ok())
|
|
||||||
.and_then(|url| url.to_file_path().ok())
|
|
||||||
.and_then(|p| Applet::try_from(Cow::from(p)).ok());
|
|
||||||
if let Some(data) = data.borrow() {
|
|
||||||
let filtered: Vec<_> = self
|
|
||||||
.info
|
|
||||||
.clone()
|
|
||||||
.into_iter()
|
|
||||||
.filter(|a| a != data)
|
|
||||||
.collect();
|
|
||||||
if filtered != self.info {
|
|
||||||
shell.publish((self.on_reorder.as_ref())(
|
|
||||||
filtered
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(pages::desktop::panel::applets_inner::Applet::into_owned)
|
.map(pages::desktop::panel::applets_inner::Applet::into_owned)
|
||||||
.collect(),
|
.collect(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DndOfferState::HandlingOffer
|
||||||
DndOfferState::HandlingOffer(mime_types, action, data)
|
|
||||||
} else {
|
|
||||||
DndOfferState::HandlingOffer(mime_types, action, data)
|
|
||||||
}
|
}
|
||||||
}
|
DndEvent::Offer(
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
rectangle,
|
||||||
wayland::Event::DndOffer(wayland::DndOfferEvent::DropPerformed),
|
OfferEvent::LeaveDestination | OfferEvent::Leave,
|
||||||
)) => {
|
) if *rectangle == Some(self.get_drag_id()) => {
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(move || {
|
let reordered = self
|
||||||
// platform_specific::wayland::data_device::ActionInner::SetActions {
|
.info
|
||||||
// preferred: DndAction::Move,
|
.iter()
|
||||||
// accepted: DndAction::Move,
|
.filter(|a| {
|
||||||
// }
|
!self
|
||||||
// })));
|
.active_applet_offer
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(move || {
|
.as_ref()
|
||||||
// platform_specific::wayland::data_device::ActionInner::Accept(Some(
|
.is_some_and(|offer| offer == *a)
|
||||||
// MIME_TYPE.to_string(),
|
})
|
||||||
// ))
|
.cloned()
|
||||||
// })));
|
.map(pages::desktop::panel::applets_inner::Applet::into_owned)
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(move || {
|
.collect();
|
||||||
// platform_specific::wayland::data_device::ActionInner::RequestDndData(
|
shell.publish((self.on_reorder.as_ref())(reordered));
|
||||||
// MIME_TYPE.to_string(),
|
|
||||||
// )
|
|
||||||
// })));
|
|
||||||
DndOfferState::Dropped
|
|
||||||
}
|
|
||||||
_ => DndOfferState::HandlingOffer(mime_types, action, data),
|
|
||||||
},
|
|
||||||
DndOfferState::Dropped => match &event {
|
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
|
||||||
wayland::Event::DndOffer(wayland::DndOfferEvent::DndData { .. }),
|
|
||||||
)) => {
|
|
||||||
if let Some(on_finish) = self.on_finish.clone() {
|
|
||||||
shell.publish(on_finish);
|
|
||||||
}
|
|
||||||
// shell.publish((self.on_dnd_task_produced.as_ref())(Box::new(move || {
|
|
||||||
// platform_specific::wayland::data_device::ActionInner::DndFinished
|
|
||||||
// })));
|
|
||||||
|
|
||||||
DndOfferState::None
|
DndOfferState::None
|
||||||
}
|
|
||||||
event::Event::PlatformSpecific(PlatformSpecific::Wayland(
|
|
||||||
wayland::Event::DndOffer(wayland::DndOfferEvent::Leave),
|
|
||||||
)) => {
|
|
||||||
// already applied the offer, so we can just finish
|
|
||||||
if let Some(on_cancel) = self.on_cancel.clone() {
|
|
||||||
shell.publish(on_cancel);
|
|
||||||
}
|
}
|
||||||
|
DndEvent::Offer(rectangle, OfferEvent::Data { .. })
|
||||||
|
if *rectangle == Some(self.get_drag_id()) =>
|
||||||
|
{
|
||||||
|
if let Some(on_finish) = self.on_finish.clone() {
|
||||||
|
shell.publish(on_finish);
|
||||||
|
}
|
||||||
|
|
||||||
DndOfferState::None
|
DndOfferState::None
|
||||||
}
|
}
|
||||||
_ => DndOfferState::Dropped,
|
_ => DndOfferState::HandlingOffer,
|
||||||
|
},
|
||||||
|
_ => DndOfferState::HandlingOffer,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1435,28 +1200,65 @@ where
|
||||||
interaction => interaction,
|
interaction => interaction,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn id(&self) -> Option<Id> {
|
||||||
|
Some(self.id.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_id(&mut self, id: Id) {
|
||||||
|
self.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drag_destinations(
|
||||||
|
&self,
|
||||||
|
_state: &Tree,
|
||||||
|
layout: layout::Layout<'_>,
|
||||||
|
_renderer: &cosmic::Renderer,
|
||||||
|
dnd_rectangles: &mut cosmic::iced_core::clipboard::DndDestinationRectangles,
|
||||||
|
) {
|
||||||
|
let Rectangle {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
} = layout.bounds();
|
||||||
|
dnd_rectangles.push(DndDestinationRectangle {
|
||||||
|
id: self.get_drag_id(),
|
||||||
|
rectangle: cosmic::iced::clipboard::dnd::Rectangle {
|
||||||
|
x: x as f64,
|
||||||
|
y: y as f64,
|
||||||
|
width: width as f64,
|
||||||
|
height: height as f64,
|
||||||
|
},
|
||||||
|
mime_types: vec![Cow::Owned(MIME_TYPE.to_string())],
|
||||||
|
actions: DndAction::Move,
|
||||||
|
preferred: DndAction::Move,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A string which can be sent to the clipboard or drag-and-dropped.
|
impl AsMimeTypes for AppletString {
|
||||||
// #[derive(Debug, Clone)]
|
fn available(&self) -> Cow<'static, [String]> {
|
||||||
// pub struct AppletString(PathBuf);
|
Cow::Owned(vec![MIME_TYPE.to_string()])
|
||||||
|
}
|
||||||
|
|
||||||
// impl DataFromMimeType for AppletString {
|
fn as_bytes(&self, mime_type: &str) -> Option<Cow<'static, [u8]>> {
|
||||||
// fn from_mime_type(&self, mime_type: &str) -> Option<Vec<u8>> {
|
if mime_type == MIME_TYPE {
|
||||||
// if mime_type == MIME_TYPE {
|
Some(Cow::Owned(
|
||||||
// let data = Some(
|
url::Url::from_file_path(self.0.clone())
|
||||||
// url::Url::from_file_path(self.0.clone())
|
.ok()?
|
||||||
// .ok()?
|
.to_string()
|
||||||
// .to_string()
|
.as_bytes()
|
||||||
// .as_bytes()
|
.to_vec(),
|
||||||
// .to_vec(),
|
))
|
||||||
// );
|
} else {
|
||||||
// data
|
None
|
||||||
// } else {
|
}
|
||||||
// None
|
}
|
||||||
// }
|
}
|
||||||
// }
|
/// A string which can be sent to the clipboard or drag-and-dropped.
|
||||||
// }
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AppletString(PathBuf);
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub enum DraggingState {
|
pub enum DraggingState {
|
||||||
|
|
@ -1473,9 +1275,7 @@ pub enum DraggingState {
|
||||||
pub(crate) enum DndOfferState {
|
pub(crate) enum DndOfferState {
|
||||||
#[default]
|
#[default]
|
||||||
None,
|
None,
|
||||||
OutsideWidget(Vec<String>, DndAction, Option<Applet<'static>>),
|
HandlingOffer,
|
||||||
HandlingOffer(Vec<String>, DndAction, Option<Applet<'static>>),
|
|
||||||
Dropped,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue