Automatic composite widgets using GtkBuilder under the hood.



Hey hackers !
    This Saturday I wrote a patch[0] that I think can revolutionize
the way we write user interfaces using GTK+, its a short patch for GTK+
but can immensely change how GTK+ can be used; as specially from higher
level bindings.

In a nutshell, GtkComposite is a mechinism that puts GtkBuilder under
the hood, basically any GtkComposite class has a GtkBuilder template
attached to its class data, the child interface of a GtkComposite is
automatically built and parented by the time any child constructors
will run, any properties defined as "composite" properties will be
assigned automatically in the same pass, leaving you with a living
and breathing smart composite object after construction.

Now I've had a hard time explaining exactly what it does to people
who dont have a good grasp of GObject in C and found it difficult,
so I'm going to try to outline whats the practical use cases for this
code before getting into details, so we can all be on the same page:

Currently the way we generally write GTK+ code with GtkBuilder is we
write an initialization routine that calls the GtkBuilder, shows the
interface and if we're fancy, maybe some of the interface objects
are implemented by our code, we go on to call gtk_builder_get_object()
and usually we connect the signals by hand just because GtkBuilder
doesnt give you that much in terms of typed user_data for signals
(nor did libglade for that matter).

This technique was cool about 10 years ago, but our losses are:
  - We are interfacing with the GtkBuilder mechanism internally and
    thus exposing alot of technical stuff a developer shoudn't have
    to understand in order to just build some widgets
  - We are adding complexity to UI code by enforcing a standard where
    the controller is not the view, i.e. generally a UI module writes
    a controller object to build its "portion of the GUI", this object
    for all intensive purposes could simply "be" a widget, but instead
    the proxy has to tell it's owned widgets to "show" for example.
  - In the worst cases we are not even writing modular code, and some
    main "bussiness logic" portion of your UI is playing god with all
    the widgets by way of a pre-historic "callbacks.c" code - ugh.

So, I'm trying to introduce a reality without those drawbacks, more
modularity, hidden usage of GtkBuilder and most of all - getting things
done "for free", i.e. when implementing a GtkComposite, you would
simply associate your widget code with a template.ui builder file,
and when you go ahead and write code - you just assume that your
instance variables exist and are assigned (the ones you would
manually assign with gtk_builder_get_object() are auto-assigned
by the syntactic sugar of declaring those properties as
"composite" properties) - furthermore you would expose callbacks
from your composite object class to be autoconnected to the
signals from your template.ui, these callbacks the user could
have the choice to implement them as just local callbacks or
even connect them to api's on the implemented composite object;
letting subclasses redifine what happens when the parent class's
button is "clicked" for instance.

In terms of devtools, what this can do is finally put us on par
with the other leading tools, i.e. imagine that in Glade you could
create a UI mockup,
and then implement portions of your UI as composite widgets at will.

For instance, you could right click on that GtkTable over there,
provide a new symbol name for it and Glade could cut it into a new
Glade file for your new custom Composite class, which can then be
re-added to other places in the interface at will, then the user
would just have to define a GtkComposite class for that newly defined
derived GtkTable, and access the table's children as instance variables
and handle the table's children's callbacks in the widget code.

Composite classes can include instances of any other type of composite
class inside it's own template.ui definition, allowing for unlimited
cascading of UI components.

Now I put an implementation up on bugzilla[0] that I dumped out
saturday afternoon.

So far its got a couple problems:

  - Rafael Burke noted that it should be added api to GtkWidget, and I agree
    only I would put it at the GtkContainer level, this would mean that any
    already existing container could furthermore be extended as composite.

  - Currently the class exposes gtk_composite_class_use_parent_template(), which
    allows you to redefine the child's template to be the fathers - currently
    GtkCompositeClass only parses one template.ui

    I think that GtkComposite should build and add every UI defined in the class
    hierarchy (starting from superclass and building downward), For non GtkBin
    GtkContainer implementations this would mean every child class adds to the
    main box

    This would be good enough to start with, but I would suggest a
mechanism that
    allows an extending class of GtkComposite to specify which exposed composite
    child of its parent that it is loading its interface into.

  - Another point is that the GtkBuilderConnectFunc used for the
composite's internal
    builder needs to be exposed for use in language bindings.

Ok for now this email is getting really long so I'll stop here, for more context
I invite anyone to download the test tarball from bugzilla and look at
test-composite.[ch] ... and then ask themselves - how much code would that be
if it were done in vala or python ? ... language bindings for this IMO should
hide GtkParamSpecComposite and provide syntactic sugar for defining those
variables on instances, like: "connectable var my_button:GtkButton" means
"my_button" will be pulled from my template.ui ... and that ... is where
the money's at...

Im eager to hear your thoughts on this,

Cheers,
          -Tristan

[0] https://bugzilla.gnome.org/show_bug.cgi?id=612036


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]