protected override void Initialize() { var property = this.Property; var attribute = this.Attribute; this.contextMenuInfos = property.Context.GetGlobal("CustomContextMenu", (Dictionary <CustomContextMenuAttribute, ContextMenuInfo>)null); this.populated = property.Context.GetGlobal("CustomContextMenu_Populated", false); if (contextMenuInfos.Value == null) { contextMenuInfos.Value = new Dictionary <CustomContextMenuAttribute, ContextMenuInfo>(); } if (!contextMenuInfos.Value.TryGetValue(attribute, out this.info)) { this.info = new ContextMenuInfo(); var methodInfo = property.ParentType .FindMember() .IsMethod() .IsInstance() .HasNoParameters() .ReturnsVoid() .IsNamed(attribute.MethodName) .GetMember <MethodInfo>(out this.info.ErrorMessage); if (this.info.ErrorMessage == null) { this.info.Name = attribute.MenuItem; this.info.MethodCaller = EmitUtilities.CreateWeakInstanceMethodCaller(methodInfo); } contextMenuInfos.Value[attribute] = this.info; } }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(InspectorProperty property, OnInspectorGUIAttribute attribute, GUIContent label) { if (property.Info.PropertyType == PropertyType.Method) { var methodConfig = property.Context.Get(this, "Config", (MethodContext)null); if (methodConfig.Value == null) { methodConfig.Value = new MethodContext(); MethodInfo methodInfo = property.Info.MemberInfo as MethodInfo; if (methodInfo.ReturnType != typeof(void)) { methodConfig.Value.ErrorMessage = "The method '" + methodInfo.Name + "' must have a return type of type void."; } else if (methodInfo.GetParameters().Length > 0) { methodConfig.Value.ErrorMessage = "The method '" + methodInfo.Name + "' cannot take any parameters."; } else { methodConfig.Value.InstanceMethod = EmitUtilities.CreateWeakInstanceMethodCaller(methodInfo); } } if (methodConfig.Value.ErrorMessage != null) { SirenixEditorGUI.ErrorMessageBox(methodConfig.Value.ErrorMessage); } else { if (methodConfig.Value.InstanceMethod != null) { methodConfig.Value.InstanceMethod(property.ParentValues[0]); } } } else { if (attribute.PrependMethodName != null) { this.DoInspectorGUI(property, "Prepend", attribute.PrependMethodName); } this.CallNextDrawer(property, label); if (attribute.AppendMethodName != null) { this.DoInspectorGUI(property, "Append", attribute.AppendMethodName); } } }
protected override void Initialize() { this.isListElement = this.Property.Parent != null && this.Property.Parent.ChildResolver is IOrderedCollectionResolver; var isList = !this.isListElement; var listProperty = isList ? this.Property : this.Property.Parent; this.baseMemberProperty = listProperty.FindParent(x => x.Info.PropertyType == PropertyType.Value, true); this.globalSelectedProperty = this.baseMemberProperty.Context.GetGlobal("selectedIndex" + this.baseMemberProperty.GetHashCode(), (InspectorProperty)null); if (isList) { var parentType = this.baseMemberProperty.ParentValues[0].GetType(); this.selectedIndexSetter = EmitUtilities.CreateWeakInstanceMethodCaller <int>(parentType.GetMethod(this.Attribute.SetSelectedMethod, Flags.AllMembers)); } }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(GUIContent label) { var property = this.Property; var attribute = this.Attribute; var contextMenuInfos = property.Context.GetGlobal("CustomContextMenu", (Dictionary <CustomContextMenuAttribute, ContextMenuInfo>)null); var populated = property.Context.GetGlobal("CustomContextMenu_Populated", false); populated.Value = false; if (contextMenuInfos.Value == null) { contextMenuInfos.Value = new Dictionary <CustomContextMenuAttribute, ContextMenuInfo>(); } ContextMenuInfo info; if (!contextMenuInfos.Value.TryGetValue(attribute, out info)) { info = new ContextMenuInfo(); var methodInfo = property.ParentType .FindMember() .IsMethod() .IsInstance() .HasNoParameters() .ReturnsVoid() .IsNamed(attribute.MethodName) .GetMember <MethodInfo>(out info.ErrorMessage); if (info.ErrorMessage == null) { info.Name = attribute.MenuItem; info.MethodCaller = EmitUtilities.CreateWeakInstanceMethodCaller(methodInfo); } contextMenuInfos.Value[attribute] = info; } if (info.ErrorMessage != null) { SirenixEditorGUI.ErrorMessageBox(info.ErrorMessage); } this.CallNextDrawer(label); }
private static void EnsureInitialized() { if (!Initialized) { Initialized = true; try { string haveAudioCallbackName = UnityVersion.IsVersionOrGreater(5, 6) ? "HasAudioCallback" : "HaveAudioCallback"; AudioUtil_HaveAudioCallback = (Func <MonoBehaviour, bool>)Delegate.CreateDelegate(typeof(Func <MonoBehaviour, bool>), typeof(Editor).Assembly.GetType("UnityEditor.AudioUtil").GetMethod(haveAudioCallbackName, BindingFlags.Public | BindingFlags.Static)); AudioUtil_GetCustomFilterChannelCount = (Func <MonoBehaviour, int>)Delegate.CreateDelegate(typeof(Func <MonoBehaviour, int>), typeof(Editor).Assembly.GetType("UnityEditor.AudioUtil").GetMethod("GetCustomFilterChannelCount", BindingFlags.Public | BindingFlags.Static)); AudioFilterGUIType = typeof(Editor).Assembly.GetType("UnityEditor.AudioFilterGUI"); DrawAudioFilterGUI = EmitUtilities.CreateWeakInstanceMethodCaller <MonoBehaviour>(AudioFilterGUIType.GetMethod("DrawAudioFilterGUI", BindingFlags.Public | BindingFlags.Instance)); HasReflectedAudioFilter = true; } catch (Exception) { Debug.LogWarning("The internal Unity class AudioFilterGUI has been changed; cannot properly mock a generic Unity inspector. This probably won't be very noticeable."); } } }
/// <summary> /// Not yet documented. /// </summary> protected override void DrawPropertyLayout(GUIContent label) { var entry = this.ValueEntry; var attribute = this.Attribute; var config = entry.Property.Context.Get(this, "Test", (CurrentContext)null); if (config.Value == null) { config.Value = new CurrentContext(); config.Value.Attribute = attribute; config.Value.Tags = attribute.Tags != null?attribute.Tags.Trim().Split(',').Select(i => i.Trim()).ToArray() : null; config.Value.LayerNames = attribute.LayerNames != null?attribute.LayerNames.Trim().Split(',').Select(i => i.Trim()).ToArray() : null; config.Value.Property = entry.Property; if (attribute.Path != null) { var path = attribute.Path.Trim('/', ' '); path = "Assets/" + path + "/"; path = Application.dataPath + "/" + path; config.Value.AssetsFolderLocation = new DirectoryInfo(path); path = attribute.Path.TrimStart('/').TrimEnd('/'); config.Value.PrettyPath = "/" + path.TrimStart('/'); } if (attribute.CustomFilterMethod != null) { MethodInfo methodInfo; string error; if (MemberFinder.Start(entry.ParentType) .IsMethod() .IsNamed(attribute.CustomFilterMethod) .HasReturnType <bool>() .HasParameters <TElement>() .TryGetMember <MethodInfo>(out methodInfo, out error)) { if (methodInfo.IsStatic) { config.Value.StaticCustomIncludeMethod = (Func <TElement, bool>)Delegate.CreateDelegate(typeof(Func <TElement, bool>), methodInfo, true); } else { config.Value.InstanceCustomIncludeMethod = EmitUtilities.CreateWeakInstanceMethodCaller <bool, TElement>(methodInfo); } } config.Value.ErrorMessage = error; } if (config.Value.ErrorMessage != null) { // We can get away with lag on load. config.Value.MaxSearchDurationPrFrameInMS = 20; config.Value.EnsureListPopulation(); config.Value.MaxSearchDurationPrFrameInMS = 1; } } var currentValue = (UnityEngine.Object)entry.WeakSmartValue; if (config.Value.ErrorMessage != null) { SirenixEditorGUI.ErrorMessageBox(config.Value.ErrorMessage); } else { config.Value.EnsureListPopulation(); } SirenixEditorGUI.BeginIndentedVertical(SirenixGUIStyles.PropertyPadding); { SirenixEditorGUI.BeginHorizontalToolbar(); if (label != null) { GUILayout.Label(label); } GUILayout.FlexibleSpace(); if (config.Value.PrettyPath != null) { GUILayout.Label(config.Value.PrettyPath, SirenixGUIStyles.RightAlignedGreyMiniLabel); SirenixEditorGUI.VerticalLineSeparator(); } if (config.Value.IsPopulated) { GUILayout.Label(config.Value.AvailableAsset.Count + " items", SirenixGUIStyles.RightAlignedGreyMiniLabel); GUIHelper.PushGUIEnabled(GUI.enabled && (config.Value.AvailableAsset.Count > 0 && config.Value.ErrorMessage == null)); } else { GUILayout.Label("Scanning " + config.Value.CurrentSearchingIndex + " / " + config.Value.NumberOfResultsToSearch, SirenixGUIStyles.RightAlignedGreyMiniLabel); GUIHelper.PushGUIEnabled(false); } SirenixEditorGUI.VerticalLineSeparator(); bool drawConflict = entry.Property.ParentValues.Count > 1; if (drawConflict == false) { var index = config.Value.AvailableAsset.IndexOf(currentValue) + 1; if (index > 0) { GUILayout.Label(index.ToString(), SirenixGUIStyles.RightAlignedGreyMiniLabel); } else { drawConflict = true; } } if (drawConflict) { GUILayout.Label("-", SirenixGUIStyles.RightAlignedGreyMiniLabel); } if (SirenixEditorGUI.ToolbarButton(EditorIcons.TriangleLeft) && config.Value.IsPopulated) { var index = config.Value.AvailableAsset.IndexOf(currentValue) - 1; index = index < 0 ? config.Value.AvailableAsset.Count - 1 : index; entry.WeakSmartValue = config.Value.AvailableAsset[index]; } if (SirenixEditorGUI.ToolbarButton(EditorIcons.TriangleDown) && config.Value.IsPopulated) { GenericMenu m = new GenericMenu(); var selected = currentValue; int itemsPrPage = 40; bool showPages = config.Value.AvailableAsset.Count > 50; string page = ""; int selectedPage = (config.Value.AvailableAsset.IndexOf(entry.WeakSmartValue as UnityEngine.Object) / itemsPrPage); for (int i = 0; i < config.Value.AvailableAsset.Count; i++) { var obj = config.Value.AvailableAsset[i]; if (obj != null) { var path = AssetDatabase.GetAssetPath(obj); var name = string.IsNullOrEmpty(path) ? obj.name : path.Substring(7).Replace("/", "\\"); var localEntry = entry; if (showPages) { var p = (i / itemsPrPage); page = (p * itemsPrPage) + " - " + Mathf.Min(((p + 1) * itemsPrPage), config.Value.AvailableAsset.Count - 1); if (selectedPage == p) { page += " (contains selected)"; } page += "/"; } m.AddItem(new GUIContent(page + name), obj == selected, () => { localEntry.Property.Tree.DelayActionUntilRepaint(() => localEntry.WeakSmartValue = obj); }); } } m.ShowAsContext(); } if (SirenixEditorGUI.ToolbarButton(EditorIcons.TriangleRight) && config.Value.IsPopulated) { var index = config.Value.AvailableAsset.IndexOf(currentValue) + 1; entry.WeakSmartValue = config.Value.AvailableAsset[index % config.Value.AvailableAsset.Count]; } GUIHelper.PopGUIEnabled(); SirenixEditorGUI.EndHorizontalToolbar(); SirenixEditorGUI.BeginVerticalList(); SirenixEditorGUI.BeginListItem(false, padding); this.CallNextDrawer(null); SirenixEditorGUI.EndListItem(); SirenixEditorGUI.EndVerticalList(); } SirenixEditorGUI.EndIndentedVertical(); }
private void DoInspectorGUI(InspectorProperty property, string config, string methodName) { var methodConfig = property.Context.Get(this, config, (MethodContext)null); if (methodConfig.Value == null) { methodConfig.Value = new MethodContext(); MethodInfo methodInfo = property.ParentType .FindMember() .IsMethod() .IsNamed(methodName) .HasNoParameters() .ReturnsVoid() .GetMember <MethodInfo>(out methodConfig.Value.ErrorMessage); if (methodConfig.Value.ErrorMessage == null && methodInfo != null) { if (methodInfo.IsStatic) { methodConfig.Value.StaticMethod = EmitUtilities.CreateStaticMethodCaller(methodInfo); } else { methodConfig.Value.InstanceMethod = EmitUtilities.CreateWeakInstanceMethodCaller(methodInfo); } } else { string otherErrorMessage; methodInfo = property.ParentType .FindMember() .IsMethod() .IsNamed(methodName) .HasParameters(property.ValueEntry.BaseValueType) .IsStatic() .ReturnsVoid() .GetMember <MethodInfo>(out otherErrorMessage); if (otherErrorMessage == null) { methodConfig.Value.ErrorMessage = null; var delegateType = typeof(Action <>).MakeGenericType(property.ValueEntry.TypeOfValue); methodConfig.Value.StaticMethodWithParam = Delegate.CreateDelegate(delegateType, methodInfo); } else { methodConfig.Value.ErrorMessage += "\nor\n" + otherErrorMessage; } } } if (methodConfig.Value.ErrorMessage != null) { SirenixEditorGUI.ErrorMessageBox(methodConfig.Value.ErrorMessage); } else { if (methodConfig.Value.InstanceMethod != null) { methodConfig.Value.InstanceMethod(property.ParentValues[0]); } else if (methodConfig.Value.StaticMethodWithParam != null) { methodConfig.Value.StaticMethodWithParam.DynamicInvoke(property.ValueEntry.WeakSmartValue); } else { methodConfig.Value.StaticMethod(); } } }
/// <summary> /// Initializes the drawer. /// </summary> protected override void Initialize() { var resolver = this.Property.ChildResolver as ICollectionResolver; bool isReadOnly = resolver.IsReadOnly; var customListDrawerOptions = this.Property.GetAttribute <ListDrawerSettingsAttribute>() ?? new ListDrawerSettingsAttribute(); isReadOnly = this.ValueEntry.IsEditable == false || isReadOnly || customListDrawerOptions.IsReadOnlyHasValue && customListDrawerOptions.IsReadOnly; info = new ListDrawerConfigInfo() { StartIndex = 0, Toggled = this.ValueEntry.Context.GetPersistent <bool>(this, "ListDrawerToggled", customListDrawerOptions.ExpandedHasValue ? customListDrawerOptions.Expanded : GeneralDrawerConfig.Instance.OpenListsByDefault), RemoveAt = -1, // Now set further down, so it can be kept updated every frame //Label = new GUIContent(label == null || string.IsNullOrEmpty(label.text) ? this.Property.ValueEntry.TypeOfValue.GetNiceName() : label.text, label == null ? string.Empty : label.tooltip), ShowAllWhilePaging = false, EndIndex = 0, CustomListDrawerOptions = customListDrawerOptions, IsReadOnly = isReadOnly, Draggable = !isReadOnly && (!customListDrawerOptions.IsReadOnlyHasValue), HideAddButton = isReadOnly || customListDrawerOptions.HideAddButton, HideRemoveButton = isReadOnly || customListDrawerOptions.HideRemoveButton, }; info.ListConfig = GeneralDrawerConfig.Instance; info.Property = this.Property; if (customListDrawerOptions.DraggableHasValue && !customListDrawerOptions.DraggableItems) { info.Draggable = false; } if (!(this.Property.ChildResolver is IOrderedCollectionResolver)) { info.Draggable = false; } if (info.CustomListDrawerOptions.OnBeginListElementGUI != null) { string error; MemberInfo memberInfo = this.Property.ParentType .FindMember() .IsMethod() .IsNamed(info.CustomListDrawerOptions.OnBeginListElementGUI) .HasParameters <int>() .ReturnsVoid() .GetMember <MethodInfo>(out error); if (memberInfo == null || error != null) { // TOOD: Do something about this "There should really be an error message here." thing. // For this to trigger both the member and the error message should be null. Can that happen? this.errorMessage = error ?? "There should really be an error message here."; } else { info.OnBeginListElementGUI = EmitUtilities.CreateWeakInstanceMethodCaller <int>(memberInfo as MethodInfo); } } if (info.CustomListDrawerOptions.OnEndListElementGUI != null) { string error; MemberInfo memberInfo = this.Property.ParentType .FindMember() .IsMethod() .IsNamed(info.CustomListDrawerOptions.OnEndListElementGUI) .HasParameters <int>() .ReturnsVoid() .GetMember <MethodInfo>(out error); if (memberInfo == null || error != null) { // TOOD: Do something about this "There should really be an error message here." thing. // For this to trigger both the member and the error message should be null. Can that happen? this.errorMessage = error ?? "There should really be an error message here."; } else { info.OnEndListElementGUI = EmitUtilities.CreateWeakInstanceMethodCaller <int>(memberInfo as MethodInfo); } } if (info.CustomListDrawerOptions.OnTitleBarGUI != null) { string error; MemberInfo memberInfo = this.Property.ParentType .FindMember() .IsMethod() .IsNamed(info.CustomListDrawerOptions.OnTitleBarGUI) .HasNoParameters() .ReturnsVoid() .GetMember <MethodInfo>(out error); if (memberInfo == null || error != null) { // TOOD: Do something about this "There should really be an error message here." thing. // For this to trigger both the member and the error message should be null. Can that happen? this.errorMessage = error ?? "There should really be an error message here."; } else { info.OnTitleBarGUI = EmitUtilities.CreateWeakInstanceMethodCaller(memberInfo as MethodInfo); } } if (info.CustomListDrawerOptions.ListElementLabelName != null) { string error; MemberInfo memberInfo = resolver.ElementType .FindMember() .HasNoParameters() .IsNamed(info.CustomListDrawerOptions.ListElementLabelName) .HasReturnType <object>(true) .GetMember(out error); if (memberInfo == null || error != null) { // TOOD: Do something about this "There should really be an error message here." thing. // For this to trigger both the member and the error message should be null. Can that happen? this.errorMessage = error ?? "There should really be an error message here."; } else { string methodSuffix = memberInfo as MethodInfo == null ? "" : "()"; info.GetListElementLabelText = DeepReflection.CreateWeakInstanceValueGetter(resolver.ElementType, typeof(object), info.CustomListDrawerOptions.ListElementLabelName + methodSuffix); } } // Resolve custom add method member reference. if (info.CustomListDrawerOptions.CustomAddFunction != null) { string error; MemberInfo memberInfo = this.Property.ParentType .FindMember() .HasNoParameters() .IsNamed(info.CustomListDrawerOptions.CustomAddFunction) .IsInstance() .HasReturnType(resolver.ElementType) .GetMember(out error); if (memberInfo == null || error != null) { string error2; memberInfo = this.Property.ParentType .FindMember() .IsMethod() .HasNoParameters() .IsNamed(info.CustomListDrawerOptions.CustomAddFunction) .IsInstance() .ReturnsVoid() .GetMember(out error2); if (memberInfo == null || error2 != null) { this.errorMessage = error + " - or - " + error2; } else { info.GetCustomAddFunctionVoid = EmitUtilities.CreateWeakInstanceMethodCaller(memberInfo as MethodInfo); } } else { string methodSuffix = memberInfo as MethodInfo == null ? "" : "()"; info.GetCustomAddFunction = DeepReflection.CreateWeakInstanceValueGetter( this.Property.ParentType, resolver.ElementType, info.CustomListDrawerOptions.CustomAddFunction + methodSuffix ); } } // Resolve custom remove index method member reference. if (info.CustomListDrawerOptions.CustomRemoveIndexFunction != null) { if (this.Property.ChildResolver is IOrderedCollectionResolver == false) { this.errorMessage = "ListDrawerSettings.CustomRemoveIndexFunction is invalid on unordered collections. Use ListDrawerSetings.CustomRemoveElementFunction instead."; } else { MethodInfo method = this.Property.ParentType .FindMember() .IsNamed(info.CustomListDrawerOptions.CustomRemoveIndexFunction) .IsMethod() .IsInstance() .HasParameters <int>() .ReturnsVoid() .GetMember <MethodInfo>(out this.errorMessage); if (method != null) { info.CustomRemoveIndexFunction = EmitUtilities.CreateWeakInstanceMethodCaller <int>(method); } } } // Resolve custom remove element method member reference. else if (info.CustomListDrawerOptions.CustomRemoveElementFunction != null) { var element = (this.Property.ChildResolver as ICollectionResolver).ElementType; MethodInfo method = this.Property.ParentType .FindMember() .IsNamed(info.CustomListDrawerOptions.CustomRemoveElementFunction) .IsMethod() .IsInstance() .HasParameters(element) .ReturnsVoid() .GetMember <MethodInfo>(out this.errorMessage); if (method != null) { // TOOD: Emit dis. info.CustomRemoveElementFunction = (o, e) => method.Invoke(o, new object[] { e }); } } }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(GUIContent label) { var property = this.Property; var entry = this.ValueEntry; var attribute = this.Attribute; var assetList = property.Context.Get(this, "assetList", (AssetList)null); var propertyTree = property.Context.Get(this, "togglableAssetListPropertyTree", (PropertyTree)null); if (property.ValueEntry.WeakSmartValue == null) { return; } if (assetList.Value == null) { assetList.Value = new AssetList(); assetList.Value.AutoPopulate = attribute.AutoPopulate; assetList.Value.AssetNamePrefix = attribute.AssetNamePrefix; assetList.Value.Tags = attribute.Tags != null?attribute.Tags.Trim().Split(',').Select(i => i.Trim()).ToArray() : null; assetList.Value.LayerNames = attribute.LayerNames != null?attribute.LayerNames.Trim().Split(',').Select(i => i.Trim()).ToArray() : null; assetList.Value.List = entry; assetList.Value.CollectionResolver = property.ChildResolver as IOrderedCollectionResolver; assetList.Value.Property = entry.Property; if (attribute.Path != null) { var path = attribute.Path.TrimStart('/', ' ').TrimEnd('/', ' '); path = attribute.Path.Trim('/', ' '); path = "Assets/" + path + "/"; path = Application.dataPath + "/" + path; assetList.Value.AssetsFolderLocation = new DirectoryInfo(path); path = attribute.Path.Trim('/', ' '); assetList.Value.PrettyPath = "/" + path.TrimStart('/'); } if (attribute.CustomFilterMethod != null) { MethodInfo methodInfo; string error; if (MemberFinder.Start(entry.ParentType) .IsMethod() .IsNamed(attribute.CustomFilterMethod) .HasReturnType <bool>() .HasParameters <TElement>() .TryGetMember <MethodInfo>(out methodInfo, out error)) { if (methodInfo.IsStatic) { assetList.Value.StaticCustomIncludeMethod = (Func <TElement, bool>)Delegate.CreateDelegate(typeof(Func <TElement, bool>), methodInfo, true); } else { assetList.Value.InstanceCustomIncludeMethod = EmitUtilities.CreateWeakInstanceMethodCaller <bool, TElement>(methodInfo); } } assetList.Value.ErrorMessage = error; } // We can get away with lag on load. assetList.Value.MaxSearchDurationPrFrameInMS = 20; assetList.Value.EnsureListPopulation(); assetList.Value.MaxSearchDurationPrFrameInMS = 1; //assetList.Value.List = list; //if (propertyTree.Value == null) //{ propertyTree.Value = PropertyTree.Create(assetList.Value); propertyTree.Value.UpdateTree(); propertyTree.Value.GetRootProperty(0).Label = label; //} } else if (Event.current.type == EventType.Layout) { assetList.Value.Property = entry.Property; assetList.Value.EnsureListPopulation(); assetList.Value.SetToggleValues(); } if (assetList.Value.ErrorMessage != null) { SirenixEditorGUI.ErrorMessageBox(assetList.Value.ErrorMessage); } assetList.Value.Property = entry.Property; propertyTree.Value.Draw(false); if (Event.current.type == EventType.Used) { assetList.Value.UpdateList(); } }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(IPropertyValueEntry <T> entry, DetailedInfoBoxAttribute attribute, GUIContent label) { PropertyContext <InfoBoxContext> context = entry.Property.Context.Get(this, "Context", (InfoBoxContext)null); if (context.Value == null) { context.Value = new InfoBoxContext() { MessageHelper = new StringMemberHelper(entry.ParentType, attribute.Message), DetailsHelper = new StringMemberHelper(entry.ParentType, attribute.Details) }; context.Value.ErrorMessage = context.Value.MessageHelper.ErrorMessage ?? context.Value.DetailsHelper.ErrorMessage; if (attribute.VisibleIf != null) { MemberInfo memberInfo; // Parameter functions if (entry.ParentType.FindMember() .IsMethod() .HasReturnType <bool>() .HasParameters <T>() .IsNamed(attribute.VisibleIf) .TryGetMember(out memberInfo, out context.Value.ErrorMessage)) { if (context.Value.ErrorMessage == null) { if (memberInfo is MethodInfo) { if (memberInfo.IsStatic()) { context.Value.StaticValidationParameterMethodCaller = (Func <T, bool>)Delegate.CreateDelegate(typeof(Func <T, bool>), memberInfo as MethodInfo); } else { context.Value.InstanceValidationParameterMethodCaller = EmitUtilities.CreateWeakInstanceMethodCaller <bool, T>(memberInfo as MethodInfo); } } else { context.Value.ErrorMessage = "Invalid member type!"; } } } // Fields, properties, and no-parameter functions. else if (entry.ParentType.FindMember() .HasReturnType <bool>() .HasNoParameters() .IsNamed(attribute.VisibleIf) .TryGetMember(out memberInfo, out context.Value.ErrorMessage)) { if (context.Value.ErrorMessage == null) { if (memberInfo is FieldInfo) { if (memberInfo.IsStatic()) { context.Value.StaticValidationCaller = EmitUtilities.CreateStaticFieldGetter <bool>(memberInfo as FieldInfo); } else { context.Value.InstanceValueGetter = EmitUtilities.CreateWeakInstanceFieldGetter(entry.ParentType, memberInfo as FieldInfo); } } else if (memberInfo is PropertyInfo) { if (memberInfo.IsStatic()) { context.Value.StaticValidationCaller = EmitUtilities.CreateStaticPropertyGetter <bool>(memberInfo as PropertyInfo); } else { context.Value.InstanceValueGetter = EmitUtilities.CreateWeakInstancePropertyGetter(entry.ParentType, memberInfo as PropertyInfo); } } else if (memberInfo is MethodInfo) { if (memberInfo.IsStatic()) { context.Value.StaticValidationCaller = (Func <bool>)Delegate.CreateDelegate(typeof(Func <bool>), memberInfo as MethodInfo); } else { context.Value.InstanceValidationMethodCaller = EmitUtilities.CreateWeakInstanceMethodCallerFunc <bool>(memberInfo as MethodInfo); } } else { context.Value.ErrorMessage = "Invalid member type!"; } } } } } if (context.Value.ErrorMessage != null) { AllEditorGUI.ErrorMessageBox(context.Value.ErrorMessage); } else { if (Event.current.type == EventType.Layout) { var parentValue = entry.Property.ParentValues[0]; try { if (entry.Property.ValueEntry != null) { context.Value.DrawMessageBox = attribute.VisibleIf == null || (context.Value.StaticValidationParameterMethodCaller != null && context.Value.StaticValidationParameterMethodCaller(entry.SmartValue)) || (context.Value.InstanceValidationParameterMethodCaller != null && context.Value.InstanceValidationParameterMethodCaller(entry.Property.ParentValues[0], entry.SmartValue)) || (context.Value.InstanceValidationMethodCaller != null && context.Value.InstanceValidationMethodCaller(entry.Property.ParentValues[0])) || (context.Value.InstanceValueGetter != null && (bool)context.Value.InstanceValueGetter(ref parentValue)) || (context.Value.StaticValidationCaller != null && context.Value.StaticValidationCaller()); } } catch (System.Exception ex) { Debug.LogException(ex); } } if (context.Value.DrawMessageBox) { var foldedConfig = entry.Property.Context.GetPersistent <bool>(this, "InfoBoxExpanded", true); switch (attribute.InfoMessageType) { case InfoMessageType.None: foldedConfig.Value = AllEditorGUI.DetailedMessageBox(context.Value.MessageHelper.GetString(entry), context.Value.DetailsHelper.GetString(entry), UnityEditor.MessageType.None, foldedConfig.Value); break; case InfoMessageType.Info: foldedConfig.Value = AllEditorGUI.DetailedMessageBox(context.Value.MessageHelper.GetString(entry), context.Value.DetailsHelper.GetString(entry), UnityEditor.MessageType.Info, foldedConfig.Value); break; case InfoMessageType.Warning: foldedConfig.Value = AllEditorGUI.DetailedMessageBox(context.Value.MessageHelper.GetString(entry), context.Value.DetailsHelper.GetString(entry), UnityEditor.MessageType.Warning, foldedConfig.Value); break; case InfoMessageType.Error: foldedConfig.Value = AllEditorGUI.DetailedMessageBox(context.Value.MessageHelper.GetString(entry), context.Value.DetailsHelper.GetString(entry), UnityEditor.MessageType.Error, foldedConfig.Value); break; default: AllEditorGUI.ErrorMessageBox("Unknown InfoBoxType: " + attribute.InfoMessageType.ToString()); break; } } } this.CallNextDrawer(entry.Property, label); }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(IPropertyValueEntry <TList> entry, GUIContent label) { var property = entry.Property; var infoContext = property.Context.Get(this, "Context", (ListDrawerConfigInfo)null); var info = infoContext.Value; bool isReadOnly = false; if (entry.TypeOfValue.IsArray == false) { for (int i = 0; i < entry.ValueCount; i++) { if ((entry.WeakValues[i] as IList <TElement>).IsReadOnly) { isReadOnly = true; break; } } } if (info == null) { var customListDrawerOptions = property.Info.GetAttribute <ListDrawerSettingsAttribute>() ?? new ListDrawerSettingsAttribute(); isReadOnly = entry.IsEditable == false || isReadOnly || customListDrawerOptions.IsReadOnlyHasValue && customListDrawerOptions.IsReadOnly; info = infoContext.Value = new ListDrawerConfigInfo() { StartIndex = 0, Toggled = entry.Context.GetPersistent <bool>(this, "ListDrawerToggled", customListDrawerOptions.ExpandedHasValue ? customListDrawerOptions.Expanded : GeneralDrawerConfig.Instance.OpenListsByDefault), RemoveAt = -1, label = new GUIContent(label == null || string.IsNullOrEmpty(label.text) ? property.ValueEntry.TypeOfValue.GetNiceName() : label.text, label == null ? string.Empty : label.tooltip), ShowAllWhilePageing = false, EndIndex = 0, CustomListDrawerOptions = customListDrawerOptions, IsReadOnly = isReadOnly, Draggable = !isReadOnly && (!customListDrawerOptions.IsReadOnlyHasValue) }; info.listConfig = GeneralDrawerConfig.Instance; info.property = property; if (customListDrawerOptions.DraggableHasValue && !customListDrawerOptions.DraggableItems) { info.Draggable = false; } if (info.CustomListDrawerOptions.OnBeginListElementGUI != null) { string errorMessage; MemberInfo memberInfo = property.ParentType .FindMember() .IsMethod() .IsNamed(info.CustomListDrawerOptions.OnBeginListElementGUI) .HasParameters <int>() .ReturnsVoid() .GetMember <MethodInfo>(out errorMessage); if (memberInfo == null || errorMessage != null) { Debug.LogError(errorMessage ?? "There should really be an error message here."); } else { info.OnBeginListElementGUI = EmitUtilities.CreateWeakInstanceMethodCaller <int>(memberInfo as MethodInfo); } } if (info.CustomListDrawerOptions.OnEndListElementGUI != null) { string errorMessage; MemberInfo memberInfo = property.ParentType .FindMember() .IsMethod() .IsNamed(info.CustomListDrawerOptions.OnEndListElementGUI) .HasParameters <int>() .ReturnsVoid() .GetMember <MethodInfo>(out errorMessage); if (memberInfo == null || errorMessage != null) { Debug.LogError(errorMessage ?? "There should really be an error message here."); } else { info.OnEndListElementGUI = EmitUtilities.CreateWeakInstanceMethodCaller <int>(memberInfo as MethodInfo); } } if (info.CustomListDrawerOptions.OnTitleBarGUI != null) { string errorMessage; MemberInfo memberInfo = property.ParentType .FindMember() .IsMethod() .IsNamed(info.CustomListDrawerOptions.OnTitleBarGUI) .HasNoParameters() .ReturnsVoid() .GetMember <MethodInfo>(out errorMessage); if (memberInfo == null || errorMessage != null) { Debug.LogError(errorMessage ?? "There should really be an error message here."); } else { info.OnTitleBarGUI = EmitUtilities.CreateWeakInstanceMethodCaller(memberInfo as MethodInfo); } } if (info.CustomListDrawerOptions.ListElementLabelName != null) { string errorMessage; MemberInfo memberInfo = typeof(TElement) .FindMember() .HasNoParameters() .IsNamed(info.CustomListDrawerOptions.ListElementLabelName) .HasReturnType <object>(true) .GetMember(out errorMessage); if (memberInfo == null || errorMessage != null) { Debug.LogError(errorMessage ?? "There should really be an error message here."); } else { string methodSuffix = memberInfo as MethodInfo == null ? "" : "()"; info.GetListElementLabelText = DeepReflection.CreateWeakInstanceValueGetter(typeof(TElement), typeof(object), info.CustomListDrawerOptions.ListElementLabelName + methodSuffix); } } } info.listConfig = GeneralDrawerConfig.Instance; info.property = property; info.ListItemStyle.padding.left = info.Draggable ? 25 : 7; info.ListItemStyle.padding.right = info.IsReadOnly ? 4 : 20; if (Event.current.type == EventType.Repaint) { info.DropZoneTopLeft = GUIUtility.GUIToScreenPoint(new Vector2(0, 0)); } info.ListValueChanger = property.ValueEntry.GetListValueEntryChanger(); info.Count = property.Children.Count; info.IsEmpty = property.Children.Count == 0; SirenixEditorGUI.BeginIndentedVertical(SirenixGUIStyles.PropertyPadding); this.BeginDropZone(info); { this.DrawToolbar(info); if (SirenixEditorGUI.BeginFadeGroup(UniqueDrawerKey.Create(property, this), info.Toggled.Value)) { GUIHelper.PushLabelWidth(EditorGUIUtility.labelWidth - info.ListItemStyle.padding.left); this.DrawItems(info); GUIHelper.PopLabelWidth(); } SirenixEditorGUI.EndFadeGroup(); } this.EndDropZone(info); SirenixEditorGUI.EndIndentedVertical(); if (info.RemoveAt >= 0 && Event.current.type == EventType.Repaint) { info.ListValueChanger.RemoveListElementAt(info.RemoveAt, CHANGE_ID); info.RemoveAt = -1; GUIHelper.RequestRepaint(); } if (info.ObjectPicker != null && info.ObjectPicker.IsReadyToClaim && Event.current.type == EventType.Repaint) { var value = info.ObjectPicker.ClaimObject(); if (info.JumpToNextPageOnAdd) { info.StartIndex = int.MaxValue; } object[] values = new object[info.ListValueChanger.ValueCount]; values[0] = value; for (int j = 1; j < values.Length; j++) { values[j] = SerializationUtility.CreateCopy(value); } info.ListValueChanger.AddListElement(values, CHANGE_ID); } }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(GUIContent label) { var entry = this.ValueEntry; var attribute = this.Attribute; var context = entry.Property.Context.Get <ButtonContext>(this, "ButtonContext", (ButtonContext)null); if (context.Value == null) { context.Value = new ButtonContext(); context.Value.LabelHelper = new StringMemberHelper(this.Property, attribute.Label ?? attribute.MemberMethod.SplitPascalCase(), ref context.Value.ErrorMessage); if (context.Value.ErrorMessage == null) { MethodInfo method; if (MemberFinder.Start(entry.ParentType) .IsMethod() .IsNamed(attribute.MemberMethod) .HasNoParameters() .TryGetMember <MethodInfo>(out method, out context.Value.ErrorMessage)) { if (method.IsStatic()) { context.Value.StaticMethodCaller = EmitUtilities.CreateStaticMethodCaller(method); } else { context.Value.InstanceMethodCaller = EmitUtilities.CreateWeakInstanceMethodCaller(method); } } else if (MemberFinder.Start(entry.ParentType) .IsMethod() .IsNamed(attribute.MemberMethod) .HasParameters <T>() .TryGetMember <MethodInfo>(out method, out context.Value.ErrorMessage)) { if (method.IsStatic()) { context.Value.ErrorMessage = "Static parameterized method is currently not supported."; } else { context.Value.InstanceParameterMethodCaller = EmitUtilities.CreateWeakInstanceMethodCaller <T>(method); } } } } if (context.Value.ErrorMessage != null) { SirenixEditorGUI.ErrorMessageBox(context.Value.ErrorMessage); this.CallNextDrawer(label); } else { EditorGUILayout.BeginHorizontal(); EditorGUILayout.BeginVertical(); this.CallNextDrawer(label); EditorGUILayout.EndVertical(); if (GUILayout.Button(context.Value.LabelHelper.GetString(entry), EditorStyles.miniButton, GUILayoutOptions.ExpandWidth(false).MinWidth(20))) { // Invoke method. if (context.Value.StaticMethodCaller != null) { context.Value.StaticMethodCaller(); } //else if(context.Value.StaticParameterMethodCaller != null) //{ // context.Value.StaticParameterMethodCaller(entry.SmartValue); //} else if (context.Value.InstanceMethodCaller != null) { context.Value.InstanceMethodCaller(entry.Property.ParentValues[0]); } else if (context.Value.InstanceParameterMethodCaller != null) { context.Value.InstanceParameterMethodCaller(entry.Property.ParentValues[0], entry.SmartValue); } else { Debug.LogError("No method found."); } } EditorGUILayout.EndHorizontal(); } }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyImplementation(InspectorProperty property, GUIContent label) { if (buttonStyle == null) { buttonStyle = new GUIStyle(GUI.skin.button); //{ // fixedHeight = 0, //}; } if (property.Info.PropertyType != PropertyType.Method) { throw new ArgumentException("A method property drawer of type " + this.GetType().GetNiceName() + " cannot draw properties of type " + property.Info.PropertyType + "."); } var methodInfo = (MethodInfo)property.Info.MemberInfo; // // If method is not valid, render error message and return // var isValid = property.Context.Get(this, "IsValid", (bool?)null); if (!isValid.Value.HasValue) { isValid.Value = methodInfo.GetParameters().Length == 0; } if (!isValid.Value.Value) { var error = property.Context.Get(this, "Error", (string)null); if (error.Value == null) { error.Value = "Cannot show button for method '" + methodInfo.DeclaringType.GetNiceName() + "." + methodInfo.GetNiceName() + "' in the inspector, because it does not have zero parameters."; } AllEditorGUI.ErrorMessageBox(error.Value); return; } // // Handle button style and label // GUIStyle style = property.Context.GetGlobal("ButtonStyle", (GUIStyle)null).Value; var buttonHeight = property.Context.GetGlobal("ButtonHeight", 0).Value; var buttonAttribute = property.Info.GetAttribute <ButtonAttribute>(); if (buttonAttribute != null) { if (buttonHeight == 0 && buttonAttribute.ButtonHeight > 0) { buttonHeight = buttonAttribute.ButtonHeight; //buttonStyle.fixedHeight = buttonAttribute.ButtonHeight; //style = buttonStyle; } if (buttonAttribute.Name != null) { var mh = property.Context.Get(this, "ButtonStringMemberHelper", (StringMemberHelper)null); if (mh.Value == null) { mh.Value = new StringMemberHelper(property.ParentType, buttonAttribute.Name); } if (mh.Value.ErrorMessage != null) { AllEditorGUI.ErrorMessageBox(mh.Value.ErrorMessage); } if (label == null) { label = new GUIContent(mh.Value.GetString(property)); } else { label.text = mh.Value.GetString(property); } } } if (style == null) { if (buttonHeight > 20) { style = SirenixGUIStyles.Button; } else { style = EditorStyles.miniButton; } } // // Render button and invoke // Rect btnRect = buttonHeight > 0 ? GUILayoutUtility.GetRect(GUIContent.none, style, GUILayoutOptions.Height(buttonHeight)) : GUILayoutUtility.GetRect(GUIContent.none, style); btnRect = EditorGUI.IndentedRect(btnRect); if (label == null) { label = GUIHelper.TempContent(property.Info.PropertyName.TitleCase_AddKongGe()); } if (GUI.Button(btnRect, label, style)) { GUIHelper.RemoveFocusControl(); var caller = property.Context.Get(this, "MethodCaller", (Action <object>)null); if (caller.Value == null) { caller.Value = EmitUtilities.CreateWeakInstanceMethodCaller(methodInfo); } var parentValueProperty = property.ParentValueProperty; var targets = property.ParentValues; for (int i = 0; i < targets.Count; i++) { object value = targets[i]; if (object.ReferenceEquals(value, null) == false) { try { caller.Value(value); } catch (ExitGUIException ex) { throw ex; } catch (Exception ex) { Debug.LogException(ex); } if (parentValueProperty != null && value.GetType().IsValueType) { // If it's a struct, it will have been boxed and the invoke call might // have changed the struct and this won't be reflected in the original, // unboxed source struct. // Therefore, set the source value to the boxed struct that we just invoked on. parentValueProperty.ValueEntry.WeakValues[i] = value; } } } } }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(GUIContent label) { var property = this.Property; var attribute = this.Attribute; if (property.Info.PropertyType == PropertyType.Method) { var methodContext = property.Context.Get(this, "Config", (MethodContext)null); if (methodContext.Value == null) { methodContext.Value = new MethodContext(); MethodInfo methodInfo = property.Info.GetMemberInfo() as MethodInfo; if (methodInfo == null) { methodInfo = property.Info.GetMethodDelegate().Method; } if (methodInfo.ReturnType != typeof(void)) { methodContext.Value.ErrorMessage = "The method '" + methodInfo.Name + "' must have a return type of type void."; } else if (methodInfo.GetParameters().Length > 0) { methodContext.Value.ErrorMessage = "The method '" + methodInfo.Name + "' cannot take any parameters."; } else if (methodInfo.IsStatic) { var del = property.Info.GetMethodDelegate(); if (del == null) { methodContext.Value.StaticMethod = EmitUtilities.CreateStaticMethodCaller(methodInfo); } else { methodContext.Value.StaticMethod = (Action)del; } } else { var del = property.Info.GetMethodDelegate(); if (del == null) { methodContext.Value.InstanceMethod = EmitUtilities.CreateWeakInstanceMethodCaller(methodInfo); } else { methodContext.Value.StaticMethod = () => del.DynamicInvoke(); } } } if (methodContext.Value.ErrorMessage != null) { SirenixEditorGUI.ErrorMessageBox(methodContext.Value.ErrorMessage); } else { if (methodContext.Value.InstanceMethod != null) { methodContext.Value.InstanceMethod(property.ParentValues[0]); } else { methodContext.Value.StaticMethod(); } } } else { if (attribute.PrependMethodName != null) { this.DoInspectorGUI(property, "Prepend", attribute.PrependMethodName); } this.CallNextDrawer(label); if (attribute.AppendMethodName != null) { this.DoInspectorGUI(property, "Append", attribute.AppendMethodName); } } }