diff --git a/src/view/mod.rs b/src/view/mod.rs index d82919c..0264ade 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -41,7 +41,7 @@ pub(crate) fn layer_surface<'a>( }), &surface.output, ); - match layout { + let container = match layout { WorkspaceLayout::Vertical => widget::cosmic_container::container( row![sidebar, toplevels] .spacing(12) @@ -53,8 +53,8 @@ pub(crate) fn layer_surface<'a>( .spacing(12) .height(iced::Length::Fill), ), - } - .into() + }; + crate::widgets::image_bg(container).into() } fn close_button(on_press: Msg) -> cosmic::Element<'static, Msg> { diff --git a/src/widgets/image_bg.rs b/src/widgets/image_bg.rs new file mode 100644 index 0000000..dafd215 --- /dev/null +++ b/src/widgets/image_bg.rs @@ -0,0 +1,197 @@ +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 image_bg<'a, Msg, T: Into>>(content: T) -> ImageBg<'a, Msg> { + ImageBg { + content: content.into(), + _msg: PhantomData, + } +} + +pub struct ImageBg<'a, Msg> { + content: cosmic::Element<'a, Msg>, + _msg: PhantomData, +} + +impl<'a, Msg> Widget for ImageBg<'a, Msg> { + fn tag(&self) -> tree::Tag { + self.content.as_widget().tag() + } + + fn state(&self) -> tree::State { + self.content.as_widget().state() + } + + fn children(&self) -> Vec { + self.content.as_widget().children() + } + + fn diff(&mut self, tree: &mut Tree) { + self.content.as_widget_mut().diff(tree); + } + + fn width(&self) -> Length { + self.content.as_widget().width() + } + + fn height(&self) -> Length { + self.content.as_widget().height() + } + + fn layout( + &self, + tree: &mut Tree, + renderer: &cosmic::Renderer, + limits: &layout::Limits, + ) -> layout::Node { + let content = self.content.as_widget().layout(tree, renderer, limits); + //let size = limits.resolve(content.size()); + let size = content.size(); + layout::Node::with_children(size, vec![content]) + } + + fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + renderer: &cosmic::Renderer, + operation: &mut dyn Operation>, + ) { + operation.container( + None, // XXX id + layout.bounds(), + &mut |operation| { + self.content.as_widget().operate( + tree, + layout.children().next().unwrap(), + renderer, + operation, + ); + }, + ); + } + + 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 { + self.content.as_widget_mut().on_event( + tree, + event, + layout.children().next().unwrap(), + cursor, + renderer, + clipboard, + shell, + viewport, + ) + } + + fn mouse_interaction( + &self, + tree: &Tree, + layout: Layout<'_>, + cursor: mouse::Cursor, + viewport: &Rectangle, + renderer: &cosmic::Renderer, + ) -> mouse::Interaction { + self.content.as_widget().mouse_interaction( + tree, + layout.children().next().unwrap(), + cursor, + viewport, + renderer, + ) + } + + fn draw( + &self, + state: &Tree, + renderer: &mut cosmic::Renderer, + theme: &cosmic::Theme, + style: &renderer::Style, + layout: Layout<'_>, + cursor: mouse::Cursor, + viewport: &Rectangle, + ) { + use cosmic::iced_core::image::Renderer; + + // TODO desktop background? + let handle = + Handle::from_path("/usr/share/backgrounds/pop/kate-hazen-COSMIC-desktop-wallpaper.png"); + + let Size { width, height } = renderer.dimensions(&handle); + let image_size = Size::new(width as f32, height as f32); + + let bounds = layout.bounds(); + let adjusted_fit = ContentFit::Cover.fit(image_size, bounds.size()); + + let offset = Vector::new( + (bounds.width - adjusted_fit.width).max(0.0) / 2.0, + (bounds.height - adjusted_fit.height).max(0.0) / 2.0, + ); + + let drawing_bounds = Rectangle { + width: adjusted_fit.width, + height: adjusted_fit.height, + ..bounds + }; + + // layer? + //renderer.with_layer(bounds, |renderer| { + renderer.draw( + handle.clone(), + FilterMethod::default(), + drawing_bounds + offset, + [0.0, 0.0, 0.0, 0.0], + ); + //}); + + self.content.draw( + state, + renderer, + theme, + style, + layout.children().next().unwrap(), + cursor, + viewport, + ) + } + + fn overlay<'b>( + &'b mut self, + tree: &'b mut Tree, + layout: Layout<'_>, + renderer: &cosmic::Renderer, + ) -> Option> { + self.content + .as_widget_mut() + .overlay(tree, layout.children().next().unwrap(), renderer) + } +} + +impl<'a, Msg: 'static> From> for cosmic::Element<'a, Msg> { + fn from(widget: ImageBg<'a, Msg>) -> Self { + cosmic::Element::new(widget) + } +} diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs index a08542e..134fb87 100644 --- a/src/widgets/mod.rs +++ b/src/widgets/mod.rs @@ -5,6 +5,8 @@ use cosmic::iced::{ }; use std::marker::PhantomData; +mod image_bg; +pub use image_bg::image_bg; mod workspace_bar; pub use workspace_bar::workspace_bar;