Beispiel #1
0
 void OnEnable()
 {
     m_tilemap        = (Tilemap)target;
     m_tilemapTileset = m_tilemap.Tileset;
     RegisterTilesetEvents(m_tilemapTileset);
     //fix missing material on prefabs tilemaps (when pressing play for example)
     if (!string.IsNullOrEmpty(AssetDatabase.GetAssetPath(m_tilemap.gameObject)))
     {
         m_tilemap.Refresh(true, false, false, false);
     }
     if (m_tilemap.ParentTilemapGroup)
     {
         m_tilemap.ParentTilemapGroup.SelectedTilemap = m_tilemap;
     }
 }
        private void DisplayCollider()
        {
            Event e = Event.current;

            if (Tileset.SelectedBrushId != Tileset.k_BrushId_Default)
            {
                EditorGUILayout.LabelField("Brush tile editing not allowed", EditorStyles.boldLabel);
                return;
            }

            bool isMultiselection = Tileset.TileSelection != null;
            bool saveChanges      = false;
            Tile selectedTile     = isMultiselection ? Tileset.Tiles[(int)(Tileset.TileSelection.selectionData[0] & Tileset.k_TileDataMask_TileId)] : Tileset.SelectedTile;

            if (e.type == EventType.MouseDown)
            {
                m_isDragging = true;
                if (selectedTile.collData.vertices != null)
                {
                    m_savedVertexData = new Vector2[selectedTile.collData.vertices.Length];
                    selectedTile.collData.vertices.CopyTo(m_savedVertexData, 0);
                }
            }
            else if (e.type == EventType.MouseUp)
            {
                m_isDragging = false;
            }

            Tileset.BackgroundColor = EditorGUILayout.ColorField(Tileset.BackgroundColor);
            if (m_prevBgColor != Tileset.BackgroundColor || Styles.Instance.colliderBgStyle.normal.background == null)
            {
                m_prevBgColor = Tileset.BackgroundColor;
                if (Styles.Instance.colliderBgStyle.normal.background == null)
                {
                    Styles.Instance.colliderBgStyle.normal.background = new Texture2D(1, 1)
                    {
                        hideFlags = HideFlags.DontSave
                    }
                }
                ;
                Styles.Instance.colliderBgStyle.normal.background.SetPixel(0, 0, Tileset.BackgroundColor);
                Styles.Instance.colliderBgStyle.normal.background.Apply();
            }

            float aspectRatio = Tileset.TilePxSize.x / Tileset.TilePxSize.y;
            float padding     = 2; // pixel size of the border around the tile
            //Rect rCollArea = GUILayoutUtility.GetRect(1, 1, GUILayout.Width(EditorGUIUtility.currentViewWidth), GUILayout.Height(EditorGUIUtility.currentViewWidth / aspectRatio));
            Rect rCollArea = GUILayoutUtility.GetRect(1, 1, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));

            GUI.BeginGroup(rCollArea, Styles.Instance.colliderBgStyle);
            if (e.type == EventType.Repaint)
            {
                float pixelSize = rCollArea.width / (Tileset.TilePxSize.x + 2 * padding);
                m_mousePos     = e.mousePosition;
                m_rTile        = new Rect(padding * pixelSize, padding * pixelSize, rCollArea.width - 2 * padding * pixelSize, (rCollArea.width / aspectRatio) - 2 * padding * pixelSize);
                m_rTile.height = Mathf.Min(m_rTile.height, rCollArea.height - 2 * padding * pixelSize);
                m_rTile.width  = (m_rTile.height * aspectRatio);
            }
            GUI.color = new Color(1f, 1f, 1f, 0.1f);
            GUI.DrawTexture(m_rTile, EditorGUIUtility.whiteTexture);
            GUI.color = Color.white;
            if (isMultiselection)
            {
                foreach (uint tileData in Tileset.TileSelection.selectionData)
                {
                    int  tileId = (int)(tileData & Tileset.k_TileDataMask_TileId);
                    Tile tile   = Tileset.GetTile(tileId);
                    if (tile != null)
                    {
                        GUI.color = new Color(1f, 1f, 1f, 1f / Tileset.TileSelection.selectionData.Count);
                        GUI.DrawTextureWithTexCoords(m_rTile, Tileset.AtlasTexture, tile.uv);
                    }
                }
                GUI.color = Color.white;
            }
            else
            {
                GUI.DrawTextureWithTexCoords(m_rTile, Tileset.AtlasTexture, selectedTile.uv);
            }

            Color savedHandleColor = Handles.color;

            if (selectedTile.collData.type != eTileCollider.None)
            {
                Vector2[] collVertices = selectedTile.collData.type == eTileCollider.Full ? s_fullCollTileVertices : selectedTile.collData.vertices;
                if (collVertices == null || collVertices.Length == 0)
                {
                    collVertices = selectedTile.collData.vertices = new Vector2[s_fullCollTileVertices.Length];
                    Array.Copy(s_fullCollTileVertices, collVertices, s_fullCollTileVertices.Length);
                    EditorUtility.SetDirty(Tileset);
                }

                // Fix and snap positions
                for (int i = 0; i < collVertices.Length; ++i)
                {
                    Vector2 s0 = collVertices[i];
                    s0.x            = Mathf.Clamp01(Mathf.Round(s0.x * Tileset.TilePxSize.x) / Tileset.TilePxSize.x);
                    s0.y            = Mathf.Clamp01(Mathf.Round(s0.y * Tileset.TilePxSize.y) / Tileset.TilePxSize.y);
                    collVertices[i] = s0;
                }

                // Draw edges
                Vector3[] polyEdges = new Vector3[collVertices.Length + 1];
                for (int i = 0; i < collVertices.Length; ++i)
                {
                    Vector2 s0 = collVertices[i];
                    s0.x = m_rTile.x + m_rTile.width * s0.x; s0.y = m_rTile.yMax - m_rTile.height * s0.y;
                    Vector2 s1 = collVertices[(i + 1) % collVertices.Length];
                    s1.x = m_rTile.x + m_rTile.width * s1.x; s1.y = m_rTile.yMax - m_rTile.height * s1.y;

                    polyEdges[i]     = s0;
                    polyEdges[i + 1] = s1;

                    Handles.color = Color.green;
                    Handles.DrawLine(s0, s1);
                    //Draw normals
                    {
                        Handles.color = Color.white;
                        Vector3 normPos = (s0 + s1) / 2f;
                        Handles.DrawLine(normPos, normPos + Vector3.Cross(s1 - s0, Vector3.forward).normalized *m_rTile.yMin);
                    }

                    Handles.color = savedHandleColor;
                }

                float pixelSize = m_rTile.width / Tileset.TilePxSize.x;
                if (selectedTile.collData.type == eTileCollider.Polygon)
                {
                    bool isAddingVertexOn   = !m_isDragging && e.shift && m_activeVertexIdx == -1;
                    bool isRemovingVertexOn = !m_isDragging && ((Application.platform == RuntimePlatform.OSXEditor)? e.command : e.control) && collVertices.Length > 3;
                    if (isRemovingVertexOn && m_activeVertexIdx != -1 && e.type == EventType.MouseUp)
                    {
                        selectedTile.collData.vertices = new Vector2[collVertices.Length - 1];
                        for (int i = 0, j = 0; i < collVertices.Length; ++i)
                        {
                            if (i == m_activeVertexIdx)
                            {
                                continue;
                            }
                            selectedTile.collData.vertices[j] = collVertices[i];
                            ++j;
                        }
                        collVertices      = selectedTile.collData.vertices;
                        m_activeVertexIdx = -1;
                    }

                    float minDist = float.MaxValue;
                    if (!m_isDragging)
                    {
                        m_activeVertexIdx = -1;
                    }
                    for (int i = 0; i < collVertices.Length; ++i)
                    {
                        Vector2 s0 = collVertices[i];
                        s0.x = m_rTile.x + m_rTile.width * s0.x;
                        s0.y = m_rTile.yMax - m_rTile.height * s0.y;

                        if (m_isDragging)
                        {
                            if (i == m_activeVertexIdx)
                            {
                                s0   = m_mousePos;
                                s0  -= m_rTile.position;
                                s0.x = Mathf.Clamp(Mathf.Round(s0.x / pixelSize) * pixelSize, 0, m_rTile.width);
                                s0.y = Mathf.Clamp(Mathf.Round(s0.y / pixelSize) * pixelSize, 0, m_rTile.height);
                                s0  += m_rTile.position;
                                collVertices[i].x = Mathf.Clamp01((s0.x - m_rTile.x) / m_rTile.width);
                                collVertices[i].y = Mathf.Clamp01((s0.y - m_rTile.yMax) / -m_rTile.height);
                            }
                        }
                        else
                        {
                            float dist = Vector2.Distance(m_mousePos, s0);
                            if (dist <= minDist && dist < Styles.Instance.collVertexHandleStyle.normal.background.width)
                            {
                                minDist           = dist;
                                m_activeVertexIdx = i;
                            }
                        }

                        if (e.type == EventType.Repaint)
                        {
                            if (i == m_activeVertexIdx)
                            {
                                Styles.Instance.vertexCoordStyle.fontSize = (int)(Mathf.Min(10f, m_rTile.yMin / 2f));
                                GUI.Label(new Rect(0, 0, m_rTile.width, m_rTile.yMin), Vector2.Scale(collVertices[i], Tileset.TilePxSize).ToString(), Styles.Instance.vertexCoordStyle);
                            }
                            GUI.color = m_activeVertexIdx == i ? (isRemovingVertexOn ? Color.red : Color.cyan) : new Color(0.7f, 0.7f, 0.7f, 0.8f);
                            Styles.Instance.collVertexHandleStyle.Draw(new Rect(s0.x - Styles.Instance.collVertexHandleStyle.normal.background.width / 2, s0.y - Styles.Instance.collVertexHandleStyle.normal.background.height / 2, 1, 1), i.ToString(), false, false, false, false);
                            GUI.color = Color.white;
                        }
                    }

                    if (isAddingVertexOn)
                    {
                        int     segmentIdx;
                        Vector2 newVertexPos = ClosestPointToPolyLine(polyEdges, out segmentIdx);

                        if (e.type == EventType.MouseUp)
                        {
                            selectedTile.collData.vertices = new Vector2[collVertices.Length + 1];
                            segmentIdx = (segmentIdx + 1) % selectedTile.collData.vertices.Length;
                            for (int i = 0, j = 0; i < selectedTile.collData.vertices.Length; ++i)
                            {
                                if (segmentIdx == i)
                                {
                                    newVertexPos.x = Mathf.Clamp(Mathf.Round(newVertexPos.x / pixelSize) * pixelSize, m_rTile.x, m_rTile.xMax);
                                    newVertexPos.y = Mathf.Clamp(Mathf.Round(newVertexPos.y / pixelSize) * pixelSize, m_rTile.y, m_rTile.yMax);
                                    selectedTile.collData.vertices[i].x = Mathf.Clamp01((newVertexPos.x - m_rTile.x) / m_rTile.width);
                                    selectedTile.collData.vertices[i].y = Mathf.Clamp01((newVertexPos.y - m_rTile.yMax) / -m_rTile.height);
                                }
                                else
                                {
                                    selectedTile.collData.vertices[i] = collVertices[j];
                                    ++j;
                                }
                            }
                            collVertices      = selectedTile.collData.vertices;
                            m_activeVertexIdx = -1;
                        }
                        else if (e.type == EventType.Repaint)
                        {
                            GUI.color = new Color(0.7f, 0.7f, 0.7f, 0.8f);
                            Styles.Instance.collVertexHandleStyle.Draw(new Rect(newVertexPos.x - Styles.Instance.collVertexHandleStyle.normal.background.width / 2, newVertexPos.y - Styles.Instance.collVertexHandleStyle.normal.background.height / 2, 1, 1), segmentIdx.ToString(), false, false, false, false);
                            GUI.color = Color.white;
                        }
                    }
                }

                if (e.type == EventType.MouseUp)
                {
                    saveChanges = true;
                    //remove duplicated vertex
                    selectedTile.collData.vertices = selectedTile.collData.vertices.Distinct().ToArray();
                    if (selectedTile.collData.vertices.Length <= 2)
                    {
                        selectedTile.collData.vertices = m_savedVertexData;
                    }
                    //snap vertex positions
                    selectedTile.collData.SnapVertices(Tileset);
                }
            }

            GUI.EndGroup();

            if (GUILayout.Button("Reverse Normals"))
            {
                selectedTile.collData.vertices = selectedTile.collData.vertices.Reverse().ToArray();
            }

            EditorGUILayout.Space();

            string helpInfo =
                "  - Click and drag over a vertex to move it" + "\n" +
                "  - Hold Shift + Click for adding a new vertex" + "\n" +
                "  - Hold " + ((Application.platform == RuntimePlatform.OSXEditor)? "Command" : "Ctrl") + " + Click for removing a vertex. (should be more than 3)" + "\n" +
                "  - Check the normals for each edge. The normal is displayed in the collision side" + "\n" +
                "";

            s_showHelp = EditorGUILayout.Foldout(s_showHelp, "Help");
            if (s_showHelp)
            {
                EditorGUILayout.HelpBox(helpInfo, MessageType.Info);
            }

            //+++ Collider Settings
            float savedLabelWidth = EditorGUIUtility.labelWidth;

            EditorGUIUtility.labelWidth = 40;
            if (isMultiselection)
            {
                EditorGUILayout.LabelField("* Multi-selection Edition", EditorStyles.boldLabel);
            }
            EditorGUILayout.BeginHorizontal(GUILayout.MinWidth(140));
            {
                EditorGUILayout.LabelField("Collider Data", EditorStyles.boldLabel);
                if (GUILayout.Button("Copy", GUILayout.Width(50)))
                {
                    m_copiedColliderData = selectedTile.collData.Clone();
                }
                if (GUILayout.Button("Paste", GUILayout.Width(50)))
                {
                    selectedTile.collData = m_copiedColliderData.Clone();
                    saveChanges           = true;
                }
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();
            EditorGUIUtility.labelWidth = 100;
            EditorGUI.BeginChangeCheck();

            //selectedTile.collData.type = (eTileCollider)EditorGUILayout.EnumPopup("Collider Type", selectedTile.collData.type);
            EditorGUILayout.LabelField("Collider Type:", EditorStyles.boldLabel);
            EditorGUI.indentLevel += 2;
            string[] tileColliderNames = System.Enum.GetNames(typeof(eTileCollider));

            selectedTile.collData.type = (eTileCollider)GUILayout.Toolbar((int)selectedTile.collData.type, tileColliderNames);
            EditorGUI.indentLevel     -= 2;

            saveChanges |= EditorGUI.EndChangeCheck();
            EditorGUIUtility.labelWidth = savedLabelWidth;
            //---

            //Save changes
            if (saveChanges)
            {
                if (isMultiselection)
                {
                    for (int i = 0; i < Tileset.TileSelection.selectionData.Count; ++i)
                    {
                        Tileset.Tiles[(int)(Tileset.TileSelection.selectionData[i] & Tileset.k_TileDataMask_TileId)].collData = selectedTile.collData.Clone();
                    }
                }
                EditorUtility.SetDirty(Tileset);
                //Refresh selected tilemap
                Tilemap selectedTilemap = Selection.activeGameObject? Selection.activeGameObject.GetComponent <Tilemap>() : null;
                if (selectedTilemap)
                {
                    selectedTilemap.Refresh(false, true);
                }
            }
        }

        /// <summary>
        //     Get the point on a polyline (in 3D space) which is closest to the current
        //     mouse position. And returns the segment index ( the vertex index of the segment with the closest point )
        /// </summary>
        /// <param name="vertices"></param>
        /// <param name="closestSegmentIdx"></param>
        /// <returns></returns>
        Vector3 ClosestPointToPolyLine(Vector3[] vertices, out int closestSegmentIdx)
        {
            float minDist = float.MaxValue;

            closestSegmentIdx = 0;
            for (int i = 0; i < vertices.Length - 1; ++i)
            {
                float dist = HandleUtility.DistanceToLine(vertices[i], vertices[i + 1]);
                if (dist < minDist)
                {
                    minDist           = dist;
                    closestSegmentIdx = i;
                }
            }
            return(HandleUtility.ClosestPointToPolyLine(vertices));
        }
        private ReorderableList CreateTilemapReorderableList()
        {
            ReorderableList reordList = new ReorderableList(serializedObject, serializedObject.FindProperty("m_tilemaps"), true, true, true, true);

            reordList.displayAdd         = reordList.displayRemove = true;
            reordList.drawHeaderCallback = (Rect rect) =>
            {
                EditorGUI.LabelField(rect, "Tilemaps", EditorStyles.boldLabel);
                Texture2D btnTexture = reordList.elementHeight == 0f ? EditorGUIUtility.FindTexture("winbtn_win_max_h") : EditorGUIUtility.FindTexture("winbtn_win_min_h");
                if (GUI.Button(new Rect(rect.x + rect.width - rect.height, rect.y, rect.height, rect.height), btnTexture, EditorStyles.label))
                {
                    GUI.changed             = true;
                    reordList.elementHeight = reordList.elementHeight == 0f ? 21f : 0f;
                    reordList.draggable     = reordList.elementHeight > 0f;
                    reordList.displayAdd    = reordList.draggable;
                    reordList.displayRemove = reordList.draggable;
                }
            };
            reordList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
            {
                if (reordList.elementHeight == 0)
                {
                    return;
                }
                var element = reordList.serializedProperty.GetArrayElementAtIndex(index);
                rect.y += 2;
                Tilemap tilemap = element.objectReferenceValue as Tilemap;
                if (tilemap)
                {
                    SerializedObject tilemapSerialized    = new SerializedObject(tilemap);
                    SerializedObject tilemapObjSerialized = new SerializedObject(tilemapSerialized.FindProperty("m_GameObject").objectReferenceValue);

                    Rect rToggle       = new Rect(rect.x, rect.y, 16f, EditorGUIUtility.singleLineHeight);
                    Rect rName         = new Rect(rect.x + 20f, rect.y, rect.width - 130f - 20f, EditorGUIUtility.singleLineHeight);
                    Rect rColliders    = new Rect(rect.x + rect.width - 125f, rect.y, 125f, EditorGUIUtility.singleLineHeight);
                    Rect rSortingLayer = new Rect(rect.x + rect.width - 125f, rect.y, 80f, EditorGUIUtility.singleLineHeight);
                    Rect rSortingOrder = new Rect(rect.x + rect.width - 40f, rect.y, 40f, EditorGUIUtility.singleLineHeight);

                    tilemap.IsVisible = EditorGUI.Toggle(rToggle, GUIContent.none, tilemap.IsVisible, STEditorStyles.Instance.visibleToggleStyle);
                    EditorGUI.PropertyField(rName, tilemapObjSerialized.FindProperty("m_Name"), GUIContent.none);
                    if (TilemapEditor.EditMode == TilemapEditor.eEditMode.Collider)
                    {
                        SerializedProperty colliderTypeProperty = tilemapSerialized.FindProperty("ColliderType");
                        string[]           colliderTypeNames    = new List <string>(System.Enum.GetNames(typeof(eColliderType)).Select(x => x.Replace('_', ' '))).ToArray();
                        EditorGUI.BeginChangeCheck();
                        colliderTypeProperty.intValue = GUI.Toolbar(rColliders, colliderTypeProperty.intValue, colliderTypeNames);
                        if (EditorGUI.EndChangeCheck())
                        {
                            tilemapSerialized.ApplyModifiedProperties();
                            tilemap.Refresh(false, true);
                        }
                    }
                    else
                    {
                        // Sorting Layer and Order in layer
                        EditorGUI.BeginChangeCheck();
                        EditorGUI.PropertyField(rSortingLayer, tilemapSerialized.FindProperty("m_sortingLayer"), GUIContent.none);
                        EditorGUI.PropertyField(rSortingOrder, tilemapSerialized.FindProperty("m_orderInLayer"), GUIContent.none);
                        tilemapSerialized.FindProperty("m_orderInLayer").intValue = (tilemapSerialized.FindProperty("m_orderInLayer").intValue << 16) >> 16; // convert from int32 to int16 keeping sign
                        if (EditorGUI.EndChangeCheck())
                        {
                            tilemapSerialized.ApplyModifiedProperties();
                            tilemap.RefreshChunksSortingAttributes();
                            SceneView.RepaintAll();
                        }
                        //---
                    }

                    if (GUI.changed)
                    {
                        tilemapObjSerialized.ApplyModifiedProperties();
                    }
                }
            };
            reordList.onReorderCallback = (ReorderableList list) =>
            {
                var targetObj   = target as TilemapGroup;
                int sibilingIdx = 0;
                foreach (Tilemap tilemap in targetObj.Tilemaps)
                {
                    tilemap.transform.SetSiblingIndex(sibilingIdx++);
                }
                Repaint();
            };
            reordList.onSelectCallback = (ReorderableList list) =>
            {
                m_selectedIndexProp.intValue = reordList.index;
                serializedObject.ApplyModifiedProperties();
                GUI.changed = true;
                TileSelectionWindow.RefreshIfVisible();
                TilePropertiesWindow.RefreshIfVisible();
            };
            reordList.onAddCallback = (ReorderableList list) =>
            {
                var targetObj = target as TilemapGroup;
                Undo.RegisterCompleteObjectUndo(targetObj, "New Tilemap");
                GameObject obj = new GameObject();
                Undo.RegisterCreatedObjectUndo(obj, "New Tilemap");
                Tilemap newTilemap = obj.AddComponent <Tilemap>();
                obj.transform.parent = targetObj.transform;
                obj.name             = GameObjectUtility.GetUniqueNameForSibling(obj.transform.parent, "New Tilemap");

                Tilemap copiedTilemap = targetObj.SelectedTilemap;
                if (copiedTilemap)
                {
                    UnityEditorInternal.ComponentUtility.CopyComponent(copiedTilemap);
                    UnityEditorInternal.ComponentUtility.PasteComponentValues(newTilemap);
                    obj.name = GameObjectUtility.GetUniqueNameForSibling(obj.transform.parent, copiedTilemap.name);
                }
            };
            reordList.onRemoveCallback = (ReorderableList list) =>
            {
                m_tilemapRemovingList.Add(m_target.SelectedTilemap.gameObject);
            };

            return(reordList);
        }
