Example #1
0
        private void PrepareForReuse()
        {
            StopAllCoroutines();

            m_FadeInData  = null;
            m_FadeOutData = null;

            cachedGameObject.name = "AudioClipPlayer";

            ClipID   = null;
            Category = null;

            m_Source.clip = null;
            m_Source.outputAudioMixerGroup = null;
            if (m_Handle != null)
            {
                m_Handle.Clear();
            }
            m_Handle = null;

            foreach (var kv in m_Filters)
            {
                kv.Value.enabled = false;
            }

            cachedTransform.position = Vector3.zero;

            IsEmpty = true;
        }
        bool IsValidReparenting(AudioManagerCategory parent, List <AudioManagerCategory> categoriesToMove)
        {
            if (parent == null)
            {
                return(true);
            }

            foreach (var cat in categoriesToMove)
            {
                //Is trying to move parent to self
                if (cat == parent)
                {
                    return(false);
                }

                //Is tryin to parent a parent to child
                if (IsHoveredAChildOfDragged(parent, cat))
                {
                    return(false);
                }

                //Is trying to move object with same name as already exists
                if (IsHoveredChildrenIdsTaken(parent, cat))
                {
                    return(false);
                }
            }

            return(true);
        }
        private void PerformParenting(AudioManagerCategory parent, List <AudioManagerCategory> categories, DragAndDropArgs args)
        {
            bool isChangingParent = categories.Any(c => c.Parent != parent);
            bool showWarning      = isChangingParent && !Event.current.control;

            if (!showWarning || EditorUtility.DisplayDialog("Reparent categories?",
                                                            "Are you sure you want to move " + categories.Count + " items to parent " + parent.ID + "?",
                                                            "Reparent", "Cancel"))
            {
                foreach (var cat in categories)
                {
                    SetParent(parent, cat);
                }

                if (args.dragAndDropPosition == DragAndDropPosition.BetweenItems)
                {
                    int insertIndex = args.insertAtIndex;
                    for (int i = categories.Count - 1; i >= 0; i--)
                    {
                        var cat = categories[i];
                        insertIndex = GetAdjustedInsertIndex(parent, cat, insertIndex);
                        SetSiblingIndex(cat, insertIndex);
                    }
                }

                m_Data.SaveTree();
                m_Data.ReconstructTreeChildren();
                m_Root = m_Data.TreeData;
            }
        }
Example #4
0
        private bool CheckCooldown(AudioManagerCategory c, float currentTime)
        {
            // Traverse all parents
            while (c != null)
            {
                if (c.NextAllowedAudioDelay >= 0 && m_ClipsLastPlayedTimes.ContainsKey(c.UniqueID) &&
                    (m_ClipsLastPlayedTimes[c.UniqueID] + c.NextAllowedAudioDelay) >= currentTime)
                {
                    return(false);
                }
                c = c.Parent;


                // only parent nodes (categories)
                if (c != null)
                {
                    for (int i = 0; i < c.BlockedByCategoryIds.Length; i++)
                    {
                        int blockedCat = c.BlockedByCategoryIds[i];
                        if (m_CurrentPlayingCategoryCounts.ContainsKey(blockedCat) && m_CurrentPlayingCategoryCounts[blockedCat] > 0)
                        {
                            //D.AudioError("Audio blocked by a different audio playing!");
                            return(false);
                        }
                    }
                }
            }
            return(true);
        }
        void AddChildrenRecursive(AudioManagerCategory category, TreeViewItem item, IList <TreeViewItem> rows)
        {
            int childCount   = category.Count;
            var childrenList = category.Children.Values.ToList();

            item.children = new List <TreeViewItem>(childCount);
            for (int i = 0; i < childCount; ++i)
            {
                var child = childrenList[i];

                var childItem = CreateTreeViewItem(child);
                item.AddChild(childItem);
                rows.Add(childItem);

                if (child.Count > 0)
                {
                    if (IsExpanded(childItem.id))
                    {
                        AddChildrenRecursive(child, childItem, rows);
                    }
                    else
                    {
                        childItem.children = CreateChildListForCollapsedParent();
                    }
                }
            }
        }
