diff --git a/haxe/ui/core/BasicItemRenderer.hx b/haxe/ui/core/BasicItemRenderer.hx index 724b3a42a..bcdd6f767 100644 --- a/haxe/ui/core/BasicItemRenderer.hx +++ b/haxe/ui/core/BasicItemRenderer.hx @@ -31,8 +31,8 @@ class BasicItemRenderer extends ItemRenderer { addComponent(hbox); } - private override function updateValues(value:Dynamic, fieldList:Array = null) { - super.updateValues(value, fieldList); + private override function updateValues(value:Dynamic, fieldList:Array = null, currentRecursionLevel:Null = 0) { + super.updateValues(value, fieldList, currentRecursionLevel); if (_label.text != null) { _label.show(); diff --git a/haxe/ui/core/ItemRenderer.hx b/haxe/ui/core/ItemRenderer.hx index 801f8a5b8..953265bae 100644 --- a/haxe/ui/core/ItemRenderer.hx +++ b/haxe/ui/core/ItemRenderer.hx @@ -1,5 +1,6 @@ package haxe.ui.core; +import haxe.ui.util.RTTI; import haxe.ui.components.Image; import haxe.ui.components.Label; import haxe.ui.containers.Box; @@ -17,6 +18,7 @@ class ItemRenderer extends Box { @:clonable public var autoRegisterInteractiveEvents:Bool = true; @:clonable public var recursiveStyling:Bool = false; @:clonable public var allowLayoutProperties:Bool = true; + @:clonable public var maxRecursionLevel:Null = 5; public function new() { super(); @@ -210,7 +212,11 @@ class ItemRenderer extends Box { dispatch(e2); } - private function updateValues(value:Dynamic, fieldList:Array = null) { + private function updateValues(value:Dynamic, fieldList:Array = null, currentRecursionLevel:Null = 0) { + if (currentRecursionLevel > maxRecursionLevel) { + return; + } + if (fieldList == null) { fieldList = Reflect.fields(value); } @@ -248,7 +254,7 @@ class ItemRenderer extends Box { setComponentProperty(c, v, property); } } else if (Type.typeof(v) == TObject) { - updateValues(v); + updateValues(v, null, currentRecursionLevel + 1); } else { var isLayoutProp = false; if (f == "layout") { @@ -258,7 +264,9 @@ class ItemRenderer extends Box { } if (!isLayoutProp) { try { - Reflect.setProperty(this, f, v); + if (RTTI.hasPrimitiveClassProperty(this.className, f)) { + Reflect.setProperty(this, f, v); + } } catch (e:Dynamic) { } } else if (allowLayoutProperties) { var layoutProp = StringUtil.uncapitalizeFirstLetter(f.substring("layout".length)); diff --git a/haxe/ui/util/RTTI.hx b/haxe/ui/util/RTTI.hx index 97c49548f..6c49da84c 100644 --- a/haxe/ui/util/RTTI.hx +++ b/haxe/ui/util/RTTI.hx @@ -96,7 +96,21 @@ class RTTI { } public static function hasClassProperty(className:String, propertyName:String) { - return getClassProperty(className, propertyName) != null; + var props = getClassProperties(className, false, true); + if (props == null) { + return false; + } + + return props.exists(propertyName); + } + + public static function hasPrimitiveClassProperty(className:String, propertyName:String) { + var props = getClassProperties(className, true, true); + if (props == null) { + return false; + } + + return props.exists(propertyName); } public static function load() { @@ -113,6 +127,62 @@ class RTTI { classInfo = unserializer.unserialize(); } + private static var _allPropertiesCache:Map> = new Map>(); + public static function getClassProperties(className:String, primitiveOnly:Bool = false, allProperties:Bool = true):Map { + className = className.toLowerCase(); + + var cacheKey = className + "_" + primitiveOnly; + + if (allProperties && _allPropertiesCache.exists(cacheKey)) { + return _allPropertiesCache.get(cacheKey); + } + + var entry = classInfo.get(className); + var properties = null; + if (entry != null) { + properties = new Map(); + for (key in entry.properties.keys()) { + var entryProp = entry.properties.get(key); + if (!isPrimitiveProperty(entryProp)) { + continue; + } + properties.set(key, entryProp); + } + + var superClass = entry.superClass; + while (superClass != null) { + var superEntry = getClassInfo(superClass); + if (superEntry == null) { + break; + } + for (key in superEntry.properties.keys()) { + var entryProp = superEntry.properties.get(key); + if (!isPrimitiveProperty(entryProp)) { + continue; + } + properties.set(key, entryProp); + } + superClass = superEntry.superClass; + } + } + + if (allProperties && properties != null) { + _allPropertiesCache.set(cacheKey, properties); + } + + return properties; + } + + private static function isPrimitiveProperty(prop:RTTIProperty):Bool { + if (prop.propertyName == "data") { + return false; + } + if (prop.propertyType == "bool" || prop.propertyType == "int" || prop.propertyType == "float" || prop.propertyType == "string" || prop.propertyType == "variant" || prop.propertyType == "dynamic") { + return true; + } + return false; + } + public static function getClassInfo(className:String):RTTIEntry { load();