Beispiel #4
0
        public override void OnInspectorGUI()
        {
            Event e = Event.current;

            if (e.type == EventType.ValidateCommand)
            {
                if (e.commandName == "UndoRedoPerformed")
                {
                    m_tilemap.Refresh();
                }
            }
            serializedObject.Update();

            Tileset prevTileset = m_tilemap.Tileset;

            GUI.backgroundColor = Color.yellow;
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            m_tilemap.Tileset = (Tileset)EditorGUILayout.ObjectField("Tileset", m_tilemap.Tileset, typeof(Tileset), false);
            EditorGUILayout.EndVertical();
            GUI.backgroundColor = Color.white;

            if (prevTileset != m_tilemap.Tileset)
            {
                UnregisterTilesetEvents(prevTileset);
                RegisterTilesetEvents(m_tilemap.Tileset);
                m_tilemapTileset = m_tilemap.Tileset;
            }

            if (m_tilemap.Tileset == null)
            {
                EditorGUILayout.HelpBox("There is no tileset selected", MessageType.Info);
                return;
            }

            string[] editModeNames = System.Enum.GetNames(typeof(eEditMode));
            s_editMode = (eEditMode)GUILayout.Toolbar((int)s_editMode, editModeNames);
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            {
                if (s_editMode == eEditMode.Renderer)
                {
                    EditorGUI.BeginChangeCheck();
                    Material prevMaterial = m_tilemap.Material;
                    EditorGUILayout.PropertyField(serializedObject.FindProperty("m_material"));
                    if (EditorGUI.EndChangeCheck())
                    {
                        serializedObject.ApplyModifiedProperties();
                        m_tilemap.Refresh();
                        if (m_tilemap.Material != prevMaterial && !AssetDatabase.Contains(prevMaterial))
                        {
                            //avoid memory leak
                            DestroyImmediate(prevMaterial);
                        }
                    }
                    // Draw Material Control

                    /*
                     * if (m_matEditor == null || EditorGUI.EndChangeCheck())
                     * {
                     *  if (m_matEditor != null) DestroyImmediate(m_matEditor);
                     *  m_matEditor = MaterialEditor.CreateEditor(m_tilemap.Material);
                     *  m_matEditor.hideFlags = HideFlags.DontSave;
                     * }
                     * float savedLabelWidth = EditorGUIUtility.labelWidth;
                     * m_matEditor.DrawHeader();
                     * m_matEditor.OnInspectorGUI();
                     * EditorGUIUtility.labelWidth = savedLabelWidth;
                     */
                    //---

                    EditorGUILayout.PropertyField(serializedObject.FindProperty("m_tintColor"));

                    //Pixel Snap
                    if (m_tilemap.Material.HasProperty("PixelSnap"))
                    {
                        EditorGUI.BeginChangeCheck();
                        bool isPixelSnapOn = EditorGUILayout.Toggle("Pixel Snap", m_tilemap.PixelSnap);
                        if (EditorGUI.EndChangeCheck())
                        {
                            m_tilemap.PixelSnap = isPixelSnapOn;
                        }
                    }

                    // Sorting Layer and Order in layer
                    EditorGUI.BeginChangeCheck();
                    EditorGUILayout.PropertyField(serializedObject.FindProperty("m_sortingLayer"));
                    EditorGUILayout.PropertyField(serializedObject.FindProperty("m_orderInLayer"));
                    serializedObject.FindProperty("m_orderInLayer").intValue = (serializedObject.FindProperty("m_orderInLayer").intValue << 16) >> 16; // convert from int32 to int16 keeping sign
                    if (EditorGUI.EndChangeCheck())
                    {
                        serializedObject.ApplyModifiedProperties();
                        m_tilemap.RefreshChunksSortingAttributes();
                        SceneView.RepaintAll();
                    }
                    //---

                    EditorGUILayout.PropertyField(serializedObject.FindProperty("InnerPadding"), new GUIContent("Inner Padding", "The size, in pixels, the tile UV will be stretched. Use this to fix pixel precision artifacts when tiles have no padding border in the atlas."));

                    m_tilemap.IsVisible = EditorGUILayout.Toggle("Visible", m_tilemap.IsVisible);
                }
                else if (s_editMode == eEditMode.Map)
                {
                    EditorGUILayout.Space();

                    if (GUILayout.Button("Refresh Map", GUILayout.MaxWidth(125)))
                    {
                        m_tilemap.Refresh(true, true, true, true);
                    }
                    if (GUILayout.Button("Clear Map", GUILayout.MaxWidth(125)))
                    {
                        if (EditorUtility.DisplayDialog("Warning!", "Are you sure you want to clear the map?\nThis action will remove all children objects under the tilemap", "Yes", "No"))
                        {
                            Undo.RegisterFullObjectHierarchyUndo(m_tilemap.gameObject, "Clear Map " + m_tilemap.name);
                            m_tilemap.IsUndoEnabled = true;
                            m_tilemap.ClearMap();
                            m_tilemap.IsUndoEnabled = false;
                        }
                    }
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    EditorGUILayout.PropertyField(serializedObject.FindProperty("m_cellSize"));
                    EditorGUILayout.PropertyField(serializedObject.FindProperty("ShowGrid"), new GUIContent("Show Grid", "Show the tilemap grid."));
                    EditorGUILayout.EndVertical();
                    EditorGUILayout.Space();

                    EditorGUILayout.LabelField("Map Size (" + m_tilemap.GridWidth + "," + m_tilemap.GridHeight + ")");

                    //+++ Display Map Bounds
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    {
                        EditorGUILayout.LabelField("Map Bounds (in tiles):", EditorStyles.boldLabel);
                        m_toggleMapBoundsEdit = EditorUtils.DoToggleIconButton("Edit Map Bounds", m_toggleMapBoundsEdit, EditorGUIUtility.IconContent("EditCollider"));

                        float savedLabelWidth = EditorGUIUtility.labelWidth;
                        EditorGUIUtility.labelWidth = 80;
                        EditorGUI.indentLevel      += 2;

                        EditorGUI.BeginChangeCheck();
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.PropertyField(serializedObject.FindProperty("m_minGridX"), new GUIContent("Left"));
                        EditorGUILayout.PropertyField(serializedObject.FindProperty("m_minGridY"), new GUIContent("Bottom"));
                        EditorGUILayout.EndVertical();

                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.PropertyField(serializedObject.FindProperty("m_maxGridX"), new GUIContent("Right"));
                        EditorGUILayout.PropertyField(serializedObject.FindProperty("m_maxGridY"), new GUIContent("Top"));
                        EditorGUILayout.EndVertical();
                        if (EditorGUI.EndChangeCheck())
                        {
                            serializedObject.ApplyModifiedProperties();
                            m_tilemap.RecalculateMapBounds();
                        }

                        EditorGUI.indentLevel      -= 2;
                        EditorGUIUtility.labelWidth = savedLabelWidth;
                    }
                    EditorGUILayout.EndVertical();
                    //---

                    EditorGUILayout.Space();

                    m_tilemap.AllowPaintingOutOfBounds = EditorGUILayout.ToggleLeft("Allow Painting Out of Bounds", m_tilemap.AllowPaintingOutOfBounds);

                    EditorGUILayout.Space();

                    if (GUILayout.Button("Shrink to Visible Area", GUILayout.MaxWidth(150)))
                    {
                        m_tilemap.ShrinkMapBoundsToVisibleArea();
                    }

                    EditorGUILayout.Space();
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    {
                        EditorGUILayout.LabelField("Advanced Options", EditorStyles.boldLabel);
                        EditorGUI.BeginChangeCheck();
                        bool isChunksVisible = IsTilemapChunksVisible();
                        isChunksVisible = EditorGUILayout.Toggle(new GUIContent("Show Tile Chunks", "Show tilemap chunk objects for debugging or other purposes. Hiding will be refreshed after collapsing the tilemap."), isChunksVisible);
                        if (EditorGUI.EndChangeCheck())
                        {
                            SetTilemapChunkHideFlag(HideFlags.HideInHierarchy, !isChunksVisible);
                        }
                        EditorGUILayout.PropertyField(serializedObject.FindProperty("m_enableUndoWhilePainting"), new GUIContent("Enable Undo", "Disable Undo when painting on big maps to improve performance."));
                    }
                    EditorGUILayout.EndVertical();
                }
                else if (s_editMode == eEditMode.Collider)
                {
                    EditorGUI.BeginChangeCheck();
                    {
                        //EditorGUILayout.PropertyField(serializedObject.FindProperty("ColliderType"));
                        EditorGUILayout.Space();

                        EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                        EditorGUILayout.LabelField("Collider Type:", EditorStyles.boldLabel);
                        EditorGUI.indentLevel += 2;
                        SerializedProperty colliderTypeProperty = serializedObject.FindProperty("ColliderType");
                        string[]           colliderTypeNames    = new List <string>(System.Enum.GetNames(typeof(eColliderType)).Select(x => x.Replace('_', ' '))).ToArray();

                        colliderTypeProperty.intValue = GUILayout.Toolbar(colliderTypeProperty.intValue, colliderTypeNames);
                        EditorGUI.indentLevel        -= 2;
                        EditorGUILayout.Space();
                        EditorGUILayout.EndVertical();

                        EditorGUILayout.Space();

                        if (m_tilemap.ColliderType == eColliderType._3D)
                        {
                            SerializedProperty colliderDepthProperty = serializedObject.FindProperty("ColliderDepth");
                            EditorGUILayout.PropertyField(colliderDepthProperty);
                            colliderDepthProperty.floatValue = Mathf.Clamp(colliderDepthProperty.floatValue, Vector3.kEpsilon, Mathf.Max(colliderDepthProperty.floatValue));
                        }
                        else if (m_tilemap.ColliderType == eColliderType._2D)
                        {
                            EditorGUILayout.PropertyField(serializedObject.FindProperty("Collider2DType"));
                            EditorGUILayout.PropertyField(serializedObject.FindProperty("ShowColliderNormals"));
                        }

                        EditorGUILayout.PropertyField(serializedObject.FindProperty("m_isTrigger"));

                        if (m_tilemap.IsTrigger)
                        {
                            EditorGUILayout.HelpBox("Activating IsTrigger could generate wrong collider lines if not used properly. Use Show Tilechunks in Map section to display the real collider lines.", MessageType.Warning);
                        }
                        else if (m_tilemap.ColliderType == eColliderType._2D && m_tilemap.Collider2DType == e2DColliderType.PolygonCollider2D)
                        {
                            EditorGUILayout.HelpBox("Using Polygon colliders could generate wrong collider lines if not used properly. Use Show Tilechunks in Map section to display the real collider lines.", MessageType.Warning);
                        }
                    }
                    if (EditorGUI.EndChangeCheck())
                    {
                        serializedObject.ApplyModifiedProperties();
                        m_tilemap.Refresh(false, true);
                    }

                    EditorGUILayout.Space();

                    if (GUILayout.Button("Update Collider Mesh"))
                    {
                        m_tilemap.Refresh(false, true);
                    }
                }
                else if (s_editMode == eEditMode.Paint)
                {
                    if (m_tilemap.Tileset != null)
                    {
                        if (m_tilesetCtrl == null)
                        {
                            m_tilesetCtrl = new TilesetControl();
                        }
                        m_tilesetCtrl.Tileset = m_tilemap.Tileset;
                        m_tilesetCtrl.Display();
                    }
                }
            }
            EditorGUILayout.EndVertical();

            Repaint();
            serializedObject.ApplyModifiedProperties();
            if (GUI.changed)
            {
                EditorUtility.SetDirty(target);
            }
        }
        private void OnToolSelected_BrushToolbar(ToolbarControl source, int selectedToolIdx, int prevSelectedToolIdx)
        {
            ToolIcons.eToolIcon toolIcon = (ToolIcons.eToolIcon)selectedToolIdx;
            switch (toolIcon)
            {
            case ToolIcons.eToolIcon.Pencil:
                TilemapEditor.s_brushMode = TilemapEditor.eBrushMode.Paint;
                Tools.current             = Tool.None;
                break;

            case ToolIcons.eToolIcon.Erase:
                TilemapEditor.s_brushMode = TilemapEditor.eBrushMode.Erase;
                brushPaintToolbar.TriggerButton(0);
                Tools.current = Tool.None;
                break;

            case ToolIcons.eToolIcon.Fill:
                TilemapEditor.s_brushMode = TilemapEditor.eBrushMode.Fill;
                brushPaintToolbar.TriggerButton(0);
                Tools.current = Tool.None;
                break;

            case ToolIcons.eToolIcon.FlipV:
                BrushBehaviour.SFlipV();
                Tools.current      = Tool.None;
                source.SelectedIdx = prevSelectedToolIdx;
                break;

            case ToolIcons.eToolIcon.FlipH:
                BrushBehaviour.SFlipH();
                Tools.current      = Tool.None;
                source.SelectedIdx = prevSelectedToolIdx;
                break;

            case ToolIcons.eToolIcon.Rot90:
                BrushBehaviour.SRot90();
                Tools.current      = Tool.None;
                source.SelectedIdx = prevSelectedToolIdx;
                break;

            case ToolIcons.eToolIcon.Info:
                TilemapEditor.s_displayHelpBox = !TilemapEditor.s_displayHelpBox;
                Tools.current      = Tool.None;
                source.SelectedIdx = prevSelectedToolIdx;
                source.SetHighlight(selectedToolIdx, TilemapEditor.s_displayHelpBox);
                break;

            case ToolIcons.eToolIcon.Refresh:
                TilemapGroup tilemapGroup = Selection.activeGameObject.GetComponent <TilemapGroup>();
                if (tilemapGroup)
                {
                    foreach (Tilemap tilemap in tilemapGroup.Tilemaps)
                    {
                        tilemap.Refresh(true, true, true, true);
                    }
                }
                else
                {
                    Tilemap tilemap = Selection.activeGameObject.GetComponent <Tilemap>();
                    if (tilemap)
                    {
                        tilemap.Refresh(true, true, true, true);
                    }
                }
                Tools.current      = Tool.None;
                source.SelectedIdx = prevSelectedToolIdx;
                break;
            }
        }
        private ReorderableList CreateTilemapReorderableList()
        {
            ReorderableList reordList = new ReorderableList(serializedObject, serializedObject.FindProperty("m_tilemaps"), true, true, true, true);

            reordList.displayAdd         = reordList.displayRemove = true;
            reordList.drawHeaderCallback = (Rect rect) =>
            {
                EditorGUI.LabelField(rect, "Tilemaps", EditorStyles.boldLabel);
                Texture2D btnTexture = reordList.elementHeight == 0f ? EditorGUIUtility.FindTexture("winbtn_win_max_h") : EditorGUIUtility.FindTexture("winbtn_win_min_h");
                if (GUI.Button(new Rect(rect.width - rect.height, rect.y, rect.height, rect.height), btnTexture, EditorStyles.label))
                {
                    reordList.elementHeight = reordList.elementHeight == 0f ? EditorGUIUtility.singleLineHeight : 0f;
                    reordList.draggable     = reordList.elementHeight > 0f;
                }
            };
            reordList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
            {
                var element = reordList.serializedProperty.GetArrayElementAtIndex(index);

                if (Event.current.type == EventType.Repaint)
                {
                    m_reordListRectsDic[m_reordIdx] = rect;
                }
                else if (Event.current.type == EventType.Layout)
                {
                    m_reordListRectsDic.TryGetValue(m_reordIdx, out rect);
                }
                m_reordIdx++;

                rect.y += 2;

                Tilemap          tilemap              = element.objectReferenceValue as Tilemap;
                SerializedObject tilemapSerialized    = new SerializedObject(tilemap);
                SerializedObject tilemapObjSerialized = new SerializedObject(tilemapSerialized.FindProperty("m_GameObject").objectReferenceValue);

                GUILayout.BeginArea(rect);
                EditorGUILayout.BeginHorizontal();
                tilemap.IsVisible = EditorGUILayout.Toggle(tilemap.IsVisible, GUILayout.Width(16));
                EditorGUILayout.PropertyField(tilemapObjSerialized.FindProperty("m_Name"), GUIContent.none);
                if (TilemapEditor.EditMode == TilemapEditor.eEditMode.Collider)
                {
                    SerializedProperty colliderTypeProperty = tilemapSerialized.FindProperty("ColliderType");
                    string[]           colliderTypeNames    = new List <string>(System.Enum.GetNames(typeof(eColliderType)).Select(x => x.Replace('_', ' '))).ToArray();
                    EditorGUI.BeginChangeCheck();
                    colliderTypeProperty.intValue = GUILayout.SelectionGrid(colliderTypeProperty.intValue, colliderTypeNames, colliderTypeNames.Length, GUILayout.MaxHeight(0.9f * EditorGUIUtility.singleLineHeight));
                    if (EditorGUI.EndChangeCheck())
                    {
                        tilemapSerialized.ApplyModifiedProperties();
                        tilemap.Refresh(false, true);
                    }
                }
                else
                {
                    // Sorting Layer and Order in layer
                    EditorGUI.BeginChangeCheck();
                    EditorGUIUtility.labelWidth = 1;
                    EditorGUILayout.PropertyField(tilemapSerialized.FindProperty("m_sortingLayer"), new GUIContent(" "));
                    EditorGUIUtility.labelWidth = 40;
                    EditorGUILayout.PropertyField(tilemapSerialized.FindProperty("m_orderInLayer"), new GUIContent("Order"), GUILayout.MaxWidth(90));
                    EditorGUIUtility.labelWidth = 0;
                    tilemapSerialized.FindProperty("m_orderInLayer").intValue = (tilemapSerialized.FindProperty("m_orderInLayer").intValue << 16) >> 16; // convert from int32 to int16 keeping sign
                    if (EditorGUI.EndChangeCheck())
                    {
                        tilemapSerialized.ApplyModifiedProperties();
                        tilemap.RefreshChunksSortingAttributes();
                        SceneView.RepaintAll();
                    }
                    //---
                }
                EditorGUILayout.EndHorizontal();
                GUILayout.EndArea();

                if (GUI.changed)
                {
                    tilemapObjSerialized.ApplyModifiedProperties();
                }
            };
            reordList.onReorderCallback = (ReorderableList list) =>
            {
                var targetObj   = target as TilemapGroup;
                int sibilingIdx = 0;
                foreach (Tilemap tilemap in targetObj.Tilemaps)
                {
                    tilemap.transform.SetSiblingIndex(sibilingIdx++);
                }
                Repaint();
            };
            reordList.onSelectCallback = (ReorderableList list) =>
            {
                serializedObject.FindProperty("m_selectedIndex").intValue = reordList.index;
                serializedObject.ApplyModifiedProperties();
                GUI.changed = true;
                TileSelectionWindow.RefreshIfVisible();
                TilePropertiesWindow.RefreshIfVisible();
            };
            reordList.onAddCallback = (ReorderableList list) =>
            {
                var targetObj = target as TilemapGroup;
                Undo.RegisterCompleteObjectUndo(targetObj, "New Tilemap");
                GameObject obj = new GameObject();
                Undo.RegisterCreatedObjectUndo(obj, "New Tilemap");
                Tilemap newTilemap = obj.AddComponent <Tilemap>();
                obj.transform.parent = targetObj.transform;
                obj.name             = GameObjectUtility.GetUniqueNameForSibling(obj.transform.parent, "New Tilemap");

                Tilemap copiedTilemap = targetObj.SelectedTilemap;
                if (copiedTilemap)
                {
                    UnityEditorInternal.ComponentUtility.CopyComponent(copiedTilemap);
                    UnityEditorInternal.ComponentUtility.PasteComponentValues(newTilemap);
                    obj.SendMessage("_DoDuplicate");
                    obj.name = GameObjectUtility.GetUniqueNameForSibling(obj.transform.parent, copiedTilemap.name);
                }
            };
            reordList.onRemoveCallback = (ReorderableList list) =>
            {
                var targetObj = target as TilemapGroup;
                Undo.DestroyObjectImmediate(targetObj.SelectedTilemap.gameObject);
                //NOTE: Fix argument exception
                if (m_tilemapReordList.index == targetObj.Tilemaps.Count - 1)
                {
                    serializedObject.FindProperty("m_selectedIndex").intValue = m_tilemapReordList.index = m_tilemapReordList.index - 1;
                }
            };

            return(reordList);
        }