From 06c37e39f5d7095f543b8dff8cdf2976863552ae Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 15 Dec 2023 15:46:41 -0800 Subject: [PATCH] WIP custom cursor for drag and drop --- src/view/mod.rs | 26 +++++- src/widgets/mod.rs | 2 + src/widgets/mouse_interaction_wrapper.rs | 105 +++++++++++++++++++++++ 3 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 src/widgets/mouse_interaction_wrapper.rs diff --git a/src/view/mod.rs b/src/view/mod.rs index b007c7f..c6e768c 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -1,5 +1,8 @@ use cctk::{ - cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1, + cosmic_protocols::{ + toplevel_info::v1::client::zcosmic_toplevel_handle_v1, + workspace::v1::client::zcosmic_workspace_handle_v1, + }, wayland_client::protocol::wl_output, }; use cosmic::{ @@ -19,6 +22,12 @@ pub(crate) fn layer_surface<'a>( app: &'a App, surface: &'a LayerSurface, ) -> cosmic::Element<'a, Msg> { + let mut drop_target = None; + if let Some((workspace, output)) = &app.drop_target { + if output == &surface.output { + drop_target = Some(workspace); + } + } let layout = app.conf.workspace_config.workspace_layout; let sidebar = workspaces_sidebar( app.workspaces @@ -27,6 +36,7 @@ pub(crate) fn layer_surface<'a>( &surface.output, layout, app.conf.workspace_config.workspace_amount, + drop_target, ); let toplevels = toplevel_previews( app.toplevels.iter().filter(|i| { @@ -83,7 +93,15 @@ pub(crate) fn workspace_item<'a>( fn workspace_sidebar_entry<'a>( workspace: &'a Workspace, output: &'a wl_output::WlOutput, + is_drop_target: bool, ) -> cosmic::Element<'a, Msg> { + /* XXX + let mouse_interaction = if is_drop_target { + iced::mouse::Interaction::Crosshair + } else { + iced::mouse::Interaction::Idle + }; + */ /* TODO allow moving workspaces (needs compositor support) iced::widget::dnd_source(workspace_item(workspace, output)) .on_drag(|size| { @@ -99,6 +117,8 @@ fn workspace_sidebar_entry<'a>( .on_cancelled(Msg::SourceFinished) .into() */ + //crate::widgets::mouse_interaction_wrapper( + // mouse_interaction, iced::widget::dnd_listener(workspace_item(workspace, output)) .on_enter(|actions, mime, pos| { Msg::DndWorkspaceEnter(workspace.handle.clone(), output.clone(), actions, mime, pos) @@ -106,6 +126,7 @@ fn workspace_sidebar_entry<'a>( .on_exit(Msg::DndWorkspaceLeave) .on_drop(Msg::DndWorkspaceDrop) .on_data(Msg::DndWorkspaceData) + //) .into() } @@ -114,9 +135,10 @@ fn workspaces_sidebar<'a>( output: &'a wl_output::WlOutput, layout: WorkspaceLayout, amount: WorkspaceAmount, + drop_target: Option<&zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1>, ) -> cosmic::Element<'a, Msg> { let sidebar_entries = workspaces - .map(|w| workspace_sidebar_entry(w, output)) + .map(|w| workspace_sidebar_entry(w, output, drop_target == Some(&w.handle))) .collect(); let axis = match layout { WorkspaceLayout::Vertical => Axis::Vertical, diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs index 134fb87..8b425e5 100644 --- a/src/widgets/mod.rs +++ b/src/widgets/mod.rs @@ -9,6 +9,8 @@ mod image_bg; pub use image_bg::image_bg; mod workspace_bar; pub use workspace_bar::workspace_bar; +mod mouse_interaction_wrapper; +pub use mouse_interaction_wrapper::mouse_interaction_wrapper; pub fn layout_wrapper>(inner: T) -> LayoutWrapper { LayoutWrapper { diff --git a/src/widgets/mouse_interaction_wrapper.rs b/src/widgets/mouse_interaction_wrapper.rs new file mode 100644 index 0000000..ad840c1 --- /dev/null +++ b/src/widgets/mouse_interaction_wrapper.rs @@ -0,0 +1,105 @@ +use cosmic::iced::{ + self, + advanced::{ + layout::{self, flex::Axis}, + mouse, overlay, renderer, + widget::{tree, Operation, OperationOutputWrapper, Tree}, + Clipboard, Layout, Shell, Widget, + }, + event::{self, Event}, + widget::image::{FilterMethod, Handle}, + ContentFit, Length, Point, Rectangle, Size, Vector, +}; +use cosmic::iced_core::Renderer as _; + +use std::marker::PhantomData; + +pub fn mouse_interaction_wrapper<'a, Msg, T: Into>>( + mouse_interaction: mouse::Interaction, + content: T, +) -> MouseInteractionWrapper<'a, Msg> { + MouseInteractionWrapper { + content: content.into(), + mouse_interaction, + _msg: PhantomData, + } +} + +pub struct MouseInteractionWrapper<'a, Msg> { + content: cosmic::Element<'a, Msg>, + mouse_interaction: mouse::Interaction, + _msg: PhantomData, +} + +impl<'a, Msg> Widget for MouseInteractionWrapper<'a, Msg> { + delegate::delegate! { + to self.content.as_widget() { + fn tag(&self) -> tree::Tag; + fn state(&self) -> tree::State; + fn children(&self) -> Vec; + fn width(&self) -> Length; + fn height(&self) -> Length; + fn layout( + &self, + tree: &mut Tree, + renderer: &cosmic::Renderer, + limits: &layout::Limits, + ) -> layout::Node; + fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + renderer: &cosmic::Renderer, + operation: &mut dyn Operation>, + ); + fn draw( + &self, + state: &Tree, + renderer: &mut cosmic::Renderer, + theme: &cosmic::Theme, + style: &renderer::Style, + layout: Layout<'_>, + cursor: mouse::Cursor, + viewport: &Rectangle, + ); + } + + to self.content.as_widget_mut() { + fn diff(&mut self, tree: &mut Tree); + fn on_event( + &mut self, + tree: &mut Tree, + event: Event, + layout: Layout<'_>, + cursor: mouse::Cursor, + renderer: &cosmic::Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, Msg>, + viewport: &Rectangle, + ) -> event::Status; + fn overlay<'b>( + &'b mut self, + tree: &'b mut Tree, + layout: Layout<'_>, + renderer: &cosmic::Renderer, + ) -> Option>; + } + } + + fn mouse_interaction( + &self, + _tree: &Tree, + _layout: Layout<'_>, + _cursor: mouse::Cursor, + _viewport: &Rectangle, + _renderer: &cosmic::Renderer, + ) -> mouse::Interaction { + self.mouse_interaction + } +} + +impl<'a, Msg: 'static> From> for cosmic::Element<'a, Msg> { + fn from(widget: MouseInteractionWrapper<'a, Msg>) -> Self { + cosmic::Element::new(widget) + } +}