Example #6
0
        public void SaveTree(AudioManagerCategory node)
        {
            if (node.Parent != null)
            {
                node.ParentUniqueId = node.Parent.UniqueID;

                int orderIdx    = -1;
                var siblingList = node.Parent.Children.Values.ToList();
                for (int i = 0; i < siblingList.Count; i++)
                {
                    if (siblingList[i] == node)
                    {
                        orderIdx = i;
                        break;
                    }
                }
                node.OrderIdx = orderIdx;
            }
            else
            {
                node.ParentUniqueId = -1;
                node.OrderIdx       = -1;
            }

            m_SavedTree.Add(node);
            //node.NextAllowedAudioDelay = -1;
            if (node.Children != null && node.Children.Count > 0)
            {
                foreach (KeyValuePair <string, AudioManagerCategory> entry in node.Children)
                {
                    SaveTree(entry.Value);
                }
            }
        }
        public AudioManagerTreeView(TreeViewState state, AudioManagerData data, AudioManagerCategory root) : base(state)
        {
            showAlternatingRowBackgrounds = true;

            m_Data = data;
            m_Root = root;
            Reload();
        }
 static TreeViewItem CreateTreeViewItem(AudioManagerCategory category)
 {
     // We can use the GameObject instanceID for TreeViewItem id, as it ensured to be unique among other items in the tree.
     // To optimize reload time we could delay fetching the transform.name until it used for rendering (prevents allocating strings
     // for items not rendered in large trees)
     // We just set depth to -1 here and then call SetupDepthsFromParentsAndChildren at the end of BuildRootAndRows to set the depths.
     return(new TreeViewItem(category.UniqueID, -1, category.ID));
 }
 int GetAdjustedInsertIndex(AudioManagerCategory parent, AudioManagerCategory categoryToInsert, int insertIndex)
 {
     if (categoryToInsert.Parent == parent && GetSiblingIndex(categoryToInsert) < insertIndex)
     {
         return(--insertIndex);
     }
     return(insertIndex);
 }
Example #10
0
        public void InitTree()
        {
            int uniqueId = 1;

            m_TreeData = new AudioManagerCategory("Master", uniqueId++);
            m_TreeData.Add(new AudioManagerCategory("Music", uniqueId++));
            m_TreeData.Add(new AudioManagerCategory("SFX", uniqueId++));
            m_TreeData.Add(new AudioManagerCategory("Characters", uniqueId++));
            m_TreeData.Add(new AudioManagerCategory("VO", uniqueId++));
            m_SavedTree = new List <AudioManagerCategory>();
        }
Example #11
0
 /// <summary>
 /// Add a child to the current node. Warning: If the given node already have a parent that parent will be overwritten.
 /// </summary>
 /// <param name="item">Child to be add.</param>
 public void ReconstructAdd(AudioManagerCategory item)
 {
     item.Parent = this;
     if (this.Children == null)
     {
         Children = new Dictionary <string, AudioManagerCategory>();                      //D.AudioLog("null children wtf");
     }
     if (Children.ContainsKey(item.ID))
     {
         Children.Remove(item.ID);
     }
     this.Children.Add(item.ID, item);
 }
        bool IsHoveredAChildOfDragged(AudioManagerCategory hovered, AudioManagerCategory dragged)
        {
            AudioManagerCategory cat = hovered.Parent;

            while (cat != null)
            {
                if (cat == dragged)
                {
                    return(true);
                }
                cat = cat.Parent;
            }
            return(false);
        }
        //TODO Move to AudioManagerCategory.cs
        private void SetParent(AudioManagerCategory parent, AudioManagerCategory category)
        {
            // D.AudioLog("SetParent: "+ category.ID + ":" + category.UniqueID + " to " + parent.ID + ":" + parent.UniqueID);

            var oldParent = category.Parent;

            oldParent.Children.Remove(category.ID);

            category.Parent = parent;
            if (parent.Children == null)
            {
                parent.Children = new Dictionary <string, AudioManagerCategory>();
            }
            parent.Children.Add(category.ID, category);
        }
