private void populateNextLevel(System.Object subTreeRoot) { //build a new wrapper for this next level var wrapper = new GameObject("sub_tree_wrapper"); //wrapper.transform.position = this.transform.position; wrapper.transform.SetParent(this.transform.parent, false); wrapper.AddComponent <HorizontalLayoutGroup>(); wrapper.GetComponent <HorizontalLayoutGroup>().spacing = 5; if (InspectorVisualization.IsList(subTreeRoot)) { Debug.Log("inputobject is a list"); foreach (var item in (IEnumerable)subTreeRoot) { var inspectabelgo = InspectorVisualization.generateInspectableElementGameObject(item, wrapper); } } else if (InspectorVisualization.IsDictionary(subTreeRoot)) { Debug.Log("inputobject is a dictionary"); foreach (var pair in (IEnumerable)subTreeRoot) { var realpair = DictionaryHelpers.CastFrom(pair); var key = realpair.Key; var value = realpair.Value; InspectorVisualization.generateInspectableElementGameObject(value, wrapper); } } else { Debug.Log("inputobject is a object"); if (subTreeRoot is IDynamicMetaObjectProvider) { Debug.Log("inputobject is a dynamic object"); var names = new List <string>(); var dynobj = subTreeRoot as IronPython.Runtime.Binding.IPythonExpandable; if (dynobj != null) { names.AddRange(dynobj.Context.LanguageContext.GetMemberNames(Expression.Constant(dynobj))); } //filter names so that python private and builtin members do not show var filterednames = names.Where(x => x.StartsWith("__") != true).ToList(); foreach (var name in filterednames) { var value = InspectorVisualization.GetDynamicValue(dynobj, name); if (value != null) { InspectorVisualization.generateInspectableElementGameObject(value, wrapper); } } } // if object was not dynamic use regular reflection else { Debug.Log("inputobject is a non dynamic object"); var propertyInfos = subTreeRoot.GetType().GetProperties( BindingFlags.Public | BindingFlags.NonPublic // Get public and non-public | BindingFlags.Static | BindingFlags.Instance // Get instance + static | BindingFlags.FlattenHierarchy); // Search up the hierarchy foreach (var prop in propertyInfos.ToList()) { if (prop.GetIndexParameters().Length > 0) { // Property is an indexer Debug.Log("this property is an indexed property, for now we won't reflect further"); continue; } try { var value = prop.GetValue(subTreeRoot, null); InspectorVisualization.generateInspectableElementGameObject(value, wrapper, prop.Name); } catch (Exception e) { Debug.Log("could not get property" + prop.Name); } } } } }
/// <summary> /// where main work is done of generating a new inspectable object and setting its properties, the object is then made a child of the parent /// /// </summary> /// /// <param name="someObject"></param> /// <param name="parent"></param> /// <param name="name"></param> /// <returns></returns> public static GameObject generateInspectableElementGameObject(object someObject, GameObject parent, string name = null) { if (someObject == null) { //GameObject.Destroy(parent); return(null); } var wrapper = new GameObject("subelement_wrapper"); //wrapper.transform.position = parent.transform.position; wrapper.transform.SetParent(parent.transform, false); wrapper.AddComponent <VerticalLayoutGroup>(); //wrapper.GetComponent<RectTransform>().sizeDelta = new Vector2(1,1); //wrapper.transform.Rotate(0,90,0); //TODO replace with call to specific item type depending on item system.type var element = Resources.Load <GameObject>("listele"); var instantiatedelement = GameObject.Instantiate(element) as GameObject; instantiatedelement.name = (someObject.GetType().ToString()); //instantiatedelement.transform.position = wrapper.transform.position; instantiatedelement.transform.SetParent(wrapper.transform, false); var inspectable = instantiatedelement.AddComponent <InspectableElement>(); inspectable.ElementType = someObject.GetType(); inspectable.Reference = someObject; inspectable.Name = name; Debug.Log("building inspectable element representing: " + someObject.ToString()); //TODO extract constants, fix this mess, possibly recalc based on distance to camera if (parent.transform.parent.GetChild(0).GetComponentInChildren <Text>().fontSize == 14) { //we are still creating the root visualization, so just set the size to 500 parent.transform.parent.GetChild(0).GetComponentInChildren <Text>().fontSize = 500; } else { //in all other cases halve it var parentfontsize = parent.transform.parent.GetChild(0).GetComponentInChildren <Text>().fontSize; inspectable.GetComponentInChildren <Text>().fontSize = parentfontsize / 2; } if (someObject == null || ReferenceEquals(someObject, null) || someObject.ToString() == "null") { Debug.Log("in here mofo"); inspectable.GetComponentInChildren <Text>().fontSize /= 2; instantiatedelement.GetComponent <Image>().color = Color.red; } //if the newly instantiated element is a list lets open it up by sending a click event if (InspectorVisualization.IsList(someObject)) { Debug.Log("the item was a list so open it"); ExecuteEvents.Execute <IPointerClickHandler>(instantiatedelement, new PointerEventData(EventSystem.current), ExecuteEvents.pointerClickHandler); } // when the text is updated the layout is regenerated, this might happen on the next frame // and so lines need to be drawn, afer that, it's best if the visualizations are hooked to an event // watching for changes on the node or the inspectable.UpdateText(); inspectable.UpdateVisualization(); return(instantiatedelement); }