Merge branch 'controls-toolbox' of https://github.com/Tryibion/FlaxEngine into Tryibion-controls-toolbox

# Conflicts:
#	Source/Editor/SceneGraph/GUI/ActorTreeNode.cs
This commit is contained in:
Wojtek Figat
2024-04-29 16:56:30 +02:00
30 changed files with 299 additions and 7 deletions

View File

@@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using FlaxEditor.SceneGraph;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Utilities;
namespace FlaxEditor.GUI.Drag;
/// <summary>
/// Control type drag handler.
/// </summary>
public sealed class DragControlType : DragActorType<DragEventArgs>
{
/// <summary>
/// Initializes a new instance of the <see cref="DragControlType"/> class.
/// </summary>
/// <param name="validateFunction">The validation function</param>
public DragControlType(Func<ScriptType, bool> validateFunction)
: base(validateFunction)
{
}
}
/// <summary>
/// Helper class for handling control type drag and drop (for spawning).
/// </summary>
/// <seealso cref="Control" />
/// <seealso cref="ActorNode" />
public class DragControlType<U> : DragHelper<ScriptType, U> where U : DragEventArgs
{
/// <summary>
/// The default prefix for drag data used for actor type drag and drop.
/// </summary>
public const string DragPrefix = "CTYPE!?";
/// <summary>
/// Creates a new DragHelper
/// </summary>
/// <param name="validateFunction">The validation function</param>
public DragControlType(Func<ScriptType, bool> validateFunction)
: base(validateFunction)
{
}
/// <inheritdoc/>
public override DragData ToDragData(ScriptType item) => GetDragData(item);
/// <inheritdoc/>
public override DragData ToDragData(IEnumerable<ScriptType> items)
{
throw new NotImplementedException();
}
/// <summary>
/// Gets the drag data.
/// </summary>
/// <param name="item">The control type.</param>
/// <returns>The data</returns>
public static DragData GetDragData(Type item)
{
if (item == null)
throw new ArgumentNullException();
return new DragDataText(DragPrefix + item.FullName);
}
/// <summary>
/// Gets the drag data.
/// </summary>
/// <param name="item">The control type.</param>
/// <returns>The data</returns>
public static DragData GetDragData(ScriptType item)
{
if (item == ScriptType.Null)
throw new ArgumentNullException();
return new DragDataText(DragPrefix + item.TypeName);
}
/// <summary>
/// Tries to parse the drag data to extract <see cref="Type"/> collection.
/// </summary>
/// <param name="data">The data.</param>
/// <returns>Gathered objects or empty array if cannot get any valid.</returns>
public override IEnumerable<ScriptType> FromDragData(DragData data)
{
if (data is DragDataText dataText)
{
if (dataText.Text.StartsWith(DragPrefix))
{
// Remove prefix and parse spitted names
var types = dataText.Text.Remove(0, DragPrefix.Length).Split('\n');
var results = new List<ScriptType>(types.Length);
for (int i = 0; i < types.Length; i++)
{
// Find type
var obj = TypeUtils.GetType(types[i]);
if (obj)
results.Add(obj);
}
return results;
}
}
return Utils.GetEmptyArray<ScriptType>();
}
}

View File

