How do you convert from a WidgetExt to a ContainerExt and vice versa?

This is a simplified version of my code:

fn get_widget_by_name<T: ContainerExt, K: WidgetExt>(widget_id: String, start: K) -> Option<K> {
    if start.widget_name().to_string() == widget_id {
        return start;
    }
    let bin_type: gtk::glib::Type = 
        gtk::prelude::ObjectExt::type_(&gtk::Window::new(gtk::WindowType::Toplevel))
            .parent()
            .unwrap();
    
    let mut is_bin = bin == start.type_();
    if !is_container {
        let tmp = start.type_().parent();
        if let Some(tmp) = tmp {
            is_container = bin_type == tmp;
        }
    }
    if is_container {
        // I want to call .children() here, but
        // I can't because WidgetExt doesn't
       // implement it, and this function
       // takes a WidgetExt.
    }
    ...
}

In this case I know more than the compiler. The code checks to see if it’s a subclass of Bin, so I’m fine with it returning an Err.

Obviously I could refactor my code so that the function only takes a ContainerExt, and works from there, but then what do I do with e.g. callbacks? Those return gtk::Widgets, which do not implement ContainerExt.

I looked at Any and downcasting,b ut that only supports downcasting to a concrete type.

Is there an idiomatic way to fix this, or am I looking at this from the wrong angle?

Hello, that is a good question. First of all you should not use WidgetExt or ContainerExt as trait bounds in a function. Instead use IsA<Widget> and IsA<Container> like in this example. If you want to know more about the implementation details, check the docs. You’ll notice that the traits like WidgetExt are only implemented in terms of the IsA trait, and they are implemented this way for all types: WidgetExt in gtk4::prelude - Rust

From there you can use upcast method to convert from a derived class to a base class, and downcast to do the reverse. There is also upcast_ref and downcast_ref if you need to avoid some cloning.

There was an old tutorial that explains this a bit more, but it was never moved over to the book.

2 Likes

Thanks, I’ll try that later. :slight_smile:

For what it’s worth, I’m using GTK 3 for this. That’s mainly because I have no idea if GTK4 will be available on the target system.