From e6450bfc7a46f205672e0132929a8756d98e9ad3 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Mon, 30 Dec 2024 16:36:10 -0600 Subject: [PATCH 1/6] Add `ControlReference` for easier UI referencing. --- .../Editors/ControlReferenceEditor.cs | 472 ++++++++++++++++++ Source/Engine/UI/ControlReference.cs | 91 ++++ 2 files changed, 563 insertions(+) create mode 100644 Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs create mode 100644 Source/Engine/UI/ControlReference.cs diff --git a/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs b/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs new file mode 100644 index 000000000..06bcb4b41 --- /dev/null +++ b/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs @@ -0,0 +1,472 @@ +using System; +using System.Collections.Generic; +using FlaxEditor.CustomEditors; +using FlaxEditor.CustomEditors.Elements; +using FlaxEditor.GUI; +using FlaxEditor.GUI.Drag; +using FlaxEditor.SceneGraph.GUI; +using FlaxEngine; +using FlaxEngine.GUI; +using FlaxEngine.Utilities; +using Object = FlaxEngine.Object; + +namespace FlaxEditor.CustomEditors.Editors; + +/// +/// The reference picker control used for UIControls using ControlReference. +/// +public class UIControlObjectRefPickerControl : Control +{ + private Type _controlType; + public 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; + + /// + /// 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 = FlaxEditor.Utilities.Utils.GetTooltip(sceneObject); + else + TooltipText = string.Empty; + + OnValueChanged(); + } + } + + /// + /// Initializes a new instance of the class. + /// + public UIControlObjectRefPickerControl() + : 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(); + }); + } + } + + private bool IsValid(Actor actor) + { + return actor is UIControl a && a.Control.GetType() == _controlType; + } + + /// + public override void Draw() + { + 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) + { + Actor actor = _value; + if (actor != null) + { + if (_linkedTreeNode != null && _linkedTreeNode.Actor == actor) + { + _linkedTreeNode.ExpandAllParents(); + _linkedTreeNode.StartHighlight(); + } + else + { + _linkedTreeNode = FlaxEditor.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(x => IsValid(x.Actor)); + 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(); + } +} + +/// +/// ControlReferenceEditor class. +/// +[CustomEditor(typeof(ControlReference<>)), DefaultEditor] +public class ControlReferenceEditor : CustomEditor +{ + private CustomElement _element; + + /// + public override DisplayStyle Style => DisplayStyle.Inline; + + /// + public override void Initialize(LayoutElementsContainer layout) + { + if (!HasDifferentTypes) + { + _element = layout.Custom(); + if (ValuesTypes == null || ValuesTypes[0] == null) + { + Editor.LogWarning("ControlReference needs to be assigned in code."); + return; + } + Type genType = ValuesTypes[0].GetGenericArguments()[0]; + if (typeof(Control).IsAssignableFrom(genType)) + { + _element.CustomControl.ControlType = genType; + } + _element.CustomControl.ValueChanged += () => + { + Type genericType = ValuesTypes[0].GetGenericArguments()[0]; + if (typeof(Control).IsAssignableFrom(genericType)) + { + Type t = typeof(ControlReference<>); + Type tw = t.MakeGenericType(new Type[] { genericType }); + var instance = Activator.CreateInstance(tw); + (instance as IControlReference).Set(_element.CustomControl.Value); + SetValue(instance); + } + }; + } + } + + /// + public override void Refresh() + { + base.Refresh(); + + if (!HasDifferentValues) + { + if (Values[0] is IControlReference cr) + { + _element.CustomControl.Value = cr.UIControl; + } + } + } +} diff --git a/Source/Engine/UI/ControlReference.cs b/Source/Engine/UI/ControlReference.cs new file mode 100644 index 000000000..84d79f3c0 --- /dev/null +++ b/Source/Engine/UI/ControlReference.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using FlaxEngine; +using FlaxEngine.GUI; + +namespace FlaxEngine; + +/// +/// The control reference interface. +/// +public interface IControlReference +{ + /// + /// The UIControl. + /// + public UIControl UIControl { get; } + + /// + /// The Control type + /// + /// The Control Type + public Type GetControlType(); + + /// + /// A safe set of the UI Control. Will warn if Control is of the wrong type. + /// + /// + public void Set(UIControl uiControl); +} + +/// +/// ControlReference class. +/// +[Serializable] +public struct ControlReference : IControlReference where T : Control +{ + [Serialize, ShowInEditor] + private UIControl _uiControl; + + /// + public Type GetControlType() + { + return typeof(T); + } + + /// + /// The Control attached to the UI Control. + /// + public T Control + { + get + { + if (_uiControl.Control is T t) + return t; + else + { + Debug.LogWarning("Trying to get Control from ControlReference but UIControl.Control is null or UIControl.Control is not the correct type."); + return null; + } + } + } + + /// + public UIControl UIControl => _uiControl; + + /// + public void Set(UIControl uiControl) + { + if (uiControl == null) + { + Clear(); + return; + } + + if (uiControl.Control is T castedControl) + _uiControl = uiControl; + else + Debug.LogWarning("Trying to set ControlReference but UIControl.Control is null or UIControl.Control is not the correct type."); + } + + /// + /// Clears the UIControl reference. + /// + public void Clear() + { + _uiControl = null; + } + + public static implicit operator T(ControlReference reference) => reference.Control; + public static implicit operator UIControl(ControlReference reference) => reference.UIControl; +} From 9219b34dc359b805f1bdcb1661cc3cdf62252621 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Mon, 30 Dec 2024 16:43:06 -0600 Subject: [PATCH 2/6] Shorten picker control name. --- .../CustomEditors/Editors/ControlReferenceEditor.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs b/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs index 06bcb4b41..c93a2aff3 100644 --- a/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs @@ -15,7 +15,7 @@ namespace FlaxEditor.CustomEditors.Editors; /// /// The reference picker control used for UIControls using ControlReference. /// -public class UIControlObjectRefPickerControl : Control +public class UIControlRefPickerControl : Control { private Type _controlType; public UIControl _value; @@ -94,9 +94,9 @@ public class UIControlObjectRefPickerControl : Control } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public UIControlObjectRefPickerControl() + public UIControlRefPickerControl() : base(0, 0, 50, 16) { @@ -420,7 +420,7 @@ public class UIControlObjectRefPickerControl : Control [CustomEditor(typeof(ControlReference<>)), DefaultEditor] public class ControlReferenceEditor : CustomEditor { - private CustomElement _element; + private CustomElement _element; /// public override DisplayStyle Style => DisplayStyle.Inline; @@ -430,7 +430,7 @@ public class ControlReferenceEditor : CustomEditor { if (!HasDifferentTypes) { - _element = layout.Custom(); + _element = layout.Custom(); if (ValuesTypes == null || ValuesTypes[0] == null) { Editor.LogWarning("ControlReference needs to be assigned in code."); From 711fc80d8cf1f9bb4ffab59bd762e512c2085837 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Mon, 30 Dec 2024 16:46:42 -0600 Subject: [PATCH 3/6] Fix comment. --- Source/Engine/UI/ControlReference.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/UI/ControlReference.cs b/Source/Engine/UI/ControlReference.cs index 84d79f3c0..b05f73682 100644 --- a/Source/Engine/UI/ControlReference.cs +++ b/Source/Engine/UI/ControlReference.cs @@ -24,7 +24,7 @@ public interface IControlReference /// /// A safe set of the UI Control. Will warn if Control is of the wrong type. /// - /// + /// The UIControl to set. public void Set(UIControl uiControl); } From c79cd82fd4070836d19658cab8477620cb52d564 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Mon, 30 Dec 2024 18:59:45 -0600 Subject: [PATCH 4/6] Fix code warnings. --- .../CustomEditors/Editors/ControlReferenceEditor.cs | 2 +- Source/Engine/UI/ControlReference.cs | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs b/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs index c93a2aff3..8a0595a0f 100644 --- a/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs @@ -18,7 +18,7 @@ namespace FlaxEditor.CustomEditors.Editors; public class UIControlRefPickerControl : Control { private Type _controlType; - public UIControl _value; + private UIControl _value; private ActorTreeNode _linkedTreeNode; private string _valueName; private bool _supportsPickDropDown; diff --git a/Source/Engine/UI/ControlReference.cs b/Source/Engine/UI/ControlReference.cs index b05f73682..a708e48fa 100644 --- a/Source/Engine/UI/ControlReference.cs +++ b/Source/Engine/UI/ControlReference.cs @@ -86,6 +86,17 @@ public struct ControlReference : IControlReference where T : Control _uiControl = null; } + /// + /// The implicit operator for the Control. + /// + /// The ControlReference + /// The Control. public static implicit operator T(ControlReference reference) => reference.Control; + + /// + /// The implicit operator for the UIControl + /// + /// The ControlReference + /// The UIControl. public static implicit operator UIControl(ControlReference reference) => reference.UIControl; } From 04fc118ddfcd803807e2ed898bf12ca92415c643 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sat, 4 Jan 2025 11:45:08 -0600 Subject: [PATCH 5/6] Small fixes. --- .../Editors/ControlReferenceEditor.cs | 21 ++++++++++++------- Source/Engine/UI/ControlReference.cs | 21 +++++++++++++------ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs b/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs index 8a0595a0f..d7bbf1502 100644 --- a/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs @@ -85,7 +85,7 @@ public class UIControlRefPickerControl : Control // Update tooltip if (_value is SceneObject sceneObject) - TooltipText = FlaxEditor.Utilities.Utils.GetTooltip(sceneObject); + TooltipText = Utilities.Utils.GetTooltip(sceneObject); else TooltipText = string.Empty; @@ -93,6 +93,15 @@ public class UIControlRefPickerControl : Control } } + /// + /// 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. /// @@ -123,7 +132,7 @@ public class UIControlRefPickerControl : Control private bool IsValid(Actor actor) { - return actor is UIControl a && a.Control.GetType() == _controlType; + return actor == null || actor is UIControl a && a.Control.GetType() == _controlType; } /// @@ -263,7 +272,7 @@ public class UIControlRefPickerControl : Control _isMouseDown = false; // Highlight actor or script reference - if (!_hasValidDragOver && !IsDragOver) + if (!_hasValidDragOver && !IsDragOver && nameRect.Contains(location)) { Actor actor = _value; if (actor != null) @@ -275,7 +284,7 @@ public class UIControlRefPickerControl : Control } else { - _linkedTreeNode = FlaxEditor.Editor.Instance.Scene.GetActorNode(actor).TreeNode; + _linkedTreeNode = Editor.Instance.Scene.GetActorNode(actor).TreeNode; _linkedTreeNode.ExpandAllParents(); Editor.Instance.Windows.SceneWin.SceneTreePanel.ScrollViewTo(_linkedTreeNode, true); _linkedTreeNode.StartHighlight(); @@ -455,7 +464,7 @@ public class ControlReferenceEditor : CustomEditor }; } } - + /// public override void Refresh() { @@ -464,9 +473,7 @@ public class ControlReferenceEditor : CustomEditor if (!HasDifferentValues) { if (Values[0] is IControlReference cr) - { _element.CustomControl.Value = cr.UIControl; - } } } } diff --git a/Source/Engine/UI/ControlReference.cs b/Source/Engine/UI/ControlReference.cs index a708e48fa..efcc42362 100644 --- a/Source/Engine/UI/ControlReference.cs +++ b/Source/Engine/UI/ControlReference.cs @@ -36,25 +36,34 @@ public struct ControlReference : IControlReference where T : Control { [Serialize, ShowInEditor] private UIControl _uiControl; - + + /// + /// Default constructor for ControlReference; + /// + public ControlReference() + { + _uiControl = null; + } + /// public Type GetControlType() { return typeof(T); } - + /// /// The Control attached to the UI Control. /// + [HideInEditor] public T Control { get { - if (_uiControl.Control is T t) + if (_uiControl != null && _uiControl.Control is T t) return t; else { - Debug.LogWarning("Trying to get Control from ControlReference but UIControl.Control is null or UIControl.Control is not the correct type."); + Debug.LogWarning("Trying to get Control from ControlReference but UIControl is null, or UIControl.Control is null, or UIControl.Control is not the correct type."); return null; } } @@ -85,14 +94,14 @@ public struct ControlReference : IControlReference where T : Control { _uiControl = null; } - + /// /// The implicit operator for the Control. /// /// The ControlReference /// The Control. public static implicit operator T(ControlReference reference) => reference.Control; - + /// /// The implicit operator for the UIControl /// From 25b8939aff946168151bebb57538077085cc4fa2 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sun, 16 Feb 2025 18:05:25 -0600 Subject: [PATCH 6/6] Update to include presenter context. --- .../Editors/ControlReferenceEditor.cs | 31 +++++++++++++++++-- Source/Engine/UI/ControlReference.cs | 4 +-- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs b/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs index d7bbf1502..700accabb 100644 --- a/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ControlReferenceEditor.cs @@ -4,7 +4,10 @@ using FlaxEditor.CustomEditors; 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 FlaxEngine; using FlaxEngine.GUI; using FlaxEngine.Utilities; @@ -31,6 +34,11 @@ public class UIControlRefPickerControl : Control private DragActors _dragActors; private DragHandlers _dragHandlers; + /// + /// The presenter using this control. + /// + public IPresenterOwner PresenterContext; + /// /// Occurs when value gets changed. /// @@ -126,7 +134,7 @@ public class UIControlRefPickerControl : Control Value = actor as UIControl; RootWindow.Focus(); Focus(); - }); + }, PresenterContext); } } @@ -134,6 +142,24 @@ public class UIControlRefPickerControl : Control { 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 override void Draw() @@ -365,7 +391,7 @@ public class UIControlRefPickerControl : Control // Ensure to have valid drag helpers (uses lazy init) if (_dragActors == null) - _dragActors = new DragActors(x => IsValid(x.Actor)); + _dragActors = new DragActors(ValidateDragActor); if (_dragHandlers == null) { _dragHandlers = new DragHandlers @@ -448,6 +474,7 @@ public class ControlReferenceEditor : CustomEditor Type genType = ValuesTypes[0].GetGenericArguments()[0]; if (typeof(Control).IsAssignableFrom(genType)) { + _element.CustomControl.PresenterContext = Presenter.Owner; _element.CustomControl.ControlType = genType; } _element.CustomControl.ValueChanged += () => diff --git a/Source/Engine/UI/ControlReference.cs b/Source/Engine/UI/ControlReference.cs index efcc42362..75b5d57a8 100644 --- a/Source/Engine/UI/ControlReference.cs +++ b/Source/Engine/UI/ControlReference.cs @@ -63,7 +63,7 @@ public struct ControlReference : IControlReference where T : Control return t; else { - Debug.LogWarning("Trying to get Control from ControlReference but UIControl is null, or UIControl.Control is null, or UIControl.Control is not the correct type."); + Debug.Write(LogType.Warning, "Trying to get Control from ControlReference but UIControl is null, or UIControl.Control is null, or UIControl.Control is not the correct type."); return null; } } @@ -84,7 +84,7 @@ public struct ControlReference : IControlReference where T : Control if (uiControl.Control is T castedControl) _uiControl = uiControl; else - Debug.LogWarning("Trying to set ControlReference but UIControl.Control is null or UIControl.Control is not the correct type."); + Debug.Write(LogType.Warning, "Trying to set ControlReference but UIControl.Control is null or UIControl.Control is not the correct type."); } ///