gtkd-developers / GtkD

GtkD is a D binding and OO wrapper of GTK+ originally created by Antonio Monteiro
http://gtkd.org
Other
320 stars 71 forks source link

Add Support for Composite Templates #328

Open Blquinn opened 3 years ago

Blquinn commented 3 years ago

Composite templates are quite convenient when you use UI files. It would be cool to add them!

https://blogs.gnome.org/tvb/2013/04/09/announcing-composite-widget-templates/

MikeWey commented 3 years ago

I agree, i'll try and investigate when i get some time.

Blquinn commented 3 years ago

@MikeWey I did some d exploration because I wanted to see if we could implement something similar to what PyGobject or Vala has in terms of succinctness with these templates. It's a really nice experience to be able to define the children, the resource path for the ui file and callbacks with attributes.

Best solution I could find was with template mixins and user defined attributes.

import std.stdio;

struct GtkTemplate
{
    string ui_resource;
}

struct GtkChild;
struct GtkCallback;

public static GtkTemplate getGtkTemplate(T)() {
    GtkTemplate res;
    static foreach (attr; __traits(getAttributes, T)) {
        static if (is(typeof(attr) == GtkTemplate)) {
            res = attr;
        }
    }
    return res;
}

mixin template GtkTemplateMixin()
{
    private const void initializeTemplate() 
    {
          import std.traits;

          const GtkTemplate res = getGtkTemplate!(typeof(this));
          static if (res.ui_resource == "") {
              pragma(msg, "error: widgets using the GtkTemplateMixin must define the @GtkTemplate attribute.");
          }
          static assert(res.ui_resource != "");

          static foreach (member; __traits(derivedMembers, typeof(this)))
          {
              static if (hasUDA!(__traits(getMember, this, member), GtkChild)) 
              {
                  // TODO: call gtk_widget_class_bind_child
                  pragma(msg, member, " is a GtkChild");
              }

              else static if (hasUDA!(__traits(getMember, this, member), GtkCallback)) 
              {
                  // TODO: call gtk_widget_class_bind_callback
                  pragma(msg, member, " is a GtkCallback");
              }
          }
    }
}

/////////////////////////////////////
// What the user sees.

@GtkTemplate("/the/ui/file.ui")
class MyWidget
{
    @GtkChild string object_property;

    this()
    {
        mixin GtkTemplateMixin;
        initializeTemplate();
    }

    @GtkCallback
    private void foo() {
    }
}

void main()
{
    auto w = new MyWidget();
}