using System; using System.Collections.Generic; using System.Linq; using Nullframes.Intrigues.EDITOR.Utils; using Nullframes.Intrigues.Graph; using Nullframes.Intrigues.Utils; using UnityEditor; using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements; namespace Nullframes.Intrigues.EDITOR { public class AssetDbWindow : EditorWindow { private static IEDatabase database; private bool isDbLoaded; private bool isUIInitialized; private VisualElement root; private VisualElement scrollView; private VisualElement tagList; private List< VisualElement > errorMsg; private ObjectField databaseField; private TextField searchField; private TextField newCategoryField; private Button newCategoryBtn; private readonly List< VisualElement > selectedItems = new(); private VisualElement lastSelected; private bool isCtrlPressed; private List< VisualElement > currentTags = new(); private List< VisualElement > categories { get { return scrollView.Query< VisualElement >() .Where(e => e.ClassListContains("categoryField")) .ToList(); } } private void OnEnable() { isDbLoaded = false; isUIInitialized = false; Undo.undoRedoPerformed += OnUndoRedoPerformed; EditorApplication.update += OnEditorUpdate; } private void OnDisable() { Undo.undoRedoPerformed -= OnUndoRedoPerformed; EditorApplication.update -= OnEditorUpdate; } private void OnUndoRedoPerformed() { if ( database == null ) return; var _selectedItems = new List< VisualElement >(selectedItems); UpdateDbList(database); if ( _selectedItems.Count > 0 ) { var groupedByParent = _selectedItems .Where(item => item is { parent: not null }) .GroupBy(item => item.parent) .OrderByDescending(g => g.Count()) .FirstOrDefault(); if ( groupedByParent != null ) { foreach ( var item in groupedByParent ) { Select(item); } } } } private void OnEditorUpdate() { if ( isCtrlPressed ) { foreach ( var tag in currentTags ) { tag.Hide(); } } } [MenuItem("Tools/Nullframes/Sprite dB")] public static void Open() { var wnd = GetWindow< AssetDbWindow >(); wnd.position = new Rect(100, 100, 800, 800); wnd.titleContent = new GUIContent("SpriteDb"); } public static void Open(IEDatabase db) { if ( db == null ) return; database = db; EditorPrefs.SetString("Nullframes.PendingDatabasePath", AssetDatabase.GetAssetPath(db)); var wnd = GetWindow< AssetDbWindow >(); wnd.position = new Rect(100, 100, 800, 800); wnd.titleContent = new GUIContent("SpriteDb"); } private void OnGUI() { if ( !isUIInitialized ) return; if ( database == null ) { errorMsg[ 0 ].Show(); errorMsg[ 1 ].Hide(); titleContent = new GUIContent("SpriteDb - Not Initialized"); isDbLoaded = false; return; } if ( !isDbLoaded ) { LoadDb(); if ( !isDbLoaded ) { return; } } errorMsg[ 0 ].Hide(); if ( database.spriteDatabase.Count > 0 ) { errorMsg[ 1 ].Hide(); } else { errorMsg[ 1 ].Show(); } titleContent = new GUIContent("SpriteDb - " + database.name); // Key handler Event e = Event.current; if ( e.type == EventType.KeyDown && e.control ) { isCtrlPressed = true; currentTags = scrollView.Query< VisualElement >() .Where(t => t.ClassListContains("tagLabel")) .ToList(); } else if ( e.type == EventType.KeyUp && e.keyCode == KeyCode.LeftControl || e.keyCode == KeyCode.RightControl ) { isCtrlPressed = false; foreach ( var tag in currentTags ) { tag.Show(); } currentTags.Clear(); } if ( Event.current.type == EventType.KeyDown ) { if ( Event.current.keyCode == KeyCode.Delete || Event.current.keyCode == KeyCode.Backspace ) { if ( selectedItems.Count > 0 ) { DeleteSelectedItems(); Save(); Event.current.Use(); } } } } public void CreateGUI() { root = rootVisualElement; var visualTree = (VisualTreeAsset)EditorGUIUtility.Load("Nullframes/AssetDb.uxml"); visualTree.CloneTree(root); var styleSheet = (StyleSheet)EditorGUIUtility.Load(EditorGUIUtility.isProSkin ? "Nullframes/AssetDb_Dark.uss" : "Nullframes/AssetDb_Light.uss"); root.styleSheets.Add(styleSheet); var toolbar = new Toolbar(); var flexibleSpacer = new VisualElement { style = { flexGrow = 1 } }; toolbar.Add(flexibleSpacer); var docButton = new Button(() => { Application.OpenURL("https://www.wlabsocks.com/wiki/index.php?title=Sprite_dB"); }) { text = "?" }; toolbar.Add(docButton); root.Insert(0, toolbar); errorMsg = new List< VisualElement > { root.Q< VisualElement >("errorMsg"), root.Q< VisualElement >("errorMsg2") }; searchField = root.Q< TextField >("searchField"); newCategoryField = root.Q< TextField >("newCategoryField"); databaseField = root.Q< ObjectField >("databaseField"); databaseField.objectType = typeof( IEDatabase ); newCategoryBtn = root.Q< Button >("newCategoryBtn"); scrollView = rootVisualElement.Q< ScrollView >("scrollView"); tagList = rootVisualElement.Q< ScrollView >("tagList"); #region New Category Button newCategoryBtn.clicked += () => { if ( database != null && newCategoryField.text != string.Empty ) { if ( database.spriteDatabase.ContainsKey(newCategoryField.text) ) return; // database.assetDatabase.Add(newCategoryField.text, new AssetDb()); var _categoryField = CreateCategory(newCategoryField.text); scrollView.Add(_categoryField); var assetField = CreateAssetField(scrollView); assetField.userData = _categoryField; _categoryField.userData = assetField; Save(); } }; #endregion #region Object Field databaseField.RegisterValueChangedCallback(_ => { string path = string.Empty; if ( databaseField.value != null ) { database = (IEDatabase)databaseField.value; path = AssetDatabase.GetAssetPath(database); } else { database = null; } UpdateDbList(database); EditorPrefs.SetString("Nullframes.PendingDatabasePath", path); }); #endregion #region Search Field var searchField_placeHolder = searchField.Q< Label >("placeHolder"); searchField.RegisterValueChangedCallback(_ => { if ( string.IsNullOrEmpty(searchField.value) ) { searchField_placeHolder.style.display = DisplayStyle.Flex; foreach ( var category in categories ) { var _assetField = (VisualElement)category.userData; foreach ( var _asset in _assetField.Children() ) { var obj = _asset.userData as Sprite; if ( obj == null ) continue; _asset.Show(); } category.style.display = DisplayStyle.Flex; } } else { searchField_placeHolder.style.display = DisplayStyle.None; foreach ( var category in categories ) { var _assetField = (VisualElement)category.userData; foreach ( var _asset in _assetField.Children() ) { var obj = _asset.userData as Sprite; if ( obj == null ) continue; if ( obj.name.Contains(searchField.value, StringComparison.OrdinalIgnoreCase) ) { _asset.Show(); } else { _asset.Hide(); } } if ( _assetField.Children().Count(c => c.style.display == DisplayStyle.Flex) == 0 ) { category.style.display = DisplayStyle.None; } } } }); #endregion #region Category Field var categoryField_placeHolder = newCategoryField.Q< Label >("placeHolder"); newCategoryField.RegisterValueChangedCallback(_ => { categoryField_placeHolder.style.display = string.IsNullOrEmpty(newCategoryField.value) ? DisplayStyle.Flex : DisplayStyle.None; }); #endregion bool isAnyChanged = false; root.RegisterCallback< MouseDownEvent >(evt => { if ( evt.button != 0 ) return; ClearSelection(); var tagFields = scrollView.Query< TextField >() .Where(e => e.ClassListContains("tagField")) .ToList(); var tagLabels = scrollView.Query< Label >() .Where(e => e.ClassListContains("tagLabel")) .ToList(); foreach ( var tagLbl in tagLabels ) { tagLbl.Show(); } foreach (var tagField in tagFields) { tagField.Hide(); if (tagField.userData is ValueTuple { Item1: true } data) { tagField.userData = (false, data.Item2); tagField.SetValueWithoutNotify(string.Empty); isAnyChanged = true; } } if ( isAnyChanged ) { isAnyChanged = false; Save(); } }); EditorRoutine.CallNextFrame(LoadDb); isUIInitialized = true; } private void LoadDb() { if ( isDbLoaded ) return; if ( database == null ) { string path = EditorPrefs.GetString("Nullframes.PendingDatabasePath", null); if ( !string.IsNullOrEmpty(path) ) { database = AssetDatabase.LoadAssetAtPath< IEDatabase >(path); } } if ( database == null ) return; databaseField.value = database; UpdateDbList(database); // UpdateTagList(); isDbLoaded = true; } private void UpdateTagList() { var uniqueTags = scrollView.Query