/************************************************************************************************************************/

        private static void DoGetSetToggleGUI(ref Rect area, MethodBase method)
        {
            // Check if the method name starts with "get_" or "set_".
            // Check the underscore first since it's hopefully the rarest so it can break out early.

            var name = method.Name;

            if (name.Length <= 4 || name[3] != '_' || name[2] != 't' || name[1] != 'e')
            {
                return;
            }

            var first = name[0];
            var isGet = first == 'g';
            var isSet = first == 's';

            if (!isGet && !isSet)
            {
                return;
            }

            var methodName             = (isGet ? "set_" : "get_") + name.Substring(4, name.Length - 4);
            var oppositePropertyMethod = method.DeclaringType.GetMethod(methodName, UltEventUtils.AnyAccessBindings);

            if (oppositePropertyMethod == null ||
                (isGet && !MethodSelectionMenu.IsSupported(method.GetReturnType())))
            {
                return;
            }

            area.width -= GetSetWidth + Padding;

            var buttonArea = new Rect(
                area.x + area.width + Padding,
                area.y,
                GetSetWidth,
                area.height);

            if (GUI.Button(buttonArea, isGet ? "Get" : "Set"))
            {
                var cachedState = new DrawerState();
                cachedState.CopyFrom(DrawerState.Current);

                EditorApplication.delayCall += () =>
                {
                    DrawerState.Current.CopyFrom(cachedState);

                    SetMethod(oppositePropertyMethod);

                    DrawerState.Current.Clear();

                    InternalEditorUtility.RepaintAllViews();
                };
            }
        }
        /************************************************************************************************************************/
        #endregion
        /************************************************************************************************************************/

        private static void DoMethodFieldGUI(Rect area, MethodBase method, bool autoOpenMethodMenu)
        {
            EditorGUI.BeginProperty(area, null, DrawerState.Current.MethodNameProperty);
            {
                if (includeRemoveButton)
                {
                    area.width -= RemoveButtonWidth;
                }

                var color = GUI.color;

                string label;
                if (EditorGUI.showMixedValue)
                {
                    label = "Mixed Values";
                }
                else if (method != null)
                {
                    label = MethodSelectionMenu.GetMethodSignature(method, false);

                    DoGetSetToggleGUI(ref area, method);
                }
                else
                {
                    var  methodName = DrawerState.Current.MethodNameProperty.stringValue;
                    Type declaringType;
                    PersistentCall.GetMethodDetails(methodName,
                                                    DrawerState.Current.TargetProperty.objectReferenceValue,
                                                    out declaringType, out label);
                    DoMethodNameSuggestionGUI(ref area, declaringType, methodName);
                    GUI.color = ErrorFieldColor;
                }

                if (autoOpenMethodMenu || (GUI.Button(area, GUIContent.none, PopupButtonStyle) && Event.current.button == 0))
                {
                    MethodSelectionMenu.ShowMenu(area);
                }

                GUI.color = color;

                PopupLabelStyle.fontStyle = DrawerState.Current.MethodNameProperty.prefabOverride ? FontStyle.Bold : FontStyle.Normal;
                GUI.Label(area, label, PopupLabelStyle);
            }
            EditorGUI.EndProperty();
        }
        /************************************************************************************************************************/

        private static void ShowLinkMenu(Rect area, SerializedProperty argumentProperty, Type systemType, int linkIndex, PersistentArgumentType linkType)
        {
            var typeProperty = argumentProperty.FindPropertyRelative(Names.PersistentArgument.Type);
            var intProperty  = argumentProperty.FindPropertyRelative(Names.PersistentArgument.Int);

            var menu = new GenericMenu();

            menu.AddDisabledItem(new GUIContent("Link to " + systemType.GetNameCS()));

            // Parameters.
            var parameters = DrawerState.Current.Event.Parameters;

            for (int i = 0; i < DrawerState.Current.Event.ParameterTypes.Length; i++)
            {
                var parameterType = DrawerState.Current.Event.ParameterTypes[i];
                if (!systemType.IsAssignableFrom(parameterType))
                {
                    continue;
                }

                var content = parameters == null ?
                              new GUIContent(string.Concat("Parameter ", i.ToString(), " (", parameterType.GetNameCS(false), ")")) :
                              new GUIContent(string.Concat("Parameter ", i.ToString(), " (", parameterType.GetNameCS(false), " ", parameters[i].Name, ")"));

                var on = i == linkIndex && linkType == PersistentArgumentType.Parameter;

                var index = i;
                menu.AddItem(content, on, () =>
                {
                    typeProperty.enumValueIndex = (int)PersistentArgumentType.Parameter;
                    intProperty.intValue        = index;
                    argumentProperty.serializedObject.ApplyModifiedProperties();
                });
            }

            // Returned Values.
            for (int i = 0; i < DrawerState.Current.PreviousCallCount; i++)
            {
                var method = DrawerState.Current.GetPreviousCall(i).GetMethodSafe();
                if (method == null || !systemType.IsAssignableFrom(method.GetReturnType()))
                {
                    continue;
                }

                var content = new GUIContent(string.Concat("Returned Value ", i.ToString(), " (", MethodSelectionMenu.GetMethodSignature(method, true), ")"));

                var on = i == linkIndex && linkType == PersistentArgumentType.ReturnValue;

                var index = i;
                menu.AddItem(content, on, () =>
                {
                    typeProperty.enumValueIndex = (int)PersistentArgumentType.ReturnValue;
                    intProperty.intValue        = index;
                    argumentProperty.serializedObject.ApplyModifiedProperties();
                });
            }

            menu.DropDown(area);
        }
        /************************************************************************************************************************/

        private static void DoLinkedValueGUI(Rect area, SerializedProperty argumentProperty, GUIContent label)
        {
            var color = GUI.color;

            label = EditorGUI.BeginProperty(area, label, argumentProperty);

            EditorGUI.PrefixLabel(area, label);

            area.xMin += EditorGUIUtility.labelWidth;

            var argument     = argumentProperty.GetValue <PersistentArgument>();
            var callIndex    = argument._Int;
            var argumentType = argument.SystemType;

            if (argumentType == null)
            {
                GUI.color = PersistentCallDrawer.ErrorFieldColor;
                GUI.Label(area, "Unable to determine argument type");
            }
            else if (DrawerState.Current.Event != null)
            {
                switch (argument.Type)
                {
                case PersistentArgumentType.Parameter:
                    label.text = "Parameter " + callIndex;
                    var parameterTypes = DrawerState.Current.Event.ParameterTypes;
                    var parameters     = DrawerState.Current.Event.Parameters;

                    if (callIndex < 0 || callIndex >= parameterTypes.Length)
                    {
                        GUI.color     = PersistentCallDrawer.ErrorFieldColor;
                        label.tooltip = "Parameter link index out of range";
                    }
                    else
                    {
                        var parameterType = parameterTypes[callIndex];

                        label.text += " (" + parameterType.GetNameCS(false);

                        if (parameters != null)
                        {
                            label.text += " " + parameters[callIndex].Name;
                        }

                        label.text += ")";

                        if (!argumentType.IsAssignableFrom(parameterType))
                        {
                            GUI.color     = PersistentCallDrawer.ErrorFieldColor;
                            label.tooltip = "Incompatible parameter type";
                        }
                    }
                    break;

                case PersistentArgumentType.ReturnValue:
                    label.text = "Return Value " + callIndex + ": ";
                    var linkedMethod = DrawerState.Current.GetLinkedMethod(callIndex);

                    if (linkedMethod == null)
                    {
                        label.text += "(no method set)";
                        GUI.color   = PersistentCallDrawer.ErrorFieldColor;
                    }
                    else
                    {
                        label.text += MethodSelectionMenu.GetMethodSignature(linkedMethod, true);

                        if (DrawerState.Current.callIndex >= 0 && DrawerState.Current.callIndex <= callIndex)
                        {
                            GUI.color     = PersistentCallDrawer.ErrorFieldColor;
                            label.tooltip = "The linked method must be called before this argument can retrieve its return value";
                        }
                        else if (!argumentType.IsAssignableFrom(linkedMethod.GetReturnType()))
                        {
                            GUI.color     = PersistentCallDrawer.ErrorFieldColor;
                            label.tooltip = "Return type is incompatible with argument type";
                        }
                    }
                    break;
                }

                if (GUI.Button(area, label, PersistentCallDrawer.PopupButtonStyle))
                {
                    if (Event.current.button == 0)
                    {
                        ShowLinkMenu(area, argumentProperty, argumentType, callIndex, argument.Type);
                    }
                }
            }

            EditorGUI.EndProperty();

            GUI.color = color;
        }