From a02f2e1d9fd6a1dd489033509bb0cbbf9fdc4bff Mon Sep 17 00:00:00 2001 From: freezy Date: Sun, 12 Jul 2026 00:09:15 +0200 Subject: [PATCH 1/5] editor: fix asset browser query and lifecycle issues --- .../AssetBrowser/AssetBrowser.cs | 38 ++++----- .../AssetBrowser/AssetBrowser_Init.cs | 46 +++++++---- .../AssetBrowser/AssetQuery.cs | 67 ++++++++------- .../AssetBrowser/AssetStructure/Asset.cs | 43 ++++++---- .../AssetBrowser/LibraryCategoryElement.cs | 3 +- .../AssetBrowser/LibraryDatabase.cs | 18 ++-- .../AssetBrowser.meta | 8 ++ .../AssetBrowser/AssetQueryTests.cs | 82 +++++++++++++++++++ .../AssetBrowser/AssetQueryTests.cs.meta | 2 + 9 files changed, 224 insertions(+), 83 deletions(-) create mode 100644 VisualPinball.Unity/VisualPinball.Unity.Test/AssetBrowser.meta create mode 100644 VisualPinball.Unity/VisualPinball.Unity.Test/AssetBrowser/AssetQueryTests.cs create mode 100644 VisualPinball.Unity/VisualPinball.Unity.Test/AssetBrowser/AssetQueryTests.cs.meta diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/AssetBrowser/AssetBrowser.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/AssetBrowser/AssetBrowser.cs index b2eb65d7a..d60aaf4dd 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/AssetBrowser/AssetBrowser.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/AssetBrowser/AssetBrowser.cs @@ -106,6 +106,9 @@ private void RefreshLibraries() } // setup query + if (Query != null) { + Query.OnQueryUpdated -= OnQueryUpdated; + } Query = new AssetQuery(Libraries.Where(lib => lib.IsActive).ToList()); Query.OnQueryUpdated += OnQueryUpdated; @@ -196,19 +199,8 @@ private void UpdateQueryResults(List results, long duration) _statusLabel.text = $"Found {results.Count} asset" + (results.Count == 1 ? "" : "s") + $" in {duration}ms."; } - private void AddAssetContextMenu(ContextualMenuPopulateEvent evt) + private void AddAssetContextMenu(ContextualMenuPopulateEvent evt, AssetResult clickedAsset) { - if (evt.target is not VisualElement target) { - Debug.Log("Early out in AddAssetContextMenu, target is no VisualElement."); - return; - } - - if (!_resultByElement.ContainsKey(target.parent.parent)) { - Debug.Log($"Early out in AddAssetContextMenu, {target.parent.parent} not in resultByElement."); - return; - } - - var clickedAsset = _resultByElement[target.parent.parent]; var libs = clickedAsset.Asset.Libraries; if (libs.All(l => l.IsLocked)) { Debug.Log("Early out in AddAssetContextMenu, all libraries are locked."); @@ -300,7 +292,7 @@ private void AddAssetContextMenu(ContextualMenuPopulateEvent evt) foreach (var attr in srcAsset.Attributes) { destAsset.AddAttribute(attr.Key, attr.Value); } - foreach (var link in srcAsset.Links.Where(link => destAsset.Links.FirstOrDefault(l => l.Name == link.Name) != null)) { + foreach (var link in srcAsset.Links.Where(link => destAsset.Links.All(l => l.Name != link.Name))) { destAsset.Links.Add(new AssetLink(link.Name, link.Url)); } @@ -370,7 +362,12 @@ private void OnAssetClicked(ClickEvent evt, VisualElement element) } public void OnCategoriesUpdated(Dictionary> categories) => Query.Filter(categories); - private void OnSearchQueryChanged(ChangeEvent evt) => Query.Search(evt.newValue); + private void OnSearchQueryChanged(ChangeEvent evt) + { + _pendingSearch = evt.newValue; + _searchScheduledItem?.Pause(); + _searchScheduledItem = _queryInput.schedule.Execute(() => Query?.Search(_pendingSearch)).StartingIn(200); + } private void OnLibraryToggled(AssetLibrary lib, bool enabled) { lib.IsActive = enabled; @@ -381,11 +378,14 @@ private void OnLibraryToggled(AssetLibrary lib, bool enabled) public AssetLibrary GetLibraryByPath(string pathToCheck) { - pathToCheck = pathToCheck.Replace('\\', '/'); - return Libraries.FirstOrDefault(assetLibrary => { - var libraryPath = assetLibrary.LibraryRoot.Replace('\\', '/'); - return pathToCheck.StartsWith(libraryPath); - }); + pathToCheck = pathToCheck.Replace('\\', '/').TrimEnd('/'); + return Libraries + .OrderByDescending(assetLibrary => assetLibrary.LibraryRoot.Length) + .FirstOrDefault(assetLibrary => { + var libraryPath = assetLibrary.LibraryRoot.Replace('\\', '/').TrimEnd('/'); + return string.Equals(pathToCheck, libraryPath, StringComparison.Ordinal) + || pathToCheck.StartsWith(libraryPath + "/", StringComparison.Ordinal); + }); } public void AddAssets(IEnumerable paths, Func getCategory) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/AssetBrowser/AssetBrowser_Init.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/AssetBrowser/AssetBrowser_Init.cs index a109b2434..abb00f285 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/AssetBrowser/AssetBrowser_Init.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/AssetBrowser/AssetBrowser_Init.cs @@ -1,4 +1,4 @@ -// Visual Pinball Engine +// Visual Pinball Engine // Copyright (C) 2023 freezy and VPE Team // // This program is free software: you can redistribute it and/or modify @@ -44,6 +44,8 @@ public partial class AssetBrowser private StyleSheet _assetStyle; private readonly Dictionary _thumbCache = new(); + private IVisualElementScheduledItem _searchScheduledItem; + private string _pendingSearch; private const string ClassDrag = "library-element--dragover"; @@ -100,6 +102,7 @@ public void CreateGUI() _categoryView = ui.Q(); _gridContent = ui.Q("gridContent"); + _gridContent.styleSheets.Add(_assetStyle); _detailsElement = ui.Q(); _statusLabel = ui.Q