diff --git a/Source/Editor/CustomEditors/Editors/FlaxObjectRefEditor.cs b/Source/Editor/CustomEditors/Editors/FlaxObjectRefEditor.cs index fd367d21f..386d8d518 100644 --- a/Source/Editor/CustomEditors/Editors/FlaxObjectRefEditor.cs +++ b/Source/Editor/CustomEditors/Editors/FlaxObjectRefEditor.cs @@ -7,6 +7,7 @@ using FlaxEditor.CustomEditors.Elements; using FlaxEditor.GUI; using FlaxEditor.GUI.Drag; using FlaxEditor.SceneGraph; +using FlaxEditor.SceneGraph.GUI; using FlaxEditor.Scripting; using FlaxEngine; using FlaxEngine.GUI; @@ -23,6 +24,7 @@ namespace FlaxEditor.CustomEditors.Editors public class FlaxObjectRefPickerControl : Control { private ScriptType _type; + private ActorTreeNode _linkedTreeNode; private Object _value; private string _valueName; private bool _supportsPickDropDown; @@ -300,7 +302,43 @@ namespace FlaxEditor.CustomEditors.Editors // 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 as Actor; + if (actor == null && _value is Script script) + actor = script.Actor; + 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); } @@ -326,6 +364,12 @@ namespace FlaxEditor.CustomEditors.Editors // 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); @@ -469,6 +513,7 @@ namespace FlaxEditor.CustomEditors.Editors _value = null; _type = ScriptType.Null; _valueName = null; + _linkedTreeNode = null; base.OnDestroy(); } diff --git a/Source/Editor/GUI/Tree/TreeNode.cs b/Source/Editor/GUI/Tree/TreeNode.cs index 9bb9d2038..90639cebc 100644 --- a/Source/Editor/GUI/Tree/TreeNode.cs +++ b/Source/Editor/GUI/Tree/TreeNode.cs @@ -23,10 +23,19 @@ namespace FlaxEditor.GUI.Tree /// public const float DefaultNodeOffsetY = 0; + private const float _targetHighlightScale = 1.25f; + private const float _highlightScaleAnimDuration = 0.85f; + private Tree _tree; private bool _opened, _canChangeOrder; private float _animationProgress, _cachedHeight; + private bool _isHightlighted; + private float _targetHighlightTimeSec; + private float _currentHighlightTimeSec; + // Used to prevent showing highlight on double mouse click + private float _debounceHighlightTime; + private float _highlightScale; private bool _mouseOverArrow, _mouseOverHeader; private float _xOffset, _textWidth; private float _headerHeight = 16.0f; @@ -605,9 +614,47 @@ namespace FlaxEditor.GUI.Tree } } + /// + /// Adds a box around the text to highlight the node. + /// + /// The duration of the highlight in seconds. + public void StartHighlight(float durationSec = 3) + { + _isHightlighted = true; + _targetHighlightTimeSec = durationSec; + _currentHighlightTimeSec = 0; + _debounceHighlightTime = 0; + _highlightScale = 2f; + } + + /// + /// Stops any current highlight. + /// + public void StopHighlight() + { + _isHightlighted = false; + _targetHighlightTimeSec = 0; + _currentHighlightTimeSec = 0; + _debounceHighlightTime = 0; + } + /// public override void Update(float deltaTime) { + // Highlight animations + if (_isHightlighted) + { + _debounceHighlightTime += deltaTime; + _currentHighlightTimeSec += deltaTime; + + // In the first second, animate the highlight to shrink into it's resting position + if (_currentHighlightTimeSec < _highlightScaleAnimDuration) + _highlightScale = Mathf.Lerp(_highlightScale, _targetHighlightScale, _currentHighlightTimeSec); + + if (_currentHighlightTimeSec >= _targetHighlightTimeSec) + _isHightlighted = false; + } + // Drop/down animation if (_animationProgress < 1.0f) { @@ -676,6 +723,18 @@ namespace FlaxEditor.GUI.Tree textRect.Width -= 18.0f; } + float textWidth = TextFont.GetFont().MeasureText(_text).X; + Rectangle trueTextRect = textRect; + trueTextRect.Width = textWidth; + trueTextRect.Scale(_highlightScale); + + if (_isHightlighted && _debounceHighlightTime > 0.1f) + { + Color highlightBackgroundColor = Editor.Instance.Options.Options.Visual.HighlightColor; + highlightBackgroundColor = highlightBackgroundColor.AlphaMultiplied(0.3f); + Render2D.FillRectangle(trueTextRect, highlightBackgroundColor); + } + // Draw text Color textColor = CacheTextColor(); Render2D.DrawText(TextFont.GetFont(), _text, textRect, textColor, TextAlignment.Near, TextAlignment.Center); @@ -730,6 +789,12 @@ namespace FlaxEditor.GUI.Tree } } + if (_isHightlighted && _debounceHighlightTime > 0.1f) + { + // Draw highlights + Render2D.DrawRectangle(trueTextRect, Editor.Instance.Options.Options.Visual.HighlightColor, 3); + } + // Base if (_opened) {