You're breathtaking!

This commit is contained in:
Wojtek Figat
2020-12-07 23:40:54 +01:00
commit 6fb9eee74c
5143 changed files with 1153594 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
using System;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.GUI
{
/// <summary>
/// Popup that shows the list of actors to pick. Supports searching and basic type filtering.
/// </summary>
/// <seealso cref="FlaxEditor.GUI.ItemsListContextMenu" />
public class ActorSearchPopup : ItemsListContextMenu
{
/// <summary>
/// The actor item.
/// </summary>
/// <seealso cref="FlaxEditor.GUI.ItemsListContextMenu.Item" />
public class ActorItemView : Item
{
private Actor _actor;
/// <summary>
/// Gets the actor.
/// </summary>
public Actor Actor => _actor;
/// <summary>
/// Initializes a new instance of the <see cref="ActorItemView"/> class.
/// </summary>
/// <param name="actor">The actor.</param>
public ActorItemView(Actor actor)
{
_actor = actor;
Name = actor.Name;
TooltipText = actor.TypeName;
}
/// <inheritdoc />
public override void OnDestroy()
{
_actor = null;
base.OnDestroy();
}
}
/// <summary>
/// Validates if the given actor item can be used to pick it.
/// </summary>
/// <param name="actor">The actor.</param>
/// <returns>True if is valid.</returns>
public delegate bool IsValidDelegate(Actor actor);
private IsValidDelegate _isValid;
private Action<Actor> _selected;
private ActorSearchPopup(IsValidDelegate isValid, Action<Actor> selected)
{
_isValid = isValid;
_selected = selected;
ItemClicked += OnItemClicked;
// TODO: use async thread to search scenes
for (int i = 0; i < Level.ScenesCount; i++)
{
Find(Level.GetScene(i));
}
SortChildren();
}
private void OnItemClicked(Item item)
{
_selected(((ActorItemView)item).Actor);
}
private void Find(Actor actor)
{
if (!actor)
return;
if (_isValid(actor))
{
AddItem(new ActorItemView(actor));
}
for (int i = 0; i < actor.ChildrenCount; i++)
{
Find(actor.GetChild(i));
}
}
/// <summary>
/// Shows the popup.
/// </summary>
/// <param name="showTarget">The show target.</param>
/// <param name="showTargetLocation">The show target location.</param>
/// <param name="isValid">Event called to check if a given actor item is valid to be used.</param>
/// <param name="selected">Event called on actor item pick.</param>
/// <returns>The dialog.</returns>
public static ActorSearchPopup Show(Control showTarget, Vector2 showTargetLocation, IsValidDelegate isValid, Action<Actor> selected)
{
var popup = new ActorSearchPopup(isValid, selected);
popup.Show(showTarget, showTargetLocation);
return popup;
}
/// <inheritdoc />
public override void OnDestroy()
{
_isValid = null;
_selected = null;
base.OnDestroy();
}
}
}

View File

