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