diff --git a/Source/Editor/Content/GUI/ContentNavigationButton.cs b/Source/Editor/Content/GUI/ContentNavigation.cs similarity index 58% rename from Source/Editor/Content/GUI/ContentNavigationButton.cs rename to Source/Editor/Content/GUI/ContentNavigation.cs index d37e1629b..7adf6aa62 100644 --- a/Source/Editor/Content/GUI/ContentNavigationButton.cs +++ b/Source/Editor/Content/GUI/ContentNavigation.cs @@ -1,6 +1,7 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using FlaxEditor.GUI; +using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.Drag; using FlaxEngine; using FlaxEngine.GUI; @@ -31,7 +32,7 @@ namespace FlaxEditor.Content.GUI : base(x, y, height) { TargetNode = targetNode; - Text = targetNode.NavButtonLabel + "/"; + Text = targetNode.NavButtonLabel; } /// @@ -72,7 +73,6 @@ namespace FlaxEditor.Content.GUI if (_dragOverItems == null) _dragOverItems = new DragItems(ValidateDragItem); - _dragOverItems.OnDragEnter(data); var result = GetDragEffect(data); _validDragOver = result != DragDropEffect.None; @@ -122,4 +122,70 @@ namespace FlaxEditor.Content.GUI return result; } } + + sealed class ContentNavigationSeparator : ComboBox + { + public ContentNavigationButton Target; + + public ContentNavigationSeparator(ContentNavigationButton target, float x, float y, float height) + { + Target = target; + Bounds = new Rectangle(x, y, 16, height); + Offsets = new Margin(Bounds.X, Bounds.Width, Bounds.Y, Bounds.Height); + UpdateTransform(); + + MaximumItemsInViewCount = 20; + var style = Style.Current; + BackgroundColor = style.BackgroundNormal; + BackgroundColorHighlighted = BackgroundColor; + BackgroundColorSelected = BackgroundColor; + } + + protected override ContextMenu OnCreatePopup() + { + // Update items + ClearItems(); + foreach (var child in Target.TargetNode.Children) + { + if (child is ContentTreeNode node) + { + if (node.Folder.VisibleInHierarchy) // Respect the filter set by ContentFilterConfig.Filter(...) + AddItem(node.Folder.ShortName); + } + } + + return base.OnCreatePopup(); + } + + public override void Draw() + { + var style = Style.Current; + var rect = new Rectangle(Float2.Zero, Size); + var color = IsDragOver ? style.BackgroundSelected * 0.6f : (_mouseDown ? style.BackgroundSelected : (IsMouseOver ? style.BackgroundHighlighted : Color.Transparent)); + Render2D.FillRectangle(rect, color); + Render2D.DrawSprite(Editor.Instance.Icons.ArrowRight12, new Rectangle(rect.Location.X, rect.Y + rect.Size.Y * 0.25f, rect.Size.X, rect.Size.X), EnabledInHierarchy ? style.Foreground : style.ForegroundDisabled); + } + + protected override void OnLayoutMenuButton(ContextMenuButton button, int index, bool construct = false) + { + button.Icon = Editor.Instance.Icons.FolderClosed32; + if (_tooltips != null && _tooltips.Length > index) + button.TooltipText = _tooltips[index]; + } + + protected override void OnItemClicked(int index) + { + base.OnItemClicked(index); + + var item = _items[index]; + foreach (var child in Target.TargetNode.Children) + { + if (child is ContentTreeNode node && node.Folder.ShortName == item) + { + Editor.Instance.Windows.ContentWin.Navigate(node); + return; + } + } + } + } } diff --git a/Source/Editor/Content/GUI/ContentView.cs b/Source/Editor/Content/GUI/ContentView.cs index 40a06c1b6..5e054e5c6 100644 --- a/Source/Editor/Content/GUI/ContentView.cs +++ b/Source/Editor/Content/GUI/ContentView.cs @@ -261,11 +261,14 @@ namespace FlaxEditor.Content.GUI ClearItems(); // Add references and link items - _items.AddRange(items); for (int i = 0; i < items.Count; i++) { - items[i].Parent = this; - items[i].AddReference(this); + if (items[i].Visible) + { + items[i].Parent = this; + items[i].AddReference(this); + _items.Add(items[i]); + } } if (selection != null) { diff --git a/Source/Editor/Content/Items/ContentItem.cs b/Source/Editor/Content/Items/ContentItem.cs index b27159aa0..94db3a5b9 100644 --- a/Source/Editor/Content/Items/ContentItem.cs +++ b/Source/Editor/Content/Items/ContentItem.cs @@ -441,6 +441,9 @@ namespace FlaxEditor.Content { get { + // Skip when hidden + if (!Visible) + return Rectangle.Empty; var view = Parent as ContentView; var size = Size; switch (view?.ViewType ?? ContentViewType.Tiles) @@ -666,7 +669,6 @@ namespace FlaxEditor.Content /// public override void Draw() { - // Cache data var size = Size; var style = Style.Current; var view = Parent as ContentView; diff --git a/Source/Editor/Content/Tree/RootContentTreeNode.cs b/Source/Editor/Content/Tree/RootContentTreeNode.cs index 6dde4cbb2..328c51874 100644 --- a/Source/Editor/Content/Tree/RootContentTreeNode.cs +++ b/Source/Editor/Content/Tree/RootContentTreeNode.cs @@ -17,6 +17,6 @@ namespace FlaxEditor.Content } /// - public override string NavButtonLabel => string.Empty; + public override string NavButtonLabel => " /"; } } diff --git a/Source/Editor/GUI/ComboBox.cs b/Source/Editor/GUI/ComboBox.cs index 2481316d0..da2106450 100644 --- a/Source/Editor/GUI/ComboBox.cs +++ b/Source/Editor/GUI/ComboBox.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using FlaxEditor.GUI.ContextMenu; using FlaxEngine; using FlaxEngine.GUI; @@ -396,14 +397,24 @@ namespace FlaxEditor.GUI _popupMenu.ButtonClicked += btn => { OnItemClicked((int)btn.Tag); - _popupMenu?.Hide(); + if (SupportMultiSelect) + { + // Don't hide in multi-select, so user can edit multiple elements instead of just one + UpdateButtons(); + _popupMenu?.PerformLayout(); + } + else + { + _popupMenu?.Hide(); + } }; } // Check if menu hs been already shown if (_popupMenu.Visible) { - _popupMenu.Hide(); + if (!SupportMultiSelect) + _popupMenu.Hide(); return; } @@ -412,27 +423,7 @@ namespace FlaxEditor.GUI // Check if has any items if (_items.Count > 0) { - // Setup items list - var itemControls = _popupMenu.Items.ToArray(); - foreach (var e in itemControls) - e.Dispose(); - if (Sorted) - _items.Sort(); - var style = Style.Current; - for (int i = 0; i < _items.Count; i++) - { - var btn = _popupMenu.AddButton(_items[i]); - if (_selectedIndices.Contains(i)) - { - btn.Icon = style.CheckBoxTick; - } - if (_tooltips != null && _tooltips.Length > i) - { - btn.TooltipText = _tooltips[i]; - } - - btn.Tag = i; - } + UpdateButtons(); // Show dropdown list _popupMenu.MinimumWidth = Width; @@ -440,6 +431,54 @@ namespace FlaxEditor.GUI } } + /// + /// Updates buttons layout. + /// + private void UpdateButtons() + { + if (_popupMenu.Items.Count() != _items.Count) + { + var itemControls = _popupMenu.Items.ToArray(); + foreach (var e in itemControls) + e.Dispose(); + if (Sorted) + _items.Sort(); + for (int i = 0; i < _items.Count; i++) + { + var btn = _popupMenu.AddButton(_items[i]); + OnLayoutMenuButton(btn, i, true); + btn.Tag = i; + } + } + else + { + var itemControls = _popupMenu.Items.ToArray(); + if (Sorted) + _items.Sort(); + for (int i = 0; i < _items.Count; i++) + { + if (itemControls[i] is ContextMenuButton btn) + { + btn.Text = _items[i]; + OnLayoutMenuButton(btn, i, true); + } + } + } + } + + /// + /// Called when button is created or updated. Can be used to customize the visuals. + /// + /// The button. + /// The item index. + /// true if button is created else it is repainting the button + protected virtual void OnLayoutMenuButton(ContextMenuButton button, int index, bool construct = false) + { + button.Checked = _selectedIndices.Contains(index); + if (_tooltips != null && _tooltips.Length > index) + button.TooltipText = _tooltips[index]; + } + /// /// Creates the popup menu. /// @@ -460,6 +499,8 @@ namespace FlaxEditor.GUI _popupMenu = null; } + if (IsDisposing) + return; _selectedIndices.Clear(); _selectedIndices = null; _items.Clear(); diff --git a/Source/Editor/GUI/ContextMenu/ContextMenuButton.cs b/Source/Editor/GUI/ContextMenu/ContextMenuButton.cs index c2b130e4e..e371f7c4b 100644 --- a/Source/Editor/GUI/ContextMenu/ContextMenuButton.cs +++ b/Source/Editor/GUI/ContextMenu/ContextMenuButton.cs @@ -138,7 +138,7 @@ namespace FlaxEditor.GUI.ContextMenu // Draw icon const float iconSize = 14; - var icon = Checked ? Style.Current.CheckBoxTick : Icon; + var icon = Checked ? style.CheckBoxTick : Icon; if (icon.IsValid) Render2D.DrawSprite(icon, new Rectangle(-iconSize - 1, (Height - iconSize) / 2, iconSize, iconSize), textColor); } diff --git a/Source/Editor/GUI/NavigationBar.cs b/Source/Editor/GUI/NavigationBar.cs index 3c717423b..b3811b4a9 100644 --- a/Source/Editor/GUI/NavigationBar.cs +++ b/Source/Editor/GUI/NavigationBar.cs @@ -50,14 +50,9 @@ namespace FlaxEditor.GUI { if (toolstrip == null) return; - var lastToolstripButton = toolstrip.LastButton; var parentSize = Parent.Size; - Bounds = new Rectangle - ( - new Float2(lastToolstripButton.Right + 8.0f, 0), - new Float2(parentSize.X - X - 8.0f, toolstrip.Height) - ); + Bounds = new Rectangle(lastToolstripButton.Right + 8.0f, 0, parentSize.X - X - 8.0f, toolstrip.Height); } } } diff --git a/Source/Editor/Modules/ContentDatabaseModule.cs b/Source/Editor/Modules/ContentDatabaseModule.cs index ecafbf5d4..29d6b2c00 100644 --- a/Source/Editor/Modules/ContentDatabaseModule.cs +++ b/Source/Editor/Modules/ContentDatabaseModule.cs @@ -902,6 +902,23 @@ namespace FlaxEditor.Modules } if (sortChildren) node.SortChildren(); + + // Ignore some special folders + if (node is MainContentTreeNode mainNode && mainNode.Folder.ShortName == "Source") + { + var mainNodeChild = mainNode.Folder.Find(StringUtils.CombinePaths(mainNode.Path, "obj")) as ContentFolder; + if (mainNodeChild != null) + { + mainNodeChild.Visible = false; + mainNodeChild.Node.Visible = false; + } + mainNodeChild = mainNode.Folder.Find(StringUtils.CombinePaths(mainNode.Path, "Properties")) as ContentFolder; + if (mainNodeChild != null) + { + mainNodeChild.Visible = false; + mainNodeChild.Node.Visible = false; + } + } } private void LoadScripts(ContentTreeNode parent, string[] files) diff --git a/Source/Editor/Windows/ContentWindow.Navigation.cs b/Source/Editor/Windows/ContentWindow.Navigation.cs index ad690c2d0..b1def7ae8 100644 --- a/Source/Editor/Windows/ContentWindow.Navigation.cs +++ b/Source/Editor/Windows/ContentWindow.Navigation.cs @@ -202,6 +202,13 @@ namespace FlaxEditor.Windows button.PerformLayout(); x += button.Width + NavigationBar.DefaultButtonsMargin; _navigationBar.AddChild(button); + if (i > 0) + { + var separator = new ContentNavigationSeparator(button, x, ToolStrip.DefaultMarginV, h); + separator.PerformLayout(); + x += separator.Width + NavigationBar.DefaultButtonsMargin; + _navigationBar.AddChild(separator); + } } nodes.Clear(); @@ -218,21 +225,13 @@ namespace FlaxEditor.Windows /// /// Gets the current view folder. /// - public ContentFolder CurrentViewFolder - { - get - { - var node = SelectedNode; - return node?.Folder; - } - } + public ContentFolder CurrentViewFolder => SelectedNode?.Folder; /// /// Shows the root folder. /// public void ShowRoot() { - // Show root folder _tree.Select(_root); } } diff --git a/Source/Editor/Windows/ContentWindow.Search.cs b/Source/Editor/Windows/ContentWindow.Search.cs index a6fd2c81e..a1072d158 100644 --- a/Source/Editor/Windows/ContentWindow.Search.cs +++ b/Source/Editor/Windows/ContentWindow.Search.cs @@ -191,6 +191,7 @@ namespace FlaxEditor.Windows } // Search by filter only + bool showAllFiles = _showAllFiles; if (string.IsNullOrWhiteSpace(query)) { if (SelectedNode == _root) @@ -199,12 +200,12 @@ namespace FlaxEditor.Windows for (int i = 0; i < _root.ChildrenCount; i++) { if (_root.GetChild(i) is ContentTreeNode node) - UpdateItemsSearchFilter(node.Folder, items, filters); + UpdateItemsSearchFilter(node.Folder, items, filters, showAllFiles); } } else { - UpdateItemsSearchFilter(CurrentViewFolder, items, filters); + UpdateItemsSearchFilter(CurrentViewFolder, items, filters, showAllFiles); } } // Search by asset ID @@ -221,12 +222,12 @@ namespace FlaxEditor.Windows for (int i = 0; i < _root.ChildrenCount; i++) { if (_root.GetChild(i) is ContentTreeNode node) - UpdateItemsSearchFilter(node.Folder, items, filters, query); + UpdateItemsSearchFilter(node.Folder, items, filters, showAllFiles, query); } } else { - UpdateItemsSearchFilter(CurrentViewFolder, items, filters, query); + UpdateItemsSearchFilter(CurrentViewFolder, items, filters, showAllFiles, query); } } @@ -234,42 +235,34 @@ namespace FlaxEditor.Windows _view.ShowItems(items, _sortType); } - private void UpdateItemsSearchFilter(ContentFolder folder, List items, bool[] filters) + private void UpdateItemsSearchFilter(ContentFolder folder, List items, bool[] filters, bool showAllFiles) { for (int i = 0; i < folder.Children.Count; i++) { var child = folder.Children[i]; - if (child is ContentFolder childFolder) { - UpdateItemsSearchFilter(childFolder, items, filters); + UpdateItemsSearchFilter(childFolder, items, filters, showAllFiles); } - else + else if (filters[(int)child.SearchFilter] && (showAllFiles || !(child is FileItem))) { - if (filters[(int)child.SearchFilter]) - { - items.Add(child); - } + items.Add(child); } } } - private void UpdateItemsSearchFilter(ContentFolder folder, List items, bool[] filters, string filterText) + private void UpdateItemsSearchFilter(ContentFolder folder, List items, bool[] filters, bool showAllFiles, string filterText) { for (int i = 0; i < folder.Children.Count; i++) { var child = folder.Children[i]; - if (child is ContentFolder childFolder) { - UpdateItemsSearchFilter(childFolder, items, filters, filterText); + UpdateItemsSearchFilter(childFolder, items, filters, showAllFiles, filterText); } - else if (filters[(int)child.SearchFilter]) + else if (filters[(int)child.SearchFilter] && (showAllFiles || !(child is FileItem)) && QueryFilterHelper.Match(filterText, child.ShortName)) { - if (filters[(int)child.SearchFilter] && QueryFilterHelper.Match(filterText, child.ShortName)) - { - items.Add(child); - } + items.Add(child); } } } diff --git a/Source/Editor/Windows/ContentWindow.cs b/Source/Editor/Windows/ContentWindow.cs index 9d782b13b..f4fb4afdc 100644 --- a/Source/Editor/Windows/ContentWindow.cs +++ b/Source/Editor/Windows/ContentWindow.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Linq; using System.Xml; using FlaxEditor.Content; using FlaxEditor.Content.GUI; @@ -45,6 +46,7 @@ namespace FlaxEditor.Windows private TextBox _itemsSearchBox; private ViewDropdown _viewDropdown; private SortType _sortType; + private bool _showEngineFiles = true, _showPluginsFiles = true, _showAllFiles = true; private RootContentTreeNode _root; @@ -64,6 +66,57 @@ namespace FlaxEditor.Windows /// public ContentView View => _view; + internal bool ShowEngineFiles + { + get => _showEngineFiles; + set + { + if (_showEngineFiles != value) + { + _showEngineFiles = value; + if (Editor.ContentDatabase.Engine != null) + { + Editor.ContentDatabase.Engine.Visible = value; + Editor.ContentDatabase.Engine.Folder.Visible = value; + RefreshView(); + } + } + } + } + + internal bool ShowPluginsFiles + { + get => _showPluginsFiles; + set + { + if (_showPluginsFiles != value) + { + _showPluginsFiles = value; + foreach (var project in Editor.ContentDatabase.Projects) + { + if (project == Editor.ContentDatabase.Game || project == Editor.ContentDatabase.Engine) + continue; + project.Visible = value; + project.Folder.Visible = value; + RefreshView(); + } + } + } + } + + internal bool ShowAllFiles + { + get => _showAllFiles; + set + { + if (_showAllFiles != value) + { + _showAllFiles = value; + RefreshView(); + } + } + } + /// /// Initializes a new instance of the class. /// @@ -107,11 +160,12 @@ namespace FlaxEditor.Windows _navigateBackwardButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.Left64, NavigateBackward).LinkTooltip("Navigate backward"); _navigateForwardButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.Right64, NavigateForward).LinkTooltip("Navigate forward"); _navigateUpButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.Up64, NavigateUp).LinkTooltip("Navigate up"); + _toolStrip.AddSeparator(); // Navigation bar _navigationBar = new NavigationBar { - Parent = this, + Parent = _toolStrip, }; // Split panel @@ -216,10 +270,6 @@ namespace FlaxEditor.Windows { var menu = new ContextMenu(); - var showFileExtensionsButton = menu.AddButton("Show file extensions", () => View.ShowFileExtensions = !View.ShowFileExtensions); - showFileExtensionsButton.Checked = View.ShowFileExtensions; - showFileExtensionsButton.AutoCheck = true; - var viewScale = menu.AddButton("View Scale"); viewScale.CloseMenuOnClick = false; var scaleValue = new FloatValueBox(1, 75, 2, 50.0f, 0.3f, 3.0f, 0.01f) @@ -243,6 +293,33 @@ namespace FlaxEditor.Windows } }; + var show = menu.AddChildMenu("Show"); + { + var b = show.ContextMenu.AddButton("File extensions", () => View.ShowFileExtensions = !View.ShowFileExtensions); + b.TooltipText = "Shows all files with extensions"; + b.Checked = View.ShowFileExtensions; + b.CloseMenuOnClick = false; + b.AutoCheck = true; + + b = show.ContextMenu.AddButton("Engine files", () => ShowEngineFiles = !ShowEngineFiles); + b.TooltipText = "Shows in-built engine content"; + b.Checked = ShowEngineFiles; + b.CloseMenuOnClick = false; + b.AutoCheck = true; + + b = show.ContextMenu.AddButton("Plugins files", () => ShowPluginsFiles = !ShowPluginsFiles); + b.TooltipText = "Shows plugin projects content"; + b.Checked = ShowPluginsFiles; + b.CloseMenuOnClick = false; + b.AutoCheck = true; + + b = show.ContextMenu.AddButton("All files", () => ShowAllFiles = !ShowAllFiles); + b.TooltipText = "Shows all files including other than assets and source code"; + b.Checked = ShowAllFiles; + b.CloseMenuOnClick = false; + b.AutoCheck = true; + } + var filters = menu.AddChildMenu("Filters"); for (int i = 0; i < _viewDropdown.Items.Count; i++) { @@ -351,7 +428,7 @@ namespace FlaxEditor.Windows { if (!item.CanRename) return; - + // Show element in the view Select(item, true); @@ -428,10 +505,7 @@ namespace FlaxEditor.Windows if (!Editor.ContentEditing.IsValidAssetName(item, newShortName, out string hint)) { // Invalid name - MessageBox.Show("Given asset name is invalid. " + hint, - "Invalid name", - MessageBoxButtons.OK, - MessageBoxIcon.Error); + MessageBox.Show("Given asset name is invalid. " + hint, "Invalid name", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } @@ -877,7 +951,7 @@ namespace FlaxEditor.Windows if (target == _root) { // Special case for root folder - List items = new List(8); + var items = new List(8); for (int i = 0; i < _root.ChildrenCount; i++) { if (_root.GetChild(i) is ContentTreeNode node) @@ -890,7 +964,10 @@ namespace FlaxEditor.Windows else { // Show folder contents - _view.ShowItems(target.Folder.Children, _sortType, false, true); + var items = target.Folder.Children; + if (!_showAllFiles) + items = items.Where(x => !(x is FileItem)).ToList(); + _view.ShowItems(items, _sortType, false, true); } } @@ -913,12 +990,6 @@ namespace FlaxEditor.Windows _navigateUpButton.Enabled = folder != null && _tree.SelectedNode != _root; } - private void RemoveFolder2Root(ContentTreeNode node) - { - // Remove from the root - _root.RemoveChild(node); - } - /// public override void OnInit() { @@ -937,8 +1008,12 @@ namespace FlaxEditor.Windows project.SortChildrenRecursive(); if (project == Editor.ContentDatabase.Game || project == Editor.ContentDatabase.Engine) continue; + project.Visible = _showPluginsFiles; + project.Folder.Visible = _showPluginsFiles; _root.AddChild(project); } + Editor.ContentDatabase.Engine.Visible = _showEngineFiles; + Editor.ContentDatabase.Engine.Folder.Visible = _showEngineFiles; _root.AddChild(Editor.ContentDatabase.Engine); Editor.ContentDatabase.Game?.Expand(true); @@ -1010,7 +1085,6 @@ namespace FlaxEditor.Windows /// public override bool OnMouseUp(Float2 location, MouseButton button) { - // Check if it's a right mouse button if (button == MouseButton.Right) { // Find control that is under the mouse @@ -1066,6 +1140,9 @@ namespace FlaxEditor.Windows LayoutSerializeSplitter(writer, "Split", _split); writer.WriteAttributeString("Scale", _view.ViewScale.ToString(CultureInfo.InvariantCulture)); writer.WriteAttributeString("ShowFileExtensions", _view.ShowFileExtensions.ToString()); + writer.WriteAttributeString("ShowEngineFiles", ShowEngineFiles.ToString()); + writer.WriteAttributeString("ShowPluginsFiles", ShowPluginsFiles.ToString()); + writer.WriteAttributeString("ShowAllFiles", ShowAllFiles.ToString()); writer.WriteAttributeString("ViewType", _view.ViewType.ToString()); } @@ -1077,6 +1154,12 @@ namespace FlaxEditor.Windows _view.ViewScale = value1; if (bool.TryParse(node.GetAttribute("ShowFileExtensions"), out bool value2)) _view.ShowFileExtensions = value2; + if (bool.TryParse(node.GetAttribute("ShowEngineFiles"), out value2)) + ShowEngineFiles = value2; + if (bool.TryParse(node.GetAttribute("ShowPluginsFiles"), out value2)) + ShowPluginsFiles = value2; + if (bool.TryParse(node.GetAttribute("ShowAllFiles"), out value2)) + ShowAllFiles = value2; if (Enum.TryParse(node.GetAttribute("ViewType"), out ContentViewType viewType)) _view.ViewType = viewType; }