#if UNITY_EDITOR using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using UnityEngine; using UnityEditor; using UnityEditor.ShortcutManagement; using UnityEngine.UIElements; using UnityEngine.SceneManagement; using UnityEditor.SceneManagement; using UnityEditor.IMGUI.Controls; using Type = System.Type; using static VFolders.Libs.VUtils; using static VFolders.Libs.VGUI; // using static VTools.VDebug; using static VFolders.VFolders; using static VFolders.VFoldersData; using static VFolders.VFoldersCache; namespace VFolders { [System.Serializable] public class VFoldersHistory { public void CheckTreeStateChange() { if (!VFoldersMenu.navigationBarEnabled) return; if (!isOneColumn) return; if (lastTreeState == null) { lastTreeState = new() { scrollPos = currentScrollPos, expandedIds = expandedIds.ToList() }; return; } var curTreeState = new TreeState(); var targetScrollPosChanged = false; var targetExpandedIdsChanged = false; void set_curState_scrollPos() { if (controller.animatingScroll) curTreeState.scrollPos = controller.targetScrollPos; else curTreeState.scrollPos = currentScrollPos; } void set_curState_expandedIds() { var expandedIdsHashset = expandedIds.ToHashSet(); if (treeViewAnimatesExpansion) if (animatingItemTragetExpanded_fromTreeViewExpandAnimator == true) expandedIdsHashset.UnionWith(new HashSet() { animatingItemId_fromTreeViewExpandAnimator }); else expandedIdsHashset.ExceptWith(new HashSet() { animatingItemId_fromTreeViewExpandAnimator }); if (controller.animatingExpansion) { foreach (var r in controller.expandQueue_toAnimate) if (r.expand) expandedIdsHashset.UnionWith(new HashSet() { r.id }); else expandedIdsHashset.ExceptWith(new HashSet() { r.id }); expandedIdsHashset.ExceptWith(controller.expandQueue_toCollapseAfterAnimation.ToHashSet()); } curTreeState.expandedIds = expandedIdsHashset.ToList(); } void checkScrollPosChange() { if (framesSinceLastExpansionAnimation < 2) return; if (framesSinceLastScrollAnimation < 2) return; if (curTreeState.scrollPos == lastTreeState.scrollPos) return; if (EditorApplication.timeSinceStartup - lastScrollTime > 2 || lastTargetStateChangeWasExpandedIds) targetScrollPosChanged = true; lastScrollTime = EditorApplication.timeSinceStartup; } void checkExpandedIdsChange() { if (lastTreeState.expandedIds.ToHashSet().SetEquals(curTreeState.expandedIds.ToHashSet())) return; targetExpandedIdsChanged = true; // lastTargetState.expandedIds.LogAll("lastTargetState"); // curTargetState.expandedIds.LogAll("curTargetState"); } void registerStateChange() { if (!targetScrollPosChanged && !targetExpandedIdsChanged) return; prevTreeStates.Add(lastTreeState); nextTreeStates.Clear(); lastTargetStateChangeWasExpandedIds = targetExpandedIdsChanged; if (prevTreeStates.Count > 50) prevTreeStates.RemoveAt(0); // if (targetScrollPosChanged && targetExpandedIdsChanged) // "expand and scroll".Log(); // else if (targetScrollPosChanged) // "scroll".Log(); // else if (targetExpandedIdsChanged) // "expand".Log(); } void updateCountersSinceAnimation() { if (controller.animatingExpansion || treeViewAnimatesExpansion) framesSinceLastExpansionAnimation = 0; else framesSinceLastExpansionAnimation++; if (controller.animatingScroll || treeViewAnimatesScroll) framesSinceLastScrollAnimation = 0; else framesSinceLastScrollAnimation++; } set_curState_scrollPos(); set_curState_expandedIds(); checkScrollPosChange(); checkExpandedIdsChange(); registerStateChange(); updateCountersSinceAnimation(); lastTreeState = curTreeState; } int framesSinceLastExpansionAnimation; int framesSinceLastScrollAnimation; public double lastScrollTime = 0; bool lastTargetStateChangeWasExpandedIds; [System.NonSerialized] TreeState lastTreeState = null; public void CheckFolderPathChange() { if (!VFoldersMenu.navigationBarEnabled) return; if (isOneColumn) return; var curFolderPath = window.GetMemberValue("m_SearchFilter").GetMemberValue("folders").FirstOrDefault(); if (curFolderPath.IsNullOrEmpty()) return; if (lastFolderPath.IsNullOrEmpty()) lastFolderPath = curFolderPath; if (curFolderPath == lastFolderPath) return; prevFolderPaths.Add(lastFolderPath); nextFolderPaths.Clear(); if (prevFolderPaths.Count > 50) prevFolderPaths.RemoveAt(0); lastFolderPath = curFolderPath; } string lastFolderPath = ""; public void UpdateState() { if (!VFoldersMenu.navigationBarEnabled) return; isOneColumn = window.GetFieldValue("m_ViewMode") == 0; var treeViewController = window.GetFieldValue(isOneColumn ? "m_AssetTree" : "m_FolderTree"); var treeViewControllerData = treeViewController?.GetPropertyValue("data"); var treeViewControllerState = treeViewController?.GetPropertyValue("state"); currentScrollPos = treeViewControllerState?.scrollPos.y ?? 0; expandedIds = treeViewControllerState?.expandedIDs ?? new List(); var treeViewAnimator = treeViewController?.GetMemberValue("m_ExpansionAnimator"); var treeViewAnimatorSetup = treeViewAnimator?.GetMemberValue("m_Setup"); treeViewAnimatesScroll = treeViewController?.GetMemberValue("m_FramingAnimFloat").isAnimating ?? false; treeViewAnimatesExpansion = treeViewAnimator?.GetMemberValue("isAnimating") ?? false; animatingItemTragetExpanded_fromTreeViewExpandAnimator = treeViewAnimatorSetup?.GetMemberValue("expanding") ?? false; animatingItemId_fromTreeViewExpandAnimator = treeViewAnimatorSetup?.GetMemberValue("item").GetMemberValue("id") ?? 0; } public bool isOneColumn; public bool isTwoColumns => !isOneColumn; public bool isSearchActive; public float currentScrollPos; public List expandedIds = new(); public bool treeViewAnimatesScroll; public bool treeViewAnimatesExpansion; public bool animatingItemTragetExpanded_fromTreeViewExpandAnimator; public int animatingItemId_fromTreeViewExpandAnimator; public void MoveBack_OneColumn(bool withAnimation = true) { var prevState = prevTreeStates.Last(); prevTreeStates.Remove(prevState); nextTreeStates.Add(lastTreeState); lastTreeState = prevState; if (withAnimation) { controller.StartScrollAnimation(prevState.scrollPos); controller.StartExpandAnimation(prevState.expandedIds); } else { controller.SetScrollPos(prevState.scrollPos); controller.SetExpandedIds(prevState.expandedIds); } } public void MoveForward_OneColumn(bool withAnimation = true) { var nextState = nextTreeStates.Last(); nextTreeStates.Remove(nextState); prevTreeStates.Add(lastTreeState); lastTreeState = nextState; if (withAnimation) { controller.StartScrollAnimation(nextState.scrollPos); controller.StartExpandAnimation(nextState.expandedIds); } else { controller.SetScrollPos(nextState.scrollPos); controller.SetExpandedIds(nextState.expandedIds); } } public List prevTreeStates = new(); public List nextTreeStates = new(); public void MoveBack_TwoColumns(bool withAnimation = true) { var prevPath = prevFolderPaths.Last(); prevFolderPaths.RemoveLast(); nextFolderPaths.Add(lastFolderPath); lastFolderPath = prevPath; if (withAnimation) { controller.RevealFolder(prevPath, expand: false, highlight: false, snapToTopMargin: false); controller.OpenFolder(prevPath); } else { window.InvokeMethod("ShowFolderContents", AssetDatabase.LoadAssetAtPath(prevPath).GetInstanceID(), true); } } public void MoveForward_TwoColumns(bool withAnimation = true) { var nextPath = nextFolderPaths.Last(); nextFolderPaths.RemoveLast(); prevFolderPaths.Add(lastFolderPath); lastFolderPath = nextPath; if (withAnimation) { controller.RevealFolder(nextPath, expand: false, highlight: false, snapToTopMargin: false); controller.OpenFolder(nextPath); } else { window.InvokeMethod("ShowFolderContents", AssetDatabase.LoadAssetAtPath(nextPath).GetInstanceID(), true); } } public List prevFolderPaths = new(); public List nextFolderPaths = new(); [System.Serializable] public class TreeState { public List expandedIds = new(); public float scrollPos; } public VFoldersHistory(EditorWindow window) => this.window = window; EditorWindow window; VFoldersGUI gui => VFolders.guis_byWindow[window]; VFoldersController controller => VFolders.controllers_byWindow[window]; } public class VFoldersHistorySingleton : ScriptableSingleton { public SerializableDictionary histories_byWindow = new(); } } #endif