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 /// ditto 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 implementation 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 }