added ViewBuilder
This commit is contained in:
@@ -142,11 +142,18 @@ class Builder {
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
private static var cache:Map<String, Builder> = new Map<String, Builder>();
|
||||
|
||||
public static function createFromAsset(asset:String, ?key:String):Dynamic {
|
||||
var data = Json.parse(Assets.getText(asset));
|
||||
if (key != null) {
|
||||
data = Reflect.field(data, key);
|
||||
var cacheKey = asset + ":" + key;
|
||||
if (!cache.exists(cacheKey)) {
|
||||
var data = Json.parse(openfl.Assets.getText(asset));
|
||||
if (key != null) {
|
||||
data = Reflect.field(data, key);
|
||||
}
|
||||
cache.set(cacheKey, new Builder(data));
|
||||
}
|
||||
return new Builder(data);
|
||||
return cache.get(cacheKey);
|
||||
}
|
||||
}
|
||||
176
haxework/gui/ViewBuilder.hx
Normal file
176
haxework/gui/ViewBuilder.hx
Normal file
@@ -0,0 +1,176 @@
|
||||
package haxework.gui;
|
||||
|
||||
import haxe.Json;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Context;
|
||||
|
||||
@:remove @:autoBuild(haxework.gui.ViewBuilderImpl.build())
|
||||
extern interface ViewBuilder {}
|
||||
|
||||
class ViewBuilderImpl {
|
||||
#if macro
|
||||
static function loadFileAsString(path:String, json:Bool = true) {
|
||||
try {
|
||||
var p = Context.resolvePath(path);
|
||||
Context.registerModuleDependency(Context.getLocalModule(), p);
|
||||
var content = sys.io.File.getContent(p);
|
||||
return json ? Json.parse(content) : content;
|
||||
}
|
||||
catch(e:Dynamic) {
|
||||
return haxe.macro.Context.error("Failed to load file $path: $e", Context.currentPos());
|
||||
}
|
||||
}
|
||||
|
||||
private static function getTemplate():Array<Dynamic> {
|
||||
var template = null;
|
||||
var style = null;
|
||||
var c = Context.getLocalClass().get();
|
||||
for (m in c.meta.get()) {
|
||||
if (m.name == ":template") {
|
||||
template = switch(m.params[0].expr) {
|
||||
case ExprDef.EConst(Constant.CString(value)): value;
|
||||
case _: null;
|
||||
}
|
||||
if (template != null) {
|
||||
var t = template.split("@");
|
||||
template = loadFileAsString(t[0]);
|
||||
if (t[1] != null) template = Reflect.field(template, t[1]);
|
||||
}
|
||||
style = switch(m.params[1].expr) {
|
||||
case ExprDef.EConst(Constant.CString(value)): value;
|
||||
case _: null;
|
||||
}
|
||||
if (style != null) {
|
||||
style = loadFileAsString(style);
|
||||
}
|
||||
}
|
||||
}
|
||||
return [
|
||||
template,
|
||||
style
|
||||
];
|
||||
}
|
||||
|
||||
private static var i = 0;
|
||||
|
||||
private static function specialValue(data:Array<Expr>, name:String, style:Dynamic, key:String, a:Array<String>):Dynamic {
|
||||
return switch (a[0]) {
|
||||
case "asset":
|
||||
switch (a[1]) {
|
||||
case "image":
|
||||
"openfl.Assets.getBitmapData(\"" + a[2] + "\")";
|
||||
case _:
|
||||
a[2];
|
||||
}
|
||||
case "res":
|
||||
var res = "haxework.provider.Provider.get(haxework.resources.IResources)." + a[1];
|
||||
var bindExpr = res + ".bind(\"" + a[2] + "\", " + name + ", \"" + key + "\")";
|
||||
data.push(Context.parse(bindExpr, Context.currentPos()));
|
||||
//res + ".get(\"" + a[2] + "\")";
|
||||
null;
|
||||
case "locale":
|
||||
"new haxework.locale.LString(\"" + a[1] + "\")";
|
||||
case "class":
|
||||
a[1];
|
||||
case "layout":
|
||||
var template = Json.parse(loadFileAsString(a[1]));
|
||||
return getValue(data, name, style, key, template);
|
||||
case "link":
|
||||
"(links == null) ? untyped this : links[\"" + a[1] + "\"]";
|
||||
case _:
|
||||
throw "Unsupported prefix \"" + a[0] + "\"";
|
||||
}
|
||||
}
|
||||
|
||||
private static function getValue(data:Array<Expr>, name:String, style:Dynamic, key:String, value:Dynamic):Dynamic {
|
||||
return if (Std.is(value, Array)) {
|
||||
value.map(function(v) { return getValue(data, null, style, null, v); });
|
||||
} else if (Std.is(value, String)) {
|
||||
if (value.charAt(0) == "@") {
|
||||
specialValue(data, name, style, key, value.substring(1, value.length).split(":"));
|
||||
} else if (~/(0x|#)[A-Fa-f\d]{6}/.match(value)) {
|
||||
Std.parseInt(StringTools.replace(Std.string(value), "#", "0x"));
|
||||
} else {
|
||||
"\"" + value + "\"";
|
||||
}
|
||||
} else if (Std.is(value, Float) || (Std.is(value, Bool))) {
|
||||
value;
|
||||
} else if (value != null) {
|
||||
if (Reflect.hasField(value, "type")) {
|
||||
var n = "a" + i++;
|
||||
var type = Reflect.field(value, "type");
|
||||
data.push(Context.parse("var " + n + " = new " + type + "()", Context.currentPos()));
|
||||
createElement(data, value, n, style);
|
||||
n;
|
||||
} else {
|
||||
value;
|
||||
}
|
||||
} else {
|
||||
value;
|
||||
}
|
||||
}
|
||||
|
||||
private static function createElement(data:Array<Expr>, template:Dynamic, name:String, style:Dynamic):String {
|
||||
if (Reflect.hasField(template, "style")) {
|
||||
var s = Reflect.field(style, Reflect.field(template, "style"));
|
||||
for (key in Reflect.fields(s)) if (!Reflect.hasField(template, key)) {
|
||||
Reflect.setField(template, key, Reflect.field(s, key));
|
||||
}
|
||||
}
|
||||
for (key in Reflect.fields(template)) {
|
||||
if (["type", "style"].indexOf(key) > -1) continue;
|
||||
var value = getValue(data, name, style, key, Reflect.field(template, key));
|
||||
if (value != null) {
|
||||
data.push(Context.parse(name + "." + key + " = untyped " + value, Context.currentPos()));
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public static function build() {
|
||||
var template = getTemplate();
|
||||
var fields = Context.getBuildFields();
|
||||
|
||||
var data = [];
|
||||
i = 0;
|
||||
createElement(data, template[0], "this", template[1]);
|
||||
|
||||
var init = false;
|
||||
for (f in fields) if (f.name == "init") {
|
||||
init = true;
|
||||
break;
|
||||
}
|
||||
|
||||
fields.push({
|
||||
name: "build",
|
||||
access: [APublic],
|
||||
pos: Context.currentPos(),
|
||||
kind: FFun({
|
||||
args: [{name:"links", type:TPath({name:"Dynamic", pack:[], params:[]}), opt:true, value:null}],
|
||||
expr: macro $b{data},
|
||||
params: [],
|
||||
ret: null
|
||||
})
|
||||
});
|
||||
|
||||
data = [];
|
||||
data.push(macro super());
|
||||
data.push(macro build(links));
|
||||
if (init) data.push(macro init());
|
||||
|
||||
fields.push({
|
||||
name: "new",
|
||||
access: [APublic],
|
||||
pos: Context.currentPos(),
|
||||
kind: FFun({
|
||||
args: [{name:"links", type:TPath({name:"Dynamic", pack:[], params:[]}), opt:true, value:null}],
|
||||
expr: macro $b{data},
|
||||
params: [],
|
||||
ret: null
|
||||
})
|
||||
});
|
||||
|
||||
return fields;
|
||||
}
|
||||
#end
|
||||
}
|
||||
@@ -17,7 +17,7 @@ class PopupView extends GroupView {
|
||||
private var contentView:IGroupView<Dynamic>;
|
||||
private var callback:ICallback<String>;
|
||||
|
||||
public function new(resource:String, ?key:String = null) {
|
||||
public function new(contentViewFactory:Class<IGroupView<Dynamic>>) {
|
||||
super();
|
||||
|
||||
pWidth = 100;
|
||||
@@ -25,7 +25,7 @@ class PopupView extends GroupView {
|
||||
inLayout = false;
|
||||
skin = new ColorSkin(0x000000, 0.6);
|
||||
|
||||
contentView = Builder.createFromAsset(resource, key).build({listener:this});
|
||||
this.contentView = Type.createInstance(contentViewFactory, [{listener:this}]);
|
||||
addView(contentView);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user