1 /// Base types for creating GUI controllers
2 module gtkui.base;
3 
4 import gtkui.exception;
5 
6 import gobject.ObjectG;
7 
8 /// Base GUI interface type
9 interface GtkUI
10 {
11     /// For `@gtkwidget` UDA
12     protected struct WidgetUDA { string ns; }
13     /// For `@gtkwidget` UDA
14     static protected auto gtkwidget(string ns="") @property
15     { return WidgetUDA(ns); }
16 
17     /// Automatic initialize `@gtkwidget` fields
18     protected void setUpGtkWidgetFields();
19     ///
20     protected ObjectG getObject(string name);
21 
22     /++ Returns:
23             casted ui object by name (widget for example)
24      +/
25     auto ui(T)(string name, string file=__FILE__, size_t line=__LINE__)
26         if (is(T : ObjectG))
27     {
28         import std.format : format;
29         import std.exception : enforce;
30         auto obj = enforce(getObject(name),
31                 new GUIException(format("can't get object '%s'", name), file, line));
32 
33         return enforce(cast(T)obj,
34                 new GUIException(format("object '%s' has type '%s', not '%s'",
35                         name, obj.getType(), typeid(T).name), file, line));
36     }
37 
38     /++ Insert this mixin in all child classes where used `@gtkwidget`
39         contains:
40             realization of `void setUpGtkWidgetFields()`
41      +/
42     mixin template GtkUIHelper()
43     {
44         protected override void setUpGtkWidgetFields()
45         {
46             import std.traits : hasUDA, getUDAs;
47             import std.format : format;
48             import gobject.ObjectG;
49 
50             alias T = typeof(this);
51 
52             foreach (m; __traits(allMembers, typeof(this)))
53             {
54                 static if (hasUDA!(__traits(getMember, T, m), WidgetUDA))
55                 {
56                     enum uda = getUDAs!(__traits(getMember, T, m), WidgetUDA)[0];
57                     enum name = (uda.ns.length ? uda.ns ~ "." : "") ~ m;
58                     alias F = typeof(__traits(getMember, T, m));
59                     static assert(is(F : ObjectG), format("%s is not an ObjectG", F.stringof));
60                     __traits(getMember, T, m) = ui!F(name);
61                 }
62             }
63         }
64     }
65 }
66 
67 /// Need parent `GtkUI` for working
68 class ChildGtkUI : GtkUI
69 {
70     mixin GtkUIHelper;
71 
72     ///
73     protected GtkUI parent;
74 
75     ///
76     this(GtkUI parent)
77     {
78         this.parent = parent;
79         setUpGtkWidgetFields();
80     }
81 
82     ///
83     override ObjectG getObject(string name)
84     { return parent.getObject(name); }
85 }