canvas based custom widget within wgpu integration

Hi ! In our wgpu application, we developped a number of custom widgets ( heavily borrowing code and ideas from iced_audio ) which are drawing geometry using the canvas API.

I’ve come up with a simple example in this repository which shows the problem. It is based on the official integration example and features a custom theme and a custom horizontal slider widget which renders geometry using the iced::advanced::graphics::geometry::Renderer draw method. A branch named with-application shows the same example this time implemented with the Application trait, and which compiles correctly.

We get that sort of error messages:

the trait bound `iced_core::Element<'_, Message, iced_widget::iced_graphics::Renderer<iced_wgpu::Backend, theme::Theme>>: From<HSlider<'_, Message, _>>` is not satisfied

I assume something is off in the widget type signature and traits implementations, but after many hours of trying I could not manage to make it work.

Some guidance would be very much appreciated :slight_smile:

I’m not at my computer to test, but your Cargo.lock has some old iced deps in it that may be the root cause here. Maybe try deleting the lock / cargo clean?

I think your hex crate is depending on an older iced version than 0.10

actually the hex crate was not even used in that example, I removed it and did delete the Cargo.lock + cargo clean ( and pushed the changes to master ), but this does not solve the pb

Your HSlider implementation is using iced::Renderer, while Controls::view is expected to return an Element that has an iced_wgpu::Renderer.

These are completely different types. If you want your widget to work everywhere, you need to implement it in a completely generic way. For that, you can only rely on the iced_core traits, which should be available in the iced::advanced module.

I recommend you to look at the custom_widget example or the actual widget implementations in iced_widget.

Alright, I’ve managed to find a solution.

In essence, the fix involved the following steps:

  1. In the controls module, we had to update the renderer so that it isn’t strictly tied to “graphics.” The generic use iced::Renderer should be used instead.

  2. After that change, there’s a type mismatch issue in main.rs where the renderer type of the Program from controls becomes incompatible. To address this, you can use the following workaround in main.rs:

// This initializes the WGPU renderer
let renderer = iced_wgpu::Renderer::new(Backend::new(&device, &queue, Settings::default(), format));

// Then, we wrap the renderer in a type that implements the iced renderer trait
let mut rd = iced_renderer::Renderer::Wgpu(renderer);

let mut state = program::State::new(
    controls,
    viewport.logical_size(),
    &mut rd, // This ensures the renderer is of the correct type
    &mut debug,
);

With these changes, everything should work seamlessly.

It’s easy to get bogged down in all these different types of renderers. (traits, structs, enums, in different crates).