diff --git a/src/main.rs b/src/main.rs index e809460..0742ab7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -359,7 +359,9 @@ impl Application for App { fn update(&mut self, message: Msg) -> Command> { match message { - Msg::SourceFinished => {} + Msg::SourceFinished => { + self.drag_surface = None; + } Msg::WaylandEvent(evt) => match evt { WaylandEvent::Output(evt, output) => { // TODO: Less hacky way to get connection from iced-sctk diff --git a/src/view/mod.rs b/src/view/mod.rs index afd9307..442dab3 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -31,6 +31,10 @@ pub(crate) fn layer_surface<'a>( drop_target = Some(workspace); } } + let mut drag_toplevel = None; + if let Some((_, DragSurface::Toplevel { handle, .. }, _)) = &app.drag_surface { + drag_toplevel = Some(handle); + } let layout = app.conf.workspace_config.workspace_layout; let sidebar = workspaces_sidebar( app.workspaces @@ -53,6 +57,7 @@ pub(crate) fn layer_surface<'a>( }), &surface.output, layout, + drag_toplevel, ); let container = match layout { WorkspaceLayout::Vertical => widget::layer_container( @@ -243,8 +248,12 @@ pub(crate) fn toplevel_preview(toplevel: &Toplevel) -> cosmic::Element { fn toplevel_previews_entry<'a>( toplevel: &'a Toplevel, output: &'a wl_output::WlOutput, + is_being_dragged: bool, ) -> cosmic::Element<'a, Msg> { - iced::widget::dnd_source(toplevel_preview(toplevel)) + // Dragged window still takes up space until moved, but isn't rendered while drag surface is + // shown. + let preview = crate::widgets::visibility_wrapper(toplevel_preview(toplevel), !is_being_dragged); + iced::widget::dnd_source(preview) .on_drag(|size| { Msg::StartDrag( size, @@ -263,13 +272,14 @@ fn toplevel_previews<'a>( toplevels: impl Iterator, output: &'a wl_output::WlOutput, layout: WorkspaceLayout, + drag_toplevel: Option<&'a zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1>, ) -> cosmic::Element<'a, Msg> { let (width, height) = match layout { WorkspaceLayout::Vertical => (iced::Length::FillPortion(4), iced::Length::Fill), WorkspaceLayout::Horizontal => (iced::Length::Fill, iced::Length::FillPortion(4)), }; let entries = toplevels - .map(|t| toplevel_previews_entry(t, output)) + .map(|t| toplevel_previews_entry(t, output, drag_toplevel == Some(&t.handle))) .collect(); //row(entries) widget::container(crate::widgets::toplevels(entries)) diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs index d5e3302..41a966b 100644 --- a/src/widgets/mod.rs +++ b/src/widgets/mod.rs @@ -19,8 +19,8 @@ mod mouse_interaction_wrapper; pub use mouse_interaction_wrapper::mouse_interaction_wrapper; mod toplevels; pub use toplevels::toplevels; - -trait Foo {} +mod visibility_wrapper; +pub use visibility_wrapper::visibility_wrapper; pub fn layout_wrapper<'a, Msg, T: Into>>( inner: T, diff --git a/src/widgets/visibility_wrapper.rs b/src/widgets/visibility_wrapper.rs new file mode 100644 index 0000000..e4ec09c --- /dev/null +++ b/src/widgets/visibility_wrapper.rs @@ -0,0 +1,110 @@ +//! If `visible` is set to `true`, behaves exactly as wrapped widget. If `false`, +//! takes the same space but does not draw. + +use cosmic::iced::{ + advanced::{ + layout, mouse, overlay, renderer, + widget::{tree, Id, Operation, OperationOutputWrapper, Tree}, + Clipboard, Layout, Shell, Widget, + }, + event::{self, Event}, + Length, Rectangle, Size, +}; +use std::marker::PhantomData; + +pub fn visibility_wrapper<'a, Msg, T: Into>>( + inner: T, + visible: bool, +) -> VisibilityWrapper<'a, Msg> { + VisibilityWrapper { + content: inner.into(), + visible, + _msg: PhantomData, + } +} + +pub struct VisibilityWrapper<'a, Msg> { + content: cosmic::Element<'a, Msg>, + visible: bool, + _msg: PhantomData, +} + +impl<'a, Msg> Widget for VisibilityWrapper<'a, Msg> { + delegate::delegate! { + to self.content.as_widget() { + fn tag(&self) -> tree::Tag; + fn state(&self) -> tree::State; + fn children(&self) -> Vec; + fn size(&self) -> Size; + fn size_hint(&self) -> Size; + 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 mouse_interaction( + &self, + _tree: &Tree, + _layout: Layout<'_>, + _cursor: mouse::Cursor, + _viewport: &Rectangle, + _renderer: &cosmic::Renderer, + ) -> mouse::Interaction; + fn id(&self) -> Option; + } + + 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 set_id(&mut self, id: Id); + } + } + + fn draw( + &self, + state: &Tree, + renderer: &mut cosmic::Renderer, + theme: &cosmic::Theme, + style: &renderer::Style, + layout: Layout<'_>, + cursor: mouse::Cursor, + viewport: &Rectangle, + ) { + if self.visible { + self.content + .as_widget() + .draw(state, renderer, theme, style, layout, cursor, viewport); + } + } +} + +impl<'a, Msg: 'a> From> for cosmic::Element<'a, Msg> { + fn from(widget: VisibilityWrapper<'a, Msg>) -> Self { + cosmic::Element::new(widget) + } + +}