Understanding Element traits

The view function from trait Application return a iced::Element<Self::Message>.

In order to avoid creating a huge view function I decided to organize the “rendering” into functions:

    fn view(&self) -> iced::Element<Self::Message> {
        match self {
            App::Loading => {
                app_loading::view()
            },
            App::Loaded(state) => {
                select_something::view(state)
            },
            App::ShowMainWindow(state) => {
                main_window::view(state)
            },
            App::ShowDetailsWindow(state) => {
                display_details::view(state)
            },
        }
    }

These new function receiving State Enum all have the same signature:

pub fn view<'a>(s: &'a State) -> Element<'a, Message>

On the main_window::view I return a container with a row! and call the .into() function from the container instance.

pub fn view<'a>(s: &'a State) -> Element<'a, Message> {
    container(
        row![
            other_view_a::view(s),
            other_view_b::view(s),
        ],
    )
    .width(Length::Fill)
    .height(Length::Fill)
    .center_y()
    .into()
}

But now I decided that was better to replace the static row! with a pane_grid. To do so I’ve created a separated module (double_pane.rs) for that as well:

// trying a dead simple implementation first
pub fn view<'a>(
        s: &'a State,
        left: &Element<'a, Message>,
        right: &Element<'a, Message>,
        ) -> Element<'a, Message> {

    let panegrid = PaneGrid::new(
        &s.main_window_panegrid_state.as_ref().unwrap(),
        |_pane, custom_pane, _is_maximized| {
            let body = if custom_pane.id == PANE_LEFT {
                left
            } else {
                right
            };
            return Content::new(body);
        }
    );

    return container(panegrid)
        .width(Length::Fill)
        .height(Length::Fill)
        .into();
}

The “two panels” are properly initialized on the State workflow and ready to display widgets.

My problem here is with setting the Content::new(body) which currently raises:

the trait bound `iced_core::element::Element<'_, _, _>: From<&iced_core::element::Element<'_, Message, iced_renderer::Renderer<Theme>>>` is not satisfied
required for `&iced_core::element::Element<'_, Message, iced_renderer::Renderer<Theme>>` to implement `Into<iced_core::element::Element<'_, _, _>>`

Which is going over my head at the moment because I’ve no idea from where did the iced_core::element::Element<'_, _, _> came from and how to implement it :sweat_smile:

Before I started passing the “left” and “right” elements I tested the panels with some “internally set” of widgets (created inside the PaneGrid::new’s view closure) and it did not complained about traits not being satisfied.

My initial idea was to reuse the pane view with any sort views but it sounds like I might need a separated pane_grid per combination of views?

Really confused here. :grimacing:

You can’t use references to Element. Pass left and right by value.

It raises:

cannot move out of left, a captured variable in an Fn closure
move occurs because left has type iced_core::element::Element<'_, Message, iced_renderer::Renderer<Theme>>, which does not implement the Copy trait

Same goes to right argument.

You need to mark the closure as move:

    let panegrid = PaneGrid::new(
        &s.main_window_panegrid_state.as_ref().unwrap(),
        move |_pane, custom_pane, _is_maximized| {
            let body = if custom_pane.id == PANE_LEFT {
                left
            } else {
                right
            };
            return Content::new(body);
        }
    );

I might be wrong here but I believe the view closure from PaneGrid::new is qualified to be called multiply times since we don’t know how many panels we need to render.

That should means: we cannot really move values from outside because it cannot assure we would NOT access the ones already consume.

Does that makes sense or am I tripping again?

You are right! Pass closures and move those:

pub fn view<'a>(
        s: &'a State,
        left: impl Fn() -> Element<'a, Message>,
        right: impl Fn() -> Element<'a, Message>,
        ) -> Element<'a, Message> {

    let panegrid = PaneGrid::new(
        &s.main_window_panegrid_state.as_ref().unwrap(),
        move |_pane, custom_pane, _is_maximized| {
            let body = if custom_pane.id == PANE_LEFT {
                left()
            } else {
                right()
            };
            return Content::new(body);
        }
    );

    return container(panegrid)
        .width(Length::Fill)
        .height(Length::Fill)
        .into();
}

starting to think that the best approach to something like this would be a macro. that would allow me to right the content of the two panels without having to write all the boilerplate all the time and would assure that the content is actually owned by the panegrid closure.