@@ -0,0 +1,176 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
using System;
using FlaxEditor.Content;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.GUI
{
/// <summary>
/// Popup that shows the list of assets to pick. Supports searching and basic items filtering.
/// </summary>
/// <seealso cref="FlaxEditor.GUI.ItemsListContextMenu" />
public class AssetSearchPopup : ItemsListContextMenu
{
/// <summary>
/// The asset item.
/// </summary>
/// <seealso cref="FlaxEditor.GUI.ItemsListContextMenu.Item" />
public class AssetItemView : Item, IContentItemOwner
{
private AssetItem _asset;
/// <summary>
/// The icon size (in pixels).
/// </summary>
public const float IconSize = 28;
/// <summary>
/// Gets the asset.
/// </summary>
public AssetItem Asset => _asset;
/// <summary>
/// Initializes a new instance of the <see cref="AssetItemView"/> class.
/// </summary>
/// <param name="asset">The asset.</param>
public AssetItemView(AssetItem asset)
{
_asset = asset;
_asset.AddReference(this);
Name = asset.ShortName;
TooltipText = asset.Path;
Height = IconSize + 4;
}
/// <inheritdoc />
protected override void GetTextRect(out Rectangle rect)
{
var height = Height;
rect = new Rectangle(IconSize + 4, (height - 16) * 0.5f, Width - IconSize - 6, 16);
}
/// <inheritdoc />
public override void Draw()
{
base.Draw();
// Draw icon
var iconRect = new Rectangle(2, 2, IconSize, IconSize);
_asset.DrawThumbnail(ref iconRect);
}
/// <inheritdoc />
public override void OnDestroy()
{
if (_asset != null)
{
_asset.RemoveReference(this);
_asset = null;
}
base.OnDestroy();
}
/// <inheritdoc />
public void OnItemDeleted(ContentItem item)
{
Dispose();
}
/// <inheritdoc />
public void OnItemRenamed(ContentItem item)
{
Name = _asset.ShortName;
}
/// <inheritdoc />
public void OnItemReimported(ContentItem item)
{
}
/// <inheritdoc />
public void OnItemDispose(ContentItem item)
{
Dispose();
}
}
/// <summary>
/// Validates if the given asset item can be used to pick it.
/// </summary>
/// <param name="asset">The asset.</param>
/// <returns>True if is valid.</returns>
public delegate bool IsValidDelegate(AssetItem asset);
private IsValidDelegate _isValid;
private Action<AssetItem> _selected;
private AssetSearchPopup(IsValidDelegate isValid, Action<AssetItem> selected)
{
_isValid = isValid;
_selected = selected;
ItemClicked += OnItemClicked;
// TODO: use async thread to search workspace items
foreach (var project in Editor.Instance.ContentDatabase.Projects)
{
if (project.Content != null)
FindAssets(project.Content.Folder);
}
SortChildren();
}
private void OnItemClicked(Item item)
{
_selected(((AssetItemView)item).Asset);
}
private void FindAssets(ContentFolder folder)
{
for (int i = 0; i < folder.Children.Count; i++)
{
if (folder.Children[i] is AssetItem asset && _isValid(asset))
{
AddItem(new AssetItemView(asset));
}
}
for (int i = 0; i < folder.Children.Count; i++)
{
if (folder.Children[i] is ContentFolder child)
{
FindAssets(child);
}
}
}
/// <summary>
/// Shows the popup.
/// </summary>
/// <param name="showTarget">The show target.</param>
/// <param name="showTargetLocation">The show target location.</param>
/// <param name="isValid">Event called to check if a given asset item is valid to be used.</param>
/// <param name="selected">Event called on asset item pick.</param>
/// <returns>The dialog.</returns>
public static AssetSearchPopup Show(Control showTarget, Vector2 showTargetLocation, IsValidDelegate isValid, Action<AssetItem> selected)
{
var popup = new AssetSearchPopup(isValid, selected);
popup.Show(showTarget, showTargetLocation);
return popup;
}
/// <inheritdoc />
public override void OnDestroy()
{
_isValid = null;
_selected = null;
base.OnDestroy();
}
}
}

View File