@@ -29,6 +29,7 @@ namespace FlaxEditor.SceneGraph.GUI
private DragScripts _dragScripts;
private DragAssets _dragAssets;
private DragActorType _dragActorType;
private DragControlType _dragControlType;
private DragScriptItems _dragScriptItems;
private DragHandlers _dragHandlers;
private List<Rectangle> _highlights;
@@ -439,6 +440,17 @@ namespace FlaxEditor.SceneGraph.GUI
}
if (_dragActorType.OnDragEnter(data))
return _dragActorType.Effect;
// Check if drag control type
if (_dragControlType == null)
{
_dragControlType = new DragControlType(ValidateDragControlType);
_dragHandlers.Add(_dragControlType);
}
if (_dragControlType.OnDragEnter(data))
return _dragControlType.Effect;
// Check if drag script item
if (_dragScriptItems == null)
{
_dragScriptItems = new DragScriptItems(ValidateDragScriptItem);
@@ -572,7 +584,7 @@ namespace FlaxEditor.SceneGraph.GUI
Editor.LogWarning("Failed to spawn actor of type " + item.TypeName);
continue;
}
actor.StaticFlags = Actor.StaticFlags;
actor.StaticFlags = newParent.StaticFlags;
actor.Name = item.Name;
actor.Transform = Actor.Transform;
ActorNode.Root.Spawn(actor, newParent);
@@ -580,6 +592,29 @@ namespace FlaxEditor.SceneGraph.GUI
}
result = DragDropEffect.Move;
}
// Drag control type
else if (_dragControlType != null && _dragControlType.HasValidDrag)
{
for (int i = 0; i < _dragControlType.Objects.Count; i++)
{
var item = _dragControlType.Objects[i];
var control = item.CreateInstance() as Control;
if (control == null)
{
Editor.LogWarning("Failed to spawn UIControl with control type " + item.TypeName);
continue;
}
var uiControl = new UIControl
{
Control = control,
StaticFlags = newParent.StaticFlags,
Name = item.Name,
};
ActorNode.Root.Spawn(uiControl, newParent);
uiControl.OrderInParent = newOrder;
}
result = DragDropEffect.Move;
}
// Drag script item
else if (_dragScriptItems != null && _dragScriptItems.HasValidDrag)
{
@@ -657,7 +692,12 @@ namespace FlaxEditor.SceneGraph.GUI
private static bool ValidateDragActorType(ScriptType actorType)
{
return true;
return Editor.Instance.CodeEditing.Actors.Get().Contains(actorType);
}
private static bool ValidateDragControlType(ScriptType controlType)
{
return Editor.Instance.CodeEditing.Controls.Get().Contains(controlType);
}
private static bool ValidateDragScriptItem(ScriptItem script)
@@ -705,6 +745,7 @@ namespace FlaxEditor.SceneGraph.GUI
_dragScripts = null;
_dragAssets = null;
_dragActorType = null;
_dragControlType = null;
_dragScriptItems = null;
_dragHandlers?.Clear();
_dragHandlers = null;

View File

@@ -65,6 +65,7 @@ namespace FlaxEditor.Windows.Assets
private PrefabWindow _window;
private DragAssets _dragAssets;
private DragActorType _dragActorType;
private DragControlType _dragControlType;
private DragScriptItems _dragScriptItems;
private DragHandlers _dragHandlers;
@@ -83,7 +84,12 @@ namespace FlaxEditor.Windows.Assets
private static bool ValidateDragActorType(ScriptType actorType)
{
return true;
return Editor.Instance.CodeEditing.Actors.Get().Contains(actorType);
}
private static bool ValidateDragControlType(ScriptType controlType)
{
return Editor.Instance.CodeEditing.Controls.Get().Contains(controlType);
}
private static bool ValidateDragScriptItem(ScriptItem script)
@@ -113,6 +119,13 @@ namespace FlaxEditor.Windows.Assets
}
if (_dragActorType.OnDragEnter(data))
return _dragActorType.Effect;
if (_dragControlType == null)
{
_dragControlType = new DragControlType(ValidateDragControlType);
_dragHandlers.Add(_dragControlType);
}
if (_dragControlType.OnDragEnter(data))
return _dragControlType.Effect;
if (_dragScriptItems == null)
{
_dragScriptItems = new DragScriptItems(ValidateDragScriptItem);
@@ -176,6 +189,27 @@ namespace FlaxEditor.Windows.Assets
}
result = DragDropEffect.Move;
}
// Drag control type
else if (_dragControlType != null && _dragControlType.HasValidDrag)
{
for (int i = 0; i < _dragControlType.Objects.Count; i++)
{
var item = _dragControlType.Objects[i];
var control = item.CreateInstance() as Control;
if (control == null)
{
Editor.LogWarning("Failed to spawn UIControl with control type " + item.TypeName);
continue;
}
var uiControl = new UIControl
{
Control = control,
Name = item.Name,
};
_window.Spawn(uiControl);
}
result = DragDropEffect.Move;
}
// Drag script item
else if (_dragScriptItems != null && _dragScriptItems.HasValidDrag)
{
@@ -207,6 +241,7 @@ namespace FlaxEditor.Windows.Assets
_window = null;
_dragAssets = null;
_dragActorType = null;
_dragControlType = null;
_dragScriptItems = null;
_dragHandlers?.Clear();
_dragHandlers = null;

View File

@@ -30,6 +30,7 @@ namespace FlaxEditor.Windows
private DragAssets _dragAssets;
private DragActorType _dragActorType;
private DragControlType _dragControlType;
private DragScriptItems _dragScriptItems;
private DragHandlers _dragHandlers;
@@ -275,7 +276,12 @@ namespace FlaxEditor.Windows
private static bool ValidateDragActorType(ScriptType actorType)
{
return true;
return Editor.Instance.CodeEditing.Actors.Get().Contains(actorType);
}
private static bool ValidateDragControlType(ScriptType controlType)
{
return Editor.Instance.CodeEditing.Controls.Get().Contains(controlType);
}
private static bool ValidateDragScriptItem(ScriptItem script)
@@ -390,6 +396,13 @@ namespace FlaxEditor.Windows
}
if (_dragActorType.OnDragEnter(data) && result == DragDropEffect.None)
return _dragActorType.Effect;
if (_dragControlType == null)
{
_dragControlType = new DragControlType(ValidateDragControlType);
_dragHandlers.Add(_dragControlType);
}
if (_dragControlType.OnDragEnter(data) && result == DragDropEffect.None)
return _dragControlType.Effect;
if (_dragScriptItems == null)
{
_dragScriptItems = new DragScriptItems(ValidateDragScriptItem);
@@ -462,6 +475,28 @@ namespace FlaxEditor.Windows
}
result = DragDropEffect.Move;
}
// Drag control type
else if (_dragControlType != null && _dragControlType.HasValidDrag)
{
for (int i = 0; i < _dragControlType.Objects.Count; i++)
{
var item = _dragControlType.Objects[i];
var control = item.CreateInstance() as Control;
if (control == null)
{
Editor.LogWarning("Failed to spawn UIControl with control type " + item.TypeName);
continue;
}
var uiControl = new UIControl
{
Control = control,
Name = item.Name,
};
Level.SpawnActor(uiControl);
Editor.Scene.MarkSceneEdited(uiControl.Scene);
}
result = DragDropEffect.Move;
}
// Drag script item
else if (_dragScriptItems != null && _dragScriptItems.HasValidDrag)
{
@@ -495,6 +530,7 @@ namespace FlaxEditor.Windows
{
_dragAssets = null;
_dragActorType = null;
_dragControlType = null;
_dragScriptItems = null;
_dragHandlers?.Clear();
_dragHandlers = null;

View File

@@ -191,6 +191,52 @@ namespace FlaxEditor.Windows
CreateGroupWithList(_actorGroups, "GUI");
CreateGroupWithList(_actorGroups, "Other");
// Add control types to tabs
foreach (var controlType in Editor.Instance.CodeEditing.Controls.Get())
{
if (controlType.IsAbstract)
continue;
_groupSearch.AddChild(CreateControlItem(Utilities.Utils.GetPropertyNameUI(controlType.Name), controlType));
ActorToolboxAttribute attribute = null;
foreach (var e in controlType.GetAttributes(false))
{
if (e is ActorToolboxAttribute actorToolboxAttribute)
{
attribute = actorToolboxAttribute;
break;
}
}
if (attribute == null)
continue;
var groupName = attribute.Group.Trim();
// Check if tab already exists and add it to the tab
var actorTabExists = false;
foreach (var child in _actorGroups.Children)
{
if (child is Tab tab)
{
if (string.Equals(tab.Text, groupName, StringComparison.OrdinalIgnoreCase))
{
var tree = tab.GetChild<Panel>().GetChild<Tree>();
if (tree != null)
{
tree.AddChild(string.IsNullOrEmpty(attribute.Name) ? CreateControlItem(Utilities.Utils.GetPropertyNameUI(controlType.Name), controlType) : CreateControlItem(attribute.Name, controlType));
tree.SortChildren();
}
actorTabExists = true;
break;
}
}
}
if (actorTabExists)
continue;
var group = CreateGroupWithList(_actorGroups, groupName);
group.AddChild(string.IsNullOrEmpty(attribute.Name) ? CreateControlItem(Utilities.Utils.GetPropertyNameUI(controlType.Name), controlType) : CreateControlItem(attribute.Name, controlType));
group.SortChildren();
}
// Add other actor types to respective tab based on attribute
foreach (var actorType in Editor.CodeEditing.Actors.Get())
{
@@ -304,6 +350,11 @@ namespace FlaxEditor.Windows
return new ScriptTypeItem(name, type, GUI.Drag.DragActorType.GetDragData(type));
}
private Item CreateControlItem(string name, ScriptType type)
{
return new ScriptTypeItem(name, type, GUI.Drag.DragControlType.GetDragData(type));
}
private ContainerControl CreateGroupWithList(Tabs parentTabs, string title, float topOffset = 0)
{
var tab = parentTabs.AddTab(new Tab(title));

View File

@@ -7,6 +7,7 @@ namespace FlaxEngine.GUI
/// <summary>
/// UI canvas scaling component for user interface that targets multiple different game resolutions (eg. mobile screens).
/// </summary>
[ActorToolbox("GUI")]
public class CanvasScaler : ContainerControl
{
/// <summary>

View File

@@ -5,6 +5,7 @@ namespace FlaxEngine.GUI
/// <summary>
/// Border control that draws the border around the control edges (inner and outer sides).
/// </summary>
[ActorToolbox("GUI")]
public class Border : ContainerControl
{
/// <summary>

View File

@@ -7,6 +7,7 @@ namespace FlaxEngine.GUI
/// <summary>
/// Button control
/// </summary>
[ActorToolbox("GUI")]
public class Button : ContainerControl
{
/// <summary>

View File

@@ -29,6 +29,7 @@ namespace FlaxEngine.GUI
/// Check box control.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.Control" />
[ActorToolbox("GUI")]
public class CheckBox : Control
{
/// <summary>

View File

@@ -9,6 +9,7 @@ namespace FlaxEngine.GUI
/// Dropdown menu control allows to choose one item from the provided collection of options.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
[ActorToolbox("GUI")]
public class Dropdown : ContainerControl
{
/// <summary>

View File

@@ -8,6 +8,7 @@ namespace FlaxEngine.GUI
/// The basic GUI image control. Shows texture, sprite or render target.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
[ActorToolbox("GUI")]
public class Image : ContainerControl
{
/// <summary>

View File

@@ -8,6 +8,7 @@ namespace FlaxEngine.GUI
/// The basic GUI label control.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
[ActorToolbox("GUI")]
public class Label : ContainerControl
{
/// <summary>

View File

@@ -8,6 +8,7 @@ namespace FlaxEngine.GUI
/// Progress bar control shows visual progress of the action or set of actions.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.Control" />
[ActorToolbox("GUI")]
public class ProgressBar : ContainerControl
{
/// <summary>

View File

@@ -5,6 +5,7 @@ namespace FlaxEngine.GUI
/// <summary>
/// UI container control that can render children to texture and display pre-cached texture instead of drawing children every frame. It can be also used to render part of UI to texture and use it in material or shader.
/// </summary>
[ActorToolbox("GUI")]
public class RenderToTextureControl : ContainerControl
{
private bool _invalid, _redrawRegistered, _isDuringTextureDraw;

View File

@@ -7,6 +7,7 @@ namespace FlaxEngine.GUI
/// <summary>
/// Rich text box control which can gather text input from the user and present text in highly formatted and stylized way.
/// </summary>
[ActorToolbox("GUI")]
public partial class RichTextBox : RichTextBoxBase
{
private TextBlockStyle _textStyle;

View File

@@ -7,6 +7,7 @@ namespace FlaxEngine.GUI;
/// <summary>
/// The slider control.
/// </summary>
[ActorToolbox("GUI")]
public class Slider : ContainerControl
{
/// <summary>

View File

@@ -6,6 +6,7 @@ namespace FlaxEngine.GUI
/// Helper control used to insert blank space into the layout.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
[ActorToolbox("GUI")]
public sealed class Spacer : ContainerControl
{
/// <summary>

View File

@@ -5,6 +5,7 @@ namespace FlaxEngine.GUI
/// <summary>
/// Text box control which can gather text input from the user.
/// </summary>
[ActorToolbox("GUI")]
public class TextBox : TextBoxBase
{
private TextLayoutOptions _layout;

View File

@@ -5,6 +5,7 @@ namespace FlaxEngine.GUI
/// <summary>
/// Changes alpha of all its children
/// </summary>
[ActorToolbox("GUI")]
public class AlphaPanel : ContainerControl
{
/// <summary>

View File

@@ -6,6 +6,7 @@ namespace FlaxEngine.GUI
/// The blur panel that applied the Gaussian-blur to all content beneath the control.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
[ActorToolbox("GUI")]
public class BlurPanel : ContainerControl
{
/// <summary>

View File

@@ -8,6 +8,7 @@ namespace FlaxEngine.GUI
/// Drop Panel arranges control vertically and provides feature to collapse contents.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
[ActorToolbox("GUI")]
public class DropPanel : ContainerControl
{
/// <summary>

View File

@@ -8,6 +8,7 @@ namespace FlaxEngine.GUI
/// A panel that divides up available space between all of its children.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
[ActorToolbox("GUI")]
public class GridPanel : ContainerControl
{
private Margin _slotPadding;

View File

@@ -6,6 +6,7 @@ namespace FlaxEngine.GUI
/// This panel arranges child controls horizontally.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.PanelWithMargins" />
[ActorToolbox("GUI")]
public class HorizontalPanel : PanelWithMargins
{
/// <summary>

View File

@@ -8,6 +8,7 @@ namespace FlaxEngine.GUI
/// Panel UI control.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ScrollableControl" />
[ActorToolbox("GUI")]
public class Panel : ScrollableControl
{
private bool _layoutChanged;

View File

@@ -8,6 +8,7 @@ namespace FlaxEngine.GUI
/// Panel that arranges child controls like tiles.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
[ActorToolbox("GUI")]
public class TilesPanel : ContainerControl
{
private Margin _tileMargin;

View File

@@ -6,6 +6,7 @@ namespace FlaxEngine.GUI
/// A panel that evenly divides up available space between all of its children.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
[ActorToolbox("GUI")]
public class UniformGridPanel : ContainerControl
{
private Margin _slotPadding;

View File

@@ -6,6 +6,7 @@ namespace FlaxEngine.GUI
/// This panel arranges child controls vertically.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.PanelWithMargins" />
[ActorToolbox("GUI")]
public class VerticalPanel : PanelWithMargins
{
/// <summary>

View File

@@ -10,7 +10,7 @@
/// <summary>
/// Sprite rendering object.
/// </summary>
API_CLASS(Attributes="ActorContextMenu(\"New/UI/Sprite Render\"), ActorToolbox(\"GUI\")")
API_CLASS(Attributes="ActorContextMenu(\"New/UI/Sprite Render\"), ActorToolbox(\"Visuals\")")
class FLAXENGINE_API SpriteRender : public Actor
{
DECLARE_SCENE_OBJECT(SpriteRender);

View File

@@ -18,7 +18,7 @@
/// <summary>
/// Text rendering object.
/// </summary>
API_CLASS(Attributes="ActorContextMenu(\"New/UI/Text Render\"), ActorToolbox(\"GUI\")")
API_CLASS(Attributes="ActorContextMenu(\"New/UI/Text Render\"), ActorToolbox(\"Visuals\")")
class FLAXENGINE_API TextRender : public Actor
{
DECLARE_SCENE_OBJECT(TextRender);

View File

@@ -8,7 +8,7 @@
/// <summary>
/// Contains a single GUI control (on C# side).
/// </summary>
API_CLASS(Sealed, Attributes="ActorContextMenu(\"New/UI/UI Control\"), ActorToolbox(\"GUI\")")
API_CLASS(Sealed, Attributes="ActorContextMenu(\"New/UI/UI Control\"), ActorToolbox(\"GUI\", \"Empty UIControl\")")
class FLAXENGINE_API UIControl : public Actor
{
DECLARE_SCENE_OBJECT(UIControl);