Merge branch 'xxSeys1-CreateAssetOptions'

This commit is contained in:
Wojtek Figat
2026-03-08 22:21:56 +01:00
3 changed files with 125 additions and 32 deletions

View File

@@ -159,7 +159,7 @@ namespace FlaxEditor.Options
}
/// <summary>
/// Options focus Game Window behaviour when play mode is entered.
/// Options for focus Game Window behaviour when play mode is entered.
/// </summary>
public enum PlayModeFocus
{
@@ -179,6 +179,22 @@ namespace FlaxEditor.Options
GameWindowThenRestore,
}
/// <summary>
/// Generic options for a disabled or hidden state. Used for example in create content button.
/// </summary>
public enum DisabledHidden
{
/// <summary>
/// Disabled state.
/// </summary>
Disabled,
/// <summary>
/// Hidden state.
/// </summary>
Hidden,
}
/// <summary>
/// Gets or sets the Editor User Interface scale. Applied to all UI elements, windows and text. Can be used to scale the interface up on a bigger display. Editor restart required.
/// </summary>
@@ -525,6 +541,13 @@ namespace FlaxEditor.Options
[EditorDisplay("Visject", "Warn when deleting used parameter"), EditorOrder(552)]
public bool WarnOnDeletingUsedVisjectParameter { get; set; } = true;
/// <summary>
/// Gets or sets a value indicating what should happen to unavaliable options in the content create menu.
/// </summary>
[DefaultValue(DisabledHidden.Hidden)]
[EditorDisplay("Content"), EditorOrder(600)]
public DisabledHidden UnavaliableContentCreateOptions { get; set; } = DisabledHidden.Hidden;
private static FontAsset DefaultFont => FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.PrimaryFont);
private static FontAsset ConsoleFont => FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.InconsolataRegularFont);

View File

