/// <summary> /// Creates an array of property descriptors that are associated with the adapted DomNode's /// DomNodeType. No duplicates will be in the array (based on the property descriptor's Name /// property).</summary> /// <returns>Array of property descriptors</returns> protected override System.ComponentModel.PropertyDescriptor[] GetPropertyDescriptors() { // Initialize property desciptors with the ones from the base class // If this is not done, the new property descriptors would be used instead of // rather than in addition to the ones defined in the schema List<System.ComponentModel.PropertyDescriptor> descriptors = new List<System.ComponentModel.PropertyDescriptor>(base.GetPropertyDescriptors()); // Add ITransformable properties: // Translation, Rotation, Scale, RotatePivot, ScalePivot (if supported by this object) ITransformable node = this.Cast<ITransformable>(); TransformationTypes transformType = node.TransformationType; NumericTupleEditor tupleEditor = new NumericTupleEditor(typeof(float), new string[] { "x", "y", "z" }); NumericTupleEditor rotationTupleEditor = new NumericTupleEditor(typeof(float), new string[] { "x", "y", "z" }); rotationTupleEditor.ScaleFactor = 360 / (2 * Math.PI); // Radians to Degrees string category = "Transform".Localize(); // Check for transform types if ((transformType & TransformationTypes.Translation) != 0) descriptors.Add( new AttributePropertyDescriptor( "Translation", Schema.transformObjectType.translateAttribute, category, "Translation of Game Object along X, Y, and Z axes".Localize(), false, tupleEditor)); if ((transformType & TransformationTypes.Rotation) != 0) descriptors.Add(new AttributePropertyDescriptor( "Rotation".Localize(), Schema.transformObjectType.rotateAttribute, category, "Origin of Rotation transform relative to Game Object Translation".Localize(), false, rotationTupleEditor)); if ((transformType & TransformationTypes.Scale) != 0) { if ((transformType & TransformationTypes.UniformScale) == 0) descriptors.Add( new AttributePropertyDescriptor( "Scale".Localize(), Schema.transformObjectType.scaleAttribute, category, "Scale of Game Object along X, Y, and Z axes".Localize(), false, tupleEditor)); else descriptors.Add( new AttributePropertyDescriptor( "Uniform Scale".Localize(), Schema.transformObjectType.scaleAttribute, category, "Scale of Game Object uniformly along X, Y, and Z axes".Localize(), false, new UniformArrayEditor<Single>())); } if ((transformType & TransformationTypes.Pivot) != 0) descriptors.Add( new AttributePropertyDescriptor( "Pivot".Localize(), Schema.transformObjectType.pivotAttribute, category, "Origin of Rotation and scale transform relative to Game Object Translation".Localize(), false, tupleEditor)); // remove hidden properties HashSet<string> hiddenProps = (HashSet<string>)this.DomNode.Type.GetTag(SchemaLoader.HiddenProperties); if (hiddenProps != null) { List<PropertyDescriptor> removeList = new List<PropertyDescriptor>(); foreach (AttributePropertyDescriptor propdescr in descriptors.AsIEnumerable<AttributePropertyDescriptor>()) { if (hiddenProps.Contains(propdescr.AttributeInfo.Name)) { removeList.Add(propdescr); } } foreach (PropertyDescriptor propDescr in removeList) descriptors.Remove(propDescr); } return descriptors.ToArray(); }
/// <summary> /// Method called after the schema set has been loaded and the DomNodeTypes have been created, but /// before the DomNodeTypes have been frozen. This means that DomNodeType.SetIdAttribute, for example, has /// not been called on the DomNodeTypes. Is called shortly before OnDomNodeTypesFrozen.</summary> /// <param name="schemaSet">XML schema sets being loaded</param> protected override void OnSchemaSetLoaded(XmlSchemaSet schemaSet) { foreach (XmlSchemaTypeCollection typeCollection in GetTypeCollections()) { m_namespace = typeCollection.TargetNamespace; m_typeCollection = typeCollection; Schema.Initialize(typeCollection); // register extensions Schema.gameType.Type.Define(new ExtensionInfo<GameEditingContext>()); Schema.gameType.Type.Define(new ExtensionInfo<UniqueIdValidator>()); // Add required property descriptors to GameObject and OrcType so it can be edited // with two column PropertyGrid. // Note: this is programmatic approach: Decorate DomNode types with // property descriptors. // Alternatively schema annotations can used. // However, programmatic approach is recommend because of type safety. // Descriptors for armorType. string general = "General".Localize(); var armorDescriptors = new PropertyDescriptorCollection(null); armorDescriptors.Add(new AttributePropertyDescriptor( "Name".Localize(), Schema.armorType.nameAttribute, general, "Armor name".Localize(), false )); armorDescriptors.Add(new AttributePropertyDescriptor( "Defense".Localize(), Schema.armorType.defenseAttribute, general, "Armor defense".Localize(), false, new NumericEditor(typeof(int)) )); armorDescriptors.Add(new AttributePropertyDescriptor( "Price".Localize(), Schema.armorType.priceAttribute, general, "Armor price in gold".Localize(), false, new NumericEditor(typeof(int)) )); Schema.armorType.Type.SetTag(armorDescriptors); // club type property descriptors. var clubDescriptors = new PropertyDescriptorCollection(null); clubDescriptors.Add(new AttributePropertyDescriptor( "Spike".Localize(), Schema.clubType.spikesAttribute, general, "Club Has Spikes".Localize(), false, new BoolEditor() )); clubDescriptors.Add(new AttributePropertyDescriptor( "Damage".Localize(), Schema.clubType.DamageAttribute, general, "Amount of damage per strike".Localize(), false, new NumericEditor(typeof(int)) )); clubDescriptors.Add(new AttributePropertyDescriptor( "Weight".Localize(), Schema.clubType.wieghtAttribute, general, "Weight of the club".Localize(), false, new NumericEditor(typeof(float)) )); Schema.clubType.Type.SetTag(clubDescriptors); var gobDescriptors = new PropertyDescriptorCollection(null); gobDescriptors.Add( new AttributePropertyDescriptor( "Name".Localize(), Schema.gameObjectType.nameAttribute, null, "Object name".Localize(), false )); // bool editor: shows checkBox instead of textual (true,false). gobDescriptors.Add( new AttributePropertyDescriptor( "Visible".Localize(), Schema.gameObjectType.visibleAttribute, null, "Show/Hide object in editor".Localize(), false, new BoolEditor() )); // NumericTupleEditor can be used for vector values. string xformCategory = "Transformation".Localize(); var transEditor = new NumericTupleEditor(typeof(float), new string[] { "Tx", "Ty", "Tz" }); gobDescriptors.Add( new AttributePropertyDescriptor( "Translate".Localize(), Schema.gameObjectType.translateAttribute, xformCategory, "Object's position".Localize(), false, transEditor )); var scaleEditor = new NumericTupleEditor(typeof(float), new string[] { "Sx", "Sy", "Sz" }); gobDescriptors.Add( new AttributePropertyDescriptor( "Scale".Localize(), Schema.gameObjectType.scaleAttribute, xformCategory, "Object's scale".Localize(), false, scaleEditor )); var rotationEditor = new NumericTupleEditor(typeof(float), new string[] { "Rx", "Ry", "Rz" }); rotationEditor.ScaleFactor = 360.0f / (2.0f * (float)Math.PI); // Radians to Degrees gobDescriptors.Add( new AttributePropertyDescriptor( "Rotation".Localize(), Schema.gameObjectType.rotateAttribute, xformCategory, "Object's orientation".Localize(), false, rotationEditor )); Schema.gameObjectType.Type.SetTag(gobDescriptors); // Defines property descriptors for orcType. var orcDescriptors = new PropertyDescriptorCollection(null); string chCategory = "Character attributes".Localize(); // Bounded int editor: used for editing bounded int properties. orcDescriptors.Add( new AttributePropertyDescriptor( "Skill".Localize(), Schema.orcType.skillAttribute, chCategory, "Skill".Localize(), false, new BoundedIntEditor(1,120) )); // Bounded float editor: similar to bounded int editor // but it operates on float instead. orcDescriptors.Add( new AttributePropertyDescriptor( "Weight".Localize(), Schema.orcType.weightAttribute, chCategory, "Weight".Localize(), false, new BoundedFloatEditor(80, 400) )); // store the value of enum as string. LongEnumEditor emotionEditor = new LongEnumEditor(typeof(OrcEmotion)); orcDescriptors.Add( new AttributePropertyDescriptor( "Emotion".Localize(), Schema.orcType.emotionAttribute, chCategory, "Emotion".Localize(), false, emotionEditor )); // FlagsUITypeEditor store flags as int. // doesn't implement IPropertyEditor FlagsUITypeEditor goalsEditor = new FlagsUITypeEditor(Enum.GetNames(typeof(OrcGoals))); FlagsTypeConverter goalsConverter = new FlagsTypeConverter(Enum.GetNames(typeof(OrcGoals))); orcDescriptors.Add( new AttributePropertyDescriptor( "Goals".Localize(), Schema.orcType.goalsAttribute, chCategory, "Goals".Localize(), false, goalsEditor, goalsConverter )); orcDescriptors.Add( new AttributePropertyDescriptor( "Health".Localize(), Schema.orcType.healthAttribute, chCategory, "Orc's health".Localize(), false, new NumericEditor(typeof(int)) )); //EmbeddedCollectionEditor edit children (edit, add, remove, move). // note: EmbeddedCollectionEditor needs some work (effecienty and implementation issues). var collectionEditor = new EmbeddedCollectionEditor(); // the following lambda's handles (add, remove, move ) items. collectionEditor.GetItemInsertersFunc = (context)=> { var insertors = new EmbeddedCollectionEditor.ItemInserter[1]; var list = context.GetValue() as IList<DomNode>; if (list != null) { var childDescriptor = context.Descriptor as ChildPropertyDescriptor; if (childDescriptor != null) { insertors[0] = new EmbeddedCollectionEditor.ItemInserter(childDescriptor.ChildInfo.Type.Name, delegate { DomNode node = new DomNode(childDescriptor.ChildInfo.Type); if (node.Type.IdAttribute != null) { node.SetAttribute(node.Type.IdAttribute, node.Type.Name); } list.Add(node); return node; }); return insertors; } } return EmptyArray<EmbeddedCollectionEditor.ItemInserter>.Instance; }; collectionEditor.RemoveItemFunc = (context, item) => { var list = context.GetValue() as IList<DomNode>; if (list != null) list.Remove(item.Cast<DomNode>()); }; collectionEditor.MoveItemFunc = (context, item, delta) => { var list = context.GetValue() as IList<DomNode>; if (list != null) { DomNode node = item.Cast<DomNode>(); int index = list.IndexOf(node); int insertIndex = index + delta; if (insertIndex < 0 || insertIndex >= list.Count) return; list.RemoveAt(index); list.Insert(insertIndex, node); } }; string weaponCategory = "Weapons and Defense".Localize(); orcDescriptors.Add( new ChildPropertyDescriptor( "Armor".Localize(), Schema.orcType.armorChild, weaponCategory, "Armors".Localize(), false, collectionEditor )); orcDescriptors.Add( new ChildPropertyDescriptor( "Club".Localize(), Schema.orcType.clubChild, weaponCategory, "Club".Localize(), false, collectionEditor )); orcDescriptors.Add( new ChildPropertyDescriptor( "Orcs".Localize(), Schema.orcType.orcChild, "Children".Localize(), "Orc children".Localize(), false, collectionEditor )); string renderingCategory = "Rendering".Localize(); // color picker. // note: ColorPickerEditor doesn't implement IPropertyEditor orcDescriptors.Add( new AttributePropertyDescriptor( "Skin".Localize(), Schema.orcType.skinColorAttribute, renderingCategory, "Skin color".Localize(), false, new ColorPickerEditor(), new IntColorConverter() )); // file picker. orcDescriptors.Add( new AttributePropertyDescriptor( "Texture file".Localize(), Schema.orcType.textureFileAttribute, renderingCategory, "Texture file".Localize(), false, new FileUriEditor("Texture file (*.dds)|*.dds") )); // Edit matrix. //NumericMatrixEditor orcDescriptors.Add( new AttributePropertyDescriptor( "Texture Transform".Localize(), Schema.orcType.textureTransformAttribute, renderingCategory, "Texture Transform".Localize(), false, new NumericMatrixEditor() )); // Edit array. // ArrayEditor, need some work, it has some efficiency and implementation issues. orcDescriptors.Add( new AttributePropertyDescriptor( "Texture Array".Localize(), Schema.orcType.textureArrayAttribute, renderingCategory, "Texture Array".Localize(), false, new ArrayEditor() )); // readonly property, // show datetime as readonly. orcDescriptors.Add( new AttributePropertyDescriptor( "Revision data".Localize(), Schema.orcType.TextureRevDateAttribute, renderingCategory, "Texture revision data and time".Localize(), true )); // folder picker. // FolderUriEditor and FolderBrowserDialogUITypeEditor orcDescriptors.Add( new AttributePropertyDescriptor( "Resource Folder".Localize(), Schema.orcType.resourceFolderAttribute, renderingCategory, "Resource folder".Localize(), false, new FolderUriEditor() )); Schema.orcType.Type.SetTag(orcDescriptors); // only one namespace break; } }
void InitializeProperties() { m_PropertyInfos.Clear(); foreach (var enumValueObj in Enum.GetValues(typeof(SF.Tong.Schema.PropertyType))) { var enumValue = (SF.Tong.Schema.PropertyType)enumValueObj; AttributeInfo newAttr = null, newListAttr = null; DomNodeType childNodeType = null; object editor = null; TypeConverter converter = null; switch (enumValue) { //case SF.Tong.Schema.PropertyType.Event: // newAttr = new AttributeInfo(enumValue.ToString(), AttributeType.BooleanType); // newListAttr = new AttributeInfo(enumValue.ToString() + "[]", AttributeType.BooleanArrayType); // break; case SF.Tong.Schema.PropertyType.Boolean: newAttr = new AttributeInfo(enumValue.ToString(), AttributeType.BooleanType); newListAttr = new AttributeInfo(enumValue.ToString() + "[]", AttributeType.BooleanArrayType); break; case SF.Tong.Schema.PropertyType.@Int: newAttr = new AttributeInfo(enumValue.ToString(), AttributeType.IntType); newListAttr = new AttributeInfo(enumValue.ToString() + "[]", AttributeType.IntArrayType); break; //case SF.Tong.Schema.PropertyType.@float: // newAttr = new AttributeInfo(enumValue.ToString(), AttributeType.FloatType); // newListAttr = new AttributeInfo(enumValue.ToString() + "[]", AttributeType.FloatArrayType); // break; //case SF.Tong.Schema.PropertyType.@double: // newAttr = new AttributeInfo(enumValue.ToString(), AttributeType.DoubleType); // newListAttr = new AttributeInfo(enumValue.ToString() + "[]", AttributeType.DoubleArrayType); // break; case SF.Tong.Schema.PropertyType.@Decimal: newAttr = new AttributeInfo(enumValue.ToString(), AttributeType.DecimalType); newListAttr = new AttributeInfo(enumValue.ToString() + "[]", AttributeType.DecimalArrayType); break; case SF.Tong.Schema.PropertyType.@String: newAttr = new AttributeInfo(enumValue.ToString(), AttributeType.StringType); newListAttr = new AttributeInfo(enumValue.ToString() + "[]", AttributeType.StringArrayType); break; case SF.Tong.Schema.PropertyType.FixedString: newAttr = new AttributeInfo(enumValue.ToString(), AttributeType.StringType); newAttr.AddRule(new StringHashRule()); newListAttr = new AttributeInfo(enumValue.ToString() + "[]", AttributeType.StringArrayType); newListAttr.AddRule(new StringHashRule()); break; case SF.Tong.Schema.PropertyType.Vector3: newAttr = new AttributeInfo(enumValue.ToString(), new AttributeType(enumValue.ToString(), typeof(float[]), 3)); editor = new Sce.Atf.Controls.PropertyEditing.NumericTupleEditor(typeof(float), new string[] { "x", "y", "z" }); break; case SF.Tong.Schema.PropertyType.Socket: childNodeType = CreateDOMType(typeof(SF.Tong.Schema.EditorSocket)); socketType.Type = childNodeType; // cache for global use break; case SF.Tong.Schema.PropertyType.Signal: newAttr = new AttributeInfo(enumValue.ToString(), AttributeType.NameStringType); newListAttr = new AttributeInfo(enumValue.ToString() + "[]", AttributeType.NameStringType); break; case SF.Tong.Schema.PropertyType.File: case SF.Tong.Schema.PropertyType.Asset: // TODO: add new types for them case SF.Tong.Schema.PropertyType.Enum: // We don't actually use Enum here. just assign string for now newAttr = new AttributeInfo(enumValue.ToString(), AttributeType.StringType); newListAttr = new AttributeInfo(enumValue.ToString() + "[]", AttributeType.StringArrayType); break; case SF.Tong.Schema.PropertyType.@Object: newAttr = new AttributeInfo(enumValue.ToString(), AttributeType.DomNodeRefType); newListAttr = new AttributeInfo(enumValue.ToString() + "[]", AttributeType.DomNodeRefArrayType); break; case SF.Tong.Schema.PropertyType.@ObjectType: newAttr = new AttributeInfo(enumValue.ToString(), AttributeType.StringType); newListAttr = new AttributeInfo(enumValue.ToString() + "[]", AttributeType.StringArrayType); editor = m_ObjectTypeEditor; converter = m_ObjectTypeConverter; break; default: throw new InvalidDataException("There is a not-handled property type"); } if (newAttr != null) { var propInfo = new PropertyInformation() { AttributeInfo = newAttr, ListAttributeInfo = newListAttr, ChildInfo = null, Editor = editor, Converter = converter, }; m_PropertyInfos.Add(propInfo); } else if (childNodeType != null) { ChildInfo newChild = new ChildInfo(enumValue.ToString(), childNodeType); var propInfo = new PropertyInformation() { AttributeInfo = null, ListAttributeInfo = null, ChildInfo = newChild, Editor = null, Converter = null, }; m_PropertyInfos.Add(propInfo); } else { Outputs.WriteLine(OutputMessageType.Warning, "Invalid property {0}", enumValue.ToString()); } } }