Просмотр исходного кода

moved uikit to a standalone library, added uikit sample

Nicolas Cannasse 6 лет назад
Родитель
Сommit
96e5ad1a6c

+ 1 - 1
all.hxml

@@ -3,7 +3,7 @@
 -lib hxbit
 -lib stb_ogg_sound
 --macro include('h3d')
---macro include('h2d',true,['h2d.uikit.MetaComponent'])
+--macro include('h2d',true,['h2d.uikit'])
 --macro include('hxsl',true,['hxsl.Macros','hxsl.CacheFile','hxsl.CacheFileBuilder'])
 --macro include('hxd',true,['hxd.res.FileTree','hxd.Res','hxd.impl.BitsBuilder','hxd.impl.Air3File','hxd.fmt.pak.Build','hxd.impl.LimeStage','hxd.fs.LimeFileSystem','hxd.net.SteamHost','hxd.snd.efx','hxd.snd.openal','hxd.res.Config'])
 --no-output

+ 35 - 12
h2d/uikit/BaseComponents.hx

@@ -1,6 +1,6 @@
 package h2d.uikit;
-import h2d.uikit.Property;
-import h2d.uikit.CssValue;
+import uikit.Property;
+import uikit.CssValue;
 
 class CustomParser extends CssValue.ValueParser {
 
@@ -25,6 +25,34 @@ class CustomParser extends CssValue.ValueParser {
 		}
 	}
 
+
+	function parseColorF( v : CssValue ) : h3d.Vector {
+		var c = parseColor(v);
+		var v = new h3d.Vector();
+		v.setColor(c);
+		return v;
+	}
+
+	function loadResource( path : String ) {
+		#if macro
+		// TODO : compile-time path check?
+		return true;
+		#else
+		return try hxd.res.Loader.currentInstance.load(path) catch( e : hxd.res.NotFound ) invalidProp("Resource not found "+path);
+		#end
+	}
+
+	public function parseTile( v : CssValue) {
+		try {
+			var c = parseColor(v);
+			return #if macro true #else h2d.Tile.fromColor(c,1,1,(c>>>24)/255) #end;
+		} catch( e : InvalidProperty ) {
+			var path = parsePath(v);
+			var p = loadResource(path);
+			return #if macro p #else p.toTile() #end;
+		}
+	}
+
 	public function parseHAlign( value ) : #if macro Bool #else h2d.Flow.FlowAlign #end {
 		switch( parseIdent(value) ) {
 		case "auto":
@@ -105,16 +133,11 @@ class CustomParser extends CssValue.ValueParser {
 		}
 	}
 
-	#if !macro
-	// force macros to be run in order to init base components
-	static var _ = @:privateAccess Macros.init();
-	#end
-
 }
 
 #if !macro
 @:uiComp("object") @:parser(h2d.uikit.BaseComponents.CustomParser)
