protected override void DrawPropertyLayout(IPropertyValueEntry <T> entry, GUIContent label) { var eventDrawer = entry.Context.Get(this, "event_drawer", (UnityEditorInternal.UnityEventDrawer)null); if (eventDrawer.Value == null) { eventDrawer.Value = new UnityEditorInternal.UnityEventDrawer(); this.drawer = eventDrawer.Value; if (UnityPropertyHandlerUtility.IsAvailable) { this.propertyHandler = UnityPropertyHandlerUtility.CreatePropertyHandler(this.drawer); } } FieldInfo fieldInfo; SerializedProperty unityProperty = entry.Property.Tree.GetUnityPropertyForPath(entry.Property.Path, out fieldInfo); if (unityProperty == null) { if (UnityVersion.IsVersionOrGreater(2017, 1)) { this.CallNextDrawer(entry, label); return; } else if (!typeof(T).IsDefined <SerializableAttribute>()) { AllEditorGUI.ErrorMessageBox("You have likely forgotten to mark your custom UnityEvent class '" + typeof(T).GetNiceName() + "' with the [Serializable] attribute! Could not get a Unity SerializedProperty for the property '" + entry.Property.NiceName + "' of type '" + entry.TypeOfValue.GetNiceName() + "' at path '" + entry.Property.Path + "'."); return; } } base.DrawPropertyLayout(entry, label); }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(InspectorProperty property, ShowIfAttribute attribute, GUIContent label) { bool result; string errorMessage; IfAttributesHelper.HandleIfAttributesCondition(this, property, attribute.MemberName, attribute.Value, out result, out errorMessage); if (errorMessage != null) { AllEditorGUI.ErrorMessageBox(errorMessage); this.CallNextDrawer(property, label); } else { if (attribute.Animate) { if (AllEditorGUI.BeginFadeGroup(UniqueDrawerKey.Create(property, this), result)) { this.CallNextDrawer(property, label); } AllEditorGUI.EndFadeGroup(); } else { if (result) { this.CallNextDrawer(property, label); } } } }
protected override void DrawPropertyLayout(InspectorProperty property, TitleAttribute attribute, GUIContent label) { var context = property.Context.Get <TitleContext>(this, "TitleContext", (TitleContext)null); if (context.Value == null) { context.Value = new TitleContext(); context.Value.TitleHelper = new StringMemberHelper(property.ParentType, attribute.Title, ref context.Value.ErrorMessage); context.Value.SubtitleHelper = new StringMemberHelper(property.ParentType, attribute.Subtitle, ref context.Value.ErrorMessage); } // Don't draw added emtpy space for the first property. if (property != property.Tree.GetRootProperty(0)) { EditorGUILayout.Space(); } if (context.Value.ErrorMessage != null) { AllEditorGUI.ErrorMessageBox(context.Value.ErrorMessage); } else { AllEditorGUI.Title( context.Value.TitleHelper.GetString(property), context.Value.SubtitleHelper.GetString(property), (TextAlignment)attribute.TitleAlignment, attribute.HorizontalLine, attribute.Bold, attribute.TextColor); } CallNextDrawer(property, label); }
/// <summary> /// Draws the attribute. /// </summary> protected override void DrawPropertyLayout(InspectorProperty property, LabelTextAttribute attribute, GUIContent label) { var context = property.Context.Get <StringMemberHelper>(this, "StringContext", (StringMemberHelper)null); if (context.Value == null) { context.Value = new StringMemberHelper(property.ParentType, attribute.Text); } if (context.Value.ErrorMessage != null) { AllEditorGUI.ErrorMessageBox(context.Value.ErrorMessage); } if (label == null) { property.Label = null; } else { property.Label = label; property.Label.text = context.Value.GetString(property); } this.CallNextDrawer(property, property.Label); }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(InspectorProperty property, DisableIfAttribute attribute, GUIContent label) { if (GUI.enabled == false) { this.CallNextDrawer(property, label); return; } bool result; string errorMessage; IfAttributesHelper.HandleIfAttributesCondition(this, property, attribute.MemberName, attribute.Value, out result, out errorMessage); if (errorMessage != null) { AllEditorGUI.ErrorMessageBox(errorMessage); this.CallNextDrawer(property, label); } else if (result) { GUIHelper.PushGUIEnabled(false); this.CallNextDrawer(property, label); GUIHelper.PopGUIEnabled(); } else { this.CallNextDrawer(property, label); } }
private void SuppressMissingEditorTypeErrorsMessage() { if (UnityVersion.Major == 2017 && UnityVersion.Minor == 1) { AllEditorGUI.ErrorMessageBox("Suppressing these error messages may cause crashes on Unity 2017.1 (see Unity issue 920772). A fix is being backported from 2017.2 - meanwhile, you may want to disable this option, and live with the constant error messages about missing editor types."); } }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(InspectorProperty property, RequiredAttribute attribute, GUIContent label) { if (property.ValueEntry.BaseValueType.IsValueType) { AllEditorGUI.ErrorMessageBox("Value types cannot be null, and thus cannot be marked as required."); return; } // Message context. PropertyContext <StringMemberHelper> context = null; if (attribute.ErrorMessage != null) { context = property.Context.Get <StringMemberHelper>(this, "ErrorMessage", (StringMemberHelper)null); if (context.Value == null) { context.Value = new StringMemberHelper(property.ParentType, attribute.ErrorMessage); } if (context.Value.ErrorMessage != null) { AllEditorGUI.ErrorMessageBox(context.Value.ErrorMessage); } } var isMissing = CheckIsMissing(property); if (isMissing) { string msg = attribute.ErrorMessage != null?context.Value.GetString(property) : (property.NiceName + " is required."); if (attribute.MessageType == InfoMessageType.Warning) { AllEditorGUI.WarningMessageBox(msg); } else if (attribute.MessageType == InfoMessageType.Error) { AllEditorGUI.ErrorMessageBox(msg); } else { EditorGUILayout.HelpBox(msg, (MessageType)attribute.MessageType); } } var key = UniqueDrawerKey.Create(property, this); AllEditorGUI.BeginShakeableGroup(key); this.CallNextDrawer(property, label); AllEditorGUI.EndShakeableGroup(key); if (!isMissing && CheckIsMissing(property)) { AllEditorGUI.StartShakingGroup(key); } }
protected override void DrawPropertyLayout(IPropertyValueEntry <T> entry, GUIContent label) { bool valueNeedsFixing = entry.ValueState == PropertyValueState.NullReference && entry.SerializationBackend == SerializationBackend.Unity; if (valueNeedsFixing) { bool possibleRecursion = false; var prop = entry.Property.Parent; while (prop != null) { if (prop.ValueEntry != null && (prop.ValueEntry.TypeOfValue == typeof(T) || prop.ValueEntry.BaseValueType == typeof(T))) { // We have a possible recursion possibleRecursion = true; break; } prop = prop.Parent; } if (possibleRecursion) { AllEditorGUI.ErrorMessageBox("Possible Unity serialization recursion detected; cutting off drawing pre-emptively."); return; // Get out of here } // If no recursion, fix value in layout if (Event.current.type == EventType.Layout) { for (int i = 0; i < entry.ValueCount; i++) { object value = UnitySerializationUtility.CreateDefaultUnityInitializedObject(typeof(T)); entry.WeakValues.ForceSetValue(i, value); } entry.ApplyChanges(); var tree = entry.Property.Tree; if (tree.UnitySerializedObject != null) { tree.UnitySerializedObject.ApplyModifiedPropertiesWithoutUndo(); Undo.RecordObjects(tree.UnitySerializedObject.targetObjects, "ODIN inspector value changed"); } entry.Property.Update(true); } } this.CallNextDrawer(entry, label); }
/// <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) { AllEditorGUI.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); } } }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(InspectorProperty property, TAttribute attribute, GUIContent label) { if (SetAttribute == null) { AllEditorGUI.ErrorMessageBox("Could not find the internal Unity field 'DecoratorDrawer.m_Attribute'; UnityDecoratorDrawer alias '" + typeof(UnityDecoratorAttributeDrawer <TDrawer, TAttribute, TAttributeConstraint>).GetNiceName() + "' has been disabled."); return; } SetAttribute(ref this.drawer, attribute); float height = this.drawer.GetHeight(); var position = EditorGUILayout.GetControlRect(false, height); this.drawer.OnGUI(position); this.CallNextDrawer(property, label); }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(IPropertyValueEntry <T> entry, GUIContent label) { FieldInfo fieldInfo; SerializedProperty unityProperty = entry.Property.Tree.GetUnityPropertyForPath(entry.Property.Path, out fieldInfo); if (unityProperty == null) { AllEditorGUI.ErrorMessageBox("Could not get a Unity SerializedProperty for the property '" + entry.Property.NiceName + "' of type '" + entry.TypeOfValue.GetNiceName() + "' at path '" + entry.Property.Path + "'."); return; } if (unityProperty.serializedObject.targetObject is EmittedScriptableObject <T> ) { var targetObjects = unityProperty.serializedObject.targetObjects; for (int i = 0; i < targetObjects.Length; i++) { EmittedScriptableObject <T> target = (EmittedScriptableObject <T>)targetObjects[i]; target.SetValue(entry.Values[i]); } unityProperty.serializedObject.Update(); unityProperty = unityProperty.serializedObject.FindProperty(unityProperty.propertyPath); } if (label == null) { label = GUIHelper.TempContent(""); } EditorGUILayout.PropertyField(unityProperty, label, true); if (unityProperty.serializedObject.targetObject is EmittedScriptableObject <T> ) { unityProperty.serializedObject.ApplyModifiedPropertiesWithoutUndo(); var targetObjects = unityProperty.serializedObject.targetObjects; for (int i = 0; i < targetObjects.Length; i++) { EmittedScriptableObject <T> target = (EmittedScriptableObject <T>)targetObjects[i]; entry.Values[i] = target.GetValue(); } } }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(InspectorProperty property, CustomContextMenuAttribute attribute, GUIContent label) { 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) { AllEditorGUI.ErrorMessageBox(info.ErrorMessage); } this.CallNextDrawer(property, label); }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(InspectorProperty property, PropertyTooltipAttribute attribute, GUIContent label) { if (label != null) { var context = property.Context.Get <StringMemberHelper>(this, "Tooltip", (StringMemberHelper)null); if (context.Value == null) { context.Value = new StringMemberHelper(property.ParentType, attribute.Tooltip); } if (context.Value.ErrorMessage != null) { AllEditorGUI.ErrorMessageBox(context.Value.ErrorMessage); } label.tooltip = context.Value.GetString(property); } this.CallNextDrawer(property, label); }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyGroupLayout(InspectorProperty property, FoldoutGroupAttribute attribute, GUIContent label) { var context = property.Context.Get <FoldoutGroupContext>(this, "FoldoutGroupContext", (FoldoutGroupContext)null); if (context.Value == null) { context.Value = new FoldoutGroupContext() { IsVisible = property.Context.GetPersistent <bool>(this, "IsVisible", attribute.HasDefinedExpanded ? attribute.Expanded : AllEditorGUI.ExpandFoldoutByDefault), TitleHelper = new StringMemberHelper(property.ParentType, attribute.GroupName) }; } if (context.Value.TitleHelper.ErrorMessage != null) { AllEditorGUI.ErrorMessageBox(context.Value.TitleHelper.ErrorMessage); } AllEditorGUI.BeginBox(); { AllEditorGUI.BeginBoxHeader(); var content = GUIHelper.TempContent(context.Value.TitleHelper.GetString(property)); var rect = GUILayoutUtility.GetRect(content, SirenixGUIStyles.Label); context.Value.IsVisible.Value = AllEditorGUI.Foldout(rect, context.Value.IsVisible.Value, content); AllEditorGUI.EndBoxHeader(); if (AllEditorGUI.BeginFadeGroup(context, context.Value.IsVisible.Value)) { for (int i = 0; i < property.Children.Count; i++) { InspectorUtilities.DrawProperty(property.Children[i]); } } AllEditorGUI.EndFadeGroup(); } AllEditorGUI.EndBox(); }
/// <summary> /// Not yet documented. /// </summary> protected override void DrawPropertyLayout(IPropertyValueEntry <string> entry, FolderPathAttribute attribute, GUIContent label) { // Create a property context for the parent path. InspectorProperty parentProperty = entry.Property.FindParent(PropertyValueCategory.Member, true); PropertyContext <FolderPathContext> context; if (entry.Context.Get <FolderPathContext>(this, "FolderPath", out context)) { context.Value = new FolderPathContext() { ParentPath = new StringMemberHelper(parentProperty.ParentType, attribute.ParentFolder), }; context.Value.Exists = PathExists(entry.SmartValue, context.Value.ParentPath.GetString(entry)); } // Display evt. errors in creating context. if (context.Value.ParentPath.ErrorMessage != null) { AllEditorGUI.ErrorMessageBox(context.Value.ParentPath.ErrorMessage); } // Display required valid path error if enabled. if (attribute.RequireValidPath && context.Value.Exists == false) { AllEditorGUI.ErrorMessageBox("The path is invalid."); } // Draw field. EditorGUI.BeginChangeCheck(); entry.SmartValue = SirenixEditorFields.FolderPathField(label, entry.SmartValue, context.Value.ParentPath.GetString(entry), attribute.AbsolutePath, attribute.UseBackslashes); // Update existing check if (EditorGUI.EndChangeCheck() && attribute.RequireValidPath) { context.Value.Exists = PathExists(entry.SmartValue, context.Value.ParentPath.GetString(entry)); } }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(IPropertyValueEntry <T> entry, AssetsOnlyAttribute attribute, GUIContent label) { for (int i = 0; i < entry.Values.Count; i++) { var val = entry.Values[i]; if (val != null) { if (AssetDatabase.Contains(val) == false) { string name = val.name; var component = val as Component; if (component != null) { name = "from " + component.gameObject.name; } AllEditorGUI.ErrorMessageBox(val.GetType().GetNiceName() + " " + name + " is not an asset."); break; } } } this.CallNextDrawer(entry.Property, label); }
/// <summary> /// Draws a property in the inspector using a given label. /// </summary> public static void DrawProperty(InspectorProperty property, GUIContent label) { if (property == null) { throw new ArgumentNullException("property"); } bool popGUIEnabled = false; try { property.PushDraw(); if ((property.RecursiveDrawDepth + InlineEditorAttributeDrawer.CurrentInlineEditorDrawDepth) > GeneralDrawerConfig.Instance.MaxRecursiveDrawDepth) { AllEditorGUI.ErrorMessageBox("The property '" + property.NiceName + "' has exceeded the maximum recursive draw depth limit of " + GeneralDrawerConfig.Instance.MaxRecursiveDrawDepth + "."); return; } if (property.ValueEntry != null && !property.SupportsPrefabModifications && property.Tree.HasPrefabs && !GUIHelper.IsDrawingDictionaryKey && (property.Info.PropertyType == PropertyType.ReferenceType || property.Info.PropertyType == PropertyType.ValueType)) { if ((property.Parent == null || property.Parent.SupportsPrefabModifications) && GeneralDrawerConfig.Instance.ShowPrefabModificationsDisabledMessage) { AllEditorGUI.InfoMessageBox("The property '" + property.NiceName + "' does not support being modified on prefab instances. (You can disable this message the general drawer config.)"); } GUIHelper.PushGUIEnabled(false); popGUIEnabled = true; } OdinDrawer[] drawers = DrawerLocator.GetDrawersForProperty(property); GUIHelper.BeginLayoutMeasuring(); { try { if (drawers.Length > 0) { bool setIsBoldState = property.ValueEntry != null && Event.current.type == EventType.Repaint; if (setIsBoldState) { var boldState = property.ValueEntry.ValueChangedFromPrefab; if (GUIHelper.IsDrawingDictionaryKey) { // Always propagate changed state down through dictionary keys boldState |= GUIHelper.IsBoldLabel; } GUIHelper.PushIsBoldLabel(boldState); } drawers[0].DrawProperty(property, label); if (setIsBoldState) { GUIHelper.PopIsBoldLabel(); } } else { if (property.Info.PropertyType == PropertyType.Method) { EditorGUILayout.LabelField(property.NiceName, "No drawers could be found for the method property '" + property.Name + "' with signature '" + property.Info.MemberInfo.GetNiceName() + "'."); } else if (property.Info.PropertyType == PropertyType.Group) { var attr = property.Info.GetAttribute <PropertyGroupAttribute>(); if (attr != null) { EditorGUILayout.LabelField(property.NiceName, "No drawers could be found for the property group '" + property.Name + "' with property group attribute type '" + attr.GetType().GetNiceName() + "'."); } else { EditorGUILayout.LabelField(property.NiceName, "No drawers could be found for the property group '" + property.Name + "'."); } } //else if (property.Info.GetAttribute<HideInInspector>() == null) //{ // EditorGUILayout.LabelField(property.NiceName, "No drawers could be found for the value property '" + property.Name + "' of type '" + property.ValueEntry.TypeOfValue.GetNiceName() + "'."); //} } } catch (Exception ex) { if (ex is ExitGUIException || ex.InnerException is ExitGUIException) { throw ex; } else { var msg = "This error occurred while being drawn by ODIN. \n" + "ODIN Property Path: " + property.Path + "\n" + "ODIN Drawer Chain: " + string.Join(", ", drawers.Select(n => n.GetType().GetNiceName()).ToArray()) + "."; Debug.LogException(new OdinPropertyException(msg, ex)); } } } if (Event.current.type != EventType.Layout) { property.LastDrawnValueRect = GUIHelper.EndLayoutMeasuring(); } } finally { property.PopDraw(); if (popGUIEnabled) { GUIHelper.PopGUIEnabled(); } } }
/// <summary> /// Not yet documented. /// </summary> protected override void DrawPropertyLayout(IPropertyValueEntry <TElement> entry, AssetListAttribute attribute, GUIContent label) { 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) { AllEditorGUI.ErrorMessageBox(config.Value.ErrorMessage); } else { config.Value.EnsureListPopulation(); } AllEditorGUI.BeginIndentedVertical(SirenixGUIStyles.PropertyPadding); { AllEditorGUI.BeginHorizontalToolbar(); if (label != null) { GUILayout.Label(label); } GUILayout.FlexibleSpace(); if (config.Value.PrettyPath != null) { GUILayout.Label(config.Value.PrettyPath, SirenixGUIStyles.RightAlignedGreyMiniLabel); AllEditorGUI.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); } AllEditorGUI.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 (AllEditorGUI.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 (AllEditorGUI.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 (AllEditorGUI.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(); AllEditorGUI.EndHorizontalToolbar(); AllEditorGUI.BeginVerticalList(); AllEditorGUI.BeginListItem(false, padding); this.CallNextDrawer(entry.Property, null); AllEditorGUI.EndListItem(); AllEditorGUI.EndVerticalList(); } AllEditorGUI.EndIndentedVertical(); }
public static float Draw <T>(OdinDrawer drawerInstance, IPropertyValueEntry <T> entry, float progress, ProgressBarAttribute attribute, GUIContent label) { PropertyContext <ProgressBarContext <T> > contextBuffer; if (entry.Context.Get <ProgressBarContext <T> >(drawerInstance, "ProgressBarContext", out contextBuffer)) { var parentType = entry.Property.FindParent(PropertyValueCategory.Member, true).ParentType; contextBuffer.Value = new ProgressBarContext <T>(); if (!attribute.ColorMember.IsNullOrWhitespace()) { MemberInfo member; if (MemberFinder.Start(parentType) .IsNamed(attribute.ColorMember) .HasReturnType <Color>() .TryGetMember(out member, out contextBuffer.Value.ErrorMessage)) { if (member is FieldInfo || member is PropertyInfo) { if (member.IsStatic()) { contextBuffer.Value.StaticColorGetter = DeepReflection.CreateValueGetter <Color>(parentType, attribute.ColorMember); } else { contextBuffer.Value.InstanceColorGetter = DeepReflection.CreateWeakInstanceValueGetter <Color>(parentType, attribute.ColorMember); } } else if (member is MethodInfo) { if (member.IsStatic()) { contextBuffer.Value.ErrorMessage = "Static method members are currently not supported."; } else { var method = member as MethodInfo; var p = method.GetParameters(); if (p.Length == 0) { contextBuffer.Value.InstanceColorMethod = EmitUtilities.CreateWeakInstanceMethodCallerFunc <Color>(method); } else if (p.Length == 1 && p[0].ParameterType == typeof(T)) { contextBuffer.Value.InstanceColorParameterMethod = EmitUtilities.CreateWeakInstanceMethodCallerFunc <T, Color>(method); } } } else { contextBuffer.Value.ErrorMessage = "Unsupported member type."; } } } if (!attribute.BackgroundColorMember.IsNullOrWhitespace()) { MemberInfo member; if (MemberFinder.Start(parentType) .IsNamed(attribute.BackgroundColorMember) .HasReturnType <Color>() .TryGetMember(out member, out contextBuffer.Value.ErrorMessage)) { if (member is FieldInfo || member is PropertyInfo) { if (member.IsStatic()) { contextBuffer.Value.StaticBackgroundColorGetter = DeepReflection.CreateValueGetter <Color>(parentType, attribute.BackgroundColorMember); } else { contextBuffer.Value.InstanceBackgroundColorGetter = DeepReflection.CreateWeakInstanceValueGetter <Color>(parentType, attribute.BackgroundColorMember); } } else if (member is MethodInfo) { if (member.IsStatic()) { contextBuffer.Value.ErrorMessage = "Static method members are currently not supported."; } else { var method = member as MethodInfo; var p = method.GetParameters(); if (p.Length == 0) { contextBuffer.Value.InstanceBackgroundColorMethod = EmitUtilities.CreateWeakInstanceMethodCallerFunc <Color>(method); } else if (p.Length == 1 && p[0].ParameterType == typeof(T)) { contextBuffer.Value.InstanceBackgroundColorParameterMethod = EmitUtilities.CreateWeakInstanceMethodCallerFunc <T, Color>(method); } } } else { contextBuffer.Value.ErrorMessage = "Unsupported member type."; } } } } var context = contextBuffer.Value; // Error message if (context.ErrorMessage != null) { AllEditorGUI.ErrorMessageBox(context.ErrorMessage); } // Construct rect. Rect rect; if (label != null) { rect = EditorGUILayout.GetControlRect(true, attribute.Height > EditorGUIUtility.singleLineHeight ? attribute.Height : EditorGUIUtility.singleLineHeight); rect = EditorGUI.PrefixLabel(rect, label); rect = rect.AlignMiddle(attribute.Height); } else { rect = EditorGUILayout.GetControlRect(false, attribute.Height); GUIHelper.IndentRect(ref rect); } // Draw if (Event.current.type == EventType.Repaint) { var parent = entry.Property.FindParent(PropertyValueCategory.Member, true).ParentValues[0]; Color color = context.StaticColorGetter != null?context.StaticColorGetter() : context.InstanceColorGetter != null?context.InstanceColorGetter(parent) : context.InstanceColorMethod != null?context.InstanceColorMethod(parent) : context.InstanceColorParameterMethod != null?context.InstanceColorParameterMethod(parent, entry.SmartValue) : new Color(attribute.R, attribute.G, attribute.B, 1f); Color backgroundColor = context.StaticBackgroundColorGetter != null?context.StaticBackgroundColorGetter() : context.InstanceBackgroundColorGetter != null?context.InstanceBackgroundColorGetter(parent) : context.InstanceBackgroundColorMethod != null?context.InstanceBackgroundColorMethod(parent) : context.InstanceBackgroundColorParameterMethod != null?context.InstanceBackgroundColorParameterMethod(parent, entry.SmartValue) : new Color(0.16f, 0.16f, 0.16f, 1f); AllEditorGUI.DrawSolidRect(rect, backgroundColor); AllEditorGUI.DrawSolidRect(rect.AlignLeft(rect.width * Mathf.Clamp01(progress)), color); AllEditorGUI.DrawBorders(rect, 1, new Color(0.16f, 0.16f, 0.16f, 1f)); } if (GUI.enabled) { int controlID = GUIUtility.GetControlID(FocusType.Passive); if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && rect.Contains(Event.current.mousePosition) || GUIUtility.hotControl == controlID && (Event.current.type == EventType.MouseMove || Event.current.type == EventType.MouseDrag)) { Event.current.Use(); GUIUtility.hotControl = controlID; GUIHelper.RequestRepaint(); GUI.changed = true; progress = (Event.current.mousePosition.x - rect.xMin) / rect.width; } else if (GUIUtility.hotControl == controlID && Event.current.rawType == EventType.MouseUp) { GUIUtility.hotControl = 0; } } return(progress); }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(InspectorProperty property, InfoBoxAttribute attribute, GUIContent label) { PropertyContext <InfoBoxContext> context = null; context = property.Context.Get(this, "Config_" + this.GetHashCode(), (InfoBoxContext)null); if (context.Value == null) { context.Value = new InfoBoxContext() { MessageHelper = new StringMemberHelper(property.ParentType, attribute.Message) }; context.Value.ErrorMessage = context.Value.MessageHelper.ErrorMessage; MemberInfo memberInfo; if (attribute.VisibleIf != null) { // Parameter functions if (property.ValueEntry != null && property.ParentType.FindMember() .IsMethod() .HasReturnType <bool>() .HasParameters(property.ValueEntry.BaseValueType) .IsNamed(attribute.VisibleIf) .TryGetMember(out memberInfo, out context.Value.ErrorMessage)) { if (context.Value.ErrorMessage == null) { if (memberInfo is MethodInfo) { if (memberInfo.IsStatic()) { context.Value.StaticValidationParameterMethod = memberInfo as MethodInfo; } else { context.Value.InstanceValidationParameterMethod = memberInfo as MethodInfo; } } else { context.Value.ErrorMessage = "Invalid member type!"; } } } // Fields, properties, and no-parameter functions. else if (property.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(property.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(property.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 = property.ParentValues[0]; try { context.Value.DrawMessageBox = attribute.VisibleIf == null || (context.Value.StaticValidationParameterMethod != null && (bool)context.Value.StaticValidationParameterMethod.Invoke(null, new object[] { property.ValueEntry.WeakSmartValue })) || (context.Value.InstanceValidationParameterMethod != null && (bool)context.Value.InstanceValidationParameterMethod.Invoke(null, new object[] { property.ParentValues[0], property.ValueEntry.WeakSmartValue })) || (context.Value.InstanceValidationMethodCaller != null && context.Value.InstanceValidationMethodCaller(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) { switch (attribute.InfoMessageType) { case InfoMessageType.None: AllEditorGUI.MessageBox(context.Value.MessageHelper.GetString(property)); break; case InfoMessageType.Info: AllEditorGUI.InfoMessageBox(context.Value.MessageHelper.GetString(property)); break; case InfoMessageType.Warning: AllEditorGUI.WarningMessageBox(context.Value.MessageHelper.GetString(property)); break; case InfoMessageType.Error: AllEditorGUI.ErrorMessageBox(context.Value.MessageHelper.GetString(property)); break; default: AllEditorGUI.ErrorMessageBox("Unknown InfoBoxType: " + attribute.InfoMessageType.ToString()); break; } } } this.CallNextDrawer(property, label); }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(IPropertyValueEntry <TDrawnType> entry, GUIContent label) { if (SetFieldInfo == null) { AllEditorGUI.ErrorMessageBox("Could not find the internal Unity field 'PropertyDrawer.m_FieldInfo'; UnityPropertyDrawer alias '" + typeof(UnityPropertyDrawer <TDrawer, TDrawnType>).GetNiceName() + "' has been disabled."); return; } FieldInfo fieldInfo; SerializedProperty unityProperty = entry.Property.Tree.GetUnityPropertyForPath(entry.Property.Path, out fieldInfo); if (unityProperty == null) { if (UnityVersion.IsVersionOrGreater(2017, 1)) { this.CallNextDrawer(entry, label); } else { AllEditorGUI.ErrorMessageBox("Could not get a Unity SerializedProperty for the property '" + entry.Property.NiceName + "' of type '" + entry.TypeOfValue.GetNiceName() + "' at path '" + entry.Property.Path + "'."); } return; } SetFieldInfo(ref this.drawer, fieldInfo); if (unityProperty.serializedObject.targetObject is EmittedScriptableObject <TDrawnType> ) { var targetObjects = unityProperty.serializedObject.targetObjects; for (int i = 0; i < targetObjects.Length; i++) { EmittedScriptableObject <TDrawnType> target = (EmittedScriptableObject <TDrawnType>)targetObjects[i]; target.SetValue(entry.Values[i]); } unityProperty.serializedObject.Update(); } else if (unityProperty.serializedObject.targetObject is EmittedScriptableObject) { var targetObjects = unityProperty.serializedObject.targetObjects; for (int i = 0; i < targetObjects.Length; i++) { EmittedScriptableObject target = (EmittedScriptableObject)targetObjects[i]; target.SetWeakValue(entry.Values[i]); } unityProperty.serializedObject.Update(); unityProperty = unityProperty.serializedObject.FindProperty(unityProperty.propertyPath); } float height = this.drawer.GetPropertyHeight(unityProperty, label); Rect position = EditorGUILayout.GetControlRect(false, height); EditorGUI.BeginChangeCheck(); if (this.propertyHandler != null) { UnityPropertyHandlerUtility.PropertyHandlerOnGUI(this.propertyHandler, position, unityProperty, label, false); } else { this.drawer.OnGUI(position, unityProperty, label); } bool changed = EditorGUI.EndChangeCheck(); if (unityProperty.serializedObject.targetObject is EmittedScriptableObject <TDrawnType> ) { if (unityProperty.serializedObject.ApplyModifiedPropertiesWithoutUndo() || changed) { var targetObjects = unityProperty.serializedObject.targetObjects; for (int i = 0; i < targetObjects.Length; i++) { EmittedScriptableObject <TDrawnType> target = (EmittedScriptableObject <TDrawnType>)targetObjects[i]; entry.Values[i] = target.GetValue(); } entry.Values.ForceMarkDirty(); } } else if (unityProperty.serializedObject.targetObject is EmittedScriptableObject) { if (unityProperty.serializedObject.ApplyModifiedPropertiesWithoutUndo() || changed) { var targetObjects = unityProperty.serializedObject.targetObjects; for (int i = 0; i < targetObjects.Length; i++) { EmittedScriptableObject target = (EmittedScriptableObject)targetObjects[i]; entry.Values[i] = (TDrawnType)target.GetWeakValue(); } entry.Values.ForceMarkDirty(); } } }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyGroupLayout(InspectorProperty property, ToggleGroupAttribute attribute, GUIContent label) { var toggleProperty = property.Children.Get(attribute.ToggleMemberName); var context = property.Context.Get <ToggleGroupConfig>(this, "ToggleGroupConfig", (ToggleGroupConfig)null); if (context.Value == null) { context.Value = new ToggleGroupConfig(); context.Value.IsVisible = property.Context.GetPersistent <bool>(this, "IsVisible", false); if (toggleProperty == null) { context.Value.ErrorMessage = "No property or field named " + attribute.ToggleMemberName + " found. Make sure the property is part of the inspector and the group."; } else { context.Value.TitleHelper = new StringMemberHelper(property.ParentType, attribute.ToggleGroupTitle, ref context.Value.ErrorMessage); } } if (context.Value.ErrorMessage != null) { AllEditorGUI.ErrorMessageBox(context.Value.ErrorMessage); } else { PropertyContext <string> openGroup = null; if (attribute.CollapseOthersOnExpand) { if (property.Parent == null) { //openGroup = GUIHelper.GetTemporaryContext<PropertyContext<string>>(property.Tree); openGroup = property.Context.Get <string>(this, "OpenGroup", (string)null); } else { var parent = (property.Parent.ValueEntry == null || property.Parent.ValueEntry.ValueCategory == PropertyValueCategory.Member) ? property.Parent : property.Parent.Parent; openGroup = parent.Context.GetGlobal <string>("OpenFoldoutToggleGroup", (string)null); } if (openGroup.Value != null && openGroup.Value != property.Path) { context.Value.IsVisible.Value = false; } } bool isEnabled = (bool)toggleProperty.ValueEntry.WeakSmartValue; string title = context.Value.TitleHelper.GetString(property) ?? attribute.GroupName; bool prev = context.Value.IsVisible.Value; bool visibleBuffer = context.Value.IsVisible.Value; if (AllEditorGUI.BeginToggleGroup(UniqueDrawerKey.Create(property, this), ref isEnabled, ref visibleBuffer, title)) { for (int i = 0; i < property.Children.Count; i++) { var child = property.Children[i]; if (child != toggleProperty) { InspectorUtilities.DrawProperty(child); } } } else { // OnValueChanged is not fired if property is not drawn. GUIHelper.BeginDrawToNothing(); InspectorUtilities.DrawProperty(toggleProperty); GUIHelper.EndDrawToNothing(); } AllEditorGUI.EndToggleGroup(); context.Value.IsVisible.Value = visibleBuffer; if (openGroup != null && prev != context.Value.IsVisible.Value && context.Value.IsVisible.Value) { openGroup.Value = property.Path; } toggleProperty.ValueEntry.WeakSmartValue = isEnabled; // Why is this here? Commenting this out for now //toggleProperty.ValueEntry.ApplyChanges(); } }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(IPropertyValueEntry <T> entry, OnValueChangedAttribute attribute, GUIContent label) { // TODO: (Optimization) Create config container class for single dictionary lookup var methodInfo = entry.Property.Context.Get(this, "method_info_" + attribute.MethodName, (MethodInfo)null); var errorMessage = entry.Property.Context.Get(this, "error_message_" + attribute.MethodName, (string)null); if (methodInfo.Value == null && errorMessage.Value == null) { methodInfo.Value = entry.Property.ParentType.FindMember().IsMethod().IsNamed(attribute.MethodName).HasParameters <T>().GetMember <MethodInfo>(out errorMessage.Value) ?? entry.Property.ParentType.FindMember().IsMethod().IsNamed(attribute.MethodName).GetMember <MethodInfo>(out errorMessage.Value); } if (methodInfo.Value == null) { AllEditorGUI.ErrorMessageBox(errorMessage.Value); } else { var subscribed = entry.Property.Context.Get(this, "onvaluechanged_subscribed_" + attribute.MethodName, false); // TODO: (Optimization) Use EmitUtilities if (subscribed.Value == false) { MethodInfo method = methodInfo.Value; var parameters = method.GetParameters(); Action <int> action; if (method.IsStatic) { if (parameters.Length == 0) { action = (int index) => { method.Invoke(null, null); }; } else { action = (int index) => { method.Invoke(null, new object[] { entry.WeakValues[index] }); }; } } else { if (parameters.Length == 0) { action = (int index) => { object inst = entry.Property.ParentValues[index]; method.Invoke(inst, null); if (entry.ParentType.IsValueType && entry.Property.ParentValueProperty != null) { entry.Property.ParentValueProperty.ValueEntry.WeakValues[index] = inst; GUIHelper.RequestRepaint(); } }; } else { action = (int index) => { object inst = entry.Property.ParentValues[index]; method.Invoke(entry.Property.ParentValues[index], new object[] { entry.WeakValues[index] }); if (entry.ParentType.IsValueType && entry.Property.ParentValueProperty != null) { entry.Property.ParentValueProperty.ValueEntry.WeakValues[index] = inst; GUIHelper.RequestRepaint(); } }; } } entry.OnValueChanged += action; if (attribute.IncludeChildren || typeof(T).IsValueType) { entry.OnChildValueChanged += action; } subscribed.Value = true; } } this.CallNextDrawer(entry, label); }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(IPropertyValueEntry <TArray> entry, GUIContent label) { TElement[,] value = entry.Values[0] as TElement[, ]; bool rowLengthConflic = false; bool colLengthConflic = false; int colCount = value.GetLength(0); int rowCount = value.GetLength(1); for (int i = 1; i < entry.Values.Count; i++) { var arr = entry.Values[i] as TElement[, ]; colLengthConflic = colLengthConflic || arr.GetLength(0) != colCount; rowLengthConflic = rowLengthConflic || arr.GetLength(1) != rowCount; colCount = Mathf.Min(colCount, arr.GetLength(0)); rowCount = Mathf.Min(rowCount, arr.GetLength(1)); } var context = entry.Context.Get(this, "context", (Context)null); if (context.Value == null || colCount != context.Value.ColCount || rowCount != context.Value.RowCount) { context.Value = new Context(); context.Value.Value = value; context.Value.ColCount = colCount; context.Value.RowCount = rowCount; context.Value.Attribute = entry.Property.Info.GetAttribute <TableMatrixAttribute>() ?? this.GetDefaultTableMatrixAttributeSettings(); if (context.Value.Attribute.DrawElementMethod != null) { string error; var drawElementMethod = entry.ParentType.FindMember() .IsMethod() .IsStatic() .HasReturnType <TElement>() .IsNamed(context.Value.Attribute.DrawElementMethod) .HasParameters <Rect, TElement>() .GetMember <MethodInfo>(out error); if (error != null) { context.Value.ErrorMessage += error + "\n\n"; } else { context.Value.DrawElement = (Func <Rect, TElement, TElement>)Delegate.CreateDelegate(typeof(Func <Rect, TElement, TElement>), drawElementMethod); } } context.Value.HorizontalTitleGetter = new StringMemberHelper(entry.ParentType, context.Value.Attribute.HorizontalTitle); context.Value.VerticalTitleGetter = new StringMemberHelper(entry.ParentType, context.Value.Attribute.VerticalTitle); context.Value.Table = GUITable.Create( Mathf.Max(colCount, 1) + (colLengthConflic ? 1 : 0), Mathf.Max(rowCount, 1) + (rowLengthConflic ? 1 : 0), (rect, x, y) => this.DrawElement(rect, entry, context.Value, x, y), context.Value.HorizontalTitleGetter.GetString(entry), context.Value.Attribute.HideColumnIndices ? (Action <Rect, int>)null : (rect, x) => this.DrawColumn(rect, entry, context.Value, x), context.Value.VerticalTitleGetter.GetString(entry), context.Value.Attribute.HideRowIndices ? (Action <Rect, int>)null : (rect, y) => this.DrawRows(rect, entry, context.Value, y), context.Value.Attribute.ResizableColumns ); if (context.Value.Attribute.RowHeight != 0) { for (int y = 0; y < context.Value.RowCount; y++) { int _y = context.Value.Table.RowCount - 1 - y; for (int x = 0; x < context.Value.Table.ColumnCount; x++) { var cell = context.Value.Table[x, _y]; if (cell != null) { cell.Height = context.Value.Attribute.RowHeight; } } } } if (colLengthConflic) { context.Value.Table[context.Value.Table.ColumnCount - 1, 1].Width = 15; } if (colLengthConflic) { for (int x = 0; x < context.Value.Table.ColumnCount; x++) { context.Value.Table[x, context.Value.Table.RowCount - 1].Height = 15; } } } if (context.Value.Attribute.SquareCells) { SetSquareRowHeights(context); } this.TableMatrixAttribute = context.Value.Attribute; context.Value.Value = value; var prev = EditorGUI.showMixedValue; this.OnBeforeDrawTable(entry, context.Value, label); if (context.Value.ErrorMessage != null) { AllEditorGUI.ErrorMessageBox(context.Value.ErrorMessage); } else { try { context.Value.Table.DrawTable(); GUILayout.Space(3); } catch (ExitGUIException ex) { throw ex; } catch (Exception ex) { Debug.LogException(ex); } } EditorGUI.showMixedValue = prev; }
/// <summary> /// Draws the property. /// </summary> protected override void DrawPropertyLayout(IPropertyValueEntry <TList> entry, AssetListAttribute attribute, GUIContent label) { var property = entry.Property; 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.ListChanger = property.ValueEntry.GetListValueEntryChanger(); 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) { AllEditorGUI.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 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(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); }
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) { AllEditorGUI.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> /// Draws the property. /// </summary> protected override void DrawPropertyGroupLayout(InspectorProperty property, HorizontalGroupAttribute attribute, GUIContent label) { var context = property.Context.Get(this, "Context", (Context)null); if (context.Value == null) { context.Value = new Context(); if (attribute.Title != null) { context.Value.TitleHelper = new StringMemberHelper(property.ParentType, attribute.Title); } context.Value.Widths = new float[property.Children.Count]; context.Value.MinWidths = new float[property.Children.Count]; context.Value.MaxWidths = new float[property.Children.Count]; context.Value.LabelWidths = new float[property.Children.Count]; context.Value.Margins = new Vector2[property.Children.Count]; context.Value.Paddings = new Vector2[property.Children.Count]; float percentageAllocated = 0; for (int i = 0; i < property.Children.Count; i++) { var child = property.Children[i]; var attr = child.Children.Recurse() .Append(child) .SelectMany(a => a.Info.GetAttributes <HorizontalGroupAttribute>()) .FirstOrDefault(x => x.GroupID == attribute.GroupID); if (attr == null) { context.Value.Widths[i] = -1; } else { context.Value.Widths[i] = attr.Width; context.Value.MinWidths[i] = attr.MinWidth; context.Value.MaxWidths[i] = attr.MaxWidth; context.Value.LabelWidths[i] = attr.LabelWidth; if (attr.Width > 0 && attr.Width < 1) { context.Value.ContainsPercentageWidth++; percentageAllocated += attr.Width; // If we allocate 100% there is no way to resize the window down. // In those cases, we convert the attribute to adjust itself automatically and Unity will ensure that // that it reaches the 100% for us. if (percentageAllocated >= 0.97) { percentageAllocated -= attr.Width; context.Value.Widths[i] = 0; attr.Width = 0; } } if (attr.MinWidth > 0 && attr.MinWidth <= 1) { context.Value.ContainsPercentageWidth++; percentageAllocated += attr.MinWidth; // Same thing for MinWidth. if (percentageAllocated >= 0.97) { percentageAllocated -= attr.MinWidth; context.Value.MinWidths[i] = 0; attr.MinWidth = 0; } } context.Value.Margins[i] = new Vector2(attr.MarginLeft, attr.MarginRight); context.Value.Paddings[i] = new Vector2(attr.PaddingLeft, attr.PaddingRight); } } } if (context.Value.TitleHelper != null) { if (context.Value.TitleHelper.ErrorMessage != null) { AllEditorGUI.ErrorMessageBox(context.Value.TitleHelper.ErrorMessage); } else { AllEditorGUI.Title(context.Value.TitleHelper.GetString(property), null, TextAlignment.Left, false); } } AllEditorGUI.BeginIndentedHorizontal(GUILayoutOptions.ExpandWidth(false)); { if (Event.current.type == EventType.Repaint) { var newWidth = GUIHelper.GetCurrentLayoutRect().width; if (context.Value.TotalWidth != newWidth) { GUIHelper.RequestRepaint(); } context.Value.TotalWidth = newWidth; } for (int i = 0; i < property.Children.Count; i++) { float width, minWidth, maxWidth; Vector2 padding, margin; if (context.Value.ContainsPercentageWidth > 1 && context.Value.TotalWidth == 0) { width = 20; // Start small and expand next frame. Instead of starting to big and slowly getting smaller. minWidth = 0; maxWidth = 0; padding = new Vector2(); margin = new Vector2(); } else { width = context.Value.Widths[i]; minWidth = context.Value.MinWidths[i]; maxWidth = context.Value.MaxWidths[i]; margin = context.Value.Margins[i]; padding = context.Value.Paddings[i]; if (padding.x > 0 && padding.x <= 1) { padding.x = padding.x * context.Value.TotalWidth; } if (padding.y > 0 && padding.y <= 1) { padding.y = padding.y * context.Value.TotalWidth; } if (margin.x > 0 && margin.x <= 1) { margin.x = margin.x * context.Value.TotalWidth; } if (margin.y > 0 && margin.y <= 1) { margin.y = margin.y * context.Value.TotalWidth; } if (width <= 1) { width = width * context.Value.TotalWidth; } width -= padding.x + padding.y; if (minWidth > 0) { if (minWidth <= 1) { minWidth = minWidth * context.Value.TotalWidth; } minWidth -= padding.x + padding.y; } if (maxWidth > 0) { if (maxWidth <= 1) { maxWidth = maxWidth * context.Value.TotalWidth; } maxWidth -= padding.x + padding.y; } } GUILayoutOptions.GUILayoutOptionsInstance options = null; if (minWidth > 0) { options = GUILayoutOptions.MinWidth(minWidth); } if (maxWidth > 0) { options = options == null?GUILayoutOptions.MaxWidth(maxWidth) : options.MaxWidth(maxWidth); } if (options == null) { options = GUILayoutOptions.Width(width < 0 ? 0 : width); } var prevFieldWidth = EditorGUIUtility.fieldWidth; EditorGUIUtility.fieldWidth = 40; GUILayout.Space(margin.x + padding.x); GUILayout.BeginVertical(options); GUILayout.Space(0); if (attribute.LabelWidth > 0) { GUIHelper.PushLabelWidth(attribute.LabelWidth); } InspectorUtilities.DrawProperty(property.Children[i], property.Children[i].Label); if (attribute.LabelWidth > 0) { GUIHelper.PopLabelWidth(); } GUILayout.Space(0); GUILayout.EndVertical(); EditorGUIUtility.fieldWidth = prevFieldWidth; GUILayout.Space(margin.y + padding.y); } } AllEditorGUI.EndIndentedHorizontal(); }
private void DrawErrorMessageBox() { AllEditorGUI.ErrorMessageBox("3. ErrorMessageBox"); }