1 module dlangui.widgets.metadata;
2 
3 import dlangui.widgets.widget;
4 
5 version = GENERATE_PROPERTY_METADATA;
6 
7 interface WidgetMetadataDef {
8     Widget create();
9     /// short class name, e.g. "EditLine"
10     string className();
11     /// module name, e.g. "dlangui.widgets.editors"
12     string moduleName();
13     /// full class name, e.g. "dlangui.widgets.editors.EditLine"
14     string fullName();
15     /// property list, e.g. "backgroundColor"
16     WidgetPropertyMetadata[] properties();
17 }
18 
19 struct WidgetSignalMetadata {
20     string name;
21     string typeString;
22     //TypeTuple
23     TypeInfo returnType;
24     TypeInfo paramsType;
25 }
26 
27 /**
28 * Stores information about property
29 *
30 */
31 struct WidgetPropertyMetadata {
32     TypeInfo type;
33     string name;
34 }
35 
36 private __gshared WidgetMetadataDef[string] _registeredWidgets;
37 
38 string[] getRegisteredWidgetsList()
39 {
40     return _registeredWidgets.keys;
41 }
42 
43 WidgetMetadataDef findWidgetMetadata(string name) {
44     if (auto p = name in _registeredWidgets)
45         return *p;
46     return null;
47 }
48 
49 void registerWidgetMetadata(string name, WidgetMetadataDef metadata) {
50     _registeredWidgets[name] = metadata;
51 }
52 
53 WidgetSignalMetadata[] getSignalList(alias T)() {
54     WidgetSignalMetadata[] res;
55     foreach(m; __traits(allMembers, T)) {
56         static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){
57             // skip non-public members
58             static if (__traits(getProtection, __traits(getMember, T, m)) == "public") {
59                 static if (__traits(compiles, __traits(getMember, T, m).params_t ) && __traits(compiles, __traits(getMember, T, m).return_t)) {
60                     alias ti = typeof(__traits(getMember, T, m));
61                     res ~= WidgetSignalMetadata(m,
62                                                 __traits(getMember, T, m).return_t.stringof ~ __traits(getMember, T, m).params_t.stringof,
63                                                 typeid(__traits(getMember, T, m).return_t),
64                                                 typeid(__traits(getMember, T, m).params_t));
65                 }
66             }
67         }
68     }
69     return res;
70 }
71 
72 template isMarkupType(T)
73 {
74     enum isMarkupType = is(T==int) ||
75                     is(T==float) ||
76                     is(T==double) ||
77                     is(T==bool) ||
78                     is(T==Rect) ||
79                     is(T==string) ||
80                     is(T==dstring) ||
81                     is(T==UIString) ||
82                     is(T==UIString[]) ||
83                     is(T==StringListValue[]);
84 }
85 
86 string generatePropertiesMetadata(alias T)() {
87     version (GENERATE_PROPERTY_METADATA) {
88         import std.algorithm.searching;
89         import std.traits;
90         import std.meta;
91         char[] str;
92         str ~= "[";
93         foreach(m; __traits(allMembers, T)) {
94             static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){
95                 // skip non-public members, only functions that takes 0 or 1 arguments, add only types that parseable in markup
96                 static if (__traits(getProtection, __traits(getMember, T, m)) == "public") {
97                     static if (isFunction!(__traits(getMember, T, m))) {
98                         immutable int fnArity = arity!(__traits(getMember, T, m));
99                         static if (fnArity == 0 || fnArity == 1) {
100                             // TODO: filter out templates, signals and such
101                             // iterates class members and process @property functions (note: foreach {if})
102                             foreach ( attr; __traits(getFunctionAttributes, __traits(getMember, T, m))) if (attr == "@property") {
103                                 alias ret = ReturnType!(__traits(getMember, T, m));
104                                 alias params = Parameters!(__traits(getMember, T, m));
105                                 string typestring;
106                                 static if (fnArity == 0 && !__traits(isTemplate,ret) && isMarkupType!ret)
107                                     typestring = ret.stringof;
108                                 else static if (fnArity == 1 && !__traits(isTemplate,params[0]) && isMarkupType!(params[0]))
109                                     typestring = params[0].stringof;
110                                 if (typestring is null)
111                                     continue;
112                                 str ~= "WidgetPropertyMetadata( typeid(" ~ typestring ~ "), " ~ m.stringof ~ " ), ";
113                             }
114                         }
115                     }
116                 }
117             }
118         }
119         str ~= "]";
120         return cast(string)str;
121     } else {
122         return "[]";
123     }
124 }
125 
126 string generateMetadataClass(alias t)() {
127     //pragma(msg, moduleName!t);
128     import std.traits;
129     //pragma(msg, getSignalList!t);
130     //pragma(msg, generatePropertiesMetadata!t);
131     immutable string metadataClassName = t.stringof ~ "Metadata";
132     return "class " ~ metadataClassName ~ " : WidgetMetadataDef { \n" ~
133         "    override Widget create() {\n" ~
134         "        return new " ~ moduleName!t ~ "." ~ t.stringof ~ "();\n" ~
135         "    }\n" ~
136         "    override string className() {\n" ~
137         "        return \"" ~ t.stringof ~ "\";\n" ~
138         "    }\n" ~
139         "    override string moduleName() {\n" ~
140         "        return \"" ~ moduleName!t ~ "\";\n" ~
141         "    }\n" ~
142         "    override string fullName() {\n" ~
143         "        return \"" ~ moduleName!t ~ "." ~ t.stringof ~ "\";\n" ~
144         "    }\n" ~
145         "    override WidgetPropertyMetadata[] properties() {" ~
146         "        return " ~ generatePropertiesMetadata!t ~ ";\n" ~
147         "    }\n" ~
148         "}\n";
149 }
150 
151 string generateRegisterMetadataClass(alias t)() {
152     immutable string metadataClassName = t.stringof ~ "Metadata";
153     return "registerWidgetMetadata(\"" ~ t.stringof ~ "\", new " ~ metadataClassName ~ "());\n";
154 }
155 
156 string registerWidgets(T...)(string registerFunctionName = "__gshared static this") {
157     string classDefs;
158     string registerDefs;
159     foreach(t; T) {
160         //pragma(msg, t.stringof);
161         //pragma(msg, moduleName!t);
162         //
163         immutable string classdef = generateMetadataClass!t;
164         //pragma(msg, classdef);
165         immutable string registerdef = generateRegisterMetadataClass!t;
166         //pragma(msg, registerdef);
167         classDefs ~= classdef;
168         registerDefs ~= registerdef;
169         //registerWidgetMetadata(T.stringof, new Metadata());
170     }
171     return classDefs ~ "\n" ~ registerFunctionName ~ "() {\n" ~ registerDefs ~ "}";
172 }
173 
174 /// returns true if passed name is identifier of registered widget class
175 bool isWidgetClassName(string name) {
176     return (name in _registeredWidgets) !is null;
177 }
178