Esempio n. 1
0
        void DrawListKeyValuePair <K, V>(List <KeyValuePair <K, V> > pairs, ref bool state, string label, Action <K> DrawItem)
        {
#if UNITY_EDITOR
            SirenixEditorGUI.BeginIndentedVertical(SirenixGUIStyles.PropertyPadding);
            {
                SirenixEditorGUI.BeginHorizontalToolbar();
                {
                    state = SirenixEditorGUI.Foldout(state, label);
                    GUILayout.FlexibleSpace();
                }
                SirenixEditorGUI.EndHorizontalToolbar();

                if (state)
                {
                    SirenixEditorGUI.BeginVerticalList(false);
                    foreach (var item in pairs)
                    {
                        SirenixEditorGUI.BeginListItem(false);
                        EditorGUILayout.BeginHorizontal();
                        DrawItem(item.Key);
                        EditorGUILayout.EndHorizontal();
                        SirenixEditorGUI.EndListItem();
                    }
                    SirenixEditorGUI.EndVerticalList();
                }
            }
            SirenixEditorGUI.EndIndentedVertical();
#endif
        }
        /// <summary>
        /// Draws the property layout.
        /// </summary>
        protected override void DrawPropertyLayout(GUIContent label)
        {
            if (this.drawAsList)
            {
                if (GUILayout.Button("Draw as table"))
                {
                    this.drawAsList = false;
                }

                this.CallNextDrawer(label);
                return;
            }


            this.picker = ObjectPicker.GetObjectPicker(this, this.resolver.ElementType);
            this.paging.Update(this.resolver.MaxCollectionLength);
            this.currPage.Value         = this.paging.CurrentPage;
            this.isPagingExpanded.Value = this.paging.IsExpanded;

            var rect = SirenixEditorGUI.BeginIndentedVertical(SirenixGUIStyles.PropertyPadding);

            {
                if (!this.Attribute.HideToolbar)
                {
                    this.DrawToolbar(label);
                }

                if (this.Attribute.AlwaysExpanded)
                {
                    this.DrawColumnHeaders();
                    this.DrawTable();
                }
                else
                {
                    if (SirenixEditorGUI.BeginFadeGroup(this, this.isVisible.Value) && this.Property.Children.Count > 0)
                    {
                        this.DrawColumnHeaders();
                        this.DrawTable();
                    }
                    SirenixEditorGUI.EndFadeGroup();
                }
            }
            SirenixEditorGUI.EndIndentedVertical();
            if (Event.current.type == EventType.Repaint)
            {
                rect.yMin   -= 1;
                rect.height -= 3;
                SirenixEditorGUI.DrawBorders(rect, 1);
            }

            this.DropZone(rect);
            this.HandleObjectPickerEvents();

            if (Event.current.type == EventType.Repaint)
            {
                this.isFirstFrame = false;
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Draws the property.
        /// </summary>
        protected override void DrawPropertyLayout(GUIContent label)
        {
            var property  = this.Property;
            var attribute = this.Attribute;

            if (attribute.HideTabGroupIfTabGroupOnlyHasOneTab && this.tabs.Count <= 1)
            {
                for (int i = 0; i < this.tabs.Count; i++)
                {
                    int pageCount = this.tabs[i].InspectorProperties.Count;
                    for (int j = 0; j < pageCount; j++)
                    {
                        var child = this.tabs[i].InspectorProperties[j];
                        child.Update();
                        child.Draw(child.Label);
                    }
                }
                return;
            }

            this.tabGroup.AnimationSpeed = 1 / SirenixEditorGUI.TabPageSlideAnimationDuration;
            this.tabGroup.FixedHeight    = attribute.UseFixedHeight;

            if (this.currentPage.Value >= this.tabs.Count || this.currentPage.Value < 0)
            {
                this.currentPage.Value = 0;
            }

            SirenixEditorGUI.BeginIndentedVertical(SirenixGUIStyles.PropertyPadding);
            tabGroup.BeginGroup(true, attribute.Paddingless ? GUIStyle.none : null);

            for (int i = 0; i < this.tabs.Count; i++)
            {
                var page = tabGroup.RegisterTab(this.tabs[i].TabName);
                page.Title = this.tabs[i].Title.GetString(property);
                if (page.BeginPage())
                {
                    this.currentPage.Value = i;
                    int pageCount = this.tabs[i].InspectorProperties.Count;
                    for (int j = 0; j < pageCount; j++)
                    {
                        var child = this.tabs[i].InspectorProperties[j];
                        child.Update(); // Since the property is not fetched through the property system, ensure it's updated before drawing it.
                        child.Draw(child.Label);
                    }
                }
                page.EndPage();
            }

            tabGroup.EndGroup();
            SirenixEditorGUI.EndIndentedVertical();
        }
Esempio n. 4
0
        /// <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();
        }
Esempio n. 5
0
        /// <summary>
        /// Draws the property.
        /// </summary>
        protected override void DrawPropertyLayout(GUIContent label)
        {
            var  resolver   = this.Property.ChildResolver as ICollectionResolver;
            bool isReadOnly = resolver.IsReadOnly;

            if (this.errorMessage != null)
            {
                SirenixEditorGUI.ErrorMessageBox(errorMessage);
            }

            if (info.Label == null || (label != null && label.text != info.Label.text))
            {
                info.Label = new GUIContent(label == null || string.IsNullOrEmpty(label.text) ? Property.ValueEntry.TypeOfValue.GetNiceName() : label.text, label == null ? string.Empty : label.tooltip);
            }

            info.IsReadOnly = resolver.IsReadOnly;

            info.ListItemStyle.padding.left  = info.Draggable ? 25 : 7;
            info.ListItemStyle.padding.right = info.IsReadOnly || info.HideRemoveButton ? 4 : 20;

            if (Event.current.type == EventType.Repaint)
            {
                info.DropZoneTopLeft = GUIUtility.GUIToScreenPoint(new Vector2(0, 0));
            }

            info.CollectionResolver        = Property.ChildResolver as ICollectionResolver;
            info.OrderedCollectionResolver = Property.ChildResolver as IOrderedCollectionResolver;
            info.Count   = Property.Children.Count;
            info.IsEmpty = Property.Children.Count == 0;

            SirenixEditorGUI.BeginIndentedVertical(SirenixGUIStyles.PropertyPadding);
            this.BeginDropZone();
            {
                this.DrawToolbar();
                if (SirenixEditorGUI.BeginFadeGroup(UniqueDrawerKey.Create(Property, this), info.Toggled.Value))
                {
                    GUIHelper.PushLabelWidth(GUIHelper.BetterLabelWidth - info.ListItemStyle.padding.left);
                    this.DrawItems();
                    GUIHelper.PopLabelWidth();
                }
                SirenixEditorGUI.EndFadeGroup();
            }
            this.EndDropZone();
            SirenixEditorGUI.EndIndentedVertical();

            if (info.OrderedCollectionResolver != null)
            {
                if (info.RemoveAt >= 0 && Event.current.type == EventType.Repaint)
                {
                    try
                    {
                        if (info.CustomRemoveIndexFunction != null)
                        {
                            foreach (var parent in this.Property.ParentValues)
                            {
                                info.CustomRemoveIndexFunction(
                                    parent,
                                    info.RemoveAt);
                            }
                        }
                        else if (info.CustomRemoveElementFunction != null)
                        {
                            for (int i = 0; i < this.Property.ParentValues.Count; i++)
                            {
                                info.CustomRemoveElementFunction(
                                    this.Property.ParentValues[i],
                                    this.Property.Children[info.RemoveAt].ValueEntry.WeakValues[i]);
                            }
                        }
                        else
                        {
                            info.OrderedCollectionResolver.QueueRemoveAt(info.RemoveAt);
                        }
                    }
                    finally
                    {
                        info.RemoveAt = -1;
                    }

                    GUIHelper.RequestRepaint();
                }
            }
            else if (info.RemoveValues != null && Event.current.type == EventType.Repaint)
            {
                try
                {
                    if (info.CustomRemoveElementFunction != null)
                    {
                        for (int i = 0; i < this.Property.ParentValues.Count; i++)
                        {
                            info.CustomRemoveElementFunction(
                                this.Property.ParentValues[i],
                                this.info.RemoveValues[i]);
                        }
                    }
                    else
                    {
                        info.CollectionResolver.QueueRemove(info.RemoveValues);
                    }
                }
                finally
                {
                    info.RemoveValues = null;
                }
                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.Property.Tree.WeakTargets.Count];

                values[0] = value;
                for (int j = 1; j < values.Length; j++)
                {
                    values[j] = SerializationUtility.CreateCopy(value);
                }

                info.CollectionResolver.QueueAdd(values);
            }
        }
