Upcast and downcast
Since there is an inheritance system in Gtk, it’s only logical to have one as well in Gtk-rs
. Normally, most people won’t need this, but it’s always nice to understand how things work.
Upcasting
This is actually quite simple:
let button = gtk::Button::new_with_label("Click me!");
let widget = button.upcast::<gtk::Widget>();
Since the Button
struct implements IsA<Widget>
, we can upcast into a Widget
. It’s important to note that the IsA
trait is implemented on every widget for every of its parents, which, in here, allows to upcast
the Button
into a Widget
.
Let’s see now a more global usage.
Checking if a widget is another widget
Let’s say you want to write a generic function and want to check if a Widget
is actually a Box
. First, let’s see a bit of code:
fn is_a_box<W: IsA<gtk::Object> + IsA<gtk::Widget> + Clone>(widget: &W) -> bool {
widget.clone().upcast::<gtk::Widget>().is::<gtk::Box>()
}
Ok, so what’s happening in there? First, you’ll note the usage of the IsA
trait. The received widget
needs to implement both IsA<Widget>
and IsA<Object>
.
We need the Object
to be able to use the Cast
trait which contains both upcast
and downcast
methods (take a look to it for other methods as well).
We don’t really need our widget to be a Widget
, we just put it here to make things easier (so we can upcast into a Widget
without troubles).
So the point of this function is to upcast the widget to the highest widget type and then try downcasting it into the wanted object. We could make even more generic like this:
fn is_a<W: IsA<gtk::Object> + IsA<gtk::Widget> + Clone,
T: IsA<gtk::Object> + IsA<gtk::Widget>>(widget: &W) -> bool {
widget.clone().upcast::<gtk::Widget>().downcast::<T>().is_ok()
}
Then let’s test it:
let button = gtk::Button::new_with_label("Click me!");
assert_eq!(is_a::<_, gtk::Container>(&button), true);
assert_eq!(is_a::<_, gtk::Label>(&button), false);