haxe/ui/styles/elements/RuleElement.hx
package haxe.ui.styles.elements;
import haxe.ui.core.Component;
import haxe.ui.styles.Value;
@:access(haxe.ui.core.Component)
class RuleElement {
public var selector:Selector;
public var directives:Map<String, Directive> = new Map<String, Directive>();
public var directiveCount:Int = 0;
public function new(selector:String, directives:Array<Directive>) {
this.selector = new Selector(selector);
//this.directives = directives;
for (d in directives) {
processDirective(d);
directiveCount++;
}
}
public function addDirective(directive:String, value:Value) {
var d = new Directive(directive, value);
processDirective(d);
}
public function match(d:Component):Bool {
return ruleMatch(selector.parts[selector.parts.length - 1], d);
}
private static function ruleMatch( c : SelectorPart, d : Component ):Bool {
if (c.nodeName == "*") {
return true;
}
if (c.id != null && c.id != d.id) {
return false;
}
if (c.className != null) {
for (p in c.classNameParts) {
if (d.hasClass(p) == false) {
return false;
}
}
}
if (c.pseudoClass != null) {
var pc = ":" + c.pseudoClass;
if (d.hasClass(pc) == false) {
return false;
}
}
if (c.nodeName != null) {
var classNodeName:String = @:privateAccess d.nodeName;
if (c.nodeName != classNodeName) {
return false;
}
}
if (c.parent != null) {
if (c.direct == true) {
var p = d.parentComponent;
if (p == null) {
return false;
}
if (!ruleMatch(c.parent, p)) {
return false;
}
} else {
var p = d.parentComponent;
while (p != null) {
if (ruleMatch(c.parent, p)) {
break;
}
p = p.parentComponent;
}
if (p == null) {
return false;
}
}
}
return true;
}
private function processDirective(d:Directive) {
switch (d.directive) {
case "padding":
var vl = ValueTools.composite(d.value);
if (vl.length == 4 || vl.length == 1) {
processComposite(d, ["padding-top", "padding-left", "padding-right", "padding-bottom"]);
} else if (vl.length == 2) {
processComposite(new Directive("", vl[0]), ["padding-top", "padding-bottom"]);
processComposite(new Directive("", vl[1]), ["padding-left", "padding-right"]);
} else if (vl.length == 0) {
processComposite(d, ["padding-top", "padding-left", "padding-right", "padding-bottom"]);
}
case "margin":
var vl = ValueTools.composite(d.value);
if (vl.length == 4 || vl.length == 1) {
processComposite(d, ["margin-top", "margin-left", "margin-right", "margin-bottom"]);
} else if (vl.length == 2) {
processComposite(new Directive("", vl[0]), ["margin-top", "margin-bottom"]);
processComposite(new Directive("", vl[1]), ["margin-left", "margin-right"]);
}
case "background-position":
processComposite(d, ["background-position-x", "background-position-y"]);
case "spacing":
processComposite(d, ["horizontal-spacing", "vertical-spacing"]);
case "background":
processComposite(d, ["background-color", "background-color-end", "background-gradient-style"]);
case "border":
processComposite(d, ["border-size", "border-style", "border-color"]);
case "border-top":
processComposite(d, ["border-top-size", "border-style", "border-top-color"]);
case "border-left":
processComposite(d, ["border-left-size", "border-style", "border-left-color"]);
case "border-bottom":
processComposite(d, ["border-bottom-size", "border-style", "border-bottom-color"]);
case "border-right":
processComposite(d, ["border-right-size", "border-style", "border-right-color"]);
case "border-size":
processComposite(d, ["border-top-size", "border-left-size", "border-right-size", "border-bottom-size"]);
case "border-color":
processComposite(d, ["border-top-color", "border-left-color", "border-right-color", "border-bottom-color"], true);
case "background-image-clip":
processComposite(d, ["background-image-clip-top", "background-image-clip-left", "background-image-clip-bottom", "background-image-clip-right"]);
case "background-image-slice":
processComposite(d, ["background-image-slice-top", "background-image-slice-left", "background-image-slice-bottom", "background-image-slice-right"]);
case "animation":
processComposite(d, ["animation-name", "animation-duration", "animation-timing-function", "animation-delay", "animation-iteration-count", "animation-direction", "animation-fill-mode"]);
case "cursor":
var vl = ValueTools.composite(d.value);
if (vl.length == 1) {
processComposite(new Directive("", Value.VComposite([vl[0], Value.VNumber(0), Value.VNumber(0)])), ["cursor-name", "cursor-offset-x", "cursor-offset-y"]);
} else if (vl.length == 3) {
processComposite(d, ["cursor-name", "cursor-offset-x", "cursor-offset-y"]);
}
case "background-size":
var vl = ValueTools.composite(d.value);
if (vl.length == 1) {
processComposite(new Directive("", vl[0]), ["background-width", "background-height"]);
} else if (vl.length == 2) {
processComposite(d, ["background-width", "background-height"]);
}
case "font-style":
var v1 = ValueTools.composite(d.value);
if (v1 == null) {
v1 = [d.value];
}
for (v in v1) {
var s = ValueTools.string(v).toLowerCase();
if (s == "bold") {
directives.set("font-bold", new Directive("font-bold", Value.VBool(true)));
} else if (s == "italic") {
directives.set("font-italic", new Directive("font-italic", Value.VBool(true)));
} else if (s == "underline") {
directives.set("font-underline", new Directive("font-underline", Value.VBool(true)));
}
}
case _:
directives.set(d.directive, d);
}
}
private function processComposite(d:Directive, parts:Array<String>, duplicate:Bool = false) {
for (p in parts) {
directives.remove(p);
}
switch (d.value) {
case Value.VConstant(_):
case Value.VColor(_):
if (duplicate == false) {
directives.set(parts[0], new Directive(parts[0], d.value));
} else {
for (p in parts) {
directives.set(p, new Directive(p, d.value));
}
}
case Value.VDimension(v):
for (p in parts) {
directives.set(p, new Directive(p, Value.VDimension(v)));
}
case Value.VNumber(_):
for (p in parts) {
directives.set(p, new Directive(p, d.value));
}
case Value.VComposite(vl):
var n = 0;
for (p in parts) {
if (vl[n] != null) {
var nd = new Directive(p, vl[n]);
processDirective(nd);
directives.set(p, nd);
}
n++;
}
case Value.VNone:
for (p in parts) {
var nd = new Directive(p, d.value);
processDirective(nd);
directives.set(p, nd);
}
case Value.VCall(f, vl):
for (p in parts) {
directives.set(p, new Directive(p, d.value));
}
case _:
trace("unknown value type", d.value);
}
}
}