@@ -39,8 +39,7 @@ namespace FlaxEditor.Windows
folder = CurrentViewFolder;
}
Assert.IsNotNull(folder);
bool isRootFolder = CurrentViewFolder == _root.Folder;
// Create context menu
ContextMenuButton b;
ContextMenu cm = new ContextMenu
@@ -78,7 +77,7 @@ namespace FlaxEditor.Windows
cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(item.Path)));
if (!String.IsNullOrEmpty(Editor.Instance.Windows.ContentWin._itemsSearchBox.Text))
{
{
cm.AddButton("Show in Content Panel", () =>
{
Editor.Instance.Windows.ContentWin.ClearItemsSearch();
@@ -178,19 +177,61 @@ namespace FlaxEditor.Windows
cm.AddSeparator();
CreateNewModuleMenu(cm, folder);
CreateNewFolderMenu(cm, folder, false, item);
CreateNewContentItemMenu(cm, folder);
if (folder.CanHaveAssets)
{
cm.AddButton("Import file", () =>
{
_view.ClearSelection();
Editor.ContentImporting.ShowImportFileDialog(CurrentViewFolder);
});
}
// Remove any leftover separator
if (cm.ItemsContainer.Children.LastOrDefault() is ContextMenuSeparator)
cm.ItemsContainer.Children.Last().Dispose();
// Show it
cm.Show(this, location);
}
private void CreateNewModuleMenu(ContextMenu menu, ContentFolder folder, bool disableUncreatable = false)
{
// Check if is source folder to add new module
if (folder?.ParentFolder?.Node is ProjectTreeNode parentFolderNode && folder.Node == parentFolderNode.Source)
{
var button = cm.AddButton("New module");
var button = menu.AddButton("New module");
button.CloseMenuOnClick = false;
button.Clicked += () => NewModule(button, parentFolderNode.Source.Path);
}
if (!isRootFolder && !(item is ContentFolder projectFolder && projectFolder.Node is ProjectTreeNode))
else if (disableUncreatable)
{
cm.AddButton("New folder", NewFolder);
var button = menu.AddButton("New module");
button.Enabled = false;
}
}
private bool CanCreateFolder(ContentItem item = null)
{
bool canCreateFolder = CurrentViewFolder != _root.Folder && !(item is ContentFolder projectFolder && projectFolder.Node is ProjectTreeNode);
return canCreateFolder;
}
private void CreateNewFolderMenu(ContextMenu menu, ContentFolder folder, bool disableUncreatable = false, ContentItem item = null)
{
bool canCreateFolder = CanCreateFolder(item);
if (canCreateFolder || disableUncreatable)
{
var b = menu.AddButton("New folder", NewFolder);
b.Enabled = canCreateFolder;
}
}
private void CreateNewContentItemMenu(ContextMenu menu, ContentFolder folder, bool showNew = true, bool disableUncreatable = false)
{
// Loop through each proxy and user defined json type and add them to the context menu
var actorType = new ScriptType(typeof(Actor));
var scriptType = new ScriptType(typeof(Script));
@@ -230,7 +271,8 @@ namespace FlaxEditor.Windows
if (p == null)
continue;
if (p.CanCreate(folder))
bool canCreate = p.CanCreate(folder);
if (canCreate || disableUncreatable)
{
var parts = attribute.Path.Split('/');
ContextMenuChildMenu childCM = null;
@@ -238,16 +280,20 @@ namespace FlaxEditor.Windows
for (int i = 0; i < parts?.Length; i++)
{
var part = parts[i].Trim();
if (part == "New" && !showNew)
continue;
if (i == parts.Length - 1)
{
if (mainCM)
{
cm.AddButton(part, () => NewItem(p));
var b = menu.AddButton(part, () => NewItem(p));
b.Enabled = canCreate;
mainCM = false;
}
else if (childCM != null)
{
childCM.ContextMenu.AddButton(part, () => NewItem(p));
var b = childCM.ContextMenu.AddButton(part, () => NewItem(p));
b.Enabled = canCreate;
childCM.ContextMenu.AutoSort = true;
}
}
@@ -255,35 +301,21 @@ namespace FlaxEditor.Windows
{
if (mainCM)
{
childCM = cm.GetOrAddChildMenu(part);
childCM = menu.GetOrAddChildMenu(part);
childCM.ContextMenu.AutoSort = true;
childCM.Enabled = canCreate;
mainCM = false;
}
else if (childCM != null)
{
childCM = childCM.ContextMenu.GetOrAddChildMenu(part);
childCM.ContextMenu.AutoSort = true;
childCM.Enabled = canCreate;
}
}
}
}
}
if (folder.CanHaveAssets)
{
cm.AddButton("Import file", () =>
{
_view.ClearSelection();
Editor.ContentImporting.ShowImportFileDialog(CurrentViewFolder);
});
}
// Remove any leftover separator
if (cm.ItemsContainer.Children.LastOrDefault() is ContextMenuSeparator)
cm.ItemsContainer.Children.Last().Dispose();
// Show it
cm.Show(this, location);
}
private void OnExpandAllClicked(ContextMenuButton button)

View File

@@ -37,6 +37,7 @@ namespace FlaxEditor.Windows
private readonly ToolStrip _toolStrip;
private readonly ToolStripButton _importButton;
private readonly ToolStripButton _createNewButton;
private readonly ToolStripButton _navigateBackwardButton;
private readonly ToolStripButton _navigateForwardButton;
private readonly ToolStripButton _navigateUpButton;
@@ -154,11 +155,12 @@ namespace FlaxEditor.Windows
{
Parent = this,
};
_importButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.Import64, () => Editor.ContentImporting.ShowImportFileDialog(CurrentViewFolder)).LinkTooltip("Import content");
_importButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.Import64, () => Editor.ContentImporting.ShowImportFileDialog(CurrentViewFolder)).LinkTooltip("Import content.");
_createNewButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.Add64, OnCreateNewItemButtonClicked).LinkTooltip("Create a new asset. Shift + left click to create a new folder.");
_toolStrip.AddSeparator();
_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");
_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
@@ -271,6 +273,42 @@ namespace FlaxEditor.Windows
InputActions.Add(options => options.Search, () => _itemsSearchBox.Focus());
}
private void OnCreateNewItemButtonClicked()
{
if (Input.GetKey(KeyboardKeys.Shift) && CanCreateFolder())
{
NewFolder();
return;
}
var menu = new ContextMenu();
InterfaceOptions interfaceOptions = Editor.Instance.Options.Options.Interface;
bool disableUnavaliable = interfaceOptions.UnavaliableContentCreateOptions == InterfaceOptions.DisabledHidden.Disabled;
CreateNewFolderMenu(menu, CurrentViewFolder, disableUnavaliable);
CreateNewModuleMenu(menu, CurrentViewFolder, disableUnavaliable);
menu.AddSeparator();
CreateNewContentItemMenu(menu, CurrentViewFolder, false, disableUnavaliable);
// Hack: Show the menu once to get the direction, then show it above or below the button depending on the direction.
menu.Show(this, _createNewButton.UpperLeft);
var direction = menu.Direction;
menu.Hide();
bool below = false;
switch (direction)
{
case ContextMenuDirection.RightDown:
case ContextMenuDirection.LeftDown:
below = true;
break;
case ContextMenuDirection.RightUp:
case ContextMenuDirection.LeftUp:
below = false;
break;
}
menu.Show(this, below ? _createNewButton.BottomLeft : _createNewButton.UpperLeft, direction);
}
private ContextMenu OnViewDropdownPopupCreate(ComboBox comboBox)
{
var menu = new ContextMenu();