diff --git a/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs b/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs
index 174dc9b20..65a6dc1a1 100644
--- a/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs
@@ -2,15 +2,9 @@
using System;
using FlaxEditor.CustomEditors.Elements;
-using FlaxEditor.GUI;
-using FlaxEditor.GUI.Drag;
-using FlaxEditor.SceneGraph;
-using FlaxEditor.SceneGraph.GUI;
-using FlaxEditor.Windows;
-using FlaxEditor.Windows.Assets;
+using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
-using FlaxEngine.Utilities;
using Object = FlaxEngine.Object;
namespace FlaxEditor.CustomEditors.Editors;
@@ -18,433 +12,17 @@ namespace FlaxEditor.CustomEditors.Editors;
///
/// The reference picker control used for UIControls using ControlReference.
///
-public class UIControlRefPickerControl : Control
+internal class UIControlRefPickerControl : FlaxObjectRefPickerControl
{
- private Type _controlType;
- private UIControl _value;
- private ActorTreeNode _linkedTreeNode;
- private string _valueName;
- private bool _supportsPickDropDown;
-
- private bool _isMouseDown;
- private Float2 _mouseDownPos;
- private Float2 _mousePos;
-
- private bool _hasValidDragOver;
- private DragActors _dragActors;
- private DragHandlers _dragHandlers;
-
///
- /// The presenter using this control.
+ /// Type of the control to pick.
///
- public IPresenterOwner PresenterContext;
-
- ///
- /// Occurs when value gets changed.
- ///
- public event Action ValueChanged;
-
- ///
- /// The type of the Control
- ///
- /// Throws exception if value is not a subclass of control.
- public Type ControlType
- {
- get => _controlType;
- set
- {
- if (_controlType == value)
- return;
- if (!value.IsSubclassOf(typeof(Control)))
- throw new ArgumentException(string.Format("Invalid type for UIControlObjectRefPicker. Input type: {0}", value));
- _controlType = value;
- _supportsPickDropDown = typeof(Control).IsAssignableFrom(value);
-
- // Deselect value if it's not valid now
- if (!IsValid(_value))
- Value = null;
- }
- }
-
- ///
- /// The UIControl value.
- ///
- public UIControl Value
- {
- get => _value;
- set
- {
- if (_value == value)
- return;
- if (!IsValid(value))
- value = null;
-
- // Special case for missing objects (eg. referenced actor in script that is deleted in editor)
- if (value != null && (Object.GetUnmanagedPtr(value) == IntPtr.Zero || value.ID == Guid.Empty))
- value = null;
-
- _value = value;
-
- // Get name to display
- if (_value != null)
- _valueName = _value.Name;
- else
- _valueName = string.Empty;
-
- // Update tooltip
- if (_value is SceneObject sceneObject)
- TooltipText = Utilities.Utils.GetTooltip(sceneObject);
- else
- TooltipText = string.Empty;
-
- OnValueChanged();
- }
- }
-
- ///
- /// Gets or sets the selected object value by identifier.
- ///
- public Guid ValueID
- {
- get => _value ? _value.ID : Guid.Empty;
- set => Value = Object.Find(ref value);
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- public UIControlRefPickerControl()
- : base(0, 0, 50, 16)
- {
- }
-
- private void OnValueChanged()
- {
- ValueChanged?.Invoke();
- }
-
- private void ShowDropDownMenu()
- {
- Focus();
- if (typeof(Control).IsAssignableFrom(_controlType))
- {
- ActorSearchPopup.Show(this, new Float2(0, Height), IsValid, actor =>
- {
- Value = actor as UIControl;
- RootWindow.Focus();
- Focus();
- }, PresenterContext);
- }
- }
-
- private bool IsValid(Actor actor)
- {
- return actor == null || actor is UIControl a && a.Control.GetType() == _controlType;
- }
-
- private bool ValidateDragActor(ActorNode a)
- {
- if (!IsValid(a.Actor))
- return false;
-
- if (PresenterContext is PrefabWindow prefabWindow)
- {
- if (prefabWindow.Tree == a.TreeNode.ParentTree)
- return true;
- }
- else if (PresenterContext is PropertiesWindow || PresenterContext == null)
- {
- if (a.ParentScene != null)
- return true;
- }
- return false;
- }
+ public Type ControlType;
///
- public override void Draw()
+ protected override bool IsValid(Object obj)
{
- base.Draw();
-
- // Cache data
- var style = Style.Current;
- bool isSelected = _value != null;
- bool isEnabled = EnabledInHierarchy;
- var frameRect = new Rectangle(0, 0, Width, 16);
- if (isSelected)
- frameRect.Width -= 16;
- if (_supportsPickDropDown)
- frameRect.Width -= 16;
- var nameRect = new Rectangle(2, 1, frameRect.Width - 4, 14);
- var button1Rect = new Rectangle(nameRect.Right + 2, 1, 14, 14);
- var button2Rect = new Rectangle(button1Rect.Right + 2, 1, 14, 14);
-
- // Draw frame
- Render2D.DrawRectangle(frameRect, isEnabled && (IsMouseOver || IsNavFocused) ? style.BorderHighlighted : style.BorderNormal);
-
- // Check if has item selected
- if (isSelected)
- {
- // Draw name
- Render2D.PushClip(nameRect);
- Render2D.DrawText(style.FontMedium, $"{_valueName} ({Utilities.Utils.GetPropertyNameUI(ControlType.GetTypeDisplayName())})", nameRect, isEnabled ? style.Foreground : style.ForegroundDisabled, TextAlignment.Near, TextAlignment.Center);
- Render2D.PopClip();
-
- // Draw deselect button
- Render2D.DrawSprite(style.Cross, button1Rect, isEnabled && button1Rect.Contains(_mousePos) ? style.Foreground : style.ForegroundGrey);
- }
- else
- {
- // Draw info
- Render2D.PushClip(nameRect);
- Render2D.DrawText(style.FontMedium, ControlType != null ? $"None ({Utilities.Utils.GetPropertyNameUI(ControlType.GetTypeDisplayName())})" : "-", nameRect, isEnabled ? style.ForegroundGrey : style.ForegroundGrey.AlphaMultiplied(0.75f), TextAlignment.Near, TextAlignment.Center);
- Render2D.PopClip();
- }
-
- // Draw picker button
- if (_supportsPickDropDown)
- {
- var pickerRect = isSelected ? button2Rect : button1Rect;
- Render2D.DrawSprite(style.ArrowDown, pickerRect, isEnabled && pickerRect.Contains(_mousePos) ? style.Foreground : style.ForegroundGrey);
- }
-
- // Check if drag is over
- if (IsDragOver && _hasValidDragOver)
- {
- var bounds = new Rectangle(Float2.Zero, Size);
- Render2D.FillRectangle(bounds, style.Selection);
- Render2D.DrawRectangle(bounds, style.SelectionBorder);
- }
- }
-
- ///
- public override void OnMouseEnter(Float2 location)
- {
- _mousePos = location;
- _mouseDownPos = Float2.Minimum;
-
- base.OnMouseEnter(location);
- }
-
- ///
- public override void OnMouseLeave()
- {
- _mousePos = Float2.Minimum;
-
- // Check if start drag drop
- if (_isMouseDown)
- {
- // Do the drag
- DoDrag();
-
- // Clear flag
- _isMouseDown = false;
- }
-
- base.OnMouseLeave();
- }
-
- ///
- public override void OnMouseMove(Float2 location)
- {
- _mousePos = location;
-
- // Check if start drag drop
- if (_isMouseDown && Float2.Distance(location, _mouseDownPos) > 10.0f)
- {
- // Do the drag
- DoDrag();
-
- // Clear flag
- _isMouseDown = false;
- }
-
- base.OnMouseMove(location);
- }
-
- ///
- public override bool OnMouseUp(Float2 location, MouseButton button)
- {
- if (button == MouseButton.Left)
- {
- // Clear flag
- _isMouseDown = false;
- }
-
- // Cache data
- bool isSelected = _value != null;
- var frameRect = new Rectangle(0, 0, Width, 16);
- if (isSelected)
- frameRect.Width -= 16;
- if (_supportsPickDropDown)
- frameRect.Width -= 16;
- var nameRect = new Rectangle(2, 1, frameRect.Width - 4, 14);
- var button1Rect = new Rectangle(nameRect.Right + 2, 1, 14, 14);
- var button2Rect = new Rectangle(button1Rect.Right + 2, 1, 14, 14);
-
- // Deselect
- if (_value != null && button1Rect.Contains(ref location))
- Value = null;
-
- // Picker dropdown menu
- if (_supportsPickDropDown && (isSelected ? button2Rect : button1Rect).Contains(ref location))
- {
- ShowDropDownMenu();
- return true;
- }
-
- if (button == MouseButton.Left)
- {
- _isMouseDown = false;
-
- // Highlight actor or script reference
- if (!_hasValidDragOver && !IsDragOver && nameRect.Contains(location))
- {
- Actor actor = _value;
- if (actor != null)
- {
- if (_linkedTreeNode != null && _linkedTreeNode.Actor == actor)
- {
- _linkedTreeNode.ExpandAllParents();
- _linkedTreeNode.StartHighlight();
- }
- else
- {
- _linkedTreeNode = Editor.Instance.Scene.GetActorNode(actor).TreeNode;
- _linkedTreeNode.ExpandAllParents();
- Editor.Instance.Windows.SceneWin.SceneTreePanel.ScrollViewTo(_linkedTreeNode, true);
- _linkedTreeNode.StartHighlight();
- }
- return true;
- }
- }
-
- // Reset valid drag over if still true at this point
- if (_hasValidDragOver)
- _hasValidDragOver = false;
- }
-
- return base.OnMouseUp(location, button);
- }
-
- ///
- public override bool OnMouseDown(Float2 location, MouseButton button)
- {
- if (button == MouseButton.Left)
- {
- // Set flag
- _isMouseDown = true;
- _mouseDownPos = location;
- }
-
- return base.OnMouseDown(location, button);
- }
-
- ///
- public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
- {
- Focus();
-
- // Check if has object selected
- if (_value != null)
- {
- if (_linkedTreeNode != null)
- {
- _linkedTreeNode.StopHighlight();
- _linkedTreeNode = null;
- }
-
- // Select object
- if (_value is Actor actor)
- Editor.Instance.SceneEditing.Select(actor);
- }
-
- return base.OnMouseDoubleClick(location, button);
- }
-
- ///
- public override void OnSubmit()
- {
- base.OnSubmit();
-
- // Picker dropdown menu
- if (_supportsPickDropDown)
- ShowDropDownMenu();
- }
-
- private void DoDrag()
- {
- // Do the drag drop operation if has selected element
- if (_value != null)
- {
- if (_value is Actor actor)
- DoDragDrop(DragActors.GetDragData(actor));
- }
- }
-
- private DragDropEffect DragEffect => _hasValidDragOver ? DragDropEffect.Move : DragDropEffect.None;
-
- ///
- public override DragDropEffect OnDragEnter(ref Float2 location, DragData data)
- {
- base.OnDragEnter(ref location, data);
-
- // Ensure to have valid drag helpers (uses lazy init)
- if (_dragActors == null)
- _dragActors = new DragActors(ValidateDragActor);
- if (_dragHandlers == null)
- {
- _dragHandlers = new DragHandlers
- {
- _dragActors,
- };
- }
-
- _hasValidDragOver = _dragHandlers.OnDragEnter(data) != DragDropEffect.None;
-
- return DragEffect;
- }
-
- ///
- public override DragDropEffect OnDragMove(ref Float2 location, DragData data)
- {
- base.OnDragMove(ref location, data);
-
- return DragEffect;
- }
-
- ///
- public override void OnDragLeave()
- {
- _hasValidDragOver = false;
- _dragHandlers.OnDragLeave();
-
- base.OnDragLeave();
- }
-
- ///
- public override DragDropEffect OnDragDrop(ref Float2 location, DragData data)
- {
- var result = DragEffect;
-
- base.OnDragDrop(ref location, data);
-
- if (_dragActors.HasValidDrag)
- {
- Value = _dragActors.Objects[0].Actor as UIControl;
- }
-
- return result;
- }
-
- ///
- public override void OnDestroy()
- {
- _value = null;
- _controlType = null;
- _valueName = null;
- _linkedTreeNode = null;
-
- base.OnDestroy();
+ return obj == null || (obj is UIControl control && control.Control.GetType() == ControlType);
}
}
@@ -452,7 +30,7 @@ public class UIControlRefPickerControl : Control
/// ControlReferenceEditor class.
///
[CustomEditor(typeof(ControlReference<>)), DefaultEditor]
-public class ControlReferenceEditor : CustomEditor
+internal class ControlReferenceEditor : CustomEditor
{
private CustomElement _element;
@@ -475,6 +53,7 @@ public class ControlReferenceEditor : CustomEditor
{
_element.CustomControl.PresenterContext = Presenter.Owner;
_element.CustomControl.ControlType = genType;
+ _element.CustomControl.Type = new ScriptType(typeof(UIControl));
}
_element.CustomControl.ValueChanged += () =>
{
@@ -484,7 +63,7 @@ public class ControlReferenceEditor : CustomEditor
Type t = typeof(ControlReference<>);
Type tw = t.MakeGenericType(new Type[] { genericType });
var instance = Activator.CreateInstance(tw);
- ((IControlReference)instance).UIControl = _element.CustomControl.Value;
+ ((IControlReference)instance).UIControl = (UIControl)_element.CustomControl.Value;
SetValue(instance);
}
};
diff --git a/Source/Editor/CustomEditors/Editors/FlaxObjectRefEditor.cs b/Source/Editor/CustomEditors/Editors/FlaxObjectRefEditor.cs
index bab748dcc..9a8b80d40 100644
--- a/Source/Editor/CustomEditors/Editors/FlaxObjectRefEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/FlaxObjectRefEditor.cs
@@ -48,7 +48,7 @@ namespace FlaxEditor.CustomEditors.Editors
public IPresenterOwner PresenterContext;
///
- /// Gets or sets the allowed objects type (given type and all sub classes). Must be type of any subclass.
+ /// Gets or sets the allowed objects type (given type and all subclasses). Must be type of any subclass.
///
public ScriptType Type
{
@@ -61,7 +61,8 @@ namespace FlaxEditor.CustomEditors.Editors
throw new ArgumentException(string.Format("Invalid type for FlaxObjectRefEditor. Input type: {0}", value != ScriptType.Null ? value.TypeName : "null"));
_type = value;
- _supportsPickDropDown = new ScriptType(typeof(Actor)).IsAssignableFrom(value) || new ScriptType(typeof(Script)).IsAssignableFrom(value);
+ _supportsPickDropDown = new ScriptType(typeof(Actor)).IsAssignableFrom(value) ||
+ new ScriptType(typeof(Script)).IsAssignableFrom(value);
// Deselect value if it's not valid now
if (!IsValid(_value))
@@ -80,7 +81,7 @@ namespace FlaxEditor.CustomEditors.Editors
if (_value == value)
return;
if (!IsValid(value))
- throw new ArgumentException("Invalid object type.");
+ value = null;
// Special case for missing objects (eg. referenced actor in script that is deleted in editor)
if (value != null && (Object.GetUnmanagedPtr(value) == IntPtr.Zero || value.ID == Guid.Empty))
@@ -91,27 +92,17 @@ namespace FlaxEditor.CustomEditors.Editors
// Get name to display
if (_value is Script script)
- {
_valueName = script.Actor ? $"{type.Name} ({script.Actor.Name})" : type.Name;
- }
else if (_value != null)
- {
_valueName = _value.ToString();
- }
else
- {
_valueName = string.Empty;
- }
// Update tooltip
if (_value is SceneObject sceneObject)
- {
TooltipText = Utilities.Utils.GetTooltip(sceneObject);
- }
else
- {
TooltipText = string.Empty;
- }
OnValueChanged();
}
@@ -150,7 +141,12 @@ namespace FlaxEditor.CustomEditors.Editors
_type = ScriptType.Object;
}
- private bool IsValid(Object obj)
+ ///
+ /// Object validation check routine.
+ ///
+ /// Input object to check.
+ /// True if it can be assigned, otherwise false.
+ protected virtual bool IsValid(Object obj)
{
var type = TypeUtils.GetObjectType(obj);
return obj == null || _type.IsAssignableFrom(type) && (CheckValid == null || CheckValid(obj, type));
@@ -168,6 +164,15 @@ namespace FlaxEditor.CustomEditors.Editors
Focus();
}, PresenterContext);
}
+ else if (new ScriptType(typeof(Control)).IsAssignableFrom(_type))
+ {
+ ActorSearchPopup.Show(this, new Float2(0, Height), IsValid, actor =>
+ {
+ Value = actor as UIControl;
+ RootWindow.Focus();
+ Focus();
+ }, PresenterContext);
+ }
else
{
ScriptSearchPopup.Show(this, new Float2(0, Height), IsValid, script =>