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 private bool hasPropertyAnnotation(alias ti)() { 87 bool res = false; 88 foreach ( attr; __traits(getFunctionAttributes, ti)) { 89 static if (attr == "@property") { 90 res = true; 91 } 92 } 93 return res; 94 } 95 /* 96 string markupPropertyGetterType(alias overload)() { 97 static if (__traits(getProtection, overload) == "public") { 98 import std.traits; 99 static if (is(typeof(overload) == function) && hasPropertyAnnotation!overload) { 100 alias ret = ReturnType!overload; 101 //alias params = Parameters!overload; 102 alias params = ParameterTypeTuple!overload; 103 static if (params.length == 0 && isMarkupType!ret && !isTemplate!ret) { 104 return ret.stringof; 105 } else { 106 return null; 107 } 108 } else { 109 return null; 110 } 111 } 112 } 113 114 string markupPropertySetterType(alias overload)() { 115 static if (__traits(getProtection, overload) == "public") { 116 import std.traits; 117 static if (is(typeof(overload) == function) && hasPropertyAnnotation!overload) { 118 //alias params = Parameters!overload; 119 alias params = ParameterTypeTuple!overload; 120 static if (params.length == 1 && isMarkupType!(params[0]) && !isTemplate!(params[0])) { 121 return params[0].stringof; 122 } else { 123 return null; 124 } 125 } else { 126 return null; 127 } 128 } 129 } 130 */ 131 132 private template isPublicPropertyFunction(alias overload) { 133 static if (__traits(getProtection, overload) == "public") { 134 static if (hasPropertyAnnotation!overload) { 135 enum isPublicPropertyFunction = true; 136 } else { 137 enum isPublicPropertyFunction = false; 138 } 139 } else { 140 enum isPublicPropertyFunction = false; 141 } 142 //pragma(msg, is(typeof(overload) == function).stringof); 143 //enum isPublicPropertyFunction = (__traits(getProtection, overload) == "public") && is(typeof(overload) == function);// && hasPropertyAnnotation!overload; 144 } 145 146 private template markupPropertyType(alias overload) { 147 import std.traits : ReturnType, ParameterTypeTuple; 148 alias ret = ReturnType!overload; 149 alias params = ParameterTypeTuple!overload; 150 static if (params.length == 0 && isMarkupType!ret /* && !isTemplate!ret*/) { 151 enum string markupPropertyType = ret.stringof; 152 } else static if (params.length == 1 && isMarkupType!(params[0]) /* && !isTemplate!(params[0])*/) { 153 enum string markupPropertyType = params[0].stringof; 154 } else { 155 enum string markupPropertyType = null; 156 } 157 } 158 159 private string[] generatePropertyTypeList(alias T)() { 160 import std.meta; 161 string[] properties; 162 properties ~= "["; 163 foreach(m; __traits(allMembers, T)) { 164 static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){ 165 //static if (is (typeof(__traits(getMember, T, m)) == function)) { 166 static if (__traits(isVirtualMethod, __traits(getMember, T, m))) {// 167 import std.traits : MemberFunctionsTuple; 168 alias overloads = typeof(__traits(getVirtualMethods, T, m)); 169 static if (overloads.length == 2) { 170 static if (isPublicPropertyFunction!(__traits(getVirtualMethods, T, m)[0]) && isPublicPropertyFunction!(__traits(getVirtualMethods, T, m)[1])) { 171 //pragma(msg, m ~ " isPublicPropertyFunction0=" ~ isPublicPropertyFunction!(__traits(getVirtualFunctions, T, m)[0]).stringof); 172 //pragma(msg, m ~ " isPublicPropertyFunction1=" ~ isPublicPropertyFunction!(__traits(getVirtualFunctions, T, m)[1]).stringof); 173 immutable getterType = markupPropertyType!(__traits(getVirtualMethods, T, m)[0]); 174 immutable setterType = markupPropertyType!(__traits(getVirtualMethods, T, m)[1]); 175 static if (getterType && setterType && getterType == setterType) { 176 //pragma(msg, "markup property found: " ~ getterType ~ " " ~ m.stringof); 177 properties ~= "WidgetPropertyMetadata( typeid(" ~ getterType ~ "), " ~ m.stringof ~ " ), "; 178 } 179 } 180 } 181 } 182 } 183 } 184 properties ~= "]"; 185 return properties; 186 } 187 188 string joinStrings(string[] lines) { 189 if (lines.length == 0) 190 return ""; 191 if (lines.length == 1) 192 return lines[0]; 193 else 194 return joinStrings(lines[0 .. $/2]) ~ joinStrings(lines[$/2 .. $]); 195 } 196 197 private string generatePropertiesMetadata(alias T)() if (is(T : Widget)) { 198 version (GENERATE_PROPERTY_METADATA) { 199 //import std.algorithm.searching; 200 //import std.traits : MemberFunctionsTuple; 201 //import std.meta; 202 auto properties = generatePropertyTypeList!T; 203 return joinStrings(properties); 204 } else { 205 return "[]"; 206 } 207 } 208 209 string generateMetadataClass(alias t)() if (is(t : Widget)) { 210 //pragma(msg, moduleName!t); 211 import std.traits; 212 //pragma(msg, getSignalList!t); 213 //pragma(msg, generatePropertiesMetadata!t); 214 immutable string metadataClassName = t.stringof ~ "Metadata"; 215 return "static class " ~ metadataClassName ~ " : WidgetMetadataDef { \n" ~ 216 " override Widget create() {\n" ~ 217 " return new " ~ moduleName!t ~ "." ~ t.stringof ~ "();\n" ~ 218 " }\n" ~ 219 " override string className() {\n" ~ 220 " return \"" ~ t.stringof ~ "\";\n" ~ 221 " }\n" ~ 222 " override string moduleName() {\n" ~ 223 " return \"" ~ moduleName!t ~ "\";\n" ~ 224 " }\n" ~ 225 " override string fullName() {\n" ~ 226 " return \"" ~ moduleName!t ~ "." ~ t.stringof ~ "\";\n" ~ 227 " }\n" ~ 228 " override WidgetPropertyMetadata[] properties() {\n" ~ 229 " return " ~ generatePropertiesMetadata!t ~ ";\n" ~ 230 " }\n" ~ 231 "}\n"; 232 } 233 234 string generateRegisterMetadataClass(alias t)() if (is(t : Widget)) { 235 immutable string metadataClassName = t.stringof ~ "Metadata"; 236 //pragma(msg, metadataClassName); 237 return "registerWidgetMetadata(\"" ~ t.stringof ~ "\", new " ~ t.stringof ~ "Metadata" ~ "());\n"; 238 } 239 240 template registerWidgetMetadataClass(alias t) if (is(t : Widget)) { 241 //pragma(msg, t.stringof); 242 //pragma(msg, generateMetadataClass!t); 243 immutable string classDef = generateMetadataClass!t; 244 immutable string registerDef = "registerWidgetMetadata(\"" ~ t.stringof ~ "\", new " ~ t.stringof ~ "Metadata" ~ "());\n"; 245 enum registerWidgetMetadataClass = classDef ~ registerDef; 246 //mixin(classDef); 247 248 //pragma(msg, "registerWidgetMetadata(\"" ~ t.stringof ~ "\", new " ~ t.stringof ~ "Metadata" ~ "());\n"); 249 //mixin("registerWidgetMetadata(\"" ~ t.stringof ~ "\", new " ~ t.stringof ~ "Metadata" ~ "());\n"); 250 } 251 252 string registerWidgetsFunction(string registerFunctionName = "__gshared static this", T...)() { 253 pragma(msg, registerFunctionName); 254 pragma(msg, T); 255 string[] registerDefs; 256 foreach(t; T) { 257 pragma(msg, t.stringof); 258 //pragma(msg, moduleName!t); 259 // 260 static if (is(t : Widget)) { 261 //pragma(msg, classdef); 262 immutable string registerdef = generateRegisterMetadataClass!t; 263 pragma(msg, registerdef); 264 registerDefs ~= registerdef; 265 } else { 266 pragma(msg, "Skipping non-widget class: " ~ t.stringof); 267 } 268 //registerWidgetMetadata(T.stringof, new Metadata()); 269 } 270 return registerFunctionName ~ "() {\n" ~ joinStrings(registerDefs) ~ "}\n"; 271 } 272 273 string registerWidgets(string registerFunctionName = "__gshared static this", T...)() { 274 pragma(msg, registerFunctionName); 275 pragma(msg, T); 276 string[] classDefs; 277 string[] registerDefs; 278 foreach(t; T) { 279 pragma(msg, t.stringof); 280 //pragma(msg, moduleName!t); 281 // 282 static if (is(t : Widget)) { 283 immutable string classdef = generateMetadataClass!t; 284 //pragma(msg, classdef); 285 immutable string registerdef = generateRegisterMetadataClass!t; 286 pragma(msg, registerdef); 287 classDefs ~= classdef; 288 registerDefs ~= registerdef; 289 } else { 290 pragma(msg, "Skipping non-widget class: " ~ t.stringof); 291 } 292 //registerWidgetMetadata(T.stringof, new Metadata()); 293 } 294 return joinStrings(classDefs) ~ "\n" ~ registerFunctionName ~ "() {\n" ~ joinStrings(registerDefs) ~ "}\n"; 295 } 296 297 /// returns true if passed name is identifier of registered widget class 298 bool isWidgetClassName(string name) { 299 return (name in _registeredWidgets) !is null; 300 } 301