@@ -0,0 +1,193 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
using System;
using FlaxEditor.GUI.ContextMenu;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.GUI
{
/// <summary>
/// Popup menu useful for renaming objects via UI. Displays text box for renaming.
/// </summary>
/// <seealso cref="ContextMenuBase" />
public class RenamePopup : ContextMenuBase
{
private string _startValue;
private TextBox _inputField;
/// <summary>
/// Occurs when renaming is done.
/// </summary>
public event Action<RenamePopup> Renamed;
/// <summary>
/// Occurs when popup is closing (after renaming done or not).
/// </summary>
public event Action<RenamePopup> Closed;
/// <summary>
/// Input value validation delegate.
/// </summary>
/// <param name="popup">The popup reference.</param>
/// <param name="value">The input text value.</param>
/// <returns>True if text is valid, otherwise false.</returns>
public delegate bool ValidateDelegate(RenamePopup popup, string value);
/// <summary>
/// Occurs when input text validation should be performed.
/// </summary>
public ValidateDelegate Validate;
/// <summary>
/// Gets or sets the initial value.
/// </summary>
/// <value>
/// The initial value.
/// </value>
public string InitialValue
{
get => _startValue;
set => _startValue = value;
}
/// <summary>
/// Gets or sets the input field text.
/// </summary>
/// <value>
/// The text.
/// </value>
public string Text
{
get => _inputField.Text;
set => _inputField.Text = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="RenamePopup"/> class.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="size">The size.</param>
/// <param name="isMultiline">Enable/disable multiline text input support</param>
public RenamePopup(string value, Vector2 size, bool isMultiline)
{
if (!isMultiline)
size.Y = TextBox.DefaultHeight;
Size = size;
_startValue = value;
_inputField = new TextBox(isMultiline, 0, 0, size.Y);
_inputField.TextChanged += OnTextChanged;
_inputField.AnchorPreset = AnchorPresets.StretchAll;
_inputField.Offsets = Margin.Zero;
_inputField.Text = _startValue;
_inputField.Parent = this;
}
private bool IsInputValid => !string.IsNullOrWhiteSpace(_inputField.Text) && (_inputField.Text == _startValue || Validate == null || Validate(this, _inputField.Text));
private void OnTextChanged()
{
if (Validate == null)
return;
var valid = IsInputValid;
var style = Style.Current;
if (valid)
{
_inputField.BorderColor = Color.Transparent;
_inputField.BorderSelectedColor = style.BackgroundSelected;
}
else
{
var color = new Color(1.0f, 0.0f, 0.02745f, 1.0f);
_inputField.BorderColor = Color.Lerp(color, style.TextBoxBackground, 0.6f);
_inputField.BorderSelectedColor = color;
}
}
/// <summary>
/// Shows the rename popup.
/// </summary>
/// <param name="control">The target control.</param>
/// <param name="area">The target control area to cover.</param>
/// <param name="value">The initial value.</param>
/// <param name="isMultiline">Enable/disable multiline text input support</param>
/// <returns>Created popup.</returns>
public static RenamePopup Show(Control control, Rectangle area, string value, bool isMultiline)
{
// Calculate the control size in the window space to handle scaled controls
var upperLeft = control.PointToWindow(area.UpperLeft);
var bottomRight = control.PointToWindow(area.BottomRight);
var size = bottomRight - upperLeft;
var rename = new RenamePopup(value, size, isMultiline);
rename.Show(control, area.Location + new Vector2(0, (size.Y - rename.Height) * 0.5f));
return rename;
}
private void OnEnd()
{
var text = Text;
if (text != _startValue && IsInputValid)
{
Renamed?.Invoke(this);
}
Hide();
}
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
// Enter
if (key == KeyboardKeys.Return)
{
OnEnd();
return true;
}
// Esc
if (key == KeyboardKeys.Escape)
{
Hide();
return true;
}
// Base
return base.OnKeyDown(key);
}
/// <inheritdoc />
protected override void OnShow()
{
_inputField.Focus();
_inputField.SelectAll();
base.OnShow();
}
/// <inheritdoc />
protected override void OnHide()
{
Closed?.Invoke(this);
Closed = null;
base.OnHide();
// Remove itself
Dispose();
}
/// <inheritdoc />
public override void OnDestroy()
{
Renamed = null;
Closed = null;
Validate = null;
_inputField = null;
base.OnDestroy();
}
}
}

View File

@@ -0,0 +1,133 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
using System;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.GUI
{
/// <summary>
/// Popup that shows the list of scripts to pick. Supports searching and basic type filtering.
/// </summary>
/// <seealso cref="FlaxEditor.GUI.ItemsListContextMenu" />
public class ScriptSearchPopup : ItemsListContextMenu
{
/// <summary>
/// The script item.
/// </summary>
/// <seealso cref="FlaxEditor.GUI.ItemsListContextMenu.Item" />
public class ScriptItemView : Item
{
private Script _script;
/// <summary>
/// Gets the script.
/// </summary>
public Script Script => _script;
/// <summary>
/// Initializes a new instance of the <see cref="ScriptItemView"/> class.
/// </summary>
/// <param name="script">The script.</param>
public ScriptItemView(Script script)
{
_script = script;
var type = TypeUtils.GetObjectType(script);
Name = script.Actor ? $"{type.Name} ({script.Actor.Name})" : type.Name;
var str = type.Name;
var o = script.Parent;
while (o)
{
str = o.Name + " -> " + str;
o = o.Parent;
}
TooltipText = str;
}
/// <inheritdoc />
public override void OnDestroy()
{
_script = null;
base.OnDestroy();
}
}
/// <summary>
/// Validates if the given script item can be used to pick it.
/// </summary>
/// <param name="script">The script.</param>
/// <returns>True if is valid.</returns>
public delegate bool IsValidDelegate(Script script);
private IsValidDelegate _isValid;
private Action<Script> _selected;
private ScriptSearchPopup(IsValidDelegate isValid, Action<Script> selected)
{
_isValid = isValid;
_selected = selected;
ItemClicked += OnItemClicked;
// TODO: use async thread to search scenes
for (int i = 0; i < Level.ScenesCount; i++)
{
Find(Level.GetScene(i));
}
SortChildren();
}
private void OnItemClicked(Item item)
{
_selected(((ScriptItemView)item).Script);
}
private void Find(Actor actor)
{
if (!actor)
return;
for (int i = 0; i < actor.ScriptsCount; i++)
{
var script = actor.GetScript(i);
if (_isValid(script))
{
AddItem(new ScriptItemView(script));
}
}
for (int i = 0; i < actor.ChildrenCount; i++)
{
Find(actor.GetChild(i));
}
}
/// <summary>
/// Shows the popup.
/// </summary>
/// <param name="showTarget">The show target.</param>
/// <param name="showTargetLocation">The show target location.</param>
/// <param name="isValid">Event called to check if a given script item is valid to be used.</param>
/// <param name="selected">Event called on script item pick.</param>
/// <returns>The dialog.</returns>
public static ScriptSearchPopup Show(Control showTarget, Vector2 showTargetLocation, IsValidDelegate isValid, Action<Script> selected)
{
var popup = new ScriptSearchPopup(isValid, selected);
popup.Show(showTarget, showTargetLocation);
return popup;
}
/// <inheritdoc />
public override void OnDestroy()
{
_isValid = null;
_selected = null;
base.OnDestroy();
}
}
}