Esempio n. 6
0
        /// <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);
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Draws the property.
        /// </summary>
        protected override void DrawPropertyLayout(GUIContent label)
        {
            var property  = this.Property;
            var attribute = this.Attribute;

            var tabGroup = SirenixEditorGUI.CreateAnimatedTabGroup(property);

            tabGroup.AnimationSpeed = 1 / SirenixEditorGUI.TabPageSlideAnimationDuration;
            tabGroup.FixedHeight    = attribute.UseFixedHeight;

            LocalPersistentContext <int> persistentPageContext = property.Context.GetPersistent(this, "CurrentPage", 0);

            bool setPersistentPage = false;
            PropertyContext <List <Tab> > tabs;

            if (property.Context.Get(this, "Tabs", out tabs))
            {
                setPersistentPage = true;
                tabs.Value        = new List <Tab>();
                var addLastTabs = new List <Tab>();

                for (int j = 0; j < property.Children.Count; j++)
                {
                    var child = property.Children[j];

                    bool added = false;

                    if (child.Info.PropertyType == PropertyType.Group)
                    {
                        var attrType = child.GetAttribute <PropertyGroupAttribute>().GetType();

                        if (attrType.IsNested && attrType.DeclaringType == typeof(TabGroupAttribute))
                        {
                            // This is a tab subgroup; add all its children to a tab for that subgroup

                            Tab tab = new Tab();

                            tab.TabName = child.NiceName;
                            tab.Title   = new StringMemberHelper(property, child.Name.TrimStart('#'));
                            for (int i = 0; i < child.Children.Count; i++)
                            {
                                tab.InspectorProperties.Add(child.Children[i]);
                            }

                            tabs.Value.Add(tab);
                            added = true;
                        }
                    }

                    if (!added)
                    {
                        // This is a group member of the tab group itself, so it gets its own tab

                        Tab tab = new Tab();

                        tab.TabName = child.NiceName;
                        tab.Title   = new StringMemberHelper(property, child.Name.TrimStart('#'));
                        tab.InspectorProperties.Add(child);

                        addLastTabs.Add(tab);
                    }
                }

                foreach (var tab in addLastTabs)
                {
                    tabs.Value.Add(tab);
                }
            }

            for (int i = 0; i < tabs.Value.Count; i++)
            {
                tabGroup.RegisterTab(tabs.Value[i].TabName);
            }

            if (setPersistentPage)
            {
                if (persistentPageContext.Value >= tabs.Value.Count || persistentPageContext.Value < 0)
                {
                    persistentPageContext.Value = 0;
                }

                tabGroup.SetCurrentPage(tabGroup.RegisterTab(tabs.Value[persistentPageContext.Value].TabName));
            }

            SirenixEditorGUI.BeginIndentedVertical(SirenixGUIStyles.PropertyPadding);
            tabGroup.BeginGroup(true, attribute.Paddingless ? GUIStyle.none : null);

            for (int i = 0; i < tabs.Value.Count; i++)
            {
                var page = tabGroup.RegisterTab(tabs.Value[i].TabName);
                page.Title = tabs.Value[i].Title.GetString(property);
                if (page.BeginPage())
                {
                    persistentPageContext.Value = i;
                    int pageCount = tabs.Value[i].InspectorProperties.Count;
                    for (int j = 0; j < pageCount; j++)
                    {
                        var child = tabs.Value[i].InspectorProperties[j];
                        child.Update(); // Since the property is not fetched through the property system, ensure it's updated before drawing it.
                        child.Draw(child.Label);
                    }
                }
                page.EndPage();
            }

            tabGroup.EndGroup();
            SirenixEditorGUI.EndIndentedVertical();
        }
