// Displays a popup menu filled with all potential atlases for the given input textures
    // Displays all available atlases if a_rTexturesToContain is null
    // Manages the serialized settings update
    public static Uni2DTextureAtlas SerializedAtlasPopup(SerializedSetting <Uni2DTextureAtlas> a_rSerializedTextureAtlas, IEnumerable <string> a_rTextureGUIDsToContain = null)
    {
        Uni2DTextureAtlas rCurrentAtlas = a_rSerializedTextureAtlas.HasMultipleDifferentValues ? null : a_rSerializedTextureAtlas.Value;

        bool bSavedShowMixedValue = EditorGUI.showMixedValue;

        EditorGUI.showMixedValue = a_rSerializedTextureAtlas.HasMultipleDifferentValues;
        {
            EditorGUI.BeginChangeCheck( );
            {
                rCurrentAtlas = Uni2DEditorGUIUtils.AtlasPopup(rCurrentAtlas, a_rTextureGUIDsToContain);
            }
            if (EditorGUI.EndChangeCheck( ))
            {
                a_rSerializedTextureAtlas.Value = rCurrentAtlas;
            }
        }
        EditorGUI.showMixedValue = bSavedShowMixedValue;

        return(rCurrentAtlas);
    }
    public override void OnInspectorGUI( )
    {
        // Update animation player used in clip header
        m_oAnimationPlayerClipHeader.Update(this.ComputeDeltaTime(ref m_lLastTimeTicks));

        // Atlas
        bool bHasMultipleDifferentGlobalAtlasValues;
        Uni2DTextureAtlas rGlobalAtlas;

        this.GetGlobalAtlas(out rGlobalAtlas, out bHasMultipleDifferentGlobalAtlasValues);

        // Atlas size
        AtlasSize eMaximumAtlasSize = AtlasSize._2048;
        //SerializedSetting<EAtlasSize> oSerializedSetting_MaximumAtlasSize;

        // Selected object count
        int  iTargetObjectCount = targets.Length;
        bool bDisplayFrames     = (iTargetObjectCount == 1);

        EditorGUI.BeginDisabledGroup(Application.isPlaying);
        {
            EditorGUILayout.BeginVertical( );
            {
                if (bDisplayFrames == false)
                {
                    EditorGUILayout.HelpBox("Animation Clip edition is restricted when inspecting multiple clips, but you can change the atlas settings to pack the clips together.", MessageType.Info, true);
                }

                if (m_bAreClipsAndAtlasSynced == false)
                {
                    EditorGUILayout.HelpBox("At least one animation frame is referencing an atlas which does not contain its texture.\nPlease regenerate the clip or manually add the frame texture to the atlas.", MessageType.Error, true);
                }

                ///// Atlas section /////
                ms_bAtlasFoldout = EditorGUILayout.Foldout(ms_bAtlasFoldout, "Atlas");

                if (ms_bAtlasFoldout)
                {
                    bool bHasAtlasSettingsChanged;
                    bool bHasAtlasChanged;

                    ++EditorGUI.indentLevel;
                    {
                        EditorGUILayout.BeginVertical( );
                        {
                            EditorGUILayout.BeginHorizontal( );
                            {
                                EditorGUILayout.PrefixLabel("Use Atlas");

                                // Atlas popup
                                EditorGUI.BeginChangeCheck( );
                                {
                                    EditorGUI.showMixedValue = bHasMultipleDifferentGlobalAtlasValues;
                                    {
                                        rGlobalAtlas = Uni2DEditorGUIUtils.AtlasPopup(rGlobalAtlas, m_oTextureGUIDs);
                                    }
                                    EditorGUI.showMixedValue = false;
                                }
                                bHasAtlasChanged = EditorGUI.EndChangeCheck( );

                                // Atlas select button
                                EditorGUI.BeginDisabledGroup(rGlobalAtlas == null);
                                {
                                    if (GUILayout.Button("Select", GUILayout.Width(80.0f)))
                                    {
                                        EditorGUIUtility.PingObject(rGlobalAtlas.gameObject);
                                    }
                                }
                                EditorGUI.EndDisabledGroup( );
                            }
                            EditorGUILayout.EndHorizontal( );

                            // Atlas max size
                            EditorGUI.BeginChangeCheck( );
                            {
                                EditorGUI.BeginDisabledGroup((bHasAtlasChanged == false && bHasMultipleDifferentGlobalAtlasValues) || rGlobalAtlas == null);
                                {
                                    eMaximumAtlasSize = (AtlasSize)EditorGUILayout.EnumPopup("Maximum Atlas Size", rGlobalAtlas != null ? rGlobalAtlas.maximumAtlasSize : eMaximumAtlasSize);
                                }
                                EditorGUI.EndDisabledGroup( );
                            }
                            bHasAtlasSettingsChanged = EditorGUI.EndChangeCheck( );
                        }
                        EditorGUILayout.EndVertical( );
                    }
                    --EditorGUI.indentLevel;

                    if (rGlobalAtlas != null && bHasAtlasSettingsChanged)
                    {
                        rGlobalAtlas.maximumAtlasSize = eMaximumAtlasSize;
                        EditorUtility.SetDirty(rGlobalAtlas);
                    }

                    if (bHasAtlasChanged)
                    {
                        this.ApplyAnimationClipGlobalAtlas(rGlobalAtlas);
                    }
                }

                EditorGUILayout.Space( );

                ///// Animation Clip Header /////
                for (int iClipIndex = 0, iClipCount = iTargetObjectCount; iClipIndex < iClipCount; ++iClipIndex)
                {
                    Uni2DAnimationClip rAnimationClip = (Uni2DAnimationClip)this.targets[iClipIndex];
                    int iFrameCount = rAnimationClip.FrameCount;

                    this.UpdateClipsFoldouts(iClipIndex, iFrameCount);

                    bool bClipHeaderFoldout = this.GetClipFoldout(iClipIndex);

                    EditorGUI.BeginDisabledGroup(bDisplayFrames == false);
                    {
                        EditorGUI.BeginChangeCheck( );
                        {
                            bClipHeaderFoldout = Uni2DEditorGUIUtils.DisplayAnimationClipHeader(rAnimationClip, m_oAnimationPlayerClipHeader, bClipHeaderFoldout);
                        }
                        if (EditorGUI.EndChangeCheck( ) && bDisplayFrames)
                        {
                            // Update animation preview player settings
                            m_oAnimationPlayerClipPreview.FrameRate = rAnimationClip.frameRate;
                            m_oAnimationPlayerClipPreview.WrapMode  = rAnimationClip.wrapMode;
                        }
                    }
                    EditorGUI.EndDisabledGroup( );

                    this.SetClipFoldout(bClipHeaderFoldout, iClipIndex);

                    ///// Clip frames section /////
                    if (bDisplayFrames && bClipHeaderFoldout)
                    {
                        EditorGUILayout.BeginHorizontal( );
                        {
                            // Dummy space
                            GUILayout.Space(32.0f);

                            EditorGUILayout.BeginVertical( );
                            {
                                // Display all frames
                                for (int iFrameIndex = 0; iFrameIndex < iFrameCount; ++iFrameIndex)
                                {
                                    // Display animation frame
                                    AnimationGUIAction eAction;                                         // = AnimationGUIAction.None;
                                    bool bFrameFoldout = this.GetClipFoldout(iClipIndex, iFrameIndex);

                                    EditorGUI.BeginChangeCheck( );
                                    {
                                        eAction = Uni2DEditorGUIUtils.DisplayAnimationFrame(rAnimationClip.frames[iFrameIndex], rGlobalAtlas, ref bFrameFoldout);
                                    }
                                    if (EditorGUI.EndChangeCheck( ))
                                    {
                                        EditorUtility.SetDirty(rAnimationClip);
                                    }

                                    this.SetClipFoldout(bFrameFoldout, iClipIndex, iFrameIndex);

                                    // Handle returned action (if any)
                                    switch (eAction)
                                    {
                                    // No action
                                    case AnimationGUIAction.None:
                                    default:
                                        break;

                                    case AnimationGUIAction.AddUp:
                                    {
                                        Uni2DAnimationFrame oNewFrame = new Uni2DAnimationFrame( );
                                        oNewFrame.atlas = rGlobalAtlas;

                                        rAnimationClip.frames.Insert(iFrameIndex, oNewFrame);
                                        ++iFrameCount;
                                        ++iFrameIndex;

                                        this.UpdateClipsFoldouts(iClipIndex, iFrameCount);

                                        EditorUtility.SetDirty(rAnimationClip);
                                    }
                                    break;

                                    case AnimationGUIAction.AddDown:
                                    {
                                        Uni2DAnimationFrame oNewFrame = new Uni2DAnimationFrame( );
                                        oNewFrame.atlas = rGlobalAtlas;

                                        rAnimationClip.frames.Insert(iFrameIndex + 1, oNewFrame);
                                        ++iFrameCount;

                                        this.UpdateClipsFoldouts(iClipIndex, iFrameCount);

                                        EditorUtility.SetDirty(rAnimationClip);
                                    }
                                    break;

                                    case AnimationGUIAction.MoveUp:
                                    {
                                        if (iFrameIndex != 0)
                                        {
                                            rAnimationClip.SwapFrames(iFrameIndex, iFrameIndex - 1);

                                            EditorUtility.SetDirty(rAnimationClip);
                                        }
                                    }
                                    break;

                                    case AnimationGUIAction.MoveDown:
                                    {
                                        if (iFrameIndex != iFrameCount - 1)
                                        {
                                            rAnimationClip.SwapFrames(iFrameIndex, iFrameIndex + 1);

                                            EditorUtility.SetDirty(rAnimationClip);
                                        }
                                    }
                                    break;

                                    case AnimationGUIAction.Close:
                                    {
                                        rAnimationClip.frames.RemoveAt(iFrameIndex);
                                        UpdateTextureGUIDsList( );

                                        --iFrameCount;
                                        --iFrameIndex;

                                        EditorUtility.SetDirty(rAnimationClip);
                                    }
                                    break;
                                    }
                                }
                                EditorGUILayout.Space( );
                            }
                            EditorGUILayout.EndVertical( );
                        }
                        EditorGUILayout.EndHorizontal( );

                        EditorGUILayout.BeginHorizontal( );
                        {
                            GUILayout.FlexibleSpace( );
                            if (GUILayout.Button("Add Frame", GUILayout.Width(225.0f)))
                            {
                                Uni2DAnimationFrame oNewFrame = new Uni2DAnimationFrame( );
                                oNewFrame.atlas = rGlobalAtlas;
                                rAnimationClip.frames.Add(oNewFrame);
                                EditorUtility.SetDirty(rAnimationClip);
                            }
                            GUILayout.FlexibleSpace( );
                        }
                        EditorGUILayout.EndHorizontal( );
                    }                           // End of clip header foldout

                    EditorGUILayout.Space( );
                }

                ///// Apply / Revert / Force regeneration buttons /////
                EditorGUILayout.BeginVertical( );
                {
                    EditorGUILayout.BeginHorizontal( );
                    {
                        EditorGUI.BeginDisabledGroup(this.DoTargetsHaveUnappliedSettings( ) == false);
                        {
                            if (GUILayout.Button("Apply"))
                            {
                                this.ApplySettings(AnimationClipRegeneration.RegenerateAlsoAtlasIfNeeded);
                            }

                            if (GUILayout.Button("Revert"))
                            {
                                this.RevertSettings( );
                            }
                        }
                        EditorGUI.EndDisabledGroup( );
                    }
                    EditorGUILayout.EndHorizontal( );

                    if (GUILayout.Button("Force Clip Regeneration"))
                    {
                        this.ApplySettings(AnimationClipRegeneration.RegenerateAll);
                    }
                }
                EditorGUILayout.EndVertical( );
            }
            EditorGUILayout.EndVertical( );
        }
        EditorGUI.EndDisabledGroup( );

        if (Application.isPlaying == false)
        {
            this.CheckTextureDragAndDrop(GUILayoutUtility.GetLastRect( ));
        }

        // Force repaint if needed (== animation players enabled)
        if (m_oAnimationPlayerClipHeader.Enabled || m_oAnimationPlayerClipPreview.Enabled)
        {
            this.Repaint( );
        }
    }
    // Displays the animation frame GUI
    // Returns the performed user action
    public static AnimationGUIAction DisplayAnimationFrame(Uni2DAnimationFrame a_rAnimationFrame, Uni2DTextureAtlas a_rGlobalAtlas, ref bool a_bEventFoldout)
    {
        AnimationGUIAction eAction = AnimationGUIAction.None;

        // Box
        EditorGUILayout.BeginVertical(EditorStyles.textField);
        {
            ///// Top toolbar /////
            EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.ExpandWidth(true));
            {
                // ^
                if (GUILayout.Button("\u25B2" /*"\u2191"*/, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
                {
                    eAction = AnimationGUIAction.MoveUp;
                }

                // v
                if (GUILayout.Button("\u25BC" /*"\u2193"*/, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
                {
                    eAction = AnimationGUIAction.MoveDown;
                }

                // + ^
                if (GUILayout.Button("+ \u25B2" /*"+ \u2191"*/, EditorStyles.toolbarButton, GUILayout.ExpandWidth(true)))
                {
                    eAction = AnimationGUIAction.AddUp;
                }

                // X
                if (GUILayout.Button("X", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
                {
                    eAction = AnimationGUIAction.Close;
                }
            }
            EditorGUILayout.EndHorizontal( );

            ///////////////

            EditorGUILayout.Space( );

            ///// Animation Frame box /////
            EditorGUILayout.BeginHorizontal( );
            {
                Texture2D rFrameTexture     = a_rAnimationFrame.textureContainer;
                string    rFrameTextureGUID = a_rAnimationFrame.textureContainer.GUID;
                bool      bHasFrameTextureChanged;

                // Display frame texture on the left
                Rect oClipTextureRect = GUILayoutUtility.GetRect(64.0f, 64.0f, 64.0f, 64.0f, GUILayout.ExpandWidth(false));

                EditorGUI.BeginChangeCheck( );
                {
                    rFrameTexture = (Texture2D)EditorGUI.ObjectField(oClipTextureRect, GUIContent.none, rFrameTexture, typeof(Texture2D), false);
                }
                bHasFrameTextureChanged = EditorGUI.EndChangeCheck( );


                EditorGUILayout.BeginVertical(GUILayout.ExpandWidth(true));
                {
                    // Frame texture name
                    GUILayout.Label(rFrameTexture != null ? rFrameTexture.name : "(No Texture)", EditorStyles.boldLabel, GUILayout.ExpandWidth(false));

                    // Frame Name
                    a_rAnimationFrame.name = EditorGUILayout.TextField("Frame Name", a_rAnimationFrame.name);

                    // Frame atlas
                    EditorGUILayout.BeginHorizontal( );
                    {
                        // Disable popup menu if global atlas is set
                        EditorGUI.BeginDisabledGroup(a_rGlobalAtlas != null);
                        {
                            // Atlas popup
                            string[] oTextureGUID = (rFrameTexture != null) ? new string[1] {
                                rFrameTextureGUID
                            } : new string[0];

                            EditorGUILayout.PrefixLabel("Use Atlas");
                            a_rAnimationFrame.atlas = Uni2DEditorGUIUtils.AtlasPopup(a_rAnimationFrame.atlas, oTextureGUID);
                        }
                        EditorGUI.EndDisabledGroup( );

                        // Atlas select button
                        EditorGUI.BeginDisabledGroup(a_rAnimationFrame.atlas == null);
                        {
                            if (GUILayout.Button("Select", GUILayout.Width(80.0f)))
                            {
                                EditorGUIUtility.PingObject(a_rAnimationFrame.atlas.gameObject);
                            }
                        }
                        EditorGUI.EndDisabledGroup( );
                    }
                    EditorGUILayout.EndHorizontal( );

                    // Trigger?
                    a_rAnimationFrame.triggerEvent = EditorGUILayout.Toggle("Trigger Event", a_rAnimationFrame.triggerEvent);

                    // Event param
                    a_bEventFoldout = EditorGUILayout.Foldout(a_bEventFoldout, "Frame Infos");
                    if (a_bEventFoldout)
                    {
                        Uni2DAnimationFrameInfos rFrameInfos = a_rAnimationFrame.frameInfos;

                        ++EditorGUI.indentLevel;
                        {
                            rFrameInfos.stringInfo = EditorGUILayout.TextField("String Info", rFrameInfos.stringInfo);
                            rFrameInfos.intInfo    = EditorGUILayout.IntField("Int Info", rFrameInfos.intInfo);
                            rFrameInfos.floatInfo  = EditorGUILayout.FloatField("Float Info", rFrameInfos.floatInfo);
                            rFrameInfos.objectInfo = EditorGUILayout.ObjectField("Object Info", rFrameInfos.objectInfo, typeof(Object), true);
                        }
                        --EditorGUI.indentLevel;
                    }
                    EditorGUILayout.Space( );
                }
                EditorGUILayout.EndVertical( );

                if (bHasFrameTextureChanged)
                {
                    // Save texture in texture container, keep reference to the asset if not using an atlas
                    a_rAnimationFrame.textureContainer = new Texture2DContainer(rFrameTexture, a_rGlobalAtlas == null);
                }
            }
            EditorGUILayout.EndHorizontal( );

            ///////////////

            EditorGUILayout.Space( );

            ///// Bottom toolbar /////
            EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.ExpandWidth(true));
            {
                // + v
                if (GUILayout.Button("+ \u25BC" /*"+ \u2193"*/, EditorStyles.toolbarButton, GUILayout.ExpandWidth(true)))
                {
                    eAction = AnimationGUIAction.AddDown;
                }
            }
            EditorGUILayout.EndHorizontal( );
        }
        EditorGUILayout.EndVertical( );

        return(eAction);
    }