View File

@@ -0,0 +1,121 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
using System;
using System.Linq;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.GUI
{
/// <summary>
/// Popup that shows the list of types to pick. Supports searching and basic type filtering.
/// </summary>
/// <seealso cref="FlaxEditor.GUI.ItemsListContextMenu" />
public class TypeSearchPopup : ItemsListContextMenu
{
/// <summary>
/// The type item.
/// </summary>
/// <seealso cref="FlaxEditor.GUI.ItemsListContextMenu.Item" />
public class TypeItemView : Item
{
private ScriptType _type;
/// <summary>
/// Gets the type.
/// </summary>
public ScriptType Type => _type;
/// <summary>
/// Initializes a new instance of the <see cref="TypeItemView"/> class.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="attributes">The type attributes.</param>
public TypeItemView(ScriptType type, object[] attributes)
{
_type = type;
Name = type.Name;
TooltipText = type.TypeName;
var tooltipAttribute = (TooltipAttribute)attributes.FirstOrDefault(x => x is TooltipAttribute);
if (tooltipAttribute != null)
{
TooltipText += '\n';
TooltipText += tooltipAttribute.Text;
}
}
/// <inheritdoc />
public override void OnDestroy()
{
_type = ScriptType.Null;
base.OnDestroy();
}
}
/// <summary>
/// Validates if the given actor item can be used to pick it.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>True if is valid.</returns>
public delegate bool IsValidDelegate(ScriptType type);
private IsValidDelegate _isValid;
private Action<ScriptType> _selected;
private TypeSearchPopup(IsValidDelegate isValid, Action<ScriptType> selected)
{
_isValid = isValid;
_selected = selected;
ItemClicked += OnItemClicked;
// TODO: use async thread to search types without UI stall
var allTypes = Editor.Instance.CodeEditing.All.Get();
for (int i = 0; i < allTypes.Count; i++)
{
var type = allTypes[i];
if (_isValid(type))
{
var attributes = type.GetAttributes(false);
if (attributes.FirstOrDefault(x => x is HideInEditorAttribute) == null)
{
AddItem(new TypeItemView(type, attributes));
}
}
}
SortChildren();
}
private void OnItemClicked(Item item)
{
_selected(((TypeItemView)item).Type);
}
/// <summary>
/// Shows the popup.
/// </summary>
/// <param name="showTarget">The show target.</param>
/// <param name="showTargetLocation">The show target location.</param>
/// <param name="isValid">Event called to check if a given asset item is valid to be used.</param>
/// <param name="selected">Event called on asset item pick.</param>
/// <returns>The dialog.</returns>
public static TypeSearchPopup Show(Control showTarget, Vector2 showTargetLocation, IsValidDelegate isValid, Action<ScriptType> selected)
{
var popup = new TypeSearchPopup(isValid, selected);
popup.Show(showTarget, showTargetLocation);
return popup;
}
/// <inheritdoc />
public override void OnDestroy()
{
_isValid = null;
_selected = null;
base.OnDestroy();
}
}
}