// Copyright (c) Wojciech Figat. All rights reserved. using System.Collections.Generic; using FlaxEditor.Content; using FlaxEditor.Content.GUI; using FlaxEditor.GUI; using FlaxEditor.GUI.Tree; namespace FlaxEditor.Windows { public partial class ContentWindow { private static readonly List NavUpdateCache = new List(8); private void OnTreeSelectionChanged(List from, List to) { bool setLastViewFolder = !IsLayoutLocked; if (!_showAllContentInTree && to.Count > 1) { _tree.Select(to[^1]); return; } if (_showAllContentInTree && to.Count > 1) { if (setLastViewFolder) { var activeNode = GetActiveTreeSelection(to); if (activeNode is ContentItemTreeNode itemNode) SaveLastViewedFolder(itemNode.Item?.ParentFolder?.Node); else SaveLastViewedFolder(activeNode as ContentFolderTreeNode); } UpdateUI(); return; } // Navigate var source = from.Count > 0 ? from[0] as ContentFolderTreeNode : null; var targetNode = GetActiveTreeSelection(to); if (targetNode is ContentItemTreeNode itemNode2) { if (setLastViewFolder) SaveLastViewedFolder(itemNode2.Item?.ParentFolder?.Node); UpdateUI(); itemNode2.Focus(); return; } var target = targetNode as ContentFolderTreeNode; Navigate(source, target); if (setLastViewFolder) SaveLastViewedFolder(target); target?.Focus(); } /// /// Navigates to the specified target content location. /// /// The target. public void Navigate(ContentFolderTreeNode target) { Navigate(SelectedNode, target); } private void Navigate(ContentFolderTreeNode source, ContentFolderTreeNode target) { if (target == null) target = _root; // Check if can do this action if (_navigationUnlocked && source != target) { // Lock navigation _navigationUnlocked = false; // Check if already added to the Undo on the top if (source != null && (_navigationUndo.Count == 0 || _navigationUndo.Peek() != source)) { // Add to Undo list _navigationUndo.Push(source); } // Show folder contents and select tree node if (!_showAllContentInTree) RefreshView(target); _tree.Select(target); target.ExpandAllParents(); // Clear redo list _navigationRedo.Clear(); // Set valid sizes for stacks //RedoList.SetSize(32); //UndoList.SetSize(32); // Update search if (!_showAllContentInTree) UpdateItemsSearch(); // Unlock navigation _navigationUnlocked = true; // Update UI UpdateUI(); } } /// /// Navigates backward. /// public void NavigateBackward() { // Check if navigation is unlocked if (_navigationUnlocked && _navigationUndo.Count > 0) { // Pop node ContentFolderTreeNode node = _navigationUndo.Pop(); // Lock navigation _navigationUnlocked = false; // Add to Redo list _navigationRedo.Push(SelectedNode); // Select node if (!_showAllContentInTree) RefreshView(node); _tree.Select(node); node.ExpandAllParents(); // Set valid sizes for stacks //RedoList.SetSize(32); //UndoList.SetSize(32); // Update search if (!_showAllContentInTree) UpdateItemsSearch(); // Unlock navigation _navigationUnlocked = true; // Update UI UpdateUI(); if (!_showAllContentInTree) _view.SelectFirstItem(); } } /// /// Navigates forward. /// public void NavigateForward() { // Check if navigation is unlocked if (_navigationUnlocked && _navigationRedo.Count > 0) { // Pop node ContentFolderTreeNode node = _navigationRedo.Pop(); // Lock navigation _navigationUnlocked = false; // Add to Undo list _navigationUndo.Push(SelectedNode); // Select node if (!_showAllContentInTree) RefreshView(node); _tree.Select(node); node.ExpandAllParents(); // Set valid sizes for stacks //RedoList.SetSize(32); //UndoList.SetSize(32); // Update search if (!_showAllContentInTree) UpdateItemsSearch(); // Unlock navigation _navigationUnlocked = true; // Update UI UpdateUI(); if (!_showAllContentInTree) _view.SelectFirstItem(); } } /// /// Navigates directory up. /// public void NavigateUp() { ContentFolderTreeNode target = _root; ContentFolderTreeNode current = SelectedNode; if (current?.Folder.ParentFolder != null) { target = current.Folder.ParentFolder.Node; } Navigate(target); } /// /// Clears the navigation history. /// public void NavigationClearHistory() { _navigationUndo.Clear(); _navigationRedo.Clear(); UpdateUI(); } private void UpdateNavigationBar() { if (_navigationBar == null) return; bool wasLayoutLocked = _navigationBar.IsLayoutLocked; _navigationBar.IsLayoutLocked = true; // Remove previous buttons _navigationBar.DisposeChildren(); // Spawn buttons var nodes = NavUpdateCache; nodes.Clear(); ContentFolderTreeNode node = SelectedNode; while (node != null) { nodes.Add(node); node = node.ParentNode; } float margin = 1; float x = NavigationBar.DefaultButtonsMargin; float h = _toolStrip.ItemsHeight - 2 * margin; for (int i = nodes.Count - 1; i >= 0; i--) { var button = new ContentNavigationButton(nodes[i], x, margin, h); button.PerformLayout(); x += button.Width + NavigationBar.DefaultButtonsMargin; _navigationBar.AddChild(button); if (i > 0) { var separator = new ContentNavigationSeparator(button, x, margin, h); separator.PerformLayout(); x += separator.Width + NavigationBar.DefaultButtonsMargin; _navigationBar.AddChild(separator); } } nodes.Clear(); // Update _navigationBar.IsLayoutLocked = wasLayoutLocked; _navigationBar.PerformLayout(); UpdateNavigationBarBounds(); } /// /// Gets the selected tree node. /// public ContentFolderTreeNode SelectedNode { get { var selected = GetActiveTreeSelection(_tree.Selection); if (selected is ContentItemTreeNode itemNode) return itemNode.Parent as ContentFolderTreeNode; return selected as ContentFolderTreeNode; } } /// /// Gets the current view folder. /// public ContentFolder CurrentViewFolder => SelectedNode?.Folder; private TreeNode GetActiveTreeSelection(List selection) { if (selection == null || selection.Count == 0) return null; return _showAllContentInTree && selection.Count > 1 ? selection[^1] : selection[0]; } /// /// Shows the root folder. /// public void ShowRoot() { _tree.Select(_root); } private void SaveLastViewedFolder(ContentFolderTreeNode node) { Editor.ProjectCache.SetCustomData(ProjectDataLastViewedFolder, node?.Path ?? string.Empty); } } }