-class ObjectComp implements h2d.uikit.Component.ComponentDecl<h2d.Object> {
+class ObjectComp implements uikit.Component.ComponentDecl<h2d.Object> {
 
 	@:p(ident) var name : String;
 	@:p var x : Float;
@@ -247,7 +270,7 @@ class ObjectComp implements h2d.uikit.Component.ComponentDecl<h2d.Object> {
 }
 
 @:uiComp("drawable")
-class DrawableComp extends ObjectComp implements h2d.uikit.Component.ComponentDecl<h2d.Drawable> {
+class DrawableComp extends ObjectComp implements uikit.Component.ComponentDecl<h2d.Drawable> {
 
 	@:p(colorF) var color : h3d.Vector;
 	@:p(auto) var smooth : Null<Bool>;
@@ -259,7 +282,7 @@ class DrawableComp extends ObjectComp implements h2d.uikit.Component.ComponentDe
 }
 
 @:uiComp("bitmap")
-class BitmapComp extends DrawableComp implements h2d.uikit.Component.ComponentDecl<h2d.Bitmap> {
+class BitmapComp extends DrawableComp implements uikit.Component.ComponentDecl<h2d.Bitmap> {
 
 	@:p(tile) var src : h2d.Tile;
 
@@ -274,7 +297,7 @@ class BitmapComp extends DrawableComp implements h2d.uikit.Component.ComponentDe
 }
 
 @:uiComp("text")
-class TextComp extends DrawableComp implements h2d.uikit.Component.ComponentDecl<h2d.Text> {
+class TextComp extends DrawableComp implements uikit.Component.ComponentDecl<h2d.Text> {
 
 	@:p var text : String = "";
 	@:p(font) var font : h2d.Font;
@@ -300,7 +323,7 @@ class TextComp extends DrawableComp implements h2d.uikit.Component.ComponentDecl
 
 
 @:uiComp("flow")
-class FlowComp extends DrawableComp implements h2d.uikit.Component.ComponentDecl<h2d.Flow> {
+class FlowComp extends DrawableComp implements uikit.Component.ComponentDecl<h2d.Flow> {
 
 	@:p(auto) var width : Null<Int>;
 	@:p(auto) var height : Null<Int>;

+ 0 - 68
h2d/uikit/Component.hx

@@ -1,68 +0,0 @@
-package h2d.uikit;
-import h2d.uikit.Property;
-
-typedef BaseObject = #if macro Dynamic #else h2d.Object #end;
-
-class PropertyHandler<O,P> {
-
-	public var parser(default,null) : CssValue -> P;
-	#if !macro
-	public var defaultValue(default,null) : P;
-	public var apply(default,null) : O -> P -> Void;
-	#end
-
-
-	#if macro
-	public var defaultValue : haxe.macro.Expr;
-	public var type : haxe.macro.Expr.ComplexType;
-	public var position : haxe.macro.Expr.Position;
-	public var parserExpr : haxe.macro.Expr;
-	public var fieldName : String;
-	#end
-
-	public function new(parser,def,applyType) {
-		this.parser = parser;
-		this.defaultValue = def;
-		#if macro
-		this.type = applyType;
-		#else
-		this.apply = applyType;
-		#end
-	}
-}
-
-interface ComponentDecl<T:BaseObject> {
-}
-
-class Component<T:BaseObject> {
-
-	public var name : String;
-	public var make : BaseObject -> T;
-	public var parent : Component<Dynamic>;
-	var propsHandler : Array<PropertyHandler<T,Dynamic>>;
-
-	public function new(name, make, parent) {
-		this.name = name;
-		this.make = make;
-		this.parent = parent;
-		propsHandler = parent == null ? [] : cast parent.propsHandler.copy();
-		COMPONENTS.set(name, this);
-	}
-
-	public inline function getHandler<P>( p : Property ) : PropertyHandler<T,P> {
-		return cast propsHandler[p.id];
-	}
-
-	function addHandler<P>( p : String, parser : CssValue -> P, def : #if macro haxe.macro.Expr #else P #end, applyType : #if macro haxe.macro.Expr.ComplexType #else T -> P -> Void #end ) {
-		var ph = new PropertyHandler(parser,def,applyType);
-		propsHandler[Property.get(p).id] = ph;
-		return ph;
-	}
-
-	public static function get( name : String ) {
-		return COMPONENTS.get(name);
-	}
-
-	@:persistent static var COMPONENTS = new Map<String,Component<Dynamic>>();
-
-}

+ 0 - 544
h2d/uikit/CssParser.hx

@@ -1,544 +0,0 @@
-package h2d.uikit;
-import h2d.uikit.CssValue;
-
-enum Token {
-	TIdent( i : String );
-	TString( s : String );
-	TInt( i : Int );
-	TFloat( f : Float );
-	TDblDot;
-	TSharp;
-	TPOpen;
-	TPClose;
-	TExclam;
-	TComma;
-	TEof;
-	TPercent;
-	TSemicolon;
-	TBrOpen;
-	TBrClose;
-	TDot;
-	TSpaces;
-	TSlash;
-	TStar;
-}
-
-class CssClass {
-	public var parent : Null<CssClass>;
-	public var node : Null<String>;
-	public var className : Null<String>;
-	public var pseudoClass : Null<String>;
-	public var id : Null<String>;
-	public function new() {
-	}
-}
-
-typedef CssSheet = Array<{ classes : Array<CssClass>, style : Array<{ p : Property, value : CssValue }> }>;
-
-class CssParser {
-
-	var css : String;
-	var pos : Int;
-
-	var spacesTokens : Bool;
-	var tokens : Array<Token>;
-	public var warnings : Array<{ start : Int, end : Int, msg : String }>;
-
-	public function new() {
-	}
-
-	function error( msg : String ) {
-		throw new Error(msg,pos);
-	}
-
-	function unexpected( t : Token ) : Dynamic {
-		error("Unexpected " + tokenString(t));
-		return null;
-	}
-
-	function tokenString( t : Token ) {
-		return switch (t) {
-			case TIdent(i): i;
-			case TString(s): '"'+s+'"';
-			case TInt(i): ""+i;
-			case TFloat(f): ""+f;
-			case TDblDot: ":";
-			case TSharp: "#";
-			case TPOpen: "(";
-			case TPClose: ")";
-			case TExclam: "!";
-			case TComma: ",";
-			case TEof: "EOF";
-			case TPercent: "%";
-			case TSemicolon: ",";
-			case TBrOpen: "{";
-			case TBrClose: "}";
-			case TDot: ".";
-			case TSpaces: "space";
-			case TSlash: "/";
-			case TStar: "*";
-		};
-	}
-
-	function expect( t : Token ) {
-		var tk = readToken();
-		if( tk != t ) unexpected(tk);
-	}
-
-	inline function push( t : Token ) {
-		tokens.push(t);
-	}
-
-	function isToken(t) {
-		var tk = readToken();
-		if( tk == t ) return true;
-		push(tk);
-		return false;
-	}
-
-	public function parse( css : String ) {
-		this.css = css;
-		pos = 0;
-		tokens = [];
-		warnings = [];
-		return parseStyle(TEof);
-	}
-
-	public function parseValue( valueStr : String ) {
-		this.css = valueStr;
-		pos = 0;
-		tokens = [];
-		warnings = [];
-		if( isToken(TEof) )
-			return VString("");
-		var v = readValue();
-		expect(TEof);
-		return v;
-	}
-
-	function valueStr(v) {
-		return switch( v ) {
-		case VIdent(i): i;
-		case VString(s): '"' + s + '"';
-		case VUnit(f, unit): f + unit;
-		case VFloat(f): Std.string(f);
-		case VInt(v): Std.string(v);
-		case VHex(v,_): "#" + v;
-		case VList(l):
-			[for( v in l ) valueStr(v)].join(", ");
-		case VGroup(l):
-			[for( v in l ) valueStr(v)].join(" ");
-		case VCall(f,args): f+"(" + [for( v in args ) valueStr(v)].join(", ") + ")";
-		case VLabel(label, v): valueStr(v) + " !" + label;
-		case VSlash: "/";
-		}
-	}
-
-	function parseStyle( eof ) {
-		var style = [];
-		while( true ) {
-			if( isToken(eof) )
-				break;
-			var start = pos;
-			var name = readIdent();
-			expect(TDblDot);
-			var value = readValue();
-			var p = Property.get(name, false);
-			if( p == null )
-				warnings.push({ start : start, end : pos, msg : "Unknown property "+name });
-			else
-				style.push({ p : p, value : value });
-			if( isToken(eof) )
-				break;
-			expect(TSemicolon);
-		}
-		return style;
-	}
-
-	public function parseSheet( css : String ) : CssSheet {
-		this.css = css;
-		pos = 0;
-		tokens = [];
-		warnings = [];
-		var rules : CssSheet = [];
-		while( true ) {
-			if( isToken(TEof) )
-				break;
-			var classes = readClasses();
-			expect(TBrOpen);
-			rules.push({ classes : classes, style : parseStyle(TBrClose) });
-		}
-		return rules;
-	}
-
-	public function parseClasses( css : String ) {
-		this.css = css;
-		pos = 0;
-		tokens = [];
-		var c = readClasses();
-		expect(TEof);
-		return c;
-	}
-
-	// ----------------- class parser ---------------------------
-
-	function readClasses() {
-		var classes = [];
-		while( true ) {
-			spacesTokens = true;
-			isToken(TSpaces); // skip
-			var c = readClass(null);
-			spacesTokens = false;
-			if( c == null ) break;
-			classes.push(c);
-			if( !isToken(TComma) )
-				break;
-		}
-		if( classes.length == 0 )
-			unexpected(readToken());
-		return classes;
-	}
-
-	function readClass( parent ) : CssClass {
-		var c = new CssClass();
-		c.parent = parent;
-		var def = false;
-		var last = null;
-		while( true ) {
-			var t = readToken();
-			if( last == null )
-				switch( t ) {
-				case TStar: def = true;
-				case TDot, TSharp, TDblDot: last = t;
-				case TIdent(i): c.node = i; def = true;
-				case TSpaces:
-					return def ? readClass(c) : null;
-				case TBrOpen, TComma, TEof:
-					push(t);
-					break;
-				default:
-					unexpected(t);
-				}
-			else
-				switch( t ) {
-				case TIdent(i):
-					switch( last ) {
-					case TDot: c.className = i; def = true;
-					case TSharp: c.id = i; def = true;
-					case TDblDot: c.pseudoClass = i; def = true;
-					default: unexpected(last);
-					}
-					last = null;
-				default:
-					unexpected(t);
-				}
-		}
-		return def ? c : parent;
-	}
-
-	// ----------------- value parser ---------------------------
-
-	function readIdent() {
-		var t = readToken();
-		return switch( t ) {
-		case TIdent(i): i;
-		default: unexpected(t);
-		}
-	}
-
-	function readValue(?opt) : CssValue {
-		var t = readToken();
-		var v = switch( t ) {
-		case TSharp:
-			var h = readHex();
-			VHex(h,Std.parseInt("0x"+h));
-		case TIdent(i):
-			var start = pos;
-			var c = next();
-			if( isStrIdentChar(c) ) {
-				do c = next() while( isIdentChar(c) || isNum(c) || isStrIdentChar(c) );
-				pos--;
-				i += css.substr(start, pos - start);
-			} else
-				pos--;
-			VIdent(i);
-		case TString(s):
-			VString(s);
-		case TInt(i):
-			readValueUnit(i, i);
-		case TFloat(f):
-			readValueUnit(f, null);
-		case TSlash:
-			VSlash;
-		default:
-			if( !opt ) unexpected(t);
-			push(t);
-			null;
-		};
-		if( v != null ) v = readValueNext(v);
-		return v;
-	}
-
-	function readHex() {
-		var start = pos;
-		while( true ) {
-			var c = next();
-			if( (c >= "A".code && c <= "F".code) || (c >= "a".code && c <= "f".code) || (c >= "0".code && c <= "9".code) )
-				continue;
-			pos--;
-			break;
-		}
-		return css.substr(start, pos - start);
-	}
-
-	function readValueUnit( f : Float, ?i : Int ) {
-		var t = readToken();
-		return switch( t ) {
-		case TIdent(u):
-			if( u == "px" )
-				(i == null ? VFloat(f) : VInt(i)); // ignore "px" unit suffit
-			else
-				VUnit(f, u);
-		case TPercent:
-			VUnit(f, "%");
-		default:
-			push(t);
-			if( i != null )
-				VInt(i);
-			else
-				VFloat(f);
-		};
-	}
-
-	function readValueNext( v : CssValue ) : CssValue {
-		var t = readToken();
-		return switch( t ) {
-		case TPOpen:
-			switch( v ) {
-			case VIdent(i):
-				switch( i ) {
-				case "url":
-					readValueNext(VCall("url",[VString(readUrl())]));
-				default:
-					var args = switch( readValue() ) {
-					case VList(l): l;
-					case x: [x];
-					}
-					expect(TPClose);
-					readValueNext(VCall(i, args));
-				}
-			default:
-				push(t);
-				v;
-			}
-		case TExclam:
-			var t = readToken();
-			switch( t ) {
-			case TIdent(i):
-				VLabel(i, v);
-			default:
-				unexpected(t);
-			}
-		case TComma:
-			loopComma(v, readValue());
-		default:
-			push(t);
-			var v2 = readValue(true);
-			if( v2 == null )
-				v;
-			else
-				loopNext(v, v2);
-		}
-	}
-
-	function loopNext(v, v2) {
-		return switch( v2 ) {
-		case VGroup(l):
-			l.unshift(v);
-			v2;
-		case VList(l):
-			l[0] = loopNext(v, l[0]);
-			v2;
-		case VLabel(lab, v2):
-			VLabel(lab, loopNext(v, v2));
-		default:
-			VGroup([v, v2]);
-		};
-	}
-
-	function loopComma(v,v2) {
-		return switch( v2 ) {
-		case VList(l):
-			l.unshift(v);
-			v2;
-		case VLabel(lab, v2):
-			VLabel(lab, loopComma(v, v2));
-		default:
-			VList([v, v2]);
-		};
-	}
-
-	// ----------------- lexer -----------------------
-
-	inline function isSpace(c) {
-		return (c == " ".code || c == "\n".code || c == "\r".code || c == "\t".code);
-	}
-
-	inline function isIdentChar(c) {
-		return (c >= "a".code && c <= "z".code) || (c >= "A".code && c <= "Z".code) || (c == "-".code) || (c == "_".code);
-	}
-
-	inline function isStrIdentChar(c) {
-		return c == "/".code || c == ".".code;
-	}
-
-	inline function isNum(c) {
-		return c >= "0".code && c <= "9".code;
-	}
-
-	inline function next() {
-		return StringTools.fastCodeAt(css, pos++);
-	}
-
-	function readUrl() {
-		var c0 = next();
-		while( isSpace(c0) )
-			c0 = next();
-		var quote = c0;
-		if( quote == "'".code || quote == '"'.code ) {
-			pos--;
-			switch( readToken() ) {
-			case TString(s):
-				var c0 = next();
-				while( isSpace(c0) )
-					c0 = next();
-				if( c0 != ")".code )
-					error("Invalid char " + String.fromCharCode(c0));
-				return s;
-			case tk:
-				unexpected(tk);
-			}
-
-		}
-		var start = pos - 1;
-		while( true ) {
-			if( StringTools.isEof(c0) )
-				break;
-			c0 = next();
-			if( c0 == ")".code ) break;
-		}
-		return StringTools.trim(css.substr(start, pos - start - 1));
-	}
-
-	#if false
-	function readToken( ?pos : haxe.PosInfos ) {
-		var t = _readToken();
-		haxe.Log.trace(t, pos);
-		return t;
-	}
-
-	function _readToken() {
-	#else
-	function readToken() {
-	#end
-		var t = tokens.pop();
-		if( t != null )
-			return t;
-		while( true ) {
-			var c = next();
-			if( StringTools.isEof(c) )
-				return TEof;
-			if( isSpace(c) ) {
-				if( spacesTokens ) {
-					while( isSpace(next()) ) {
-					}
-					pos--;
-					return TSpaces;
-				}
-
-				continue;
-			}
-			if( isNum(c) || c == '-'.code ) {
-				var i = 0, neg = false;
-				if( c == '-'.code ) { c = "0".code; neg = true; }
-				do {
-					i = i * 10 + (c - "0".code);
-					c = next();
-				} while( isNum(c) );
-				if( c == ".".code ) {
-					var f : Float = i;
-					var k = 0.1;
-					while( isNum(c = next()) ) {
-						f += (c - "0".code) * k;
-						k *= 0.1;
-					}
-					pos--;
-					return TFloat(neg? -f : f);
-				}
-				pos--;
-				return TInt(neg ? -i : i);
-			}
-			if( isIdentChar(c) ) {
-				var pos = pos - 1;
-				var isStr = false;
-				do c = next() while( isIdentChar(c) || isNum(c) );
-				this.pos--;
-				return TIdent(css.substr(pos,this.pos - pos));
-			}
-			switch( c ) {
-			case ":".code: return TDblDot;
-			case "#".code: return TSharp;
-			case "(".code: return TPOpen;
-			case ")".code: return TPClose;
-			case "!".code: return TExclam;
-			case "%".code: return TPercent;
-			case ";".code: return TSemicolon;
-			case ".".code: return TDot;
-			case "{".code: return TBrOpen;
-			case "}".code: return TBrClose;
-			case ",".code: return TComma;
-			case "*".code: return TStar;
-			case "/".code:
-				var start = pos - 1;
-				if( (c = next()) != '*'.code ) {
-					pos--;
-					return TSlash;
-				}
-				while( true ) {
-					while( (c = next()) != '*'.code ) {
-						if( StringTools.isEof(c) ) {
-							pos = start;
-							error("Unclosed comment");
-						}
-					}
-					c = next();
-					if( c == "/".code ) break;
-					if( StringTools.isEof(c) ) {
-						pos = start;
-						error("Unclosed comment");
-					}
-				}
-				return readToken();
-			case "'".code, '"'.code:
-				var pos = pos;
-				var k;
-				while( (k = next()) != c ) {
-					if( StringTools.isEof(k) ) {
-						this.pos = pos;
-						error("Unclosed string constant");
-					}
-					if( k == "\\".code ) {
-						throw "todo";
-						continue;
-					}
-				}
-				return TString(css.substr(pos, this.pos - pos - 1));
-			default:
-			}
-			pos--;
-			error("Invalid char " + css.charAt(pos));
-		}
-		return null;
-	}
-
-}

+ 0 - 188
h2d/uikit/CssStyle.hx

@@ -1,188 +0,0 @@
-package h2d.uikit;
-
-private class RuleStyle {
-	public var p : Property;
-	public var value : CssValue;
-	public var lastHandler : Component.PropertyHandler<Dynamic,Dynamic>;
-	public var lastValue : Dynamic;
-	public function new(p,value) {
-		this.p = p;
-		this.value = value;
-	}
-}
-
-private class Rule {
-	public var id : Int;
-	public var priority : Int;
-	public var cl : CssParser.CssClass;
-	public var style : Array<RuleStyle>;
-	public var next : Rule;
-	public function new() {
-	}
-}
-
-@:access(h2d.uikit.Element)
-class CssStyle {
-
-	static var TAG = 0;
-
-	var rules : Array<Rule>;
-	var needSort = true;
-
-	public function new() {
-		rules = [];
-	}
-
-	function sortByPriority(r1:Rule, r2:Rule) {
-		var dp = r2.priority - r1.priority;
-		return dp == 0 ? r2.id - r1.id : dp;
-	}
-
-	function applyStyle( e : Element, force : Bool ) {
-		if( needSort ) {
-			needSort = false;
-			rules.sort(sortByPriority);
-		}
-		if( e.needStyleRefresh || force ) {
-			e.needStyleRefresh = false;
-			var head = null;
-			var tag = ++TAG;
-			for( p in e.currentSet )
-				p.tag = tag;
-			for( r in rules ) {
-				if( !ruleMatch(r.cl,e) ) continue;
-				var match = false;
-				for( p in r.style )
-					if( p.p.tag != tag ) {
-						p.p.tag = tag;
-						match = true;
-					}
-				if( match ) {
-					r.next = head;
-					head = r;
-				}
-			}
-			// reset to default previously set properties that are no longer used
-			var changed = false;
-			var ntag = ++TAG;
-			var i = e.currentSet.length - 1;
-			while( i >= 0 ) {
-				var p = e.currentSet[i--];
-				if( p.tag == tag )
-					p.tag = ntag;
-				else {
-					changed = true;
-					e.currentSet.remove(p);
-					var h = e.component.getHandler(p);
-					h.apply(e.obj,h.defaultValue);
-				}
-			}
-			// apply new properties
-			var r = head;
-			while( r != null ) {
-				for( p in r.style ) {
-					var pr = p.p;
-					var h = e.component.getHandler(pr);
-					if( h == null ) continue;
-					if( p.lastHandler != h ) {
-						try {
-							var value = h.parser(p.value);
-							p.lastHandler = h;
-							p.lastValue = value;
-						} catch( e : Property.InvalidProperty ) {
-							// invalid property
-							continue;
-						}
-					}
-					h.apply(e.obj, p.lastValue);
-					changed = true;
-					if( pr.tag != ntag ) {
-						e.currentSet.push(pr);
-						pr.tag = ntag;
-					}
-				}
-				var n = r.next;
-				r.next = null;
-				r = n;
-			}
-			// reapply style properties
-			if( changed )
-				for( p in e.style ) {
-					var h = e.component.getHandler(p.p);
-					if( h != null ) h.apply(e.obj, p.value);
-				}
-			// parent style has changed, we need to sync children
-			force = true;
-		}
-		for( c in e.children )
-			applyStyle(c, force);
-	}
-
-	public function add( sheet : CssParser.CssSheet ) {
-		for( r in sheet ) {
-			for( cl in r.classes ) {
-				var nids = 0, nothers = 0, nnodes = 0;
-				var c = cl;
-				while( c != null ) {
-					if( c.id != null ) nids++;
-					if( c.node != null ) nnodes++;
-					if( c.pseudoClass != null ) nothers++;
-					if( c.className != null ) nothers++;
-					c = c.parent;
-				}
-				var priority = (nids << 16) | (nothers << 8) | nnodes;
-				var rule = new Rule();
-				rule.id = rules.length;
-				rule.cl = cl;
-				rule.style = [for( s in r.style ) new RuleStyle(s.p,s.value)];
-				rule.priority = priority;
-				rules.push(rule);
-			}
-		}
-		needSort = true;
-	}
-
-	public static function ruleMatch( c : CssParser.CssClass, e : Element ) {
-		if( c.pseudoClass != null ) {
-			if( e.classes == null )
-				return false;
-			var pc = ":" + c.pseudoClass;
-			var found = false;
-			for( cc in e.classes )
-				if( cc == pc ) {
-					found = true;
-					break;
-				}
-			if( !found )
-				return false;
-		}
-		if( c.className != null ) {
-			if( e.classes == null )
-				return false;
-			var found = false;
-			for( cc in e.classes )
-				if( cc == c.className ) {
-					found = true;
-					break;
-				}
-			if( !found )
-				return false;
-		}
-		if( c.node != null && c.node != e.component.name )
-			return false;
-		if( c.id != null && c.id != e.id )
-			return false;
-		if( c.parent != null ) {
-			var p = e.parent;
-			while( p != null ) {
-				if( ruleMatch(c.parent, p) )
-					break;
-				p = p.parent;
-			}
-			if( p == null )
-				return false;
-		}
-		return true;
-	}
-
-}

+ 0 - 175
h2d/uikit/CssValue.hx

@@ -1,175 +0,0 @@
-package h2d.uikit;
-import h2d.uikit.Property.InvalidProperty;
-
-enum CssValue {
-	VIdent( i : String );
-	VString( s : String );
-	VUnit( v : Float, unit : String );
-	VFloat( v : Float );
-	VInt( v : Int );
-	VHex( h : String, v : Int );
-	VList( l : Array<CssValue> );
-	VGroup( l : Array<CssValue> );
-	VCall( f : String, vl : Array<CssValue> );
-	VLabel( v : String, val : CssValue );
-	VSlash;
-}
-
-class ValueParser {
-
-	public function new() {
-	}
-
-	public function invalidProp( ?msg ) : Dynamic {
-		throw new InvalidProperty(msg);
-	}
-
-	public function parseIdent( v : CssValue ) {
-		return switch( v ) { case VIdent(v): v; default: invalidProp(); }
-	}
-
-	public function parseString( v : CssValue ) {
-		return switch( v ) {
-		case VIdent(i): i;
-		case VString(s): s;
-		default: invalidProp();
-		}
-	}
-
-	public function parseColor( v : CssValue ) {
-		switch( v ) {
-		case VHex(h,color):
-			if( h.length == 3 ) {
-				var r = color >> 8;
-				var g = (color & 0xF0) >> 4;
-				var b = color & 0xF;
-				r |= r << 4;
-				g |= g << 4;
-				b |= b << 4;
-				color = (r << 16) | (g << 8) | b;
-			}
-			return color | 0xFF000000;
-		default:
-			return invalidProp();
-		}
-	}
-
-	function parseColorF( v : CssValue ) : h3d.Vector {
-		var c = parseColor(v);
-		var v = new h3d.Vector();
-		v.setColor(c);
-		return v;
-	}
-
-	function loadResource( path : String ) {
-		#if macro
-		// TODO : compile-time path check?
-		return true;
-		#else
-		return try hxd.res.Loader.currentInstance.load(path) catch( e : hxd.res.NotFound ) invalidProp("Resource not found "+path);
-		#end
-	}
-
-	public function parseTile( v : CssValue) {
-		try {
-			var c = parseColor(v);
-			return #if macro true #else h2d.Tile.fromColor(c,1,1,(c>>>24)/255) #end;
-		} catch( e : InvalidProperty ) {
-			var path = parsePath(v);
-			var p = loadResource(path);
-			return #if macro p #else p.toTile() #end;
-		}
-	}
-
-	public function parseArray<T>( elt : CssValue -> T, v : CssValue ) : Array<T> {
-		return switch( v ) {
-		case VGroup(vl): [for( v in vl ) elt(v)];
-		default: [elt(v)];
-		}
-	}
-
-	public function parsePath( v : CssValue ) {
-		return switch( v ) {
-		case VString(v): v;
-		case VIdent(v): v;
-		case VCall("url",[VIdent(v) | VString(v)]): v;
-		default: invalidProp();
-		}
-	}
-
-	public function parseBool( v : CssValue ) : Null<Bool> {
-		return switch( v ) {
-		case VIdent("true") | VInt(1): true;
-		case VIdent("false") | VInt(0): false;
-		default: invalidProp();
-		}
-	}
-
-	public function parseAuto<T>( either : CssValue -> T, v : CssValue ) : Null<T> {
-		return v.match(VIdent("auto")) ? null : either(v);
-	}
-
-	public function parseNone<T>( either : CssValue -> T, v : CssValue ) : Null<T> {
-		return v.match(VIdent("none")) ? null : either(v);
-	}
-
-	public function parseInt( v : CssValue ) : Null<Int> {
-		return switch( v ) {
-		case VInt(i): i;
-		default: invalidProp();
-		}
-	}
-
-	public function parseFloat( v : CssValue ) : Float {
-		return switch( v ) {
-		case VInt(i): i;
-		case VFloat(f): f;
-		default: invalidProp();
-		}
-	}
-
-	public function parseXY( v : CssValue ) {
-		return switch( v ) {
-		case VGroup([x,y]): { x : parseFloat(x), y : parseFloat(y) };
-		default: invalidProp();
-		}
-	}
-
-	public function parseBox( v : CssValue ) {
-		switch( v ) {
-		case VInt(v):
-			return { top : v, right : v, bottom : v, left : v };
-		case VGroup([VInt(v),VInt(h)]):
-			return { top : v, right : h, bottom : v, left : h };
-		case VGroup([VInt(v),VInt(h),VInt(k)]):
-			return { top : v, right : h, bottom : k, left : h };
-		case VGroup([VInt(v),VInt(h),VInt(k),VInt(l)]):
-			return { top : v, right : h, bottom : k, left : l };
-		default:
-			return invalidProp();
-		}
-	}
-
-	public function makeEnumParser<T:EnumValue>( e : Enum<T> ) : CssValue -> T {
-		var h = new Map();
-		var all = [];
-		for( v in e.createAll() ) {
-			var id = v.getName().toLowerCase();
-			h.set(id, v);
-			all.push(id);
-		}
-		var choices = all.join("|");
-		return function( v : CssValue ) {
-			return switch( v ) {
-			case VIdent(i):
-				var v = h.get(i);
-				if( v == null ) invalidProp(i+" should be "+choices);
-				return v;
-			default:
-				invalidProp();
-			}
-		}
-
-	}
-
-}

+ 0 - 28
h2d/uikit/Document.hx

@@ -1,28 +0,0 @@
-package h2d.uikit;
-
-class Document {
-
-	public var elements : Array<Element> = [];
-	public var style(default,null) : CssStyle;
-
-	public function new() {
-	}
-
-	public function setStyle( s : CssStyle ) {
-		if( s == null ) s = new CssStyle();
-		style = s;
-		for( e in elements )
-			@:privateAccess s.applyStyle(e,true);
-	}
-
-	public function remove() {
-		for( e in elements )
-			e.remove();
-	}
-
-	public function addTo( obj : h2d.Object ) {
-		for( e in elements )
-			obj.addChild(e.obj);
-	}
-
-}

+ 0 - 127
h2d/uikit/Element.hx

@@ -1,127 +0,0 @@
-package h2d.uikit;
-
-enum SetAttributeResult {
-	Ok;
-	Unknown;
-	Unsupported;
-	InvalidValue( ?msg : String );
-}
-
-class Element {
-
-	public var id : String;
-	public var obj : h2d.Object;
-	public var component : Component<Dynamic>;
-	public var classes : Array<String>;
-	public var parent : Element;
-	public var children : Array<Element> = [];
-	var style : Array<{ p : Property, value : Any }> = [];
-	var currentSet : Array<Property> = [];
-	var needStyleRefresh : Bool = true;
-
-	public function new(obj,component,?parent) {
-		this.obj = obj;
-		this.component = component;
-		this.parent = parent;
-		if( parent != null ) parent.children.push(this);
-	}
-
-	public function remove() {
-		if( parent != null ) {
-			parent.children.remove(this);
-			parent = null;
-		}
-		obj.remove();
-	}
-
-	function initStyle( p : String, value : Dynamic ) {
-		style.push({ p : Property.get(p), value : value });
-	}
-
-	public function initAttributes( attr : haxe.DynamicAccess<String> ) {
-		var parser = new CssParser();
-		for( a in attr.keys() ) {
-			var ret;
-			var p = Property.get(a,false);
-			if( p == null )
-				ret = Unknown;
-			else {
-				var h = component.getHandler(p);
-				if( h == null && p != pclass && p != pid )
-					ret = Unsupported;
-				else
-					ret = setAttribute(a, parser.parseValue(attr.get(a)));
-			}
-			#if sys
-			if( ret != Ok )
-				Sys.println(component.name+"."+a+"> "+ret);
-			#end
-		}
-	}
-
-	public function setAttribute( p : String, value : CssValue ) : SetAttributeResult {
-		var p = Property.get(p,false);
-		if( p == null )
-			return Unknown;
-		if( p.id == pid.id ) {
-			switch( value ) {
-			case VIdent(i):
-				if( id != i ) {
-					id = i;
-					needStyleRefresh = true;
-				}
-			default: return InvalidValue();
-			}
-			return Ok;
-		}
-		if( p.id == pclass.id ) {
-			switch( value ) {
-			case VIdent(i): classes = [i];
-			case VGroup(vl): classes = [for( v in vl ) switch( v ) { case VIdent(i): i; default: return InvalidValue(); }];
-			default: return InvalidValue();
-			}
-			needStyleRefresh = true;
-			return Ok;
-		}
-		var handler = component.getHandler(p);
-		if( handler == null )
-			return Unsupported;
-		var v : Dynamic;
-		try {
-			v = handler.parser(value);
-		} catch( e : Property.InvalidProperty ) {
-			return InvalidValue(e.message);
-		}
-		var found = false;
-		for( s in style )
-			if( s.p == p ) {
-				s.value = v;
-				style.remove(s);
-				style.push(s);
-				found = true;
-				break;
-			}
-		if( !found ) {
-			style.push({ p : p , value : v });
-			for( s in currentSet )
-				if( s == p ) {
-					found = true;
-					break;
-				}
-			if( !found ) currentSet.push(p);
-		}
-		handler.apply(obj,v);
-		return Ok;
-	}
-
-	static var pclass = Property.get("class");
-	static var pid = Property.get("id");
-	public static function create( comp : String, attributes : haxe.DynamicAccess<String>, ?parent : Element, ?value : h2d.Object ) {
-		var c = Component.get(comp);
-		if( c == null ) throw "Unknown component "+comp;
-		var e = new Element(value == null ? c.make(parent == null ? null : parent.obj) : value, c, parent);
-		if( attributes != null ) e.initAttributes(attributes);
-		return e;
-	}
-
-}

+ 0 - 25
h2d/uikit/Error.hx

@@ -1,25 +0,0 @@
-package h2d.uikit;
-
-class Error {
-	public var message : String;
-	public var pmin : Int;
-	public var pmax : Int;
-
-	public function new( messsage, pmin = -1, pmax = -1 ) {
-		this.message = messsage;
-		this.pmin = pmin;
-		this.pmax = pmax < 0 ? pmin + 1 : pmax;
-	}
-
-	public function toString() {
-		var msg = "UIKitError("+message+")";
-		if( pmin < 0 )
-			return msg;
-		msg += " "+pmin;
-		if( pmax == pmin )
-			return msg;
-		msg += ":"+(pmax - pmin);
-		return msg;
-	}
-
-}

+ 19 - 0
h2d/uikit/InitComponents.hx

@@ -0,0 +1,19 @@
+package h2d.uikit;
+import h2d.uikit.BaseComponents.CustomParser;
+
+class InitComponents {
+
+	#if macro
+	public static function initOnce() : Array<haxe.macro.Expr.Field> {
+		if( @:privateAccess uikit.Macros.COMPONENTS.get("object") == null ) {
+			uikit.Macros.registerComponent(macro : h2d.uikit.BaseComponents.ObjectComp);
+			uikit.Macros.registerComponent(macro : h2d.uikit.BaseComponents.DrawableComp);
+			uikit.Macros.registerComponent(macro : h2d.uikit.BaseComponents.FlowComp);
+			uikit.Macros.registerComponent(macro : h2d.uikit.BaseComponents.BitmapComp);
+			uikit.Macros.registerComponent(macro : h2d.uikit.BaseComponents.TextComp);
+		}
+		return null;
+	}
+	#end
+
+}

+ 0 - 195
h2d/uikit/Macros.hx

@@ -1,195 +0,0 @@
-package h2d.uikit;
-#if macro
-import haxe.macro.Context;
-import haxe.macro.Expr;
-import h2d.uikit.BaseComponents.CustomParser;
-import h2d.uikit.Error;
-#end
-
-class Macros {
-
-	static macro function init() {
-		return macro null;
-	}
-
-	#if macro
-
-	@:persistent static var COMPONENTS = new Map<String, h2d.uikit.MetaComponent>();
-	@:persistent static var _ = initComponents();
-	static var __ = addComponents(); // each compilation
-
-	static function initComponents() {
-		registerComponent(macro : h2d.uikit.BaseComponents.ObjectComp);
-		registerComponent(macro : h2d.uikit.BaseComponents.DrawableComp);
-		registerComponent(macro : h2d.uikit.BaseComponents.FlowComp);
-		registerComponent(macro : h2d.uikit.BaseComponents.BitmapComp);
-		registerComponent(macro : h2d.uikit.BaseComponents.TextComp);
-		return 0;
-	}
-
-	public static function registerComponent( type : ComplexType ) {
-		var pos = Context.currentPos();
-		var t = Context.resolveType(type, pos);
-		try {
-			var mt = new h2d.uikit.MetaComponent(t);
-			var td = mt.buildRuntimeComponent();
-			Context.defineType(td);
-			COMPONENTS.set(mt.name, mt);
-		} catch( e : h2d.uikit.MetaComponent.MetaError ) {
-			Context.error(e.message, e.position);
-		}
-	}
-
-	static function addComponents() {
-		haxe.macro.Context.onAfterTyping(function(_) {
-			for( mt in COMPONENTS )
-				Context.resolveType(mt.getRuntimeComponentType(), Context.currentPos());
-		});
-	}
-
-	static function buildComponentsInit( m : MarkupParser.Markup, fields : Array<haxe.macro.Expr.Field>, pos : Position, isRoot = false ) : Expr {
-		switch (m.kind) {
-		case Node(name):
-			var comp = COMPONENTS.get(name);
-			if( comp == null )
-				error("Unknown component "+name, m.pmin, m.pmax);
-			var avalues = [];
-			var aexprs = [];
-			for( attr in m.attributes ) {
-				var p = Property.get(attr.name, false);
-				if( p == null ) {
-					error("Unknown property "+attr.name, attr.pmin, attr.pmin + attr.name.length);
-					continue;
-				}
-				var h = comp.getHandler(p);
-				if( h == null ) {
-					error("Component "+comp.name+" does not handle property "+p.name, attr.pmin, attr.pmin + attr.name.length);
-					continue;
-				}
-				switch( attr.value ) {
-				case RawValue(aval):
-					var css = try new CssParser().parseValue(aval) catch( e : Error ) error("Invalid CSS ("+e.message+")", attr.vmin + e.pmin, attr.vmin + e.pmax);
-					try {
-						if( h.parser == null ) throw new Property.InvalidProperty("Null parser");
-						h.parser(css);
-					} catch( e : Property.InvalidProperty ) {
-						error("Invalid "+comp.name+"."+p.name+" value '"+attr.value+"'"+(e.message == null ? "" : " ("+e.message+")"), attr.vmin, attr.pmax);
-					}
-					avalues.push({ attr : attr.name, value : aval });
-				case Code(e):
-					var mc = Std.instance(comp, MetaComponent);
-					var eset = null;
-					while( mc != null ) {
-						eset = mc.setExprs.get(p.name);
-						if( eset != null ) break;
-						mc = cast(mc.parent, MetaComponent);
-					}
-					aexprs.push(macro var attrib = $e);
-					aexprs.push({ expr : EMeta({ pos : e.pos, name : ":privateAccess" }, { expr : ECall(eset,[macro cast tmp.obj,macro attrib]), pos : e.pos }), pos : e.pos });
-					aexprs.push(macro @:privateAccess tmp.initStyle($v{p.name},attrib));
-				}
-			}
-			var attributes = { expr : EObjectDecl([for( m in avalues ) { field : m.attr, expr : { expr : EConst(CString(m.value)), pos : pos } }]), pos : pos };
-			var ct = comp.baseType;
-			var exprs : Array<Expr> = if( isRoot )
-				[
-					(macro document = new h2d.uikit.Document()),
-					(macro var tmp = h2d.uikit.Element.create($v{name},$attributes,null,(this : $ct))),
-					(macro document.elements.push(tmp)),
-				];
-			else
-				[macro var tmp = h2d.uikit.Element.create($v{name},$attributes, tmp)];
-			for( a in m.attributes )
-				if( a.name == "name" ) {
-					var field = switch( a.value ) {
-					case RawValue(v): v;
-					default: continue;
-					}
-					exprs.push(macro this.$field = cast tmp.obj);
-					fields.push({
-						name : field,
-						access : [APublic],
-						pos : makePos(pos, a.pmin, a.pmax),
-						kind : FVar(ct),
-					});
-				}
-			for( e in aexprs )
-				exprs.push(e);
-			for( c in m.children ) {
-				var e = buildComponentsInit(c, fields, pos);
-				if( e != null ) exprs.push(e);
-			}
-			return macro $b{exprs};
-		case Text(text):
-			var text = StringTools.trim(text);
-			if( text == "" ) return null;
-			return macro {
-				var tmp = h2d.uikit.Element.create("text",null,tmp);
-				tmp.setAttribute("text",VString($v{text}));
-			};
-		}
-	}
-
-	public static function buildObject() {
-		var fields = Context.getBuildFields();
-		for( f in fields )
-			if( f.name == "SRC" ) {
-				switch( f.kind ) {
-				case FVar(_,{ expr : EMeta(_,{ expr : EConst(CString(str)) }), pos : pos }):
-					try {
-						var p = new MarkupParser();
-						var pinf = Context.getPosInfos(pos);
-						var root = p.parse(str,pinf.file,pinf.min).children[0];
-
-						var initExpr = buildComponentsInit(root, fields, pos, true);
-						fields = fields.concat((macro class {
-							public var document : h2d.uikit.Document;
-							public function setStyle( style : h2d.uikit.CssStyle ) {
-								document.setStyle(style);
-							}
-						}).fields);
-
-						var found = false;
-						for( f in fields )
-							if( f.name == "new" ) {
-								switch( f.kind ) {
-								case FFun(f):
-									function replace( e : Expr ) {
-										switch( e.expr ) {
-										case ECall({ expr : EConst(CIdent("initComponent")) },[]): e.expr = initExpr.expr; found = true;
-										default: haxe.macro.ExprTools.iter(e, replace);
-										}
-									}
-									replace(f.expr);
-									if( !found ) Context.error("Constructor missing initComponent() call", f.expr.pos);
-									break;
-								default:
-								}
-							}
-						if( !found )
-							Context.error("Missing constructor", Context.currentPos());
-
-					} catch( e : Error ) {
-						Context.error(e.message, makePos(pos,e.pmin,e.pmax));
-					}
-					fields.remove(f);
-					break;
-				default:
-				}
-			}
-		return fields;
-	}
-
-
-	static function error( msg : String, pmin : Int, pmax : Int = -1 ) : Dynamic {
-		throw new Error(msg, pmin, pmax);
-	}
-
-	static function makePos( p : Position, pmin : Int, pmax : Int ) {
-		var p0 = Context.getPosInfos(p);
-		return Context.makePosition({ min : p0.min + pmin, max : p0.min + pmax, file : p0.file });
-	}
-
-	#end
-
-}

+ 0 - 446
h2d/uikit/MarkupParser.hx

@@ -1,446 +0,0 @@
-package h2d.uikit;
-
-using StringTools;
-
-enum abstract MToken(Int) {
-	var IGNORE_SPACES;
-	var BEGIN;
-	var BEGIN_NODE;
-	var TAG_NAME;
-	var BODY;
-	var ATTRIB_NAME;
-	var EQUALS;
-	var ATTVAL_BEGIN;
-	var ATTRIB_VAL;
-	var ATTRIB_VAL_CODE;
-	var CHILDS;
-	var CLOSE;
-	var WAIT_END;
-	var WAIT_END_RET;
-	var PCDATA;
-	var HEADER;
-	var COMMENT;
-	var DOCTYPE;
-	var CDATA;
-	var ESCAPE;
-}
-
-enum MarkupKind {
-	Node( name : String );
-	Text( text : String );
-}
-
-enum AttributeValue {
-	RawValue( v : String );
-	Code( v : haxe.macro.Expr );
-}
-
-typedef Markup = {
-	var kind : MarkupKind;
-	var pmin : Int;
-	var pmax : Int;
-	var ?attributes : Array<{ name : String, value : AttributeValue, pmin : Int, vmin : Int, pmax : Int }>;
-	var ?children : Array<Markup>;
-}
-
-class MarkupParser {
-
-	static var escapes = {
-		var h = new haxe.ds.StringMap();
-		h.set("lt", "<");
-		h.set("gt", ">");
-		h.set("amp", "&");
-		h.set("quot", '"');
-		h.set("apos", "'");
-		h;
-	}
-
-	var fileName : String;
-	var filePos : Int;
-
-	public function new() {
-	}
-
-	public function parse(str:String,fileName:String,filePos:Int) {
-		var p : Markup = {
-			kind : Node(null),
-			pmin : 0,
-			pmax : 0,
-			children : [],
-		};
-		this.fileName = fileName;
-		this.filePos = filePos;
-		doParse(str, 0, p);
-		return p;
-	}
-
-	function error( msg : String, position : Int, pmax = -1 ) : Dynamic {
-		throw new Error(msg, position, pmax);
-		return null;
-	}
-
-	function parseAttr( val : String, start : Int ) {
-		var v = StringTools.trim(val);
-		if( v.length == 0 || v.charCodeAt(0) != "$".code )
-			return RawValue(val);
-		if( v.charCodeAt(1) == "{".code && v.charCodeAt(v.length-1) == "}".code )
-			v = v.substr(2,v.length - 3);
-		else
-			v = v.substr(1);
-		start += val.indexOf(v);
-		return parseCode(v, start);
-	}
-
-	function parseCode( v : String, start : Int ) {
-		#if macro
-		var e = try haxe.macro.Context.parseInlineString(v,haxe.macro.Context.makePosition({ min : filePos + start, max : filePos + start + v.length, file : fileName })) catch( e : Dynamic ) error(""+e, start, start + v.length);
-		return Code(e);
-		#else
-		return error("Unsupported runtime code attribute", start, start + v.length);
-		#end
-	}
-
-	function doParse(str:String, p:Int = 0, ?parent:Markup):Int {
-		var obj : Markup = null;
-		var state = BEGIN;
-		var next = BEGIN;
-		var aname = null;
-		var start = 0;
-		var nsubs = 0;
-		var nbrackets = 0;
-		var nbraces = 0;
-		var attr_start = 0;
-		var c = str.fastCodeAt(p);
-		var buf = new StringBuf();
-		// need extra state because next is in use
-		var escapeNext = BEGIN;
-		var attrValQuote = -1;
-		inline function addChild(m:Markup) {
-			parent.children.push(m);
-			nsubs++;
-		}
-		while (!StringTools.isEof(c)) {
-			switch(state) {
-				case IGNORE_SPACES:
-					switch(c)
-					{
-						case
-							'\n'.code,
-							'\r'.code,
-							'\t'.code,
-							' '.code:
-						default:
-							state = next;
-							continue;
-					}
-				case BEGIN:
-					switch(c)
-					{
-						case '<'.code:
-							state = IGNORE_SPACES;
-							next = BEGIN_NODE;
-						default:
-							start = p;
-							state = PCDATA;
-							continue;
-					}
-				case PCDATA:
-					if (c == '<'.code)
-					{
-						buf.addSub(str, start, p - start);
-						var child : Markup = {
-							kind : Text(buf.toString()),
-							pmin : start,
-							pmax : p,
-						};
-						buf = new StringBuf();
-						addChild(child);
-						state = IGNORE_SPACES;
-						next = BEGIN_NODE;
-					} else if (c == '&'.code) {
-						buf.addSub(str, start, p - start);
-						state = ESCAPE;
-						escapeNext = PCDATA;
-						start = p + 1;
-					}
-				case CDATA:
-					if (c == ']'.code && str.fastCodeAt(p + 1) == ']'.code && str.fastCodeAt(p + 2) == '>'.code)
-					{
-						var child : Markup = {
-							kind : Text(str.substr(start, p - start)),
-							pmin : start,
-							pmax : p,
-						};
-						addChild(child);
-						p += 2;
-						state = BEGIN;
-					}
-				case BEGIN_NODE:
-					switch(c)
-					{
-						case '!'.code:
-							if (str.fastCodeAt(p + 1) == '['.code)
-							{
-								p += 2;
-								if (str.substr(p, 6).toUpperCase() != "CDATA[")
-									error("Expected <![CDATA[", p);
-								p += 5;
-								state = CDATA;
-								start = p + 1;
-							}
-							else if (str.fastCodeAt(p + 1) == 'D'.code || str.fastCodeAt(p + 1) == 'd'.code)
-							{
-								if(str.substr(p + 2, 6).toUpperCase() != "OCTYPE")
-									error("Expected <!DOCTYPE", p);
-								p += 8;
-								state = DOCTYPE;
-								start = p + 1;
-							}
-							else if( str.fastCodeAt(p + 1) != '-'.code || str.fastCodeAt(p + 2) != '-'.code )
-								error("Expected <!--", p);
-							else
-							{
-								p += 2;
-								state = COMMENT;
-								start = p + 1;
-							}
-						case '?'.code:
-							state = HEADER;
-							start = p;
-						case '/'.code:
-							if( parent == null )
-								error("Expected node name", p);
-							start = p + 1;
-							state = IGNORE_SPACES;
-							next = CLOSE;
-						default:
-							state = TAG_NAME;
-							start = p;
-							continue;
-					}
-				case TAG_NAME:
-					if (!isValidChar(c))
-					{
-						if( p == start )
-							error("Expected node name", p);
-						obj = {
-							kind : Node(str.substr(start, p - start)),
-							pmin : start,
-							pmax : p,
-							attributes : [],
-							children : [],
-						};
-						addChild(obj);
-						state = IGNORE_SPACES;
-						next = BODY;
-						continue;
-					}
-				case BODY:
-					switch(c)
-					{
-						case '/'.code:
-							state = WAIT_END;
-						case '>'.code:
-							state = CHILDS;
-						default:
-							state = ATTRIB_NAME;
-							start = p;
-							continue;
-					}
-				case ATTRIB_NAME:
-					if (!isValidChar(c))
-					{
-						var tmp;
-						if( start == p )
-							error("Expected attribute name", p);
-						tmp = str.substr(start,p-start);
-						aname = tmp;
-						for( a in obj.attributes )
-							if( a.name == aname )
-								error("Duplicate attribute '" + aname + "'", p);
-						attr_start = start;
-						state = IGNORE_SPACES;
-						next = EQUALS;
-						continue;
-					}
-				case EQUALS:
-					switch(c)
-					{
-						case '='.code:
-							state = IGNORE_SPACES;
-							next = ATTVAL_BEGIN;
-						default:
-							error("Expected =", p);
-					}
-				case ATTVAL_BEGIN:
-					switch(c)
-					{
-						case '"'.code | '\''.code:
-							buf = new StringBuf();
-							state = ATTRIB_VAL;
-							start = p + 1;
-							attrValQuote = c;
-						case '{'.code:
-							state = ATTRIB_VAL_CODE;
-							start = p + 1;
-							nbraces = 1;
-						default:
-							error("Expected \"", p);
-					}
-				case ATTRIB_VAL:
-					switch (c) {
-						case '&'.code:
-							buf.addSub(str, start, p - start);
-							state = ESCAPE;
-							escapeNext = ATTRIB_VAL;
-							start = p + 1;
-						case '>'.code | '<'.code:
-							// HTML allows these in attributes values
-							error("Invalid unescaped " + String.fromCharCode(c) + " in attribute value", p);
-						case _ if (c == attrValQuote):
-							buf.addSub(str, start, p - start);
-							var val = buf.toString();
-							buf = new StringBuf();
-							obj.attributes.push({ name : aname, value : parseAttr(val,start), pmin : attr_start, vmin : start, pmax : p });
-							state = IGNORE_SPACES;
-							next = BODY;
-					}
-				case ATTRIB_VAL_CODE:
-					switch( c ) {
-					case '{'.code:
-						nbraces++;
-					case '}'.code:
-						nbraces--;
-						if( nbraces == 0 ) {
-							obj.attributes.push({ name : aname, value : parseCode(str.substr(start, p-start),start), pmin : attr_start, vmin : start, pmax : p });
-							state = IGNORE_SPACES;
-							next = BODY;
-						}
-					}
-				case CHILDS:
-					p = doParse(str, p, obj);
-					start = p;
-					state = BEGIN;
-				case WAIT_END:
-					switch(c)
-					{
-						case '>'.code:
-							state = BEGIN;
-						default :
-							error("Expected >", p);
-					}
-				case WAIT_END_RET:
-					switch(c)
-					{
-						case '>'.code:
-							if( nsubs == 0 )
-								parent.children.push({ kind : Text(""), pmin : p, pmax : p });
-							return p;
-						default :
-							error("Expected >", p);
-					}
-				case CLOSE:
-					if (!isValidChar(c))
-					{
-						if( start == p )
-							error("Expected node name", p);
-
-						var v = str.substr(start,p - start);
-						var ok = true;
-						if( parent == null )
-							ok = false;
-						else switch( parent.kind ) {
-						case Node(name) if( v == name ): // ok
-						case Node(name):
-							error("Unclosed node", parent.pmin, parent.pmax);
-						default:
-							ok = false;
-						}
-						if( !ok )
-							error('Unexpected </$v>', p);
-						state = IGNORE_SPACES;
-						next = WAIT_END_RET;
-						continue;
-					}
-				case COMMENT:
-					if (c == '-'.code && str.fastCodeAt(p +1) == '-'.code && str.fastCodeAt(p + 2) == '>'.code)
-					{
-						//addChild(Xml.createComment(str.substr(start, p - start)));
-						p += 2;
-						state = BEGIN;
-					}
-				case DOCTYPE:
-					if(c == '['.code)
-						nbrackets++;
-					else if(c == ']'.code)
-						nbrackets--;
-					else if (c == '>'.code && nbrackets == 0)
-					{
-						//addChild(Xml.createDocType(str.substr(start, p - start)));
-						state = BEGIN;
-					}
-				case HEADER:
-					if (c == '?'.code && str.fastCodeAt(p + 1) == '>'.code)
-					{
-						p++;
-						var str = str.substr(start + 1, p - start - 2);
-						//addChild(Xml.createProcessingInstruction(str));
-						state = BEGIN;
-					}
-				case ESCAPE:
-					if (c == ';'.code)
-					{
-						var s = str.substr(start, p - start);
-						if (s.fastCodeAt(0) == '#'.code) {
-							var c = s.fastCodeAt(1) == 'x'.code
-								? Std.parseInt("0" +s.substr(1, s.length - 1))
-								: Std.parseInt(s.substr(1, s.length - 1));
-							buf.addChar(c);
-						} else if (!escapes.exists(s)) {
-							error("Undefined entity: " + s, p);
-							buf.add('&$s;');
-						} else {
-							buf.add(escapes.get(s));
-						}
-						start = p + 1;
-						state = escapeNext;
-					} else if (!isValidChar(c) && c != "#".code) {
-						error("Invalid character in entity: " + String.fromCharCode(c), p);
-						buf.addChar("&".code);
-						buf.addSub(str, start, p - start);
-						p--;
-						start = p + 1;
-						state = escapeNext;
-					}
-			}
-			c = str.fastCodeAt(++p);
-		}
-
-		if (state == BEGIN)
-		{
-			start = p;
-			state = PCDATA;
-		}
-
-		if (state == PCDATA)
-		{
-			switch( parent.kind ) {
-			case Node(name) if( name != null ):
-				error("Unclosed node <" + name + ">", p);
-			default:
-			}
-			if (p != start || nsubs == 0) {
-				buf.addSub(str, start, p-start);
-				addChild({ kind : Text(buf.toString()), pmin : start, pmax : p });
-			}
-			return p;
-		}
-
-		error("Unexpected end", p);
-		return p;
-	}
-
-	static inline function isValidChar(c) {
-		return (c >= 'a'.code && c <= 'z'.code) || (c >= 'A'.code && c <= 'Z'.code) || (c >= '0'.code && c <= '9'.code) || c == ':'.code || c == '.'.code || c == '_'.code || c == '-'.code;
-	}
-}

+ 0 - 368
h2d/uikit/MetaComponent.hx

@@ -1,368 +0,0 @@
-package h2d.uikit;
-import haxe.macro.Type;
-import haxe.macro.Expr;
-using haxe.macro.Tools;
-
-class MetaError {
-	public var message : String;
-	public var position : Position;
-	public function new(msg,pos) {
-		this.message = msg;
-		this.position = pos;
-	}
-}
-
-enum ParserMode {
-	PNone;
-	PAuto;
-}
-
-class MetaComponent extends Component<Dynamic> {
-
-	public var baseType : ComplexType;
-	public var parserType : ComplexType;
-	public var setExprs : Map<String, Expr> = new Map();
-	var parser : h2d.uikit.CssValue.ValueParser;
-	var classType : ClassType;
-	var baseClass : ClassType;
-
-	public function new( t : Type ) {
-		classType = switch( t ) {
-		case TInst(c, _): c.get();
-		default: error("Invalid type",haxe.macro.Context.currentPos());
-		}
-
-		var c = classType;
-		var name = getCompName(c);
-		if( name == null ) error("Missing :uiComp", c.pos);
-
-		var fields = [];
-		var ccur = c;
-		var metaParent = null;
-		while( true ) {
-			var fl = ccur.fields.get();
-			fields = fields.concat(fl);
-			if( ccur.superClass == null ) break;
-			var csup = ccur.superClass.t.get();
-			var cname = getCompName(csup);
-			if( cname != null ) {
-				metaParent = Component.get(cname);
-				if( metaParent == null ) error("Missing super component registration "+cname, c.pos);
-				break;
-			}
-			ccur = csup;
-		}
-		super(name,null,metaParent);
-
-		initParser(c);
-		if( name == "object" ) {
-			addHandler("class", parser.parseArray.bind(parser.parseIdent), null, macro : String);
-			addHandler("id", parser.parseIdent, null, macro : String);
-		}
-
-		var baseT = t;
-		for( i in c.interfaces )
-			if( i.t.toString() == "h2d.uikit.ComponentDecl" )
-				baseT = i.params[0];
-		baseClass = switch( baseT.follow() ) { case TInst(c,_): c.get(); default: throw "assert"; };
-		baseType = baseT.toComplexType();
-
-		for( f in fields ) {
-			if( !f.meta.has(":p") ) continue;
-			defineField(f);
-		}
-	}
-
-	function initParser( c : ClassType ) {
-		var pdef = c.meta.extract(":parser")[0];
-		if( pdef == null ) {
-			if( parent != null ) {
-				var parent = cast(parent,MetaComponent);
-				parserType = parent.parserType;
-				parser = parent.parser;
-			} else {
-				parserType = macro : h2d.uikit.CssValue.ValueParser;
-				parser = new h2d.uikit.CssValue.ValueParser();
-			}
-			return;
-		}
-		if( pdef.params.length == 0 )
-			error("Invalid parser definition", pdef.pos);
-		var e = pdef.params[0];
-		var path = [];
-		while( true ) {
-			switch( e.expr ) {
-			case EField(e2, field):
-				path.unshift(field);
-				e = e2;
-			case EConst(CIdent(i)):
-				path.unshift(i);
-				break;
-			default:
-				error("Invalid parser definition", e.pos);
-			}
-		}
-		var name = path.pop();
-		inline function isUpper(str:String) return str.charCodeAt(0) >= 'A'.code && str.charCodeAt(0) <= 'Z'.code;
-		var subType = path.length > 0 && isUpper(path[path.length - 1]) ? path.pop() : null;
-		parserType = TPath({ pack : path, name : subType == null ? name : subType, sub : subType == null ? null : name });
-
-		var clPath = path.length == 0 ? name : path.join(".")+"."+name;
-		var cl = std.Type.resolveClass(clPath);
-		if( cl == null )
-			error("Class "+clPath+" has not been compiled in macros", pdef.pos);
-		parser = std.Type.createInstance(cl,[]);
-	}
-
-	function defineField( f : ClassField ) {
-		var pm = f.meta.extract(":p")[0];
-		var propType = f.type.toComplexType();
-		var t = f.type;
-		while( true )
-			switch( t ) {
-			case TType(_), TLazy(_): t = t.follow(true);
-			default: break;
-			}
-		var prop = null;
-		var parserMode = PNone;
-
-		if( pm.params.length > 0 )
-			switch( pm.params[0].expr ) {
-			case EConst(CIdent("none")):
-				parserMode = PNone;
-			case EConst(CIdent("auto")):
-				parserMode = PAuto;
-			case EConst(CIdent(name)):
-				var fname = "parse"+name.charAt(0).toUpperCase()+name.substr(1);
-				var meth = Reflect.field(this.parser,fname);
-				if( meth == null )
-					error(parserType.toString()+" has no field "+fname, pm.params[0].pos);
-				prop = {
-					def : null,
-					expr : macro (parser.$fname : h2d.uikit.CssValue -> $propType),
-					value : function(css:CssValue) : Dynamic {
-						return Reflect.callMethod(this.parser,meth,[css]);
-					}
-				};
-			default:
-			}
-
-		if( prop == null ) {
-			prop = parserFromType(t, f.pos, parserMode);
-			if( prop == null ) error("Unsupported type "+t.toString()+", use custom parser", f.pos);
-		} else {
-			var pdef = parserFromType(t, f.pos, parserMode);
-			if( pdef != null ) prop.def = pdef.def;
-		}
-
-		switch( f.expr() ) {
-		case null:
-		case { expr : TConst(c), pos : pos }:
-			prop.def = { expr : EConst(switch( c ) {
-				case TString(s): CString(s);
-				case TInt(i): CInt(""+i);
-				case TFloat(f): CFloat(f);
-				case TNull: CIdent("null");
-				case TBool(b): CIdent(b?"true":"false");
-				default: error("Unsupported constant", pos);
-			}), pos : pos };
-		case { expr : TField(_,FEnum(en,ef)), pos : pos }:
-			prop.def = { expr : EConst(CIdent(ef.name)), pos : pos };
-		default:
-			error("Invalid default expr", f.pos);
-		}
-
-		var h = addHandler(fieldToProp(f.name), prop.value, prop.def, propType);
-		h.position = f.pos;
-		h.fieldName = f.name;
-		h.parserExpr = prop.expr;
-	}
-
-	function fieldToProp( name : String ) {
-		if( name.toUpperCase() == name )
-			return name.toLowerCase();
-		var out = new StringBuf();
-		for( i in 0...name.length ) {
-			var c = name.charCodeAt(i);
-			if( c >= "A".code && c <= "Z".code ) {
-				if( i > 0 ) out.addChar("-".code);
-				out.addChar(c - "A".code + "a".code);
-			} else
-				out.addChar(c);
-		}
-		return out.toString().split("_").join("-");
-	}
-
-	function makeTypeExpr( t : BaseType, pos : Position ) {
-		var path = t.module.split(".");
-		if( t.name != path[path.length-1] ) path.push(t.name);
-		return haxe.macro.MacroStringTools.toFieldExpr(path);
-	}
-
-	function parserFromType( t : Type, pos : Position, mode : ParserMode ) : { expr : Expr, value : CssValue -> Dynamic, def : Expr } {
-		switch( t ) {
-		case TAbstract(a,params):
-			switch( a.toString() ) {
-			case "Int": return { expr : macro parser.parseInt, value : parser.parseInt, def : macro 0 };
-			case "Float": return { expr : macro parser.parseFloat, value : parser.parseFloat, def : macro 0. };
-			case "Bool": return { expr : macro parser.parseBool, value : parser.parseBool, def : macro false };
-			case "Null":
-				var p = parserFromType(params[0],pos,mode);
-				if( p != null && p.def != null ) {
-					switch( mode ) {
-					case PNone:
-						p.expr = macro parser.parseNone.bind(${p.expr});
-						p.value = parser.parseNone.bind(p.value);
-					case PAuto:
-						p.expr = macro parser.parseAuto.bind(${p.expr});
-						p.value = parser.parseAuto.bind(p.value);
-					}
-				}
-				return p;
-			default:
-			}
-		case TInst(c,_):
-			switch( c.toString() ) {
-			case "String":
-				return  { expr : macro parser.parseString, value : parser.parseString, def : null };
-			default:
-			}
-		case TEnum(en,_):
-			var idents = [for( n in en.get().names ) n.toLowerCase()];
-			var enexpr = makeTypeExpr(en.get(), pos);
-			return {
-				expr : macro parser.makeEnumParser($enexpr),
-				value : function(css:CssValue) {
-					return switch( css ) {
-					case VIdent(i) if( idents.indexOf(i) >= 0 ): true;
-					case VIdent(v): parser.invalidProp(v+" should be "+idents.join("|"));
-					default: parser.invalidProp();
-					}
-				},
-				def : null,
-			};
-		default:
-		}
-		return null;
-	}
-
-	function getCompName( c : ClassType ) {
-		var name = c.meta.extract(":uiComp")[0];
-		if( name == null ) return null;
-		if( name.params.length == 0 ) error("Invalid :uiComp", name.pos);
-		return switch( name.params[0].expr ) {
-		case EConst(CString(name)): name;
-		default: error("Invalid :uiComp", name.pos);
-		}
-	}
-
-	function error( msg : String, pos : Position ) : Dynamic {
-		throw new MetaError(msg, pos);
-	}
-
-	static function runtimeName( name : String ) {
-		return "Comp"+name.charAt(0).toUpperCase()+name.substr(1);
-	}
-
-	static function setPosRec( e : haxe.macro.Expr, p : Position ) {
-		e.pos = p;
-		haxe.macro.ExprTools.iter(e, function(e) setPosRec(e,p));
-	}
-
-	public function buildRuntimeComponent() {
-		var cname = runtimeName(name);
-		var createMethod = null;
-		var parentExpr;
-		if( parent == null )
-			parentExpr = macro null;
-		else {
-			var parentName = runtimeName(parent.name);
-			parentExpr = macro @:privateAccess h2d.uikit.$parentName.inst;
-		}
-		var path;
-		var setters = new Map();
-		for( f in classType.statics.get() ) {
-			if( !f.kind.match(FMethod(_)) )
-				continue;
-			if( f.name == "create" )
-				createMethod = f;
-			else if( StringTools.startsWith(f.name,"set_") )
-				setters.set(fieldToProp(f.name.substr(4)), true);
-		}
-
-		var classPath = classType.module.split(".");
-		if( classType.name != classPath[classPath.length-1] ) classPath.push(classType.name);
-
-		var newType;
-		if( createMethod != null ) {
-			path = classPath.concat(["create"]);
-			newType = createMethod.type;
-		} else {
-			path = switch( baseType ) {
-			case TPath(p):
-				var path = p.pack.copy();
-				path.push(p.name);
-				if( p.sub != null ) path.push(p.sub);
-				path.push("new");
-				path;
-			default: throw "assert";
-			}
-			newType = baseClass.constructor.get().type;
-		}
-
-		var newExpr = haxe.macro.MacroStringTools.toFieldExpr(path, classType.pos);
-		switch( newType.follow() ) {
-		case TFun(args,_):
-			args.pop(); // parent
-			if( args.length > 0 ) {
-				error("TODO: constructor arguments support", classType.pos);
-			}
-		default:
-		}
-
-		var handlers = [];
-		for( i in 0...propsHandler.length ) {
-			var h = propsHandler[i];
-			if( h == null || h.position == null ) continue;
-			var p = @:privateAccess Property.ALL[i];
-			if( parent != null && parent.propsHandler[i] == h && !setters.exists(p.name) ) continue;
-			var ptype = h.type;
-			var fname = h.fieldName;
-			var set = setters.exists(p.name) ? haxe.macro.MacroStringTools.toFieldExpr(classPath.concat(["set_"+fname])) : macro function(o:$baseType,v:$ptype) o.$fname = v;
-			var def = h.defaultValue == null ? macro null : h.defaultValue;
-			var expr = macro addHandler($v{p.name},@:privateAccess ${h.parserExpr},($def : $ptype),@:privateAccess $set);
-			setPosRec(expr,h.position);
-			setExprs.set(p.name, set);
-			handlers.push(expr);
-		}
-
-		var parserClass = switch( parserType ) {
-		case TPath(t): t;
-		default: throw "assert";
-		}
-		var fields = (macro class {
-			var parser : $parserType;
-			function new() {
-				super($v{this.name},@:privateAccess $newExpr,$parentExpr);
-				parser = new $parserClass();
-				$b{handlers};
-			}
-			static var inst = new h2d.uikit.$cname();
-		}).fields;
-
-		var td : TypeDefinition = {
-			pos : classType.pos,
-			pack : ["h2d","uikit"],
-			name : cname,
-			kind : TDClass({ pack : ["h2d","uikit"], name : "Component", params : [TPType(baseType)] }),
-			fields : fields,
-		};
-		return td;
-	}
-
-	public function getRuntimeComponentType() {
-		var name = runtimeName(name);
-		return macro : h2d.uikit.$name;
-	}
-
-}

+ 3 - 3
h2d/uikit/Object.hx

@@ -1,5 +1,5 @@
 package h2d.uikit;
 
-@:autoBuild(h2d.uikit.Macros.buildObject())
-interface Object {
-}
+@:autoBuild(h2d.uikit.InitComponents.initOnce())
+interface Object extends uikit.Object {
+}

+ 0 - 36
h2d/uikit/Property.hx

@@ -1,36 +0,0 @@
-package h2d.uikit;
-
-class InvalidProperty {
-	public var message : String;
-	public function new(?msg) {
-		this.message = msg;
-	}
-}
-
-class Property {
-	public var name(default,null) : String;
-	public var id(default,null) : Int;
-	@:allow(h2d.uikit.CssStyle) var tag : Int = 0;
-
-	function new(name) {
-		this.id = ALL.length;
-		this.name = name;
-		ALL.push(this);
-		MAP.set(name, this);
-	}
-
-	public static function get( name : String, create = true ) {
-		if( MAP == null ) {
-			MAP = new Map();
-			ALL = [];
-		}
-		var p = MAP.get(name);
-		if( p == null && create )
-			p = new Property(name);
-		return p;
-	}
-
-	@:persistent static var ALL : Array<Property>;
-	@:persistent static var MAP : Map<String, Property>;
-
-}

+ 39 - 0
samples/Uikit.hx

@@ -0,0 +1,39 @@
+
+class View extends h2d.Flow implements h2d.uikit.Object {
+
+	static var SRC =
+	<flow background="#024" padding="20" min-width="200" content-halign={align}>
+		Hello World
+	</flow>;
+
+	public function new(align,?parent) {
+		super(parent);
+		initComponent();
+	}
+
+}
+
+//PARAM=-lib uikit
+class Uikit extends hxd.App {
+
+	var center : h2d.Flow;
+
+	override function init() {
+		var view = new View(Right);
+		center = new h2d.Flow(s2d);
+		center.horizontalAlign = center.verticalAlign = Middle;
+
+		center.addChild(view.document.root.obj);
+		onResize();
+	}
+
+	override function onResize() {
+		center.minWidth = center.maxWidth = s2d.width;
+		center.minHeight = center.maxHeight = s2d.height;
+	}
+
+	static function main() {
+		new Uikit();
+	}
+
+}