public CollectionEditor(Func <Object> value, Action <Object> setValue, CelestialBody body, String name, MemberInfo member, ParserTargetCollection collection, Func <Object> getReference) : base(value, setValue, body, name) { Member = member; _getReference = getReference; Collection = collection; }
/** * Load collection for ParserTargetCollection * * @param member Member to load data for * @param o Instance of the object which owns member * @param node Configuration node from which to load data **/ public static void LoadCollectionMemberFromConfigurationNode(MemberInfo member, object o, ConfigNode node, bool getChilds = true) { // Get the target attribute ParserTargetCollection target = (member.GetCustomAttributes(typeof(ParserTargetCollection), true) as ParserTargetCollection[]) [0]; // Figure out if this field exists and if we care bool isNode = node.HasNode(target.fieldName); bool isValue = node.HasValue(target.fieldName); // Obtain the type the member is (can only be field or property) Type targetType = null; object targetValue = null; if (member.MemberType == MemberTypes.Field) { targetType = (member as FieldInfo).FieldType; if (getChilds) { targetValue = (member as FieldInfo).GetValue(o); } else { targetValue = null; } } else { targetType = (member as PropertyInfo).PropertyType; try { if ((member as PropertyInfo).CanRead && getChilds) { targetValue = (member as PropertyInfo).GetValue(o, null); } else { targetValue = null; } } catch (Exception) { // ignored } } // If there was no data found for this node if (!isNode && !isValue) { if (!target.optional && !(target.allowMerge && targetValue != null)) { // Error - non optional field is missing throw new ParserTargetMissingException("Missing non-optional field: " + o.GetType() + "." + target.fieldName); } // Nothing to do, so return return; } // If we are dealing with a generic collection if (targetType.IsGenericType) { // If the target is a generic dictionary if (typeof(IDictionary).IsAssignableFrom(targetType)) { throw new Exception("Generic dictionaries are unsupported at this time"); } // If the target is a generic collection else if (typeof(IList).IsAssignableFrom(targetType)) { // We need a node for this decoding if (!isNode) { throw new Exception("Loading a generic list requires sources to be nodes"); } // Get the target value as a collection IList collection = targetValue as IList; // Get the internal type of this collection Type genericType = targetType.GetGenericArguments() [0]; // Create a new collection if merge is disallowed or if the collection is null if (collection == null || !target.allowMerge) { collection = Activator.CreateInstance(targetType) as IList; targetValue = collection; } // Iterate over all of the nodes in this node foreach (ConfigNode subnode in node.GetNode(target.fieldName).nodes) { // Check for the name significance if (target.nameSignificance == NameSignificance.None) { // Just processes the contents of the node collection.Add(CreateObjectFromConfigNode(genericType, subnode, target.getChild)); } // Otherwise throw an exception because we don't support named ones yet else if (target.nameSignificance == NameSignificance.Type) { // Generate the type from the name Type elementType = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).FirstOrDefault(t => t.Name == subnode.name); // Add the object to the collection collection.Add(CreateObjectFromConfigNode(elementType, subnode, target.getChild)); } } } } // If we are dealing with a non generic collection else { // Check for invalid scenarios if (target.nameSignificance == NameSignificance.None) { throw new Exception("Can not infer type from non generic target; can not infer type from zero name significance"); } } // If the member type is a field, set the value if (member.MemberType == MemberTypes.Field) { (member as FieldInfo).SetValue(o, targetValue); } // If the member wasn't a field, it must be a property. If the property is writable, set it. else if ((member as PropertyInfo).CanWrite) { (member as PropertyInfo).SetValue(o, targetValue, null); } }
/// <summary> /// Displays a parser target in the window /// </summary> private void DisplayParserTarget(ParserTarget target, MemberInfo member) { // Don't display hidden options if (Tools.HasAttribute <KittopiaHideOption>(member) && !Tools.GetAttributes <KittopiaHideOption>(member)[0].Show) { return; } // Check if the object is a list or a single element if (!Tools.IsCollection(target)) { GUIHorizontalLayout(() => { GUILabel(target.FieldName, modifier: Alignment(TextAlignmentOptions.Left)); GUIFlexibleSpace(); GUILabel(target.Optional ? "Optional" : "Required", modifier: Alignment(TextAlignmentOptions.Right) .And(TextColor(Color.gray))); }); // Display a KittopiaDescription String description = Tools.GetDescription(member); if (!String.IsNullOrEmpty(description)) { GUISpace(2f); GUILabel(description, modifier: TextColor(Color.gray)); } GUISpace(5f); // If the element is loaded from a config node, it needs a new window // Simply values can be edited with an inline textfield ConfigType configType = Tools.GetConfigType(Tools.GetValue(member, Info.Value)?.GetType() ?? Tools.MemberType(member)); if (configType == ConfigType.Node) { GUIHorizontalLayout(() => { // Edit Button GUIToggleButton( () => Children.ContainsKey(target.FieldName) && Children[target.FieldName].IsVisible, "Edit", e => ToggleSubEditor(target, member, e), -1f, 25f, Enabled <DialogGUIToggleButton>(() => Tools.GetValue(member, Info.Value) != null)); // Button to create or destroy the element if (Tools.HasAttribute <KittopiaUntouchable>(member)) { GUIButton(Tools.GetValue(member, Info.Value) != null ? "x" : "+", () => { }, 25f, 25f, false, () => { }, Enabled <DialogGUIButton>(() => false)); } else { GUIButton(() => Tools.GetValue(member, Info.Value) != null ? "x" : "+", () => { Object value = Tools.GetValue(member, Info.Value); if (value != null) { Tools.Destruct(value); Tools.SetValue(member, Info.Value, null); SetValue(null); } else { Object v = Tools.Construct(Tools.MemberType(member), Info.Body); Tools.SetValue(member, Info.Value, v); SetValue(v); } }, 25f, 25f, false, () => { }); } }); } else { GUIHorizontalLayout(() => { GUITextInput("", false, Int32.MaxValue, s => Tools.ApplyInput(member, s, Info.Value), () => Tools.FormatParsable(Tools.GetValue(member, Info.Value)) ?? "", TMP_InputField.ContentType.Standard, 25f); GUIToggleButton( () => ValueEditors.ContainsKey(target.FieldName) && ValueEditors[target.FieldName].IsVisible, ">", e => ToggleValueEditor(target, member, e), 25f, 25f, Enabled <DialogGUIToggleButton>(() => HasValueEditor(member))); }); } } else { ParserTargetCollection collection = (ParserTargetCollection)target; // Is the collection parsing a subnode, or this one? if (collection.FieldName != "self") { GUIHorizontalLayout(() => { GUILabel(target.FieldName, modifier: Alignment(TextAlignmentOptions.Left)); GUIFlexibleSpace(); GUILabel(target.Optional ? "Optional" : "Required", modifier: Alignment(TextAlignmentOptions.Right) .And(TextColor(Color.gray))); }); // Display a KittopiaDescription String description = Tools.GetDescription(member); if (!String.IsNullOrEmpty(description)) { GUISpace(2f); GUILabel(description, modifier: TextColor(Color.gray)); } GUISpace(5f); GUIHorizontalLayout(() => { // Edit Button GUIToggleButton(() => Children.ContainsKey(target.FieldName) && Children[target.FieldName].IsVisible, "Edit", e => ToggleCollectionEditor(target, member, e), -1f, 25f, Enabled <DialogGUIToggleButton>(() => Tools.GetValue(member, Info.Value) != null)); // Button to create or destroy the element if (Tools.HasAttribute <KittopiaUntouchable>(member)) { GUIButton(Tools.GetValue(member, Info.Value) != null ? "x" : "+", () => { }, 25f, 25f, false, () => { }, Enabled <DialogGUIButton>(() => false)); } else { GUIButton(() => Tools.GetValue(member, Info.Value) != null ? "x" : "+", () => { Object value = Tools.GetValue(member, Info.Value); if (value != null) { Tools.Destruct(value); Tools.SetValue(member, Info.Value, null); SetValue(null); } else { Object v = Tools.Construct(Tools.MemberType(member), Info.Body); Tools.SetValue(member, Info.Value, v); SetValue(v); } }, 25f, 25f, false, () => { }); } }); } else { new CollectionEditor(() => Tools.GetValue(member, Info.Value), v => Tools.SetValue(member, Info.Value, v), Info.Body, Info.Body.transform.name + " - " + target.FieldName, member, (ParserTargetCollection)target, () => Info.Value).DisplayCollection(); } } if (target.FieldName != "self") { // Use a box as a seperator GUISpace(5f); GUIBox(-1f, 1f, () => { }); GUISpace(5f); } }