protected virtual void DrawBottomBar()
        {
            // Draw add new item

            if (_mmfeedbacksList.arraySize > 0)
            {
                MMF_PlayerStyling.DrawSplitter();
            }

            EditorGUILayout.Space();

            EditorGUILayout.BeginHorizontal();
            {
                // Feedback list

                int newItem = EditorGUILayout.Popup(0, _typeDisplays) - 1;
                if (newItem >= 0)
                {
                    serializedObject.Update();
                    Undo.RecordObject(target, "Add new feedback");
                    AddFeedback(_typesAndNames[newItem].FeedbackType);
                    serializedObject.ApplyModifiedProperties();
                    PrefabUtility.RecordPrefabInstancePropertyModifications(TargetMmfPlayer);
                }

                // Paste feedback copy as new

                if (MMF_PlayerCopy.HasCopy())
                {
                    if (GUILayout.Button(_pasteAsNewText, EditorStyles.miniButton, _pasteAsNewOption))
                    {
                        PasteAsNew();
                    }
                }

                if (MMF_PlayerCopy.HasMultipleCopies())
                {
                    if (GUILayout.Button(_replaceAllText, EditorStyles.miniButton, _replaceAllOption))
                    {
                        ReplaceAll();
                    }
                    if (GUILayout.Button(_pasteAllAsNewText, EditorStyles.miniButton, _pasteAllAsNewOption))
                    {
                        PasteAllAsNew();
                    }
                }
            }

            if (!MMF_PlayerCopy.HasMultipleCopies())
            {
                if (GUILayout.Button(_copyAllText, EditorStyles.miniButton, _pasteAsNewOption))
                {
                    CopyAll();
                }
            }

            EditorGUILayout.EndHorizontal();
        }
        protected virtual void DrawFeedbacksList()
        {
            MMF_PlayerStyling.DrawSection(_feedbacksSectionTitle);
            for (int i = 0; i < _mmfeedbacksList.arraySize; i++)
            {
                DrawFeedbackHeader(i);

                // If expanded, draw feedback editor
                _feedbackListProperty.isExpanded = _feedbackListIsExpanded;
                if (_feedbackListIsExpanded)
                {
                    MMF_PlayerStyling.DrawSplitter();
                    EditorGUI.BeginDisabledGroup(!_feedbackListFeedback.Active);

                    DrawFeedbackHelp();

                    EditorGUILayout.Space();

                    // ---------------------------------------------------------------------------------------------------------------------------------

                    SerializedProperty currentProperty = _feedbackListProperty;

                    if (_feedbackListProperty.isExpanded)
                    {
                        if (MMF_FeedbackInspectors.TryGetValue(_feedbackListFeedback.UniqueID, out _mmfFeedbackInspector))
                        {
                            _mmfFeedbackInspector.DrawInspector(currentProperty, _feedbackListFeedback);
                        }
                        else
                        {
                            MMF_FeedbackInspector newInspector = new MMF_FeedbackInspector();
                            MMF_FeedbackInspectors.Add(_feedbackListFeedback.UniqueID, newInspector);
                            newInspector.Initialization(currentProperty, _feedbackListFeedback, _expandGroupsInInspectors);
                        }
                    }

                    // ---------------------------------------------------------------------------------------------------------------------------------

                    EditorGUI.EndDisabledGroup();

                    DrawFeedbackBottomBar(i);
                }
            }
        }
        protected virtual void InspectorCaching()
        {
            if (_cachedGUI)
            {
                return;
            }

            MMF_PlayerStyling.CacheStyling();

            _directionIconUp   = new GUIContent(Resources.Load("FeelArrowUp") as Texture);
            _directionIconDown = new GUIContent(Resources.Load("FeelArrowDown") as Texture);
            _whiteTexture      = Texture2D.whiteTexture;

            _redWarningBoxBackgroundTexture = new Texture2D(2, 2);
            _redWarningBoxBackgroundTexture.CreateColorTexture(_redBackgroundColor);

            _directionButtonStyle.border.left   = 0;
            _directionButtonStyle.border.right  = 0;
            _directionButtonStyle.border.top    = 0;
            _directionButtonStyle.border.bottom = 0;

            _playingStyle.normal.textColor = Color.yellow;

            _pasteAsNewGUIContent     = new GUIContent(_pasteAsNewText);
            _replaceAllGUIContent     = new GUIContent(_replaceAllText);
            _pasteAllAsNewGUIContent  = new GUIContent(_pasteAllAsNewText);
            _feedbackPlayGUIContent   = new GUIContent(_playText);
            _feedbackRemoveGUIContent = new GUIContent(_removeText);
            _feedbackCopyGUIContent   = new GUIContent(_copyText);
            _feedbackPasteGUIContent  = new GUIContent(_pasteText);
            _pasteAsNewOption         = GUILayout.Width(EditorStyles.miniButton.CalcSize(_pasteAsNewGUIContent).x);
            _replaceAllOption         = GUILayout.Width(EditorStyles.miniButton.CalcSize(_replaceAllGUIContent).x);
            _pasteAllAsNewOption      = GUILayout.Width(EditorStyles.miniButton.CalcSize(_pasteAllAsNewGUIContent).x);

            _helptextStyle          = new GUIStyle(EditorStyles.helpBox);
            _helptextStyle.richText = true;
            _helptextStyle.fontSize = 11;
            _helptextStyle.padding  = new RectOffset(8, 8, 8, 8);
        }
        protected virtual void DrawFeedbackHeader(int i)
        {
            MMF_PlayerStyling.DrawSplitter();
            _feedbackListProperty = _mmfeedbacksList.GetArrayElementAtIndex(i);

            // Retrieve feedback
            _feedbackListFeedback = TargetMmfPlayer.FeedbacksList[i];

            if (_feedbackListFeedback == null)
            {
                return;
            }

            // Draw header
            _feedbackListIsExpanded = _feedbackListProperty.isExpanded;
            _feedbackListLabel      = _feedbackListFeedback.Label;
            _feedbackListPause      = false;

            if (_feedbackListFeedback.Pause != null)
            {
                _feedbackListPause = true;
            }
            if ((_feedbackListFeedback.LooperPause == true) && (Application.isPlaying))
            {
                if ((_feedbackListFeedback as MMF_Looper).InfiniteLoop)
                {
                    _feedbackListLabel = _feedbackListLabel + _infiniteLoopText;
                }
                else
                {
                    _feedbackListLabel = _feedbackListLabel + "[ " + (_feedbackListFeedback as MMF_Looper).NumberOfLoopsLeft + " loops left ] ";
                }
            }

            Rect headerRect = MMF_PlayerStyling.DrawHeader(
                ref _feedbackListIsExpanded,
                ref _feedbackListFeedback.Active,
                _feedbackListLabel,
                _feedbackListFeedback.FeedbackColor,
                (GenericMenu menu) =>
            {
                if (Application.isPlaying)
                {
                    menu.AddItem(_feedbackPlayGUIContent, false, () => PlayFeedback(i));
                }
                else
                {
                    menu.AddDisabledItem(_feedbackPlayGUIContent);
                }
                menu.AddSeparator(null);
                menu.AddItem(_feedbackRemoveGUIContent, false, () => RemoveFeedback(i));
                menu.AddSeparator(null);
                menu.AddItem(_feedbackCopyGUIContent, false, () => CopyFeedback(i));
                if (MMF_PlayerCopy.HasCopy())
                {
                    menu.AddItem(_feedbackPasteGUIContent, false, PasteAsNew);
                }
                else
                {
                    menu.AddDisabledItem(_feedbackPasteGUIContent);
                }
            },
                _feedbackListFeedback.FeedbackStartedAt,
                _feedbackListFeedback.FeedbackDuration,
                _feedbackListFeedback.TotalDuration,
                _feedbackListFeedback.Timing,
                _feedbackListPause,
                _feedbackListFeedback.RequiresSetup,
                _feedbackListFeedback.RequiredTarget,
                _feedbackListFeedback.DisplayColor,
                TargetMmfPlayer
                );

            // Check if we start dragging this feedback

            switch (_currentEvent.type)
            {
            case EventType.MouseDown:
                if (headerRect.Contains(_currentEvent.mousePosition))
                {
                    _draggedStartID = i;
                    _currentEvent.Use();
                }
                break;
            }

            // Draw blue rect if feedback is being dragged

            if (_draggedStartID == i && headerRect != Rect.zero)
            {
                EditorGUI.DrawRect(headerRect, _draggedColor);
            }

            // If hovering at the top of the feedback while dragging one, check where the feedback should be dropped : top or bottom

            if (headerRect.Contains(_currentEvent.mousePosition))
            {
                if (_draggedStartID >= 0)
                {
                    _draggedEndID = i;
                    Rect headerSplit = headerRect;
                    headerSplit.height *= 0.5f;
                    headerSplit.y      += headerSplit.height;
                    if (headerSplit.Contains(_currentEvent.mousePosition))
                    {
                        _draggedEndID = i + 1;
                    }
                }
            }
        }
        protected virtual void DrawDebugControls()
        {
            MMF_PlayerStyling.DrawSection(_allFeedbacksDebugText);

            // Testing buttons

            EditorGUI.BeginDisabledGroup(!Application.isPlaying);
            EditorGUILayout.BeginHorizontal();
            {
                // initialize button
                if (GUILayout.Button(_initializeText, EditorStyles.miniButtonLeft))
                {
                    (target as MMF_Player).Initialization();
                }

                // play button
                _originalBackgroundColor = GUI.backgroundColor;
                GUI.backgroundColor      = _playButtonColor;
                if (GUILayout.Button(_playText, EditorStyles.miniButtonMid))
                {
                    (target as MMF_Player).PlayFeedbacks();
                }
                GUI.backgroundColor = _originalBackgroundColor;

                // pause button
                if ((target as MMF_Player).ContainsLoop)
                {
                    if (GUILayout.Button(_pauseText, EditorStyles.miniButtonMid))
                    {
                        (target as MMF_Player).PauseFeedbacks();
                    }
                }

                // stop button
                if (GUILayout.Button(_stopText, EditorStyles.miniButtonMid))
                {
                    (target as MMF_Player).StopFeedbacks();
                }

                // skip button
                if (GUILayout.Button(_skipText, EditorStyles.miniButtonMid))
                {
                    (target as MMF_Player).SkipToTheEnd();
                }

                // reset button
                if (GUILayout.Button(_resetText, EditorStyles.miniButtonMid))
                {
                    (target as MMF_Player).ResetFeedbacks();
                }
                EditorGUI.EndDisabledGroup();

                // reverse button
                if (GUILayout.Button(_revertText, EditorStyles.miniButtonMid))
                {
                    (target as MMF_Player).Revert();
                }
            }
            EditorGUILayout.EndHorizontal();

            // keep runtime changes button
            _originalBackgroundColor = GUI.backgroundColor;
            if (_keepPlayModeChanges.boolValue)
            {
                GUI.backgroundColor = _keepPlaymodeChangesButtonColor;
            }
            if (GUILayout.Button(_keepPlaymodeChangesText))
            {
                _keepPlayModeChanges.boolValue = !_keepPlayModeChanges.boolValue;
            }
            GUI.backgroundColor = _originalBackgroundColor;

            float pingPong = Mathf.PingPong(Time.unscaledTime, 0.25f);

            // if in pause, we display additional controls
            if (TargetMmfPlayer.InScriptDrivenPause)
            {
                // draws a warning box
                _scriptDrivenBoxColor          = Color.Lerp(_scriptDrivenBoxColorFrom, _scriptDrivenBoxColorTo, pingPong);
                GUI.skin.box.normal.background = _whiteTexture;
                GUI.backgroundColor            = _scriptDrivenBoxColor;
                GUI.skin.box.normal.textColor  = Color.black;
                GUILayout.Box(_scriptDrivenInProgressText, GUILayout.ExpandWidth(true));
                GUI.backgroundColor            = _originalBackgroundColor;
                GUI.skin.box.normal.background = _scriptDrivenBoxBackgroundTexture;

                // draws resume button
                if (GUILayout.Button(_resumeText))
                {
                    TargetMmfPlayer.ResumeFeedbacks();
                }
            }
        }