Example #14
0
        public void SetFilters(AudioManagerCategory cat)
        {
            if (cat.UseLowPassFilter)
            {
                AudioLowPassFilter filter = EnableFilter <AudioLowPassFilter>(EAudioFilter.LowPass);
                cat.AudioFilters.LowPass.SetToFilter(filter);
            }

            if (cat.UseHighPassFilter)
            {
                AudioHighPassFilter filter = EnableFilter <AudioHighPassFilter>(EAudioFilter.HighPass);
                cat.AudioFilters.HighPass.SetToFilter(filter);
            }

            if (cat.UseChorusFilter)
            {
                AudioChorusFilter filter = EnableFilter <AudioChorusFilter>(EAudioFilter.Chorus);
                cat.AudioFilters.Chorus.SetToFilter(filter);
            }

            if (cat.UseDistortionFilter)
            {
                AudioDistortionFilter filter = EnableFilter <AudioDistortionFilter>(EAudioFilter.Distortion);
                cat.AudioFilters.Distortion.SetToFilter(filter);
            }

            if (cat.UseEchoFilter)
            {
                AudioEchoFilter filter = EnableFilter <AudioEchoFilter>(EAudioFilter.Echo);
                cat.AudioFilters.Echo.SetToFilter(filter);
            }

            if (cat.UseReverbFilter)
            {
                AudioReverbFilter filter = EnableFilter <AudioReverbFilter>(EAudioFilter.Reverb);
                cat.AudioFilters.Reverb.SetToFilter(filter);
            }

            if (cat.UseFadeIn)
            {
                m_FadeInData = cat.AudioFilters.FadeIn;
            }

            if (cat.UseFadeOut)
            {
                m_FadeOutData = cat.AudioFilters.FadeOut;
            }
        }
        bool IsHoveredChildrenIdsTaken(AudioManagerCategory hovered, AudioManagerCategory dragged)
        {
            if (hovered.Children == null)
            {
                return(false);
            }
            foreach (var child in hovered.Children)
            {
                if (child.Value != dragged && child.Value.ID == dragged.ID)
                {
                    return(true);
                }
            }

            return(false);
        }
        //TODO Move to AudioManagerCategory.cs
        private int GetSiblingIndex(AudioManagerCategory category)
        {
            if (category.Parent == null)
            {
                return(-1);
            }
            var parentChildren = category.Parent.Children.Values.ToList();

            for (int i = 0; i < parentChildren.Count; i++)
            {
                if (parentChildren[i] == category)
                {
                    return(i);
                }
            }
            return(-1);
        }
Example #17
0
        private void FreeCooldown(AudioManagerCategory c)
        {
            // Traverse all parents
            while (c != null)
            {
                c = c.Parent;

                // only parent nodes (categories)
                if (c != null)
                {
                    if (!m_CurrentPlayingCategoryCounts.ContainsKey(c.UniqueID))
                    {
                        m_CurrentPlayingCategoryCounts[c.UniqueID] = 0;
                    }
                    m_CurrentPlayingCategoryCounts[c.UniqueID]--;
                }
            }
        }
Example #18
0
        private void UpdateCooldown(AudioManagerCategory c, float currentTime)
        {
            // Traverse all parents
            while (c != null)
            {
                m_ClipsLastPlayedTimes[c.UniqueID] = currentTime;
                c = c.Parent;

                // only parent nodes (categories)
                if (c != null)
                {
                    if (!m_CurrentPlayingCategoryCounts.ContainsKey(c.UniqueID))
                    {
                        m_CurrentPlayingCategoryCounts[c.UniqueID] = 0;
                    }
                    m_CurrentPlayingCategoryCounts[c.UniqueID]++;
                }
            }
        }
Example #19
0
        /// <summary>
        /// Add a child to the current node. Warning: If the given node already have a parent that parent will be overwritten.
        /// </summary>
        /// <param name="item">Child to be add.</param>
        public void Add(AudioManagerCategory item)
        {
            if (item.Parent != null)
            {
                item.Parent.Children.Remove(item.ID);
            }
            item.Parent     = this;
            item.DefaultBus = this.DefaultBus;
            int countInChildren = CountIDInChildren(item.ID);

            if (countInChildren > 0)
            {
                item.m_ID = item.m_ID + countInChildren;
            }
            if (this.Children == null)
            {
                Children = new Dictionary <string, AudioManagerCategory>();                      //D.AudioLog("null children wtf");
            }
            this.Children.Add(item.ID, item);
        }
Example #20
0
 public void RemoveChild(AudioManagerCategory item)
 {
     if (Children != null)
     {
         string key   = "";
         bool   found = false;
         foreach (KeyValuePair <string, AudioManagerCategory> entry in Children)
         {
             if (entry.Value.ID == item.ID)
             {
                 found = true;
                 key   = entry.Key;
             }
         }
         if (found)
         {
             Children.Remove(key);
         }
     }
     item = null;
 }
