Trouble implementing Widget::overlay

I’m creating a custom grid widgets similar to the one in iced_aw but with a different API and to allow for some more flexible layouts like not all rows having the same number of elements.

The idea is that the Grid widget holds GridRows that hold the Elements:

use iced::Element;
use iced_widget::core::{self, overlay, Widget};

pub struct Grid<'a, Message, Renderer = crate::Renderer> {
    rows: Vec<GridRow<'a, Message, Renderer>>,
}

pub struct GridRow<'a, Message, Renderer = crate::Renderer> {
    elements: Vec<Element<'a, Message, Renderer>>,
}

I’m implementing the Widget trait on Grid and following the implementation in iced_aw, I’m deferring most of the actual implementations to the underlying Elements. This works for most methods but I’m getting stuck at the overlay method:

impl<'a, Message, Renderer> Widget<Message, Renderer> for Grid<'a, Message, Renderer>
where
    Renderer: core::Renderer,
{
    // Other trait methods

    fn overlay<'b>(
        &'b mut self,
        tree: &'b mut iced_widget::core::widget::Tree,
        layout: iced_widget::core::Layout<'_>,
        renderer: &Renderer,
    ) -> Option<iced_widget::core::overlay::Element<'b, Message, Renderer>> {
        let mut elements: Vec<&Element<'b, Message, Renderer>> = self
            .rows
            .iter()
            .flat_map(|row| row.elements.iter())
            .collect();
        overlay::from_children(&mut elements, tree, layout, renderer)
    }
}

The problem is that overlay takes a &'a mut [crate::Element<'_, Message, Renderer>] and I’m only able to access references to the Elements so I can’t supply the correct type. I failing to see a way around this issue.

I can refactor Grid to keep a simple Vec of elements but I would need to keep track of their position in the grid which would be a bit messy so I wanted to ask if there’s something I’m overlooking that could make my current approach work.

1 Like

Just in case, did you find the pane_grid example in the iced repo?

Yes but I need something else. I want to lay out widgets that control settings of a program so I need something similar to eguis grid widget. It’s not for displayig data so iced_tableis overkill.

I got it to compile by copy-pasting the implementation of overlay::from_children into my overlay function.

fn overlay<'b>(
    &'b mut self,
    tree: &'b mut iced_widget::core::widget::Tree,
    layout: iced_widget::core::Layout<'_>,
    renderer: &Renderer,
) -> Option<overlay::Element<'b, Message, Renderer>> {
    let children = self
        .rows
        .iter_mut()
        .flat_map(|row| row.elements.iter_mut())
        .zip(&mut tree.children)
        .zip(layout.children())
        .filter_map(|((child, state), layout)| {
            child.as_widget_mut().overlay(state, layout, renderer)
        })
        .collect::<Vec<_>>();
    (!children.is_empty()).then(|| Group::with_children(children).overlay())
}

I feel like the API could be improved to make it a little more flexible but I wasn’t immediately able to get that working.