private static bool GetPropertyTrackArchetype(Type valueType, out TrackArchetype archetype, out string name) { // Validate value type and pick the track archetype name = valueType.Name; if (BasicTypesTrackArchetypes.TryGetValue(valueType, out archetype)) { // Basic type if (!BasicTypesNames.TryGetValue(valueType, out name)) { name = valueType.Name; } } else if (valueType.IsEnum) { // Enum archetype = KeyframesPropertyTrack.GetArchetype(); } else if (valueType.IsValueType) { // Structure archetype = StructPropertyTrack.GetArchetype(); } else if (typeof(FlaxEngine.Object).IsAssignableFrom(valueType)) { // Flax object reference archetype = ObjectReferencePropertyTrack.GetArchetype(); } else if (CanAnimateObjectType(valueType)) { // Nested object archetype = ObjectPropertyTrack.GetArchetype(); } else { // Not supported return(true); } return(false); }
/// <summary> /// Adds the object events track options to menu. /// </summary> /// <param name="parentTrack">The parent track.</param> /// <param name="menu">The menu.</param> /// <param name="type">The object type.</param> /// <param name="memberCheck">The custom callback that can reject the members that should not be animated. Returns true if member is valid. Can be null to skip this feature.</param> /// <returns>The added options count.</returns> public static int AddEvents(Track parentTrack, ContextMenu.ContextMenu menu, Type type, Func <MemberInfo, bool> memberCheck = null) { int count = 0; menu.Tag = parentTrack; // TODO: implement editor-wide cache for animated properties per object type (add this in CodeEditingModule) var members = type.GetMembers(BindingFlags.Public | BindingFlags.Instance); var sb = new StringBuilder(); for (int i = 0; i < members.Length; i++) { var m = members[i] as MethodInfo; if (m == null) { continue; } if (memberCheck != null && !memberCheck(m)) { continue; } // Skip properties getters/setters and events add/remove var mName = m.Name; if (mName.StartsWith("get_", StringComparison.Ordinal) || mName.StartsWith("set_", StringComparison.Ordinal) || mName.StartsWith("add_", StringComparison.Ordinal) || mName.StartsWith("remove_", StringComparison.Ordinal)) { continue; } // Allow to invoke only void functions with basic parameter types var parameters = m.GetParameters(); if (m.ReturnType != typeof(void) || parameters.Length > 8 || m.IsGenericMethod || parameters.Any(IsEventParamInvalid)) { continue; } var attributes = m.GetCustomAttributes(); // Check if has attribute to skip animating if (attributes.Any(x => x is NoAnimateAttribute)) { continue; } // Prevent from adding the same track twice if (parentTrack.SubTracks.Any(x => x is MemberTrack y && y.MemberName == m.Name)) { continue; } // Build function name for UI sb.Clear(); sb.Append(mName); sb.Append('('); for (int j = 0; j < parameters.Length; j++) { if (j != 0) { sb.Append(", "); } var p = parameters[j]; if (!BasicTypesNames.TryGetValue(p.ParameterType, out var pName)) { pName = p.ParameterType.Name; } sb.Append(pName); sb.Append(' '); sb.Append(p.Name); } sb.Append(')'); AddMemberTag tag; tag.Member = m; tag.Archetype = EventTrack.GetArchetype(); menu.AddButton(sb.ToString(), OnAddMemberTrack).Tag = tag; count++; } return(count); }