Last active
August 29, 2024 04:18
-
-
Save Raptorij/a4b20e2aa0f14c3564bb08df4f33382c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEditor; | |
using System.IO; | |
using System.Linq; | |
using System.Runtime.Serialization.Formatters.Binary; | |
public class QbarEditor : EditorWindow | |
{ | |
const int CELL_SIZE = 50; | |
private List<Object> setOfObjects = new List<Object>(); | |
private QBarSaves qBarSaves = new(); | |
private Vector2 scrollView; | |
private string searchString = ""; | |
private Vector2 clickPos; | |
private float zoom = 1f; | |
private bool lockClick; | |
private string FolderPath => Path.Combine(Path.Combine( Application.dataPath, "../" ), "UserSettings"); | |
private string FullPath => Path.Combine(FolderPath, "Qbar.asset"); | |
[System.Serializable] | |
private class QBarSaves | |
{ | |
public List<string> ObjectsPaths = new List<string>(); | |
public float Zoom; | |
} | |
[MenuItem("Tools/Qbar")] | |
private static void Init() | |
{ | |
var window = EditorWindow.CreateInstance<QbarEditor>(); | |
GUIContent titleContent = new GUIContent("Qbar", EditorGUIUtility.IconContent("GridLayoutGroup Icon").image); | |
window.titleContent = titleContent; | |
window.Show(); | |
} | |
private void OnFocus() | |
{ | |
Load(); | |
} | |
private void OnLostFocus() | |
{ | |
GUI.FocusControl(null); | |
Repaint(); | |
} | |
private void OnEnable() | |
{ | |
Load(); | |
} | |
private void Load() | |
{ | |
setOfObjects.Clear(); | |
if (!File.Exists(FullPath)) | |
{ | |
return; | |
} | |
using (var file = File.Open(FullPath, FileMode.Open, FileAccess.Read, FileShare.Read)) | |
{ | |
var formatter = new BinaryFormatter(); | |
qBarSaves = (QBarSaves)formatter.Deserialize(file); | |
} | |
if (qBarSaves != null) | |
{ | |
for (int i = 0; i < qBarSaves.ObjectsPaths.Count; i++) | |
{ | |
var path = AssetDatabase.GUIDToAssetPath(qBarSaves.ObjectsPaths[i]); | |
var obj = AssetDatabase.LoadAssetAtPath<Object>(path); | |
if (obj != null) | |
{ | |
setOfObjects.Add(obj); | |
} | |
} | |
zoom = qBarSaves.Zoom; | |
} | |
else | |
{ | |
qBarSaves = new QBarSaves(); | |
Save(); | |
} | |
} | |
private void Save() | |
{ | |
qBarSaves.ObjectsPaths.Clear(); | |
for (int i = 0; i < setOfObjects.Count; i++) | |
{ | |
var path = AssetDatabase.GetAssetPath(setOfObjects[i]); | |
var guid = AssetDatabase.GUIDFromAssetPath(path); | |
var guidString = guid.ToString(); | |
qBarSaves.ObjectsPaths.Add(guidString); | |
} | |
qBarSaves.Zoom = zoom; | |
if (!File.Exists(FullPath)) | |
{ | |
using (var file = File.Create(FullPath)) | |
{ | |
var formatter = new BinaryFormatter(); | |
formatter.Serialize(file, qBarSaves); | |
} | |
} | |
else | |
{ | |
using (var file = File.Open(FullPath, FileMode.Create, FileAccess.Write, FileShare.Write)) | |
{ | |
var formatter = new BinaryFormatter(); | |
formatter.Serialize(file, qBarSaves); | |
} | |
} | |
} | |
private void OnGUI() | |
{ | |
var zoomRect = new Rect(new Vector2(0, Screen.height - 42), new Vector2(Screen.width, 42)); | |
var dropArea = new Rect(0, 0, Screen.width, Screen.height); | |
DropAreaGUI(dropArea); | |
GUILayout.BeginHorizontal(GUI.skin.FindStyle("Toolbar")); | |
GUILayout.Space(5); | |
//var searchStyle = GUI.skin.FindStyle("ToolbarSeachTextField"); | |
searchString = GUILayout.TextField(searchString /*, searchStyle*/); | |
if (GUILayout.Button("", GUI.skin.FindStyle("ToolbarSearchCancelButton"))) | |
{ | |
searchString = ""; | |
GUI.FocusControl(null); | |
} | |
GUILayout.EndHorizontal(); | |
var e = Event.current; | |
lockClick = zoomRect.Contains(Event.current.mousePosition); | |
if (zoom >= 0.75f) | |
{ | |
DisplayPrefabsGrid(setOfObjects); | |
} | |
else | |
{ | |
DisplayPrefabsList(setOfObjects); | |
} | |
GUI.Box(zoomRect, "", "ProjectBrowserBottomBarBg"); | |
zoomRect = new Rect(new Vector2(Screen.width - 80, Screen.height - 40), new Vector2(60, 25)); | |
EditorGUI.BeginChangeCheck(); | |
zoom = GUI.HorizontalSlider(zoomRect, zoom, 0, 2); | |
if (EditorGUI.EndChangeCheck()) | |
{ | |
Save(); | |
} | |
} | |
private void Remove(Object @object) | |
{ | |
setOfObjects.Remove(@object); | |
Save(); | |
Repaint(); | |
} | |
private bool TryShowContextMenu(Rect r, Object @object) | |
{ | |
var e = Event.current; | |
if (e.type == EventType.ContextClick) | |
{ | |
Vector2 mousePos = e.mousePosition; | |
if (r.Contains(mousePos)) | |
{ | |
GenericMenu menu = new GenericMenu(); | |
menu.AddItem(new GUIContent("Remove"), false, (x) => Remove(@object), "item 1"); | |
menu.ShowAsContext(); | |
e.Use(); | |
return true; | |
} | |
} | |
return false; | |
} | |
public void DisplayPrefabsList(List<Object> prefabs) | |
{ | |
if (prefabs == null || prefabs.Count == 0) | |
{ | |
return; | |
} | |
int numberOfPrefabs = searchString == "" | |
? prefabs.Count | |
: prefabs.Where(x => x.name.ToLower().Contains(searchString.ToLower())).Count(); | |
var searchedPrefabs = searchString == "" | |
? prefabs | |
: prefabs.Where(x => x.name.ToLower().Contains(searchString.ToLower())).ToList(); | |
int y = (int)(EditorGUIUtility.singleLineHeight); | |
float heightScroll = 5 + prefabs.Count * EditorGUIUtility.singleLineHeight + EditorGUIUtility.singleLineHeight; | |
scrollView = GUI.BeginScrollView(new Rect(0 - 2, y + 2, Screen.width, Screen.height - y - 42), scrollView, | |
new Rect(0, 0, Screen.width - 20, heightScroll)); | |
var e = Event.current; | |
if (e.type == EventType.KeyDown) | |
{ | |
if (e.keyCode == KeyCode.Escape) | |
{ | |
GUI.FocusControl(null); | |
} | |
} | |
for (int i = 0; i < numberOfPrefabs; i++) | |
{ | |
var go = searchedPrefabs[i]; | |
float posX = 5; | |
float posY = 5 + i * EditorGUIUtility.singleLineHeight; | |
Rect r = new Rect(posX, posY, 20, 20); | |
var clickRect = r; | |
clickRect.x = 0; | |
clickRect.width = Screen.width; | |
if (TryShowContextMenu(clickRect, go)) | |
{ | |
return; | |
} | |
if (clickRect.Contains(Event.current.mousePosition) && !lockClick) | |
{ | |
if (Event.current.type == EventType.MouseDrag) | |
{ | |
DragAndDrop.PrepareStartDrag(); | |
DragAndDrop.StartDrag("Dragging title"); | |
DragAndDrop.objectReferences = new Object[] { go }; | |
DragAndDrop.visualMode = DragAndDropVisualMode.Copy; | |
break; | |
} | |
else | |
{ | |
if (e.type == EventType.MouseDown && e.button == 0) | |
{ | |
GUI.FocusControl(null); | |
clickPos = Event.current.mousePosition; | |
if (clickPos == Event.current.mousePosition) | |
{ | |
if (e.clickCount == 2) | |
{ | |
Selection.activeObject = null; | |
AssetDatabase.OpenAsset(go); | |
Repaint(); | |
} | |
else | |
{ | |
Selection.activeObject = go; | |
EditorGUIUtility.PingObject(go); | |
if (e.control) | |
{ | |
} | |
} | |
} | |
} | |
else if (e.type == EventType.MouseUp && e.button == 0) | |
{ | |
GUI.FocusControl(null); | |
} | |
} | |
} | |
var path = AssetDatabase.GetAssetPath(go); | |
GUI.Label(r, AssetDatabase.GetCachedIcon(path)); | |
r.x += 2 + 20; | |
r.width = Screen.width; | |
GUI.Label(r, go.name); | |
} | |
GUI.EndScrollView(); | |
} | |
public void DisplayPrefabsGrid(List<Object> prefabs) | |
{ | |
if (prefabs == null || prefabs.Count == 0) | |
{ | |
return; | |
} | |
int numberOfPrefabs = searchString == "" | |
? prefabs.Count | |
: prefabs.Where(x => x.name.ToLower().Contains(searchString.ToLower())).Count(); | |
int windowWidth = Mathf.FloorToInt(Screen.width); | |
int columns = Mathf.FloorToInt((float)windowWidth / ((CELL_SIZE + 1f) * zoom)); | |
int rows = Mathf.FloorToInt(numberOfPrefabs / columns); | |
int y = (int)(EditorGUIUtility.singleLineHeight); | |
scrollView = GUI.BeginScrollView(new Rect(0 - 2, y + 2, Screen.width, Screen.height - y - 42), scrollView, | |
new Rect(0, 0, 0, ((CELL_SIZE + 15) * zoom) * rows)); | |
var searchedPrefabs = searchString == "" | |
? prefabs | |
: prefabs.Where(x => x.name.ToLower().Contains(searchString.ToLower())).ToList(); | |
var e = Event.current; | |
if (e.type == EventType.KeyDown) | |
{ | |
if (e.keyCode == KeyCode.Escape) | |
{ | |
GUI.FocusControl(null); | |
} | |
} | |
for (int i = 0; i < numberOfPrefabs; i++) | |
{ | |
var go = searchedPrefabs[i]; | |
float posX = 5 + CELL_SIZE * zoom * (i - (Mathf.FloorToInt(i / columns)) * columns); | |
float posY = CELL_SIZE * zoom * Mathf.FloorToInt(i / columns); | |
Rect r = new Rect(posX, posY + 10 * (i / columns), CELL_SIZE * zoom, CELL_SIZE * zoom); | |
Rect border = new Rect(r.x + 2 * zoom, r.y + 6 * zoom, r.width - 4 * zoom, r.height - 4 * zoom); | |
if (TryShowContextMenu(r, go)) | |
{ | |
return; | |
} | |
if (r.Contains(Event.current.mousePosition) && !lockClick) | |
{ | |
if (Event.current.type == EventType.MouseDrag) | |
{ | |
DragAndDrop.PrepareStartDrag(); | |
DragAndDrop.StartDrag("Dragging title"); | |
DragAndDrop.objectReferences = new Object[] { go }; | |
DragAndDrop.visualMode = DragAndDropVisualMode.Copy; | |
break; | |
} | |
else | |
{ | |
if (e.type == EventType.MouseDown && e.button == 0) | |
{ | |
GUI.FocusControl(null); | |
clickPos = Event.current.mousePosition; | |
if (clickPos == Event.current.mousePosition) | |
{ | |
if (e.clickCount == 2) | |
{ | |
Selection.activeObject = null; | |
AssetDatabase.OpenAsset(go); | |
Repaint(); | |
} | |
else | |
{ | |
Selection.activeObject = go; | |
EditorGUIUtility.PingObject(go); | |
if (e.control) | |
{ | |
} | |
} | |
} | |
} | |
else if (e.type == EventType.MouseUp && e.button == 0) | |
{ | |
GUI.FocusControl(null); | |
} | |
} | |
} | |
border.x += 2 * zoom; | |
border.y += 2 * zoom; | |
border.width -= 4 * zoom; | |
border.height -= 4 * zoom; | |
var preview = AssetPreview.GetAssetPreview(go); | |
if (preview != null) | |
{ | |
EditorGUI.DrawTextureTransparent(border, preview, ScaleMode.ScaleToFit, 1f); | |
} | |
else | |
{ | |
EditorGUI.DrawRect(border, new Color(0.32156862745f, 0.32156862745f, 0.32156862745f)); | |
var path = AssetDatabase.GetAssetPath(go); | |
GUI.Label(border, AssetDatabase.GetCachedIcon(path)); | |
} | |
border.x -= 2 * zoom; | |
border.y += (CELL_SIZE * zoom) / 2f + 5 * zoom; | |
GUI.Label(border, go.name); | |
} | |
GUI.EndScrollView(); | |
} | |
public void DropAreaGUI(Rect r) | |
{ | |
var e = Event.current; | |
var dropArea = r; | |
GUI.Box(dropArea, string.Empty); | |
GUI.Label(dropArea, "+", EditorStyles.centeredGreyMiniLabel); | |
switch (e.type) | |
{ | |
case EventType.DragUpdated: | |
case EventType.DragPerform: | |
if (!dropArea.Contains(e.mousePosition)) | |
{ | |
return; | |
} | |
DragAndDrop.visualMode = DragAndDropVisualMode.Copy; | |
foreach (var dragged_object in DragAndDrop.objectReferences) | |
{ | |
Object go = (Object)dragged_object; | |
if (AssetDatabase.GetAssetPath(go) == "") | |
{ | |
DragAndDrop.visualMode = DragAndDropVisualMode.Rejected; | |
return; | |
} | |
} | |
if (e.type == EventType.DragPerform) | |
{ | |
DragAndDrop.AcceptDrag(); | |
foreach (var dragged_object in DragAndDrop.objectReferences) | |
{ | |
Object go = (Object)dragged_object; | |
if (AssetDatabase.GetAssetPath(go) != "") | |
{ | |
if (setOfObjects.Contains(go)) | |
{ | |
Debug.Log($"<color=yellow>[Qtbar] </color>Object \"{go.name}\" already exist in Qbar."); | |
} | |
else | |
{ | |
setOfObjects.Add(go); | |
Save(); | |
} | |
} | |
else | |
{ | |
Debug.Log($"<color=yellow>[Qbar] </color>Object \"{go.name}\" is belong scene"); | |
} | |
} | |
} | |
break; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment