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