Search code examples
gtkgtk3vala

Determine number of visible Gtk.FlowBox children


I'm using a Gtk.FlowBox with a number of Gtk.FlowBoxChild children. Based on buttons selected by a user I'm applying different Gtk.FlowBoxFilterFunc functions. I would like to determine at any point in time how many of the children are visible (i.e. unfiltered). I've tried checking all the various visible, no_show_all properties, as well as the is_visible(), get_visible() functions. I can't seem to find any property or method for determining which children are unfiltered - is this possible?

I've noticed that when I use the GTK Inspector for debugging, it seems to detect the change, because the text in the hierarchy tree changes from black go grey. This makes me think that it must be possible somehow!

MCVE:

public class Mcve.Application : Gtk.Application {

    public Application () {
        Object (
            application_id: Constants.APP_ID,
            flags: ApplicationFlags.FLAGS_NONE
        );
    }

    protected override void activate () {
        var flow_box = new Gtk.FlowBox () {
            expand = true
        };
        var child1 = new Gtk.FlowBoxChild ();
        child1.child = new Gtk.Label ("Child 1");
        var child2 = new Gtk.FlowBoxChild ();
        child2.child = new Gtk.Label ("Child 2");

        flow_box.add (child1);
        flow_box.add (child2);

        var button = new Gtk.Button.with_label ("Filter");
        button.clicked.connect (() => {
            flow_box.set_filter_func ((child) => {
                var item = child.get_child () as Gtk.Label;
                return item.label == "Child 1";
            });
            foreach (var child in flow_box.get_children ()) {
                var item = child as Gtk.FlowBoxChild;
                int index = item.get_index () + 1;
                debug ("[Child %d] item.visible = %s", index, item.visible.to_string ());
                debug ("[Child %d] item.no_show_all = %s", index, item.no_show_all.to_string ());
                debug ("[Child %d] item.is_visible () = %s", index, item.is_visible ().to_string ());
                debug ("[Child %d] item.get_visible () = %s", index, item.get_visible ().to_string ());
                debug ("[Child %d] item.get_child ().visible = %s", index, item.get_child ().visible.to_string ());
                debug ("[Child %d] item.get_child ().no_show_all = %s", index, item.get_child ().no_show_all.to_string ());
                debug ("[Child %d] item.get_child ().is_visible () = %s", index, item.get_child ().is_visible ().to_string ());
                debug ("[Child %d] item.get_child ().get_visible () = %s", index, item.get_child ().get_visible ().to_string ());
            }
        });

        var grid = new Gtk.Grid ();
        grid.attach (flow_box, 0, 0);
        grid.attach (button, 0, 1);

        var window = new Gtk.Window ();
        window.add (grid);

        this.add_window (window);

        window.present ();
        window.show_all ();
    }

    public static int main (string[] args) {
        var app = new Mcve.Application ();
        return app.run (args);
    }

}

Output when clicking to filter:

[Child 1] item.visible = true
[Child 1] item.no_show_all = false
[Child 1] item.is_visible () = true
[Child 1] item.get_visible () = true
[Child 1] item.get_child ().visible = true
[Child 1] item.get_child ().no_show_all = false
[Child 1] item.get_child ().is_visible () = true
[Child 1] item.get_child ().get_visible () = true
[Child 2] item.visible = true
[Child 2] item.no_show_all = false
[Child 2] item.is_visible () = true
[Child 2] item.get_visible () = true
[Child 2] item.get_child ().visible = true
[Child 2] item.get_child ().no_show_all = false
[Child 2] item.get_child ().is_visible () = true
[Child 2] item.get_child ().get_visible () = true

In the GTK Inspector, I can see that it somehow knows that the second child is not visible:

GTK Inspector


Edit: Looks like the GTK Inspector responds to the mapped signal: https://github.com/GNOME/gtk/blob/main/gtk/inspector/object-tree.c#L700, and indeed calling get_mapped () on the FlowBoxChild will return true or false depending on whether the item is visible. I'm not really sure what it means for a widget to be mapped though, so I'm a bit hesitant to trust this.


Solution

  • This is possible using the get_mapped() method on the Gtk.FlowBoxChild widget.

    Like @BobMorane mentioned in the comments, the GTK documentation has the following entry for the map signal:

    A widget is mapped when the widget is visible (which is controlled with GtkWidget:visible) and all its parents up to the toplevel widget are also visible. The ::map signal can be used to determine whether a widget will be drawn