/// <summary> /// Selects tiles given two sets of points that define the min and max dimensions or a selection rectangle. /// </summary> /// <param name="minVector"> /// The top left location in pixel co-ordinates of the selection rectangle. /// </param> /// <param name="maxVector"> /// The bottom right location in pixel co-ordinates of the selection rectangle. /// </param> public void SelectTiles(Vector2 minVector, Vector2 maxVector) { // determine if the tile set starts with spacing var startOffset = this.StartSpacing ? this.Spacing : 0; Vector2 minTilePosition; // calculate min tile position; minTilePosition.X = (int)((minVector.X - startOffset) / (this.TileWidth + this.Spacing)); minTilePosition.Y = (int)((minVector.Y - startOffset) / (this.TileHeight + this.Spacing)); Vector2 maxTilePosition; // calculate max tile position; maxTilePosition.X = (int)((maxVector.X - startOffset) / (this.TileWidth + this.Spacing)); maxTilePosition.Y = (int)((maxVector.Y - startOffset) / (this.TileHeight + this.Spacing)); // clear any previous selection this.selectedTiles.Clear(); this.firstTileLocation = minTilePosition; // add tile entries for the selection for (var idx = minTilePosition.X; idx < maxTilePosition.X; idx++) { for (var idy = minTilePosition.Y; idy < maxTilePosition.Y; idy++) { this.selectedTiles.Add(new Vector2(idx, idy)); } } }
/// <summary> /// Is used to draw the control. /// </summary> public void Draw() { // setup a scroll view so the user can scroll large textures this.mainPreviewScroll = GUILayout.BeginScrollView(this.mainPreviewScroll, false, false); // check if a texture asset is available if (this.textureAsset != null) { // we draw a label here with the same dimensions of the texture so scrolling will work var texture = this.textureAsset; GUILayout.Label(string.Empty, GUILayout.Width((texture.width * this.zoom) + 4), GUILayout.Height((texture.height * this.zoom) + 4)); // draw the preview texture GUI.DrawTexture(new Rect(4, 4, texture.width * this.zoom, texture.height * this.zoom), texture, ScaleMode.StretchToFill, true, 1); // draw the selection rectangles this.DrawSelection(Event.current); } GUILayout.EndScrollView(); }
/// <summary> /// Draws a list of recent prefabs used. /// </summary> private void DrawRecentPrefabList() { // don't draw if quick prefab selection is not gear icon if (this.currentPrefabIndex != 0) { return; } GUILayout.BeginVertical(); // get reference to settings instance var settings = SettingsManager.Instance; // let localization instance var local = LocalizationManager.Instance; // the currently selected prefab GUILayout.Label(local.Get("CurrentPrefab")); // get grid mapping service var gridMappingService = GridMappingService.Instance; // draw current prefab control var value = (GameObject) EditorGUILayout.ObjectField( gridMappingService.CurrentPrefab != null ? gridMappingService.CurrentPrefab.name : string.Empty, gridMappingService.CurrentPrefab, typeof(GameObject), true); // if selection has changed add or move it to the top of the recently used prefab list if (value != gridMappingService.CurrentPrefab) { gridMappingService.CurrentPrefab = value; if (value != null) { // ensure there are no duplicates in the list var i = 1; while (i < gridMappingService.RecentlyUsedPrefabs.Count) { if (gridMappingService.RecentlyUsedPrefabs[i] != null && value.GetInstanceID() == gridMappingService.RecentlyUsedPrefabs[i].GetInstanceID()) { gridMappingService.RecentlyUsedPrefabs.RemoveAt(i); } else { i++; } } // inset selection at top of recently used list gridMappingService.RecentlyUsedPrefabs.Insert(0, value); // store current selection in settings settings.SetValue(GlobalConstants.CurrentPrefabKey, AssetDatabase.AssetPathToGUID(GridMapping.Helpers.GetSourcePrefab(value))); } else { settings.RemoveValue(GlobalConstants.CurrentPrefabKey); } } // add some spacing GUILayout.Space(4); // get various settings related to the recent prefab list var maxItems = settings.GetSetting(GlobalConstants.MaxNumberOfRecentPrefabsKey, 64); var maxHeight = settings.GetSetting(GlobalConstants.MaxHeightOfRecentPrefabsKey, 64); var showRecentPrefabs = settings.GetSetting(GlobalConstants.RecentInspectorPrefabListEnabledKey, true); var showAsList = settings.GetSetting(GlobalConstants.ShowRecentPrefabAsListKey, true); var buttonSize = settings.GetSetting(GlobalConstants.RecentPrefabButtonSizeKey, 32); var showPreview = settings.GetSetting(GlobalConstants.ShowRecentPrefabAssetPreviewsKey, true); var showAddPrefab = settings.GetSetting(GlobalConstants.ShowAddPrefabButtonsKey, true); GUILayout.EndVertical(); // check if recent prefabs list should be shown if (!showRecentPrefabs) { return; } // provides a button to add new prefabs to the list if (showAddPrefab && GUILayout.Button(local.Get("AddPrefab"), GUILayout.MaxWidth(100))) { gridMappingService.RecentlyUsedPrefabs.Add(null); } GUILayout.Space(4); // limit max items in the list based on settings while (gridMappingService.RecentlyUsedPrefabs.Count > 0 && gridMappingService.RecentlyUsedPrefabs.Count > maxItems) { gridMappingService.RecentlyUsedPrefabs.RemoveAt(gridMappingService.RecentlyUsedPrefabs.Count - 1); } this.prefabScroll = GUILayout.BeginScrollView(this.prefabScroll, false, false, GUILayout.Height(maxHeight), GUILayout.MaxHeight(maxHeight)); if (showAsList) { this.DrawRecentPrefabsAsList(buttonSize, showPreview); } else { this.DrawRecentPrefabsAsSelectionGrid(buttonSize, showPreview); } GUILayout.EndScrollView(); }
/// <summary> /// Draws a list of recent materials used. /// </summary> private void DrawRecentMaterialList() { // don't draw if prefab is the selected type if (this.currentPrefabIndex == 0) { return; } GUILayout.BeginVertical(); // get reference to settings instance var settings = SettingsManager.Instance; // let localization instance var local = LocalizationManager.Instance; // show apply material check box var boolValue = GUILayout.Toggle(this.applyMaterial, local.Get("ApplyMaterial")); // check if state changed if (boolValue != this.applyMaterial) { this.applyMaterial = boolValue; settings.SetValue(GlobalConstants.ApplyMaterialKey, this.applyMaterial); } // draw the current material selection GUILayout.Label(local.Get("CurrentMaterial")); // get grid mapping service var gridMappingService = GridMappingService.Instance; // draw current material control var value = (Material) EditorGUILayout.ObjectField( gridMappingService.CurrentMaterial != null ? gridMappingService.CurrentMaterial.name : string.Empty, gridMappingService.CurrentMaterial, typeof(Material), true); // if a different material was selected make it the current material and save the instance id in settings if (value != gridMappingService.CurrentMaterial) { gridMappingService.CurrentMaterial = value; if (value != null) { // ensure there are no duplicates in the list var i = 1; while (i < gridMappingService.RecentlyUsedMaterials.Count) { if (gridMappingService.RecentlyUsedMaterials[i] != null && value.GetInstanceID() == gridMappingService.RecentlyUsedMaterials[i].GetInstanceID()) { gridMappingService.RecentlyUsedMaterials.RemoveAt(i); } else { i++; } } // inset selection at top of recently used list gridMappingService.RecentlyUsedMaterials.Insert(0, value); // store current selection in settings settings.SetValue(GlobalConstants.CurrentMaterialKey, AssetDatabase.AssetPathToGUID(GridMapping.Helpers.GetSourcePrefab(value))); } else { settings.RemoveValue(GlobalConstants.CurrentMaterialKey); } } // add some spacing GUILayout.Space(4); // get various settings related to the recent material list var maxItems = settings.GetSetting(GlobalConstants.MaxNumberOfRecentMaterialsKey, 64); var maxHeight = settings.GetSetting(GlobalConstants.MaxHeightOfRecentMaterialsKey, 64); var showRecentMaterials = settings.GetSetting(GlobalConstants.RecentInspectorMaterialListEnabledKey, true); var showAsList = settings.GetSetting(GlobalConstants.ShowRecentMaterialAsListKey, true); var buttonSize = settings.GetSetting(GlobalConstants.RecentMaterialButtonSizeKey, 32); var showPreview = settings.GetSetting(GlobalConstants.ShowRecentMaterialAssetPreviewsKey, true); var showAddMaterial = settings.GetSetting(GlobalConstants.ShowAddMaterialButtonsKey, true); GUILayout.EndVertical(); // check if recent materials list should be shown if (!showRecentMaterials) { return; } // provides a button to add new materials to the list if (showAddMaterial && GUILayout.Button(local.Get("AddMaterial"), GUILayout.MaxWidth(100))) { gridMappingService.RecentlyUsedMaterials.Add(null); } GUILayout.Space(4); // limit max items in the list based on settings while (gridMappingService.RecentlyUsedMaterials.Count > 0 && gridMappingService.RecentlyUsedMaterials.Count > maxItems) { gridMappingService.RecentlyUsedMaterials.RemoveAt(gridMappingService.RecentlyUsedMaterials.Count - 1); } this.materialScroll = GUILayout.BeginScrollView(this.materialScroll, false, false, GUILayout.Height(maxHeight), GUILayout.MaxHeight(maxHeight)); GUILayout.BeginVertical(); if (showAsList) { this.DrawRecentMaterialsAsList(buttonSize, showPreview); } else { this.DrawRecentMaterialsAsSelectionGrid(buttonSize, showPreview); } GUILayout.EndVertical(); GUILayout.EndScrollView(); }
/// <summary> /// Used to draw the layer list. /// </summary> /// <param name="scrollable">If true will display scroll bars for the list.</param> private void DrawLayerList(bool scrollable) { // get reference to the GridMap component var map = (GridMap)this.target; var settings = SettingsManager.Instance; var showLocks = settings.GetSetting(GlobalConstants.ShowLayerLocksKey, true); var showVisibility = settings.GetSetting(GlobalConstants.ShowLayerVisibilityKey, true); var showActiveLayer = settings.GetSetting(GlobalConstants.ShowActiveLayerKey, true); var layerStyle = settings.GetSetting(GlobalConstants.LayerListStyleKey, 1); var layerIconSize = settings.GetSetting(GlobalConstants.LayerIconSizeKey, 16); var listHeight = settings.GetSetting(GlobalConstants.LayerListHeightKey, 96); var showDelete = settings.GetSetting(GlobalConstants.ShowDeleteLayerButtonKey, true); var showMove = settings.GetSetting(GlobalConstants.ShowMoveLayerButtonsKey, true); // draw the list if map layers are scrollable var scrollStarted = false; if (scrollable && map.Layers.Length > 3) { var height = Math.Min((map.Layers.Length * layerIconSize) + 2, listHeight); this.layerScroll = GUILayout.BeginScrollView(this.layerScroll, false, false, GUILayout.Height(height)); scrollStarted = true; } switch (layerStyle) { case 0: var index = GUILayout.SelectionGrid(this.ActiveLayer, map.GetLayerNames(), 1); // if the selected layer has changed be sure to immediately update the scene views if (index != this.ActiveLayer) { this.ActiveLayer = index; EditorCallbackService.Instance.Register(SceneView.RepaintAll); } break; case 1: var local = LocalizationManager.Instance; GUILayout.BeginVertical(); for (var i = 0; i < map.Layers.Length; i++) { var layer = map.Layers[i]; GUILayout.BeginHorizontal(GUILayout.ExpandHeight(false)); GUILayout.Space(4); if (showLocks) { var content = this.layerStyles[layer.Locked ? 2 : 3]; GUI.SetNextControlName(string.Format("chkLayerLock{0}", i)); layer.Locked = GUILayout.Toggle(layer.Locked, string.Empty, content, GUILayout.Width(layerIconSize), GUILayout.MaxWidth(layerIconSize), GUILayout.Height(layerIconSize), GUILayout.MaxHeight(layerIconSize)); } if (showVisibility) { var content = this.layerStyles[layer.Visible ? 0 : 1]; GUI.SetNextControlName(string.Format("icoLayerVisible{0}", i)); var visible = GUILayout.Toggle(layer.Visible, string.Empty, content, GUILayout.Width(layerIconSize), GUILayout.MaxWidth(layerIconSize), GUILayout.Height(layerIconSize), GUILayout.MaxHeight(layerIconSize)); if (visible != layer.Visible) { //Undo.RegisterSceneUndo(local.Get("LayerVisibility")); map.SetLayerVisibility(i, visible, objs => Undo.RecordObjects(objs, local.Get("LayerVisibility"))); } } if (showActiveLayer) { GUI.SetNextControlName(string.Format("icoActiveLayer{0}", i)); GUILayout.Label(GUIContent.none, i == this.activeLayer ? this.layerStyles[4] : GUI.skin.label, GUILayout.Width(layerIconSize), GUILayout.MaxWidth(layerIconSize), GUILayout.Height(layerIconSize), GUILayout.MaxHeight(layerIconSize)); } if (i == this.activeLayer && showActiveLayer) { GUILayout.Space(GUI.skin.label.padding.left + GUI.skin.label.padding.right); } // check whether or not to show the move buttons if (showMove) { Action<SwapModel> moveCallback = model => { var localizedString = local.Get("MoveLayer"); Undo.RecordObject(model.Map, localizedString); //Undo.RecordObject(model.Map.Layers[model.LayerIndex], localizedString); //Undo.RecordObject(model.Map.Layers[model.NewLayerIndex], localizedString); Undo.RegisterCompleteObjectUndo(model.LayerAObjects, localizedString); Undo.RegisterCompleteObjectUndo(model.LayerBObjects, localizedString); }; Action<SwapModel> moveCompletedCallback = model => { EditorUtility.SetDirty(model.Map); //EditorUtility.SetDirty(model.Map.Layers[model.LayerIndex]); //EditorUtility.SetDirty(model.Map.Layers[model.NewLayerIndex]); foreach (var gameObject in model.LayerAObjects) { EditorUtility.SetDirty(gameObject); } foreach (var gameObject in model.LayerBObjects) { EditorUtility.SetDirty(gameObject); } }; // show move up button if (GUILayout.Button(this.buttonContent[3], GUI.skin.label, GUILayout.Width(layerIconSize), GUILayout.Height(layerIconSize), GUILayout.MaxHeight(layerIconSize))) { map.MoveLayerUp(i, 1, moveCallback, moveCompletedCallback); this.Repaint(); } // show move down button if (GUILayout.Button(this.buttonContent[4], GUI.skin.label, GUILayout.Width(layerIconSize), GUILayout.Height(layerIconSize), GUILayout.MaxHeight(layerIconSize))) { map.MoveLayerDown(i, 1, moveCallback, moveCompletedCallback); this.Repaint(); } } if (this.activeLayer == i) { GUI.SetNextControlName(string.Format("txtLayerName{0}", i)); layer.Name = EditorGUILayout.TextField(layer.Name, GUILayout.Height(layerIconSize), GUILayout.MaxHeight(layerIconSize)); } else { GUI.SetNextControlName(string.Format("btnLayerName{0}", i)); if (GUILayout.Button(layer.Name, GUILayout.Height(layerIconSize), GUILayout.MaxHeight(layerIconSize))) { this.ActiveLayer = i; GUI.FocusControl(string.Format("txtLayerName{0}", i)); EditorCallbackService.Instance.Register(SceneView.RepaintAll); } } // check whether or not to show delete button if (showDelete && !layer.Locked && map.Layers.Length > 1 && GUILayout.Button(this.buttonContent[2], GUI.skin.label, GUILayout.Width(layerIconSize), GUILayout.Height(layerIconSize), GUILayout.MaxHeight(layerIconSize))) { var promptToDeleteLayer = settings.GetSetting(GlobalConstants.PromptToDeleteLayerKey, true); if (!promptToDeleteLayer || (promptToDeleteLayer && EditorUtility.DisplayDialog( local.Get("AreYouSure"), string.Format(local.Get("ConfirmDeleteLayer"), map.Layers[i].Name), local.Get("Accept"), local.Get("Cancel")))) { map.DeleteLayer(i, true); } } GUILayout.EndHorizontal(); GUILayout.Space(1); } GUILayout.EndVertical(); break; } if (scrollStarted) { GUILayout.Space(3); GUILayout.EndScrollView(); } }
/// <summary> /// Used to draw the currently selected tiles. /// </summary> /// <param name="eventReference"> /// A reference to the <see cref="Event"/>. /// </param> protected virtual void DrawTileSelection(Event eventReference) { // if no event reference provided just exit if (eventReference == null) { return; } // used to store the top left tile coordinates of the tile position Point tilePosition; // determine if the tile set starts with spacing var startOffset = this.StartSpacing ? this.Spacing : 0; // convert the mouse position into a tile position var mousePosition = eventReference.mousePosition; tilePosition.X = (int)((mousePosition.x - startOffset) / ((this.TileWidth * this.Zoom) + this.Spacing)); tilePosition.Y = (int)((mousePosition.y - startOffset) / ((this.TileHeight * this.Zoom) + this.Spacing)); // calculate the min and max positions based on the location of the mouse and the first selected tile location this.min = new Vector2(Math.Min(this.firstTileLocation.X, tilePosition.X), Math.Min(this.firstTileLocation.Y, tilePosition.Y)); if (this.MultipleTileSelection) { this.max = new Vector2(Math.Max(this.firstTileLocation.X, tilePosition.X), Math.Max(this.firstTileLocation.Y, tilePosition.Y)); } else { this.max = this.min; } // cap the min max values to the dimensions of the texture this.min = this.CapValues(this.min); this.max = this.CapValues(this.max) + new Point(1, 1); // determine if user is selecting if (this.isSelecting && eventReference.type == EventType.MouseDrag && eventReference.button == 0) { // this event has been used eventReference.Use(); // clear any previous selection this.selectedTiles.Clear(); // check if allowed to select multiple tiles if (this.MultipleTileSelection) { // add tile entries for the selection for (var idx = this.min.X; idx < this.max.X; idx++) { for (var idy = this.min.Y; idy < this.max.Y; idy++) { this.selectedTiles.Add(new Vector2(idx, idy)); } } } else { this.firstTileLocation = tilePosition; // clear any previously selected tiles and add the first tile location this.selectedTiles.Add(this.firstTileLocation); } // save last mouse position this.selectionStatus = TileSelectionStatus.Selecting; this.OnTileSelection(); } // draw selected tiles float x; float y; foreach (var tile in this.selectedTiles) { // calculate rectangle Top Left for tile location x = startOffset + (tile.X * ((this.TileWidth * this.Zoom) + this.Spacing)); y = startOffset + (tile.Y * ((this.TileHeight * this.Zoom) + this.Spacing)); // draw the selected tile rectangle Helpers.DrawRect( new Rect( x, y, (this.TileWidth * this.Zoom) + this.Spacing - startOffset, (this.TileHeight * this.Zoom) + this.Spacing - startOffset), this.SelectionRectangleColor); } // draw blue rectangle indicating what tile the mouse is hovering over x = startOffset + (tilePosition.X * ((this.TileWidth * this.Zoom) + this.Spacing)); y = startOffset + (tilePosition.Y * ((this.TileHeight * this.Zoom) + this.Spacing)); if (this.ShowHoverRectangle) { Helpers.DrawRect( new Rect(x, y, (this.TileWidth * this.Zoom) + this.Spacing - startOffset, (this.TileHeight * this.Zoom) + this.Spacing - startOffset), this.HoverRectangleColor); } // check if were beginning to select tiles with the left mouse button if (!this.isSelecting && eventReference.isMouse && eventReference.type == EventType.MouseDown && eventReference.button == 0) { // this event has been used eventReference.Use(); this.isSelecting = true; this.firstTileLocation = tilePosition; // clear any previously selected tiles and add the first tile location this.selectedTiles.Clear(); this.selectedTiles.Add(this.firstTileLocation); // save last mouse position this.selectionStatus = TileSelectionStatus.Begin; this.OnTileSelection(); } // check if were releasing left mouse button (IE stop selecting) if (this.isSelecting && eventReference.isMouse && eventReference.type == EventType.MouseUp && eventReference.button == 0) { // this event has been used eventReference.Use(); this.isSelecting = false; this.selectionStatus = TileSelectionStatus.Complete; this.OnTileSelection(); } }
/// <summary> /// Used to draw the current free form selection rectangle. /// </summary> /// <param name="eventReference"> /// A reference to the <see cref="Event"/>. /// </param> protected virtual void DrawFreeFormSelection(Event eventReference) { // get mouse position Point mousePosition = eventReference.mousePosition; // determine if user is selecting if (this.isSelecting && eventReference.type == EventType.MouseDrag && eventReference.button == 0) { // this event has been used eventReference.Use(); // clear any previous selection this.selectedTiles.Clear(); // calculate the min and max positions based on the location of the mouse and the first position of mouse down var minVector = new Vector2(Math.Min(this.firstTileLocation.X, mousePosition.X), Math.Min(this.firstTileLocation.Y, mousePosition.Y)) / new Vector2(1f / this.zoom); var maxVector = new Vector2(Math.Max(this.firstTileLocation.X, mousePosition.X), Math.Max(this.firstTileLocation.Y, mousePosition.Y)) / new Vector2(1f / this.zoom); // set the free form rectangle this.FreeFormRectangle = new Rect(minVector.X, minVector.Y, maxVector.X - minVector.X, maxVector.Y - minVector.Y); // raise the selection changed event this.selectionStatus = TileSelectionStatus.Selecting; this.OnFreeFormSelection(); } // draw the selected free form rectangle Helpers.DrawRect( new Rect( this.FreeFormRectangle.x * this.zoom, this.FreeFormRectangle.y * this.zoom, this.FreeFormRectangle.width * this.zoom, this.FreeFormRectangle.height * this.zoom), this.SelectionRectangleColor); // check if were beginning to select tiles with the left mouse button if (!this.isSelecting && eventReference.isMouse && eventReference.type == EventType.MouseDown && eventReference.button == 0) { this.isSelecting = true; this.firstTileLocation = mousePosition; // clear any previously selected tiles and add the first tile location this.selectedTiles.Clear(); this.selectedTiles.Add(this.firstTileLocation); // raise the selection changed event this.selectionStatus = TileSelectionStatus.Begin; this.OnFreeFormSelection(); // this event has been used eventReference.Use(); } // check if were releasing left mouse button (IE stop selecting) if (this.isSelecting && eventReference.isMouse && eventReference.type == EventType.MouseUp && eventReference.button == 0) { // this event has been used eventReference.Use(); this.isSelecting = false; this.selectionStatus = TileSelectionStatus.Complete; this.OnFreeFormSelection(); } }