/// <summary>
    /// Handle deleting a difficulty that was previously saved
    /// </summary>
    /// <param name="row">UI row that was clicked on</param>
    /// <param name="r">Confirmation from the user</param>
    private void HandleDeleteDifficulty(DifficultyRow row, int r)
    {
        if (r == 1) // User canceled out
        {
            row.Toggle.isOn = true;
            return;
        }

        var diff = diffs[row.Name].DifficultyBeatmap;

        string fileToDelete = Song.GetMapFromDifficultyBeatmap(diff)?.directoryAndFile;

        if (File.Exists(fileToDelete))
        {
            FileOperationAPIWrapper.MoveToRecycleBin(fileToDelete);
        }

        // Remove status effects if present
        if (copySource != null && row == copySource.Obj && currentCharacteristic == copySource.Characteristic)
        {
            CancelCopy();
        }
        if (row == selected)
        {
            DeselectDiff();
        }

        currentCharacteristic.difficultyBeatmaps.Remove(diffs[row.Name].DifficultyBeatmap);
        if (currentCharacteristic.difficultyBeatmaps.Count == 0)
        {
            Song.difficultyBeatmapSets.Remove(currentCharacteristic);
        }

        diffs.Remove(row.Name);
        Song.SaveSong();

        row.SetInteractable(false);
        row.NameInput.text = "";
        row.ShowDirtyObjects(false, false);
        characteristicSelect.Recalculate();
    }
    /// <summary>
    /// Handle adding and deleting difficulties, they aren't added to the
    /// song being edited until they are saved so this method stages them
    /// </summary>
    /// <param name="row">UI row that was clicked on</param>
    /// <param name="val">True if the diff is being added</param>
    private void OnChange(DifficultyRow row, bool val)
    {
        if (!val && diffs.ContainsKey(row.Name)) // Delete if exists
        {
            // ForceDirty = has never been saved, don't ask for permission
            if (diffs[row.Name].ForceDirty)
            {
                if (row == selected)
                {
                    DeselectDiff();
                }

                diffs.Remove(row.Name);
                row.SetInteractable(false);
                row.NameInput.text = "";
                row.ShowDirtyObjects(false, false);
                return;
            }

            // This diff has previously been saved, confirm deletion
            PersistentUI.Instance.ShowDialogBox("SongEditMenu", "deletediff.dialog",
                                                (r) => HandleDeleteDifficulty(row, r), PersistentUI.DialogBoxPresetType.YesNo, new object[] { diffs[row.Name].DifficultyBeatmap.difficulty });
        }
        else if (val && !diffs.ContainsKey(row.Name)) // Create if does not exist
        {
            DifficultyBeatmap map = new DifficultyBeatmap(currentCharacteristic)
            {
                difficulty     = row.Name,
                difficultyRank = diffRankLookup[row.Name]
            };

            map.UpdateName();

            if (copySource != null)
            {
                var fromDiff = copySource.DifficultySettings;

                CancelCopy();

                if (fromDiff != null)
                {
                    map.noteJumpMovementSpeed   = fromDiff.DifficultyBeatmap.noteJumpMovementSpeed;
                    map.noteJumpStartBeatOffset = fromDiff.DifficultyBeatmap.noteJumpStartBeatOffset;

                    map.customData = fromDiff.DifficultyBeatmap.customData?.Clone();

                    // This sets the current filename as the filename for another diff and will trigger the copy on save
                    map.UpdateName(fromDiff.DifficultyBeatmap.beatmapFilename);
                }
            }

            diffs[row.Name] = new DifficultySettings(map, true);

            row.ShowDirtyObjects(diffs[row.Name]);
            row.SetInteractable(true);
            OnClick(row);
        }
        else if (val) // Create, but already exists
        {
            // I don't know how this would happen anymore
            row.ShowDirtyObjects(diffs[row.Name]);
            row.SetInteractable(true);
            if (!loading)
            {
                OnClick(row);
            }
        }
    }