浏览代码

working css apply

ncannasse 6 年之前
父节点
当前提交
1199cc7905
共有 5 个文件被更改,包括 122 次插入22 次删除
  1. 22 12
      h2d/uikit/Builder.hx
  2. 67 8
      h2d/uikit/CssStyle.hx
  3. 28 0
      h2d/uikit/Document.hx
  4. 4 1
      h2d/uikit/Element.hx
  5. 1 1
      h2d/uikit/Property.hx

+ 22 - 12
h2d/uikit/Builder.hx

@@ -12,21 +12,31 @@ class Builder {
 	}
 
 	function error( msg : String ) {
-		errors.push(path.join(".")+": "+msg);
+		errors.push(msg+" "+path.join("."));
 	}
 
 	function loadTile( path : String ) {
 		return hxd.res.Loader.currentInstance.load(path).toTile();
 	}
 
-	public function build( x : Xml, ?root : Element ) {
-		if( root == null )
-			root = new Element(new h2d.Flow(), Component.get("flow"));
+	public function build( x : Xml ) : Document {
+		var doc = new Document();
 		switch( x.nodeType ) {
 		case Document:
-			for( e in x )
-				build(e, root);
-		case Comment, DocType, ProcessingInstruction:
+			for( e in x ) {
+				var e = buildRec(e, null);
+				if( e != null ) doc.elements.push(e);
+			}
+		default:
+			var e = buildRec(x, null);
+			if( e != null ) doc.elements.push(e);
+		}
+		return doc;
+	}
+
+	function buildRec( x : Xml, root : Element ) {
+		switch( x.nodeType ) {
+		case Comment, DocType, ProcessingInstruction, Document:
 			// nothing
 		case CData, PCData:
 			if( !IS_EMPTY.match(x.nodeValue) ) {
@@ -36,9 +46,9 @@ class Builder {
 			path.push(x.nodeName);
 			var comp = @:privateAccess Component.COMPONENTS.get(x.nodeName);
 			if( comp == null ) {
-				error("Uknown node");
+				error("Unknown node");
 			} else {
-				var inst = new Element(comp.make(root.obj), comp, root);
+				var inst = new Element(comp.make(root == null ? null : root.obj), comp, root);
 				var css = new CssParser();
 				for( a in x.attributes() ) {
 					var v = x.get(a);
@@ -60,17 +70,17 @@ class Builder {
 						value = p.parser(pval);
 					} catch( e : Property.InvalidProperty ) {
 						path.push(a);
-						error("Invalid attribute value"+(e.message == null ? "" : " ("+e.message+")"));
+						error("Invalid attribute value"+(e.message == null ? "" : " ("+e.message+") for"));
 						path.pop();
 						continue;
 					}
 					if( !inst.setAttribute(p,value) )
-						error("Unsupported attribute "+a);
+						error("Unsupported attribute "+a+" in");
 				}
 				root = inst;
 			}
 			for( e in x )
-				build(e, root);
+				buildRec(e, root);
 			path.pop();
 		}
 		return root;

+ 67 - 8
h2d/uikit/CssEngine.hx → h2d/uikit/CssStyle.hx

@@ -4,13 +4,16 @@ private class Rule {
 	public var id : Int;
 	public var priority : Int;
 	public var cl : CssParser.CssClass;
-	public var properties : Array<Property.PValue<Dynamic>>;
+	public var style : Array<Property.PValue<Dynamic>>;
+	public var next : Rule;
 	public function new() {
 	}
 }
 
 @:access(h2d.uikit.Element)
-class CssEngine {
+class CssStyle {
+
+	static var TAG = 0;
 
 	var rules : Array<Rule>;
 	var needSort = true;
@@ -20,21 +23,77 @@ class CssEngine {
 	}
 
 	function sortByPriority(r1:Rule, r2:Rule) {
-		var dp = r1.priority - r2.priority;
-		return dp == 0 ? r1.id - r2.id : dp;
+		var dp = r2.priority - r1.priority;
+		return dp == 0 ? r2.id - r1.id : dp;
 	}
 
-	public function applyStyle( e : Element ) {
+	function applyStyle( e : Element, force : Bool ) {
 		if( needSort ) {
 			needSort = false;
 			rules.sort(sortByPriority);
 		}
-		if( e.needStyleRefresh ) {
+		if( e.needStyleRefresh || force ) {
 			e.needStyleRefresh = false;
+			var head = null;
+			var tag = ++TAG;
+			for( p in e.style )
+				p.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);
+					e.component.getHandler(p)(e.obj,p.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;
+					h(e.obj, p.v);
+					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(e.obj, p.v);
+				}
+			// 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 ) {
@@ -53,7 +112,7 @@ class CssEngine {
 				var rule = new Rule();
 				rule.id = rules.length;
 				rule.cl = cl;
-				rule.properties = r.style;
+				rule.style = r.style;
 				rule.priority = priority;
 				rules.push(rule);
 			}
@@ -85,7 +144,7 @@ class CssEngine {
 			if( !found )
 				return false;
 		}
-		if( c.node != null && c.node != e.obj.name )
+		if( c.node != null && c.node != e.component.name )
 			return false;
 		if( c.id != null && c.id != e.id )
 			return false;

+ 28 - 0
h2d/uikit/Document.hx

@@ -0,0 +1,28 @@
+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);
+	}
+
+}

+ 4 - 1
h2d/uikit/Element.hx

@@ -9,6 +9,7 @@ class Element {
 	public var parent : Element;
 	public var children : Array<Element> = [];
 	public var style : Array<Property.PValue<Dynamic>> = [];
+	var currentSet : Array<Property<Dynamic>> = [];
 	var needStyleRefresh : Bool = true;
 
 	public function new(obj,component,?parent) {
@@ -45,8 +46,10 @@ class Element {
 				found = true;
 				break;
 			}
-		if( !found )
+		if( !found ) {
+			currentSet.push(p);
 			style.push(new Property.PValue(p,value));
+		}
 		handler(obj,value);
 		return true;
 	}

+ 1 - 1
h2d/uikit/Property.hx

@@ -12,7 +12,7 @@ class Property<T> {
 	public var id(default,null) : Int;
 	public var defaultValue(default,null) : T;
 	public var parser(default,null) : CssParser.Value -> Dynamic;
-	var tag : Int = 0;
+	@:allow(h2d.uikit.CssStyle) var tag : Int = 0;
 
 	public function new(name,parser,def) {
 		if( MAP.exists(name) )