Example #21
0
        public AudioManagerCategory FindCategoryWithUniqueId(int id)
        {
            if (m_UniqueId == id)
            {
                return(this);
            }

            if (m_Children != null)
            {
                AudioManagerCategory found = null;
                foreach (AudioManagerCategory c in m_Children.Values)
                {
                    found = c.FindCategoryWithUniqueId(id);
                    if (found != null)
                    {
                        return(found);
                    }
                }
            }

            return(null);
        }
        //TODO Move to AudioManagerCategory.cs
        //TODO Optimize
        private void SetSiblingIndex(AudioManagerCategory category, int insertIdx)
        {
            // D.AudioLog("SetSiblingIndex - category: " + category.ID + ", insertIdx: "+ insertIdx);

            if (category.Parent == null)
            {
                return;
            }
            var buffer = category.Parent.Children.Values.ToList();

            int childCount = buffer.Count;

            var newChildren = new Dictionary <string, AudioManagerCategory>();
            int idx         = 0;

            while (buffer.Count > 0 || !newChildren.ContainsKey(category.ID))
            {
                if (idx == insertIdx)
                {
                    newChildren.Add(category.ID, category);
                    buffer.Remove(category);
                    idx++;
                }
                else
                {
                    var child = buffer[0];
                    buffer.Remove(child);
                    if (child != category)
                    {
                        newChildren.Add(child.ID, child);
                        idx++;
                    }
                }
            }

            category.Parent.Children = newChildren;
        }
Example #23
0
        AudioClipPlayer PrepareClip(AudioClip clip, AudioManagerCategory trigger, bool loop = false, bool startPaused = false, AudioMixerGroup outBus = null, float volume = 1.0f, float delay = 0.0f, bool in3D = false, Vector3?position = null, float minDistance = 1f, float maxDistance = 500f, AudioRolloffMode volumeRolloffMode = AudioRolloffMode.Logarithmic, float pitchRandomisation = 0.0f, Transform trackTrans = null, AudioSource referenceAudioSource = null)
        {
            AudioClipPlayer go = m_AudioClipPlayerPool.RentObject().GetComponent <AudioClipPlayer>();

            go.Setup(m_AudioClipPlayerPool, this, signalBus);
            go.Category = trigger;

            if (go.IsEmpty == false)
            {
                D.LogError("Rented AudioClipPlayer is not empty! Used for " + go.ClipID);
            }

            go.transform.parent        = transform;
            go.transform.localPosition = Vector3.zero;

            var audioSource = go.AudioSource;

            if (outBus != null)
            {
                audioSource.outputAudioMixerGroup = outBus;
            }

            audioSource.pitch        = referenceAudioSource ? referenceAudioSource.pitch : 1;
            audioSource.loop         = loop;
            audioSource.clip         = clip;
            audioSource.volume       = volume;
            audioSource.spatialBlend = referenceAudioSource ? referenceAudioSource.spatialBlend : (in3D) ? 1.0f : 0.0f;
            if (in3D || m_AudioMode == AudioMode.AUDIO_3D)
            {
                audioSource.minDistance = referenceAudioSource ? referenceAudioSource.minDistance : minDistance;
                audioSource.maxDistance = referenceAudioSource ? referenceAudioSource.maxDistance : maxDistance;
                audioSource.rolloffMode = referenceAudioSource ? referenceAudioSource.rolloffMode : volumeRolloffMode;
                if (position != null)
                {
                    go.transform.position = position.Value;
                }

                if (audioSource.rolloffMode == AudioRolloffMode.Custom && referenceAudioSource)
                {
                    foreach (AudioSourceCurveType audioCurve in (AudioSourceCurveType[])Enum.GetValues(typeof(AudioSourceCurveType)))
                    {
                        audioSource.SetCustomCurve(audioCurve, referenceAudioSource.GetCustomCurve(audioCurve));
                    }
                }
                audioSource.dopplerLevel          = referenceAudioSource ? referenceAudioSource.dopplerLevel : audioSource.dopplerLevel;
                audioSource.spread                = referenceAudioSource ? referenceAudioSource.spread : audioSource.spread;
                audioSource.spatialize            = referenceAudioSource ? referenceAudioSource.spatialize : audioSource.spatialize;
                audioSource.spatializePostEffects = referenceAudioSource ? referenceAudioSource.spatializePostEffects : audioSource.spatializePostEffects;
            }

            if (pitchRandomisation != 0.0f)
            {
                pitchRandomisation = Mathf.Abs(pitchRandomisation);
                float defaultPitch = referenceAudioSource ? referenceAudioSource.pitch : 1.0f;
                audioSource.pitch = defaultPitch + UnityEngine.Random.Range(-pitchRandomisation, pitchRandomisation);
            }

            float releaseDelayGameTime = 0;
            float releaseDelayRealTime = 0;

            if (!loop && !startPaused)
            {
                // Return to pool after the clip is played
                releaseDelayGameTime = delay;
                releaseDelayRealTime = clip.length + 0.1f;
            }

            go.SetClip(clip, trackTrans, releaseDelayGameTime, releaseDelayRealTime, trigger.ID);

            return(go);
        }
