1 /+ 2 Vasaro Copyright © 2018 Andrea Fontana 3 This file is part of Vasaro. 4 5 Vasaro is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 3 of the License, or 8 (at your option) any later version. 9 10 Vasaro is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with Vasaro. If not, see <http://www.gnu.org/licenses/>. 17 +/ 18 module gtkattributes; 19 20 template GtkAttributes() 21 { 22 import std.traits; 23 import std.exception : enforce; 24 import gtk.Builder; 25 26 // UDA to support both @ui and @ui("id"); 27 _ui ui(string id = "") { return _ui(id); } 28 struct _ui { string id = ""; } 29 30 // UDA to tag gtk events 31 struct event(T) 32 { 33 string id; 34 string eventName; 35 private alias eventType = T; 36 } 37 38 private string __getWidgetId(alias T, string s)() 39 { 40 // The member we're analyzing 41 mixin("alias member = T." ~ s ~ ";"); 42 43 alias funcUDAs = getUDAs!(member, ui); // @ui("id"); 44 alias structUDAs = getUDAs!(member, _ui); // @ui 45 46 static if (funcUDAs.length + structUDAs.length == 0) return ""; 47 else if (funcUDAs.length + structUDAs.length > 1) assert(0, "You must use only one @ui attribute for `" ~ fullyQualifiedName!s ~ "`"); 48 else 49 { 50 static if (funcUDAs.length == 1) return s; 51 else return structUDAs[0].id; 52 } 53 54 } 55 56 // Version for non-static methods/var 57 private void bindWidgets(T)(ref T obj, Builder b) 58 { 59 foreach( s; __traits( allMembers, T)) 60 { 61 // The member we're analyzing 62 static if (__traits(compiles, mixin("T." ~ s))) 63 { 64 mixin("alias member = T." ~ s ~ ";"); 65 66 static if (isExpressions!member) 67 { 68 enum widgetId = __getWidgetId!(T,s); 69 70 static if (widgetId.length == 0) continue; 71 else 72 { 73 auto tmpObj = b.getObject(widgetId); 74 enforce(tmpObj !is null, "Can't find any widget with id `" ~ widgetId ~ "`"); 75 mixin("obj." ~ s ~ " = cast(typeof(member)) tmpObj;"); 76 mixin("auto tmpMember = obj." ~ s ~ ";"); 77 enforce(tmpMember !is null, "Can't convert `" ~ widgetId ~ "` to `" ~ fullyQualifiedName!(typeof(tmpMember)) ~ "`"); 78 } 79 } 80 } 81 } 82 } 83 84 // Version for static methods/var 85 private void bindWidgets(alias T)(Builder b) 86 { 87 foreach( s; __traits( allMembers, T)) 88 { 89 90 // The member we're analyzing 91 static if (__traits(compiles, mixin("T." ~ s))) 92 { 93 mixin("alias member = T." ~ s ~ ";"); 94 95 static if (isExpressions!member ) 96 { 97 enum widgetId = __getWidgetId!(T,s); 98 99 static if (widgetId.length == 0) continue; 100 else { 101 auto tmpObj = b.getObject(widgetId); 102 enforce(tmpObj !is null, "Can't find any widget with id `" ~ widgetId ~ "`"); 103 member = cast(typeof(member)) tmpObj; 104 enforce(member !is null, "Can't convert `" ~ widgetId ~ "` to `" ~ fullyQualifiedName!(typeof(member)) ~ "`"); 105 } 106 } 107 } 108 } 109 } 110 111 // Version for static methods/var 112 private void bindEvents(alias T)(Builder b) 113 { 114 import std.functional : toDelegate; 115 116 foreach( s; __traits( allMembers, T)) 117 { 118 // The member we're analyzing 119 static if (__traits(compiles, mixin("T." ~ s))) 120 { 121 mixin("alias member = T." ~ s ~ ";"); 122 123 static if (isFunction!member) 124 { 125 alias udas = getUDAs!(member, event); 126 127 static if (udas.length > 0) 128 foreach(u; udas) 129 { 130 enum hasMethod = __traits(hasMember, u.eventType, "add" ~ u.eventName); 131 static assert(hasMethod, "Can't find a method named `add" ~ u.eventName ~ "` for type `" ~ fullyQualifiedName!(u.eventType) ~"`"); 132 133 auto tmpObj = b.getObject(u.id); 134 enforce(tmpObj !is null, "Can't find any widget with id `" ~ u.id ~ "`"); 135 auto obj = cast(u.eventType) tmpObj; 136 enforce(obj !is null, "Can't convert `" ~ u.id ~ "` to `" ~ fullyQualifiedName!(u.eventType) ~ "`"); 137 mixin ("obj.add" ~ u.eventName ~ "((&member).toDelegate());"); 138 } 139 } 140 } 141 } 142 } 143 144 // Version for non-static methods/var 145 private void bindEvents(T)(ref T handler, Builder b) 146 { 147 foreach( s; __traits( allMembers, T)) 148 { 149 static if (__traits(compiles, mixin("T." ~ s))) 150 { 151 mixin("alias member = T." ~ s ~ ";"); 152 153 static if (isFunction!member) 154 { 155 alias udas = getUDAs!(member, event); 156 157 static if (udas.length > 0) 158 foreach(u; udas) 159 { 160 enum hasMethod = __traits(hasMember, u.eventType, "add" ~ u.eventName); 161 static assert(hasMethod, "Can't find a method named `add" ~ u.eventName ~ "` for type `" ~ fullyQualifiedName!(u.eventType) ~"`"); 162 163 auto tmpObj = b.getObject(u.id); 164 enforce(tmpObj !is null, "Can't find any widget with id `" ~ u.id ~ "`"); 165 auto obj = cast(u.eventType) tmpObj; 166 enforce(obj !is null, "Can't convert `" ~ u.id ~ "` to `" ~ fullyQualifiedName!(u.eventType) ~ "`"); 167 mixin ("obj.add" ~ u.eventName ~ "(&handler." ~s ~");"); 168 } 169 } 170 } 171 } 172 } 173 174 private void bindAll(T)(ref T handler, Builder b) 175 { 176 bindWidgets(handler, b); 177 bindEvents(handler, b); 178 } 179 180 private void bindAll(alias T)(Builder b) 181 { 182 bindWidgets!T(b); 183 bindEvents!T(b); 184 } 185 186 }