Esempio n. 8
0
        /// <summary>
        /// Draws the property.
        /// </summary>
        protected override void DrawPropertyLayout(GUIContent label)
        {
            var entry = this.ValueEntry;

            this.dictionaryResolver          = entry.Property.ChildResolver as StrongDictionaryPropertyResolver <TDictionary, TKey, TValue>;
            this.config                      = GeneralDrawerConfig.Instance;
            this.paging.NumberOfItemsPerPage = this.config.NumberOfItemsPrPage;
            listItemStyle.padding.right      = !entry.IsEditable || this.attrSettings.IsReadOnly ? 4 : 20;

            SirenixEditorGUI.BeginIndentedVertical(SirenixGUIStyles.PropertyPadding);
            {
                this.paging.Update(elementCount: entry.Property.Children.Count);
                this.DrawToolbar(entry);
                this.paging.Update(elementCount: entry.Property.Children.Count);

                if (!this.disableAddKey && this.attrSettings.IsReadOnly == false)
                {
                    this.DrawAddKey(entry);
                }

                float t;
                GUIHelper.BeginLayoutMeasuring();
                if (SirenixEditorGUI.BeginFadeGroup(UniqueDrawerKey.Create(entry.Property, this), this.toggled.Value, out t))
                {
                    var rect = SirenixEditorGUI.BeginVerticalList(false);
                    if (this.attrSettings.DisplayMode == DictionaryDisplayOptions.OneLine)
                    {
                        var maxWidth = rect.width - 90;
                        rect.xMin           = this.keyWidthOffset + 22;
                        rect.xMax           = rect.xMin + 10;
                        this.keyWidthOffset = this.keyWidthOffset + SirenixEditorGUI.SlideRect(rect).x;

                        if (Event.current.type == EventType.Repaint)
                        {
                            this.keyWidthOffset = Mathf.Clamp(this.keyWidthOffset, 90, maxWidth);
                        }

                        if (this.paging.ElementCount != 0)
                        {
                            var headerRect = SirenixEditorGUI.BeginListItem(false);
                            {
                                GUILayout.Space(14);
                                if (Event.current.type == EventType.Repaint)
                                {
                                    GUI.Label(headerRect.SetWidth(this.keyWidthOffset), this.keyLabel, SirenixGUIStyles.LabelCentered);
                                    GUI.Label(headerRect.AddXMin(this.keyWidthOffset), this.valueLabel, SirenixGUIStyles.LabelCentered);
                                    SirenixEditorGUI.DrawSolidRect(headerRect.AlignBottom(1), SirenixGUIStyles.BorderColor);
                                }
                            }
                            SirenixEditorGUI.EndListItem();
                        }
                    }

                    GUIHelper.PushHierarchyMode(false);
                    this.DrawElements(entry, label);
                    GUIHelper.PopHierarchyMode();
                    SirenixEditorGUI.EndVerticalList();
                }
                SirenixEditorGUI.EndFadeGroup();

                // Draw borders
                var outerRect = GUIHelper.EndLayoutMeasuring();
                if (t > 0.01f && Event.current.type == EventType.Repaint)
                {
                    Color col = SirenixGUIStyles.BorderColor;
                    outerRect.yMin -= 1;
                    SirenixEditorGUI.DrawBorders(outerRect, 1, col);
                    col.a *= t;
                    if (this.attrSettings.DisplayMode == DictionaryDisplayOptions.OneLine)
                    {
                        // Draw Slide Rect Border
                        outerRect.width = 1;
                        outerRect.x    += this.keyWidthOffset + 13;
                        SirenixEditorGUI.DrawSolidRect(outerRect, col);
                    }
                }
            }
            SirenixEditorGUI.EndIndentedVertical();
        }
        /// <summary>
        /// Draws the property.
        /// </summary>
        protected override void DrawPropertyLayout(IPropertyValueEntry <TDictionary> entry, GUIContent label)
        {
            var context = entry.Property.Context.Get(this, "context", (Context)null);

            if (context.Value == null)
            {
                context.Value                = new Context();
                context.Value.Toggled        = entry.Context.GetPersistent(this, "Toggled", GeneralDrawerConfig.Instance.OpenListsByDefault);
                context.Value.KeyWidthOffset = 130;
                context.Value.Label          = label ?? new GUIContent(typeof(TDictionary).GetNiceName());
                context.Value.AttrSettings   = entry.Property.Info.GetAttribute <DictionaryDrawerSettings>() ?? new DictionaryDrawerSettings();
                context.Value.DisableAddKey  = entry.Property.Tree.HasPrefabs && !entry.GetDictionaryHandler().SupportsPrefabModifications;

                if (!context.Value.DisableAddKey)
                {
                    context.Value.TempKeyValue = new TempKeyValue();

                    var tree = PropertyTree.Create(context.Value.TempKeyValue);
                    tree.UpdateTree();

                    context.Value.TempKeyEntry   = (IPropertyValueEntry <TKey>)tree.GetPropertyAtPath("Key").ValueEntry;
                    context.Value.TempValueEntry = (IPropertyValueEntry <TValue>)tree.GetPropertyAtPath("Value").ValueEntry;
                }
            }

            context.Value.DictionaryHandler           = (DictionaryHandler <TDictionary, TKey, TValue>)entry.GetDictionaryHandler();
            context.Value.Config                      = GeneralDrawerConfig.Instance;
            context.Value.Paging.NumberOfItemsPerPage = context.Value.Config.NumberOfItemsPrPage;
            context.Value.ListItemStyle.padding.right = !entry.IsEditable || context.Value.AttrSettings.IsReadOnly ? 4 : 20;

            //if (!IsSupportedKeyType)
            //{
            //    var message = entry.Property.Context.Get(this, "error_message", (string)null);
            //    var detailedMessage = entry.Property.Context.Get(this, "error_message_detailed", (string)null);
            //    var folded = entry.Property.Context.Get(this, "error_message_folded", true);

            //    if (message.Value == null)
            //    {
            //        string str = "";

            //        if (label != null)
            //        {
            //            str += label.text + "\n\n";
            //        }

            //        str += "The dictionary key type '" + typeof(TKey).GetNiceFullName() + "' is not supported in prefab instances. Expand this box to see which key types are supported.";

            //        message.Value = str;
            //    }

            //    if (detailedMessage.Value == null)
            //    {
            //        var sb = new StringBuilder("The following key types are supported:");

            //        sb.AppendLine()
            //          .AppendLine();

            //        foreach (var type in DictionaryKeyUtility.GetPersistentPathKeyTypes())
            //        {
            //            sb.AppendLine(type.GetNiceName());
            //        }

            //        sb.AppendLine("Enums of any type");

            //        detailedMessage.Value = sb.ToString();
            //    }

            //    folded.Value = SirenixEditorGUI.DetailedMessageBox(message.Value, detailedMessage.Value, MessageType.Error, folded.Value);

            //    return;
            //}

            SirenixEditorGUI.BeginIndentedVertical(SirenixGUIStyles.PropertyPadding);
            {
                context.Value.Paging.Update(elementCount: entry.Property.Children.Count);
                this.DrawToolbar(entry, context.Value);
                context.Value.Paging.Update(elementCount: entry.Property.Children.Count);

                if (!context.Value.DisableAddKey && context.Value.AttrSettings.IsReadOnly == false)
                {
                    this.DrawAddKey(entry, context.Value);
                }

                float t;
                GUIHelper.BeginLayoutMeasuring();
                if (SirenixEditorGUI.BeginFadeGroup(UniqueDrawerKey.Create(entry.Property, this), context.Value.Toggled.Value, out t))
                {
                    var rect = SirenixEditorGUI.BeginVerticalList(false);
                    if (context.Value.AttrSettings.DisplayMode == DictionaryDisplayOptions.OneLine)
                    {
                        var maxWidth = rect.width - 90;
                        rect.xMin = context.Value.KeyWidthOffset + 22;
                        rect.xMax = rect.xMin + 10;
                        context.Value.KeyWidthOffset = context.Value.KeyWidthOffset + SirenixEditorGUI.SlideRect(rect).x;

                        if (Event.current.type == EventType.Repaint)
                        {
                            context.Value.KeyWidthOffset = Mathf.Clamp(context.Value.KeyWidthOffset, 90, maxWidth);
                        }

                        if (context.Value.Paging.ElementCount != 0)
                        {
                            var headerRect = SirenixEditorGUI.BeginListItem(false);
                            {
                                GUILayout.Space(14);
                                if (Event.current.type == EventType.Repaint)
                                {
                                    GUI.Label(headerRect.SetWidth(context.Value.KeyWidthOffset), context.Value.AttrSettings.KeyLabel, SirenixGUIStyles.LabelCentered);
                                    GUI.Label(headerRect.AddXMin(context.Value.KeyWidthOffset), context.Value.AttrSettings.ValueLabel, SirenixGUIStyles.LabelCentered);
                                    SirenixEditorGUI.DrawSolidRect(headerRect.AlignBottom(1), SirenixGUIStyles.BorderColor);
                                }
                            }
                            SirenixEditorGUI.EndListItem();
                        }
                    }

                    this.DrawElements(entry, label, context.Value);
                    SirenixEditorGUI.EndVerticalList();
                }
                SirenixEditorGUI.EndFadeGroup();

                // Draw borders
                var outerRect = GUIHelper.EndLayoutMeasuring();
                if (t > 0.01f && Event.current.type == EventType.Repaint)
                {
                    Color col = SirenixGUIStyles.BorderColor;
                    outerRect.yMin -= 1;
                    SirenixEditorGUI.DrawBorders(outerRect, 1, col);
                    col.a *= t;
                    if (context.Value.AttrSettings.DisplayMode == DictionaryDisplayOptions.OneLine)
                    {
                        // Draw Slide Rect Border
                        outerRect.width = 1;
                        outerRect.x    += context.Value.KeyWidthOffset + 13;
                        SirenixEditorGUI.DrawSolidRect(outerRect, col);
                    }
                }
            }
            SirenixEditorGUI.EndIndentedVertical();
        }
        /// <summary>
        /// Draws the property.
        /// </summary>
        protected override void DrawPropertyImplementation(InspectorProperty property, GUIContent label)
        {
            if (label == null)
            {
                SirenixEditorGUI.BeginIndentedVertical();
                for (int i = 0; i < property.Children.Count; i++)
                {
                    InspectorUtilities.DrawProperty(property.Children[i]);
                }
                SirenixEditorGUI.EndIndentedVertical();
            }
            else
            {
                Context context;
                if (property.Context.Get <Context>(this, "context", out context))
                {
                    context.IsVisisble       = property.Context.GetPersistent(this, "IsVisible", SirenixEditorGUI.ExpandFoldoutByDefault);
                    context.IsInlineProperty =
                        property.ValueEntry.TypeOfValue.GetAttribute <InlinePropertyAttribute>() ??
                        property.Info.GetAttribute <InlinePropertyAttribute>();
                }

                if (context.IsInlineProperty != null)
                {
                    var outerRect = EditorGUILayout.BeginHorizontal();
                    {
                        if (Event.current.type == EventType.Repaint)
                        {
                            outerRect.y += 1;
                            EditorGUI.PrefixLabel(outerRect, label);
                        }

                        GUILayout.Space(EditorGUIUtility.labelWidth);
                        GUILayout.BeginVertical();
                        {
                            if (context.IsInlineProperty.LabelWidth > 0)
                            {
                                GUIHelper.PushLabelWidth(context.IsInlineProperty.LabelWidth);
                            }
                            GUIHelper.PushIndentLevel(0);
                            for (int i = 0; i < property.Children.Count; i++)
                            {
                                InspectorUtilities.DrawProperty(property.Children[i]);
                            }
                            GUIHelper.PopIndentLevel();
                            if (context.IsInlineProperty.LabelWidth > 0)
                            {
                                GUIHelper.PopLabelWidth();
                            }
                        }
                        GUILayout.EndVertical();
                    }
                    EditorGUILayout.EndHorizontal();
                }
                else
                {
                    context.IsVisisble.Value = SirenixEditorGUI.Foldout(context.IsVisisble.Value, label);
                    if (SirenixEditorGUI.BeginFadeGroup(context, context.IsVisisble.Value))
                    {
                        EditorGUI.indentLevel++;
                        for (int i = 0; i < property.Children.Count; i++)
                        {
                            InspectorUtilities.DrawProperty(property.Children[i]);
                        }
                        EditorGUI.indentLevel--;
                    }
                    SirenixEditorGUI.EndFadeGroup();
                }
            }
        }
        private int DrawEntry(int index, ref bool collectionChanged)
        {
            SirenixEditorGUI.BeginIndentedHorizontal(new GUILayoutOption[] {});
            SirenixEditorGUI.BeginBox();
            SirenixEditorGUI.Title(this.Attribute.ListItemType.Name.Split('`')[0] + " " + index + "", "", TextAlignment.Center, true, false);
            SirenixEditorGUI.BeginIndentedVertical();

            EditorGUI.BeginChangeCheck();

            foreach (var child in this.Property.Children[index].Children)
            {
                child.Draw();
                if (true /*is node port?*/)
                {
                    NodeEditorGUILayout.PortField(/*port*/ null, new GUILayoutOption[] {});

                    /*
                     * To draw a port field here:
                     * - have a port to populate this field
                     * - the port should represent the set of properties for this item in
                     *  the list
                     * - I (hopefully) shouldn't have to add a port within the dynamic list
                     *  property's type
                     * To get the ports:
                     * - The list of ports is stored in the node at edit time. Somehow,
                     *  they need to end up here, and in the right order.
                     * - The NodeEditor does something similar already using attributes, so
                     *  it can't be *totally* impossible.
                     * Complications:
                     * - This property drawer isn't specific to the Node Editor Window.
                     *  This means ports shouldn't get drawn in every context.
                     * - There doesn't seem to be a way to get info about the node directly
                     *  into the property attribute as would be the simplest solution...
                     *  instead, online the suggestion is to use some kind of 3rd class to
                     *  look at class instances and pull information from point A to point
                     *  B. Sounds difficult to do elegantly in this scenario...but again,
                     *  the NodeEditor can accomplish drawing port handles over existing
                     *  property draws, so it must be possible.
                     * Observations:
                     *  - NodeEditor passes target.DynamicPorts into
                     *    NodeEditorGUILayout.PortField. That's the call we care about.
                     *  - target is almost certainly the Node that the NodeEditor is
                     *    tasked with rendering.
                     *  - target is defined in NodeEditorBase, as generic type K (which
                     *    for us is XNode.Node...)
                     *  - target seems to be handed to NodeEditorBase via GetEditor, which
                     *    seems like some weird roundabout constructor...
                     *    - is a static method that creates an instance of type T (NodeEditor in our case,
                     *      which again directly inherits from NodeEditorBase) using
                     *      reflection
                     *    - populates target (and other props)
                     *    - hands back the created instance
                     *  - NodeEditorBase.GetEditor() used by:
                     *    - NodeEditor: to add context menu stuff (not useful)
                     *    - NodeEditorAction: to handle mouse behavior (not useful)
                     *    - NodeEditorGUI: to draw all the nodes (sounds about right)
                     *      - Soon after GetEditor(), NodeEditorGUI calls OnBodyGUI() on
                     *        the instance, which in turn draws the port fields, so yes,
                     *        this is correct spot...
                     *      - NodeEditorGUI gets the node in question from a reference to
                     *        the graph.
                     *      - graph in this case is a property belonging to
                     *        NodeEditorGUI's outer class...yes, NodeEditorGUI is
                     *        enclosed within a partial class of NodeEditorWindow...wow,
                     *        the code smell is funky down here in XNode land.
                     *      - this, in turn, looks to be set in NodeEditorWindow.Open()
                     *    - NodeEditorWindow:
                     *      - Open() called by OnOpen(), which pulls in the graph via
                     *        Unity API (EditorUtility.InstanceIDToObject()), which is fed
                     *        an instanceID given to them by (you guessed it) the Unity
                     *        Engine...crap. That's gonna be way too much work.
                     *  - Where do I already have access to the graph?
                     *    - well, the graph has access to itself (obviously)
                     *    - each node has a reference to the graph.
                     *    - I can create a custom node editor script, and that would have
                     *      access to the graph.
                     *    - Right now, my assumption is that NodeEditors are specific to a
                     *      given type of node. I could supply a NodeEditor that's
                     *      specific to nodes of type AutoNode...but, well, much of the
                     *      drawing logic would be identical.
                     *      - NodeEditor walks through all visible properties and draws
                     *        them using NodeEditorGUILayout.PropertyField.
                     *      - Wait, the call we care about may actually be PropertyField,
                     *        which supposedly automatically displays ports if relevant. How
                     *        the heck does that work?
                     *      - It looks like that method grabs the Node directly from the
                     *        SerializedProperty. You don't need to explicitly pass it in!
                     *      - But how do I know if that'd even be set in
                     *        AutoTableAttributeDrawer? Am I even working with
                     *        SerializedProperties in my case? I don't think I am...
                     *      - Nope, I'm working with OdinInspector's InspectorProperty
                     *        class.
                     *      - Could the serialized property be buried somewhere in that
                     *        class's properties? Hold on...
                     *        - ValueEntry? BaseValueEntry? Oooh, SerializationRoot sounds
                     *          promising...trouble is, that's also an
                     *          InspectorProperty...dang it.
                     *      - Maybe the OdinAttributeDrawer base class has some hints!
                     *        - It has ValueEntry...which at least will get us the values
                     *          that we're trying to draw. That's a good start!
                     *        - Can you get the object ValueEntry belongs to, perhaps?
                     *          That'd be an odd, but doable way of getting the Ports.
                     *        - ValueEntry.SmartValue is the actual list of stuff, but not
                     *          the ports.
                     *          - oh, hold on...SmartValue may have the elements, but they
                     *            may be separated from the Node's property at this point.
                     *          - Wait wait, we have access to the instance values of the
                     *            Attribute
                     *          - Can I get the property an attribute belongs to in that
                     *            case?
                     *          - ...I think we're allllll the way back to square one. I'd
                     *            be able to do this if I had .NET 4.5 to work with, but
                     *            that seems to be from THIS YEAR (2021), and the latest
                     *            stable unity version is from last year, so there's no
                     *            way their dist of .NET would be 4.5.
                     *          - ...2012.
                     *          - .NET 4.5 was released in 2012.
                     *          - That's...GREAT in this case!
                     *          - I just tried it. It works (like, we ARE using 4.5), but the calling function
                     *            didn't turn out to be helpful at all.
                     *          - ASDLJHDFLKJHSJSLDFH
                     *          -
                     *          - ...
                     *          -
                     *          - *sad 4:00 AM programmer noises.*
                     *
                     *
                     *
                     */
                }
            }

            if (EditorGUI.EndChangeCheck())
            {
                collectionChanged = true;
            }


            SirenixEditorGUI.EndIndentedVertical();
            SirenixEditorGUI.EndBox();
            if (!SirenixEditorGUI.IconButton(EditorIcons.Minus))
            {
                index++;
            }
            else
            {
                this.ValueEntry.SmartValue.RemoveAt(index);
            }
            SirenixEditorGUI.EndIndentedHorizontal();

            return(index);
        }