Example #24
0
        private AudioClipPlayer PlayAudioInternal(PlayConfig c)
        {
            if (c == null || string.IsNullOrEmpty(c.SoundID))
            {
                D.AudioWarning("Null config or sound ID: " + (c != null ? c.SoundID : ""));
                return(null);
            }

            if (!m_Leafs.ContainsKey(c.SoundID))
            {
                PlayMissingSound(c.SoundID);
                return(null);
            }

            AudioClip clipToPlay = GetClip(c.SoundID);

            if (clipToPlay == null)
            {
                D.AudioWarning("Null clipToPlay: " + (c != null ? c.SoundID : ""));
                PlayMissingSound(c.SoundID);
                return(null);
            }


            AudioManagerCategory cat = m_Leafs[c.SoundID];
            var closestOutbus        = cat.GetClosestBus();
            //D.AudioLog("Playing sound: " + c.SoundID + " through mixer: " + closestOutbus.name);
            bool startPaused = c.StartPaused.HasValue ? c.StartPaused.Value : false;

            // Skip processing if only allowing for one sound instance.
            float currentTime = Time.time;

            if (!startPaused)
            {
                if (CheckCooldown(cat, currentTime) == false)
                {
                    D.AudioWarning("Skipping sound '" + c.SoundID + "' as it would be played too soon or because it is blocked by some playing category");
                    return(null);
                }
            }

            Vector3?pos = null;

            if (c.Position.HasValue)
            {
                pos = c.Position.Value;
            }

            AudioClipPlayer player = PrepareClip(clipToPlay,
                                                 cat,
                                                 c.Loop.HasValue ? c.Loop.Value : cat.Loop,
                                                 startPaused,
                                                 closestOutbus,
                                                 c.Volume.HasValue ? c.Volume.Value : cat.Volume,
                                                 c.Delay.HasValue ? c.Delay.Value : 0,
                                                 c.In3D.HasValue ? c.In3D.Value : false,
                                                 pos,
                                                 c.MinDistance.HasValue ? c.MinDistance.Value : 1f,
                                                 c.MaxDistance.HasValue ? c.MaxDistance.Value : 500f,
                                                 c.VolumeRolloffMode.HasValue ? c.VolumeRolloffMode.Value : AudioRolloffMode.Logarithmic,
                                                 c.PitchRandomisation.HasValue ? c.PitchRandomisation.Value : cat.PitchRandomizationValue,
                                                 c.TrackTransform,
                                                 c.ReferenceAudioSource);

            //D.AudioLogFormat("Playing sound {0} with delay {1}", c.SoundID, (c.Delay.HasValue ? c.Delay.Value : 0));

            player.SetFilters(cat);

            if (!startPaused)
            {
                UpdateCooldown(cat, currentTime);
                player.PlayDelayed(c.Delay.HasValue ? c.Delay.Value : 0);
            }

#if NN_OCULUS
            if (m_AudioMode == AudioMode.OCULUS_READY)
            {
                ONSPAudioSource tempOculusSource = audio.gameObject.AddComponent <ONSPAudioSource>();
                tempOculusSource.EnableSpatialization = true;
                tempOculusSource.EnableRfl            = true;
                tempOculusSource.Gain = 10;
                tempOculusSource.Near = 0.25f;
                tempOculusSource.Far  = 20000f;
            }
#endif

            if (m_AudioMode == AudioMode.STEREO_CONTROL)
            {
                AddStereoControl(player.AudioSource, cat.StereoPan);
            }

            if ((m_AudioMode == AudioMode.AUDIO_3D || m_AudioMode == AudioMode.OCULUS_READY) && ((c.In3D.HasValue && c.In3D.Value) || (!c.In3D.HasValue)) &&
                !c.ReferenceAudioSource)
            {
                Add3DData(player.AudioSource, m_Preferences.Default3DSettings);
            }

            return(player);
        }
