static void PasteSteps(MenuCommand command)
 {
     try {
         string       text     = EditorGUIUtility.systemCopyBuffer;
         StepsWrapper sw       = JsonUtility.FromJson <StepsWrapper> (text);
         StepData[]   refSteps = sw.steps;
         StepData[]   newSteps = new StepData[refSteps.Length];
         for (int k = 0; k < refSteps.Length; k++)
         {
             newSteps [k] = refSteps [k];
         }
         ITerrainDefaultGenerator thisTG = (ITerrainDefaultGenerator)command.context;
         thisTG.Steps = newSteps;
         EditorUtility.SetDirty(command.context);
     } catch {
     }
 }
        // Draw the property inside the given rect
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            position.height -= 5f;
            Rect box = new Rect(position.x - 2f, position.y - 2f, position.width + 4f, position.height + 4f);

            EditorGUI.DrawRect(box, new Color(0, 0, 0.175f, 0.15f));

            float lineHeight = EditorGUIUtility.standardVerticalSpacing + EditorGUIUtility.singleLineHeight;

            position.height = EditorGUIUtility.singleLineHeight;

            ITerrainDefaultGenerator tg = (ITerrainDefaultGenerator)property.serializedObject.targetObject;

            if (tg.Steps == null)
            {
                return;
            }

            int[] stepIndices = new int[tg.Steps.Length];
            for (int k = 0; k < tg.Steps.Length; k++)
            {
                stepIndices[k] = k;
            }
            GUIContent[] stepLabels = new GUIContent[tg.Steps.Length];
            for (int k = 0; k < tg.Steps.Length; k++)
            {
                stepLabels[k] = new GUIContent("Step " + k.ToString());
            }

            EditorGUIUtility.labelWidth = 120;

            SerializedProperty enabled = property.FindPropertyRelative("enabled");
            Rect prevPosition          = position;

            position.x    -= 14;
            position.width = 35;
            EditorGUI.PropertyField(position, enabled, GUIContent.none);
            position = prevPosition;
            SerializedProperty stepType = property.FindPropertyRelative("operation");
            int index = property.GetArrayIndex();

            EditorGUI.PropertyField(position, stepType, new GUIContent("Step " + index));
            if (enabled.boolValue)
            {
                switch (stepType.intValue)
                {
                case (int)TerrainStepType.SampleHeightMapTexture:
                case (int)TerrainStepType.SampleRidgeNoiseFromTexture:
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("noiseTexture"));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("frecuency"), new GUIContent("Frecuency", "The scale applied to the noise texture"));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("noiseRangeMin"), new GUIContent("Min", "The value of noise is mapped to min-max range"));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("noiseRangeMax"), new GUIContent("Max", "The value of noise is mapped to min-max range"));
                    break;

                case (int)TerrainStepType.Constant:
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("param"), new GUIContent("Constant", "Outputs a constant value."));
                    break;

                case (int)TerrainStepType.Copy:
                    position.y += lineHeight;
                    EditorGUI.IntPopup(position, property.FindPropertyRelative("inputIndex0"), stepLabels, stepIndices, new GUIContent("Copy Output From", "Copies a result from a previous step."));
                    break;

                case (int)TerrainStepType.Random:
                    break;

                case (int)TerrainStepType.Invert:
                    break;

                case (int)TerrainStepType.Shift:
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("param"), new GUIContent("Add", "The value to add to the previous result."));
                    break;

                case (int)TerrainStepType.BeachMask:
                    position.y += lineHeight;
                    EditorGUI.IntPopup(position, property.FindPropertyRelative("inputIndex0"), stepLabels, stepIndices, new GUIContent("Mask Source", "If mask value is zero and altitude is at beach level then altitude will be reduced."));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("threshold"), new GUIContent("Threshold", "Values greater than this threshold will cancel beach."));
                    break;

                case (int)TerrainStepType.AddAndMultiply:
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("param"), new GUIContent("Add", "The value to add to the previous result."));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("param2"), new GUIContent("Then Multiply", "Multiply the result by this value."));
                    break;

                case (int)TerrainStepType.MultiplyAndAdd:
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("param"), new GUIContent("Multiply", "Multiply the value by this value."));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("param2"), new GUIContent("Then Add", "Add this value to the result."));
                    break;

                case (int)TerrainStepType.Exponential:
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("param"), new GUIContent("Exponent", "Result = exp(previous_value, exponent)"));
                    break;

                case (int)TerrainStepType.Threshold:
                    position.y += lineHeight;
                    EditorGUI.IntPopup(position, property.FindPropertyRelative("inputIndex0"), stepLabels, stepIndices, new GUIContent("Input", "The source for the threshold operation"));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("threshold"), new GUIContent("Threshold", "Only values greater than threshold are preserved. Otherwise 0 is output."));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("thresholdShift"), new GUIContent("If Greater, Add", "A value that is added to the previous value if it passes the threshold."));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("thresholdParam"), new GUIContent("If Not, Output...", "A value that is set if the previous value does not pass the threshold."));
                    break;

                case (int)TerrainStepType.FlattenOrRaise:
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("threshold"), new GUIContent("Min Elevation", "Values greater than this threshold will be flattened."));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("thresholdParam"), new GUIContent("Multiplier", "Flatten multiplier."));
                    break;

                case (int)TerrainStepType.BlendAdditive:
                    position.y    += lineHeight;
                    prevPosition   = position;
                    position.width = 190;
                    float labelWidth = EditorGUIUtility.labelWidth;
                    EditorGUI.IntPopup(position, property.FindPropertyRelative("inputIndex0"), stepLabels, stepIndices, new GUIContent("Input A", "One of the inputs to combine"));
                    position.x    += 190;
                    position.width = 120;
                    EditorGUIUtility.labelWidth = 60;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("weight0"), new GUIContent("Weight", "Input A is multiplied by Weight"));
                    position       = prevPosition;
                    position.y    += lineHeight;
                    prevPosition   = position;
                    position.width = 190;
                    EditorGUIUtility.labelWidth = labelWidth;
                    EditorGUI.IntPopup(position, property.FindPropertyRelative("inputIndex1"), stepLabels, stepIndices, new GUIContent("Input B", "The other part of combination"));
                    position.x    += 190;
                    position.width = 120;
                    EditorGUIUtility.labelWidth = 60;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("weight1"), new GUIContent("Weight", "Input A is multiplied by Weight"));
                    position = prevPosition;
                    break;

                case (int)TerrainStepType.BlendMultiply:
                    position.y += lineHeight;
                    EditorGUI.IntPopup(position, property.FindPropertyRelative("inputIndex0"), stepLabels, stepIndices, new GUIContent("Input A", "Result = input A * input B"));
                    position.y += lineHeight;
                    EditorGUI.IntPopup(position, property.FindPropertyRelative("inputIndex1"), stepLabels, stepIndices, new GUIContent("Input B", "Result = input A * input B"));
                    break;

                case (int)TerrainStepType.Clamp:
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("min"), new GUIContent("Min", "Outputs value or Min if value < Min"));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("max"), new GUIContent("Max", "Outputs value or Max if value > Max"));
                    break;

                case (int)TerrainStepType.Select:
                    position.y += lineHeight;
                    EditorGUI.IntPopup(position, property.FindPropertyRelative("inputIndex0"), stepLabels, stepIndices, new GUIContent("Input", "Choose a step as a source"));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("min"), new GUIContent("Range Min", "Outputs 0 if value is less than Min"));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("max"), new GUIContent("Range Max", "Outputs 0 if value is greater than Max"));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("thresholdParam"), new GUIContent("Outside Value", "Outputs a different value if it's out of range"));
                    break;

                case (int)TerrainStepType.Fill:
                    position.y += lineHeight;
                    EditorGUI.IntPopup(position, property.FindPropertyRelative("inputIndex0"), stepLabels, stepIndices, new GUIContent("Input", "Choose a step as a source"));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("min"), new GUIContent("Range Min", "Outputs fill value if value is between min and max"));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("max"), new GUIContent("Range Max", "Outputs fill value if value is between min and max"));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("thresholdParam"), new GUIContent("Fill Value", "Replaces input value if it's inside the min-max range"));
                    break;

                case (int)TerrainStepType.Test:
                    position.y += lineHeight;
                    EditorGUI.IntPopup(position, property.FindPropertyRelative("inputIndex0"), stepLabels, stepIndices, new GUIContent("Input", "Choose a step as a source"));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("min"), new GUIContent("Range Min", "Outputs 0 if value is less than Min"));
                    position.y += lineHeight;
                    EditorGUI.PropertyField(position, property.FindPropertyRelative("max"), new GUIContent("Range Max", "Outputs 0 if value is greater than Max"));
                    break;
                }

                // Buttons
                prevPosition = position;
                position.x  += 20;
                position.y  += lineHeight;
                const float buttonWidth   = 60;
                const float buttonSpacing = 70;
                position.width = buttonWidth;
                bool markSceneChanges = false;

                if (GUI.Button(position, "Add"))
                {
                    List <StepData> od       = new List <StepData>(tg.Steps);
                    StepData        stepData = new StepData();
                    stepData.inputIndex0 = index;
                    od.Insert(index + 1, stepData);
                    tg.Steps = od.ToArray();
                    // Shift any input reference
                    for (int k = 0; k < tg.Steps.Length; k++)
                    {
                        if (tg.Steps[k].inputIndex0 > index)
                        {
                            tg.Steps[k].inputIndex0++;
                        }
                        if (tg.Steps[k].inputIndex1 > index)
                        {
                            tg.Steps[k].inputIndex1++;
                        }
                    }
                    markSceneChanges = true;
                }
                position.x += buttonSpacing;
                if (GUI.Button(position, "Remove"))
                {
                    List <StepData> od = new List <StepData>(tg.Steps);
                    od.RemoveAt(index);
                    tg.Steps = od.ToArray();
                    // Shift any input reference
                    for (int k = 0; k < tg.Steps.Length; k++)
                    {
                        if (tg.Steps[k].inputIndex0 >= index)
                        {
                            tg.Steps[k].inputIndex0--;
                        }
                        if (tg.Steps[k].inputIndex1 >= index)
                        {
                            tg.Steps[k].inputIndex1--;
                        }
                    }
                    markSceneChanges = true;
                }
                if (index > 0)
                {
                    position.x += buttonSpacing;
                    if (GUI.Button(position, "Up"))
                    {
                        StepData o = tg.Steps[index - 1];
                        tg.Steps[index - 1] = tg.Steps[index];
                        tg.Steps[index]     = o;
                        // Shift any input reference
                        for (int k = 0; k < tg.Steps.Length; k++)
                        {
                            if (tg.Steps[k].inputIndex0 == index)
                            {
                                tg.Steps[k].inputIndex0--;
                            }
                            if (tg.Steps[k].inputIndex1 == index)
                            {
                                tg.Steps[k].inputIndex1--;
                            }
                        }
                        markSceneChanges = true;
                    }
                }
                if (index < tg.Steps.Length - 1)
                {
                    position.x += buttonSpacing;
                    if (GUI.Button(position, "Down"))
                    {
                        StepData o = tg.Steps[index + 1];
                        tg.Steps[index + 1] = tg.Steps[index];
                        tg.Steps[index]     = o;
                        // Shift any input reference
                        for (int k = 0; k < tg.Steps.Length; k++)
                        {
                            if (tg.Steps[k].inputIndex0 == index)
                            {
                                tg.Steps[k].inputIndex0++;
                            }
                            if (tg.Steps[k].inputIndex1 == index)
                            {
                                tg.Steps[k].inputIndex1++;
                            }
                        }
                        markSceneChanges = true;
                    }
                }

                if (markSceneChanges && !Application.isPlaying)
                {
                    UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene());
                }
            }
        }