Example #25
0
 public void ReconstructClear()
 {
     m_Parent   = null;
     m_Children = null;
 }
Example #26
0
        public AudioManagerCategory CreateAudioManagerCategory(string name)
        {
            AudioManagerCategory c = new AudioManagerCategory(name, CreateNewUniqueId());

            return(c);
        }
Example #27
0
        public void ReconstructTreeChildren()
        {
            Dictionary <int, AudioManagerCategory> lookup = new Dictionary <int, AudioManagerCategory>();
            AudioManagerCategory root = null;

            //Build look up dictionary, clear non-serialized data
            for (int i = 0; i < m_SavedTree.Count; i++)
            {
                var category = m_SavedTree[i];
                lookup[category.UniqueID] = category;
                category.ReconstructClear();

                if (category.ParentUniqueId < 0)
                {
                    root = category;
                }
            }

            //Use parentUniqueId to reconstruct parent relations
            for (int i = 0; i < m_SavedTree.Count; i++)
            {
                var category = m_SavedTree[i];
                if (category.ParentUniqueId >= 0)
                {
                    if (!lookup.ContainsKey(category.ParentUniqueId))
                    {
                        D.AudioError("No parent found for category: " + category.UniqueID + " - " + category.ID);
                    }

                    var parentCategory = lookup[category.ParentUniqueId];
                    category.Parent = parentCategory;
                    parentCategory.ReconstructAdd(category);
                }
            }

            //Use orderIdx to reconstruct children order
            for (int i = 0; i < m_SavedTree.Count; i++)
            {
                var category = m_SavedTree[i];
                if (category.Children != null && category.Children.Count > 0)
                {
                    var newChildren = new Dictionary <string, AudioManagerCategory>();

                    var sortedChildrenList = category.Children.Values.OrderBy(c => c.OrderIdx).ToList();
                    for (int j = 0; j < sortedChildrenList.Count; j++)
                    {
                        var childCategory = sortedChildrenList[j];
                        newChildren.Add(childCategory.ID, childCategory);
                    }

                    category.Children = newChildren;
                }
            }

            if (m_SavedTree.Count > 0)
            {
                m_TreeData = root;
            }

            D.AudioLog("Audio data loaded!");
        }
        protected override DragAndDropVisualMode HandleDragAndDrop(DragAndDropArgs args)
        {
            if (hasSearch)
            {
                return(DragAndDropVisualMode.Rejected);
            }

            // Check if we can handle the current drag data (could be dragged in from other areas/windows in the editor)
            var draggedRows = DragAndDrop.GetGenericData(k_GenericDragID) as List <TreeViewItem>;

            if (draggedRows == null)
            {
                return(DragAndDropVisualMode.None);
            }
            var categories = new List <AudioManagerCategory>(draggedRows.Count);

            foreach (var obj in draggedRows)
            {
                var category = GetAudioCategory(obj.id);
                categories.Add(category);
            }


            // Filter out any unnecessary transforms before the reparent operation
            // RemoveItemsThatAreDescendantsFromOtherItems (transforms);

            // Reparent
            if (args.performDrop)
            {
                D.AudioLog("HandleDragAndDrop - dragAndDropPosition: " + args.dragAndDropPosition + ", insertAtIndex: " + args.insertAtIndex + ", parentItem: " + args.parentItem + ", performDrop: " + args.performDrop);
                switch (args.dragAndDropPosition)
                {
                case DragAndDropPosition.UponItem:
                case DragAndDropPosition.BetweenItems:
                    AudioManagerCategory parent = args.parentItem != null?GetAudioCategory(args.parentItem.id) : null;

                    if (parent == null)
                    {
                        break;
                    }

                    if (!IsValidReparenting(parent, categories))
                    {
                        return(DragAndDropVisualMode.None);
                    }

                    PerformParenting(parent, categories, args);

                    break;

                case DragAndDropPosition.OutsideItems:
                    PerformParenting(m_Root, categories, args);

                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                Reload();
                SetSelection(categories.Select(c => c.UniqueID).ToList(), TreeViewSelectionOptions.RevealAndFrame);
            }

            return(DragAndDropVisualMode.Move);
        }