Merge remote-tracking branch 'origin/master' into 1.7
# Conflicts: # Source/Engine/Level/Actors/AnimatedModel.cpp
This commit is contained in:
@@ -5,7 +5,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.GUI.Input;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
@@ -41,6 +40,8 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
public delegate List<SurfaceParameter> ParameterGetterDelegate();
|
||||
|
||||
private readonly List<VisjectCMGroup> _groups = new List<VisjectCMGroup>(16);
|
||||
private CheckBox _contextSensitiveToggle;
|
||||
private bool _contextSensitiveSearchEnabled = true;
|
||||
private readonly TextBox _searchBox;
|
||||
private bool _waitingForInput;
|
||||
private VisjectCMGroup _surfaceParametersGroup;
|
||||
@@ -128,7 +129,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
_parameterSetNodeArchetype = info.ParameterSetNodeArchetype ?? Archetypes.Parameters.Nodes[3];
|
||||
|
||||
// Context menu dimensions
|
||||
Size = new Float2(320, 248);
|
||||
Size = new Float2(300, 400);
|
||||
|
||||
var headerPanel = new Panel(ScrollBars.None)
|
||||
{
|
||||
@@ -140,17 +141,41 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
};
|
||||
|
||||
// Title bar
|
||||
var titleFontReference = new FontReference(Style.Current.FontLarge.Asset, 10);
|
||||
var titleLabel = new Label
|
||||
{
|
||||
Width = Width - 8,
|
||||
Width = Width * 0.5f - 8f,
|
||||
Height = 20,
|
||||
X = 4,
|
||||
Parent = headerPanel,
|
||||
Text = "Select Node",
|
||||
HorizontalAlignment = TextAlignment.Center,
|
||||
Font = new FontReference(Style.Current.FontLarge.Asset, 10),
|
||||
HorizontalAlignment = TextAlignment.Near,
|
||||
Font = titleFontReference,
|
||||
};
|
||||
|
||||
// Context sensitive toggle
|
||||
var contextSensitiveLabel = new Label
|
||||
{
|
||||
Width = Width * 0.5f - 28,
|
||||
Height = 20,
|
||||
X = Width * 0.5f,
|
||||
Parent = headerPanel,
|
||||
Text = "Context Sensitive",
|
||||
TooltipText = "Should the nodes be filtered to only show those that can be connected in the current context?",
|
||||
HorizontalAlignment = TextAlignment.Far,
|
||||
Font = titleFontReference,
|
||||
};
|
||||
|
||||
_contextSensitiveToggle = new CheckBox
|
||||
{
|
||||
Width = 20,
|
||||
Height = 20,
|
||||
X = Width - 24,
|
||||
Parent = headerPanel,
|
||||
Checked = _contextSensitiveSearchEnabled,
|
||||
};
|
||||
_contextSensitiveToggle.StateChanged += OnContextSensitiveToggleStateChanged;
|
||||
|
||||
// Search box
|
||||
_searchBox = new SearchBox(false, 2, 22)
|
||||
{
|
||||
@@ -291,6 +316,10 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
OnSearchFilterChanged();
|
||||
}
|
||||
}
|
||||
else if (_contextSensitiveSearchEnabled)
|
||||
{
|
||||
group.EvaluateVisibilityWithBox(_selectedBox);
|
||||
}
|
||||
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
@@ -324,6 +353,8 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
Parent = group
|
||||
};
|
||||
}
|
||||
if (_contextSensitiveSearchEnabled)
|
||||
group.EvaluateVisibilityWithBox(_selectedBox);
|
||||
group.SortChildren();
|
||||
if (ShowExpanded)
|
||||
group.Open(false);
|
||||
@@ -423,8 +454,26 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
return;
|
||||
|
||||
Profiler.BeginEvent("VisjectCM.OnSearchFilterChanged");
|
||||
|
||||
if (string.IsNullOrEmpty(_searchBox.Text))
|
||||
UpdateFilters();
|
||||
_searchBox.Focus();
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
private void OnContextSensitiveToggleStateChanged(CheckBox checkBox)
|
||||
{
|
||||
// Skip events during setup or init stuff
|
||||
if (IsLayoutLocked)
|
||||
return;
|
||||
|
||||
Profiler.BeginEvent("VisjectCM.OnContextSensitiveToggleStateChanged");
|
||||
_contextSensitiveSearchEnabled = checkBox.Checked;
|
||||
UpdateFilters();
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
private void UpdateFilters()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_searchBox.Text) && _selectedBox == null)
|
||||
{
|
||||
ResetView();
|
||||
Profiler.EndEvent();
|
||||
@@ -435,7 +484,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
LockChildrenRecursive();
|
||||
for (int i = 0; i < _groups.Count; i++)
|
||||
{
|
||||
_groups[i].UpdateFilter(_searchBox.Text);
|
||||
_groups[i].UpdateFilter(_searchBox.Text, _contextSensitiveSearchEnabled ? _selectedBox : null);
|
||||
_groups[i].UpdateItemSort(_selectedBox);
|
||||
}
|
||||
SortGroups();
|
||||
@@ -448,9 +497,6 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
PerformLayout();
|
||||
if (SelectedItem != null)
|
||||
_panel1.ScrollViewTo(SelectedItem);
|
||||
_searchBox.Focus();
|
||||
Profiler.EndEvent();
|
||||
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
@@ -508,7 +554,11 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
_searchBox.Clear();
|
||||
SelectedItem = null;
|
||||
for (int i = 0; i < _groups.Count; i++)
|
||||
{
|
||||
_groups[i].ResetView();
|
||||
if (_contextSensitiveSearchEnabled)
|
||||
_groups[i].EvaluateVisibilityWithBox(_selectedBox);
|
||||
}
|
||||
UnlockChildrenRecursive();
|
||||
|
||||
SortGroups();
|
||||
@@ -764,5 +814,12 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
{
|
||||
return GetPreviousSiblings(item).OfType<T>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
_contextSensitiveToggle.StateChanged -= OnContextSensitiveToggleStateChanged;
|
||||
base.OnDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
{
|
||||
if (_children[i] is VisjectCMItem item)
|
||||
{
|
||||
item.UpdateFilter(null);
|
||||
item.UpdateFilter(null, null);
|
||||
item.UpdateScore(null);
|
||||
}
|
||||
}
|
||||
@@ -84,23 +84,42 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
/// Updates the filter.
|
||||
/// </summary>
|
||||
/// <param name="filterText">The filter text.</param>
|
||||
public void UpdateFilter(string filterText)
|
||||
/// <param name="selectedBox">The optionally selected box to show hints for it.</param>
|
||||
public void UpdateFilter(string filterText, Box selectedBox)
|
||||
{
|
||||
Profiler.BeginEvent("VisjectCMGroup.UpdateFilter");
|
||||
|
||||
// Update items
|
||||
bool isAnyVisible = false;
|
||||
bool groupHeaderMatches = QueryFilterHelper.Match(filterText, HeaderText);
|
||||
for (int i = 0; i < _children.Count; i++)
|
||||
{
|
||||
if (_children[i] is VisjectCMItem item)
|
||||
{
|
||||
item.UpdateFilter(filterText);
|
||||
item.UpdateFilter(filterText, selectedBox, groupHeaderMatches);
|
||||
isAnyVisible |= item.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
// Update header title
|
||||
if (QueryFilterHelper.Match(filterText, HeaderText))
|
||||
// Update itself
|
||||
if (isAnyVisible)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(filterText))
|
||||
Open(false);
|
||||
Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hide group if none of the items matched the filter
|
||||
Visible = false;
|
||||
}
|
||||
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
internal void EvaluateVisibilityWithBox(Box selectedBox)
|
||||
{
|
||||
if (selectedBox == null)
|
||||
{
|
||||
for (int i = 0; i < _children.Count; i++)
|
||||
{
|
||||
@@ -109,14 +128,25 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
item.Visible = true;
|
||||
}
|
||||
}
|
||||
isAnyVisible = true;
|
||||
Visible = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Profiler.BeginEvent("VisjectCMGroup.EvaluateVisibilityWithBox");
|
||||
|
||||
bool isAnyVisible = false;
|
||||
for (int i = 0; i < _children.Count; i++)
|
||||
{
|
||||
if (_children[i] is VisjectCMItem item)
|
||||
{
|
||||
item.Visible = item.CanConnectTo(selectedBox);
|
||||
isAnyVisible |= item.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
// Update itself
|
||||
if (isAnyVisible)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(filterText))
|
||||
Open(false);
|
||||
Visible = true;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Surface.Elements;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine;
|
||||
@@ -56,7 +57,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
/// <param name="groupArchetype">The group archetype.</param>
|
||||
/// <param name="archetype">The archetype.</param>
|
||||
public VisjectCMItem(VisjectCMGroup group, GroupArchetype groupArchetype, NodeArchetype archetype)
|
||||
: base(0, 0, 120, 12)
|
||||
: base(0, 0, 120, 14)
|
||||
{
|
||||
Group = group;
|
||||
_groupArchetype = groupArchetype;
|
||||
@@ -77,7 +78,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
if (!Visible)
|
||||
return;
|
||||
|
||||
if (selectedBox != null && CanConnectTo(selectedBox, NodeArchetype))
|
||||
if (selectedBox != null && CanConnectTo(selectedBox))
|
||||
SortScore += 1;
|
||||
if (Data != null)
|
||||
SortScore += 1;
|
||||
@@ -92,35 +93,93 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
textRect = new Rectangle(22, 0, Width - 24, Height);
|
||||
}
|
||||
|
||||
private bool CanConnectTo(Box startBox, NodeArchetype nodeArchetype)
|
||||
/// <summary>
|
||||
/// Checks if this context menu item can be connected to a given box, before a node is actually spawned.
|
||||
/// </summary>
|
||||
/// <param name="startBox">The connected box</param>
|
||||
/// <returns>True if the connected box is compatible with this item</returns>
|
||||
public bool CanConnectTo(Box startBox)
|
||||
{
|
||||
// Is compatible if box is null for reset reasons
|
||||
if (startBox == null)
|
||||
return false;
|
||||
if (!startBox.IsOutput)
|
||||
return false; // For now, I'm only handing the output box case
|
||||
return true;
|
||||
|
||||
if (nodeArchetype.Elements != null)
|
||||
if (_archetype == null)
|
||||
return false;
|
||||
|
||||
bool isCompatible = false;
|
||||
if (startBox.IsOutput && _archetype.IsInputCompatible != null)
|
||||
{
|
||||
for (int i = 0; i < nodeArchetype.Elements.Length; i++)
|
||||
{
|
||||
if (nodeArchetype.Elements[i].Type == NodeElementType.Input &&
|
||||
startBox.CanUseType(nodeArchetype.Elements[i].ConnectionsType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
isCompatible |= _archetype.IsInputCompatible.Invoke(_archetype, startBox.CurrentType, _archetype.ConnectionsHints);
|
||||
}
|
||||
return false;
|
||||
else if (!startBox.IsOutput && _archetype.IsOutputCompatible != null)
|
||||
{
|
||||
isCompatible |= _archetype.IsOutputCompatible.Invoke(_archetype, startBox.CurrentType, startBox.ParentNode.Archetype.ConnectionsHints);
|
||||
}
|
||||
else if (_archetype.Elements != null)
|
||||
{
|
||||
// Check compatibility based on the defined elements in the archetype. This handles all the default groups and items
|
||||
isCompatible = CheckElementsCompatibility(startBox);
|
||||
}
|
||||
|
||||
return isCompatible;
|
||||
}
|
||||
|
||||
private bool CheckElementsCompatibility(Box startBox)
|
||||
{
|
||||
bool isCompatible = false;
|
||||
foreach (NodeElementArchetype element in _archetype.Elements)
|
||||
{
|
||||
// Ignore all elements that aren't inputs or outputs (e.g. input fields)
|
||||
if (element.Type != NodeElementType.Output && element.Type != NodeElementType.Input)
|
||||
continue;
|
||||
|
||||
// Ignore elements with the same direction as the box
|
||||
if ((startBox.IsOutput && element.Type == NodeElementType.Output) || (!startBox.IsOutput && element.Type == NodeElementType.Input))
|
||||
continue;
|
||||
|
||||
ScriptType fromType;
|
||||
ScriptType toType;
|
||||
ConnectionsHint hint;
|
||||
if (startBox.IsOutput)
|
||||
{
|
||||
fromType = element.ConnectionsType;
|
||||
toType = startBox.CurrentType;
|
||||
hint = _archetype.ConnectionsHints;
|
||||
}
|
||||
else
|
||||
{
|
||||
fromType = startBox.CurrentType;
|
||||
toType = element.ConnectionsType;
|
||||
hint = startBox.ParentNode.Archetype.ConnectionsHints;
|
||||
}
|
||||
|
||||
isCompatible |= VisjectSurface.FullCastCheck(fromType, toType, hint);
|
||||
}
|
||||
|
||||
return isCompatible;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the filter.
|
||||
/// </summary>
|
||||
/// <param name="filterText">The filter text.</param>
|
||||
public void UpdateFilter(string filterText)
|
||||
/// <param name="selectedBox">The optionally selected box to show hints for it.</param>
|
||||
/// <param name="groupHeaderMatches">True if item's group header got a filter match and item should stay visible.</param>
|
||||
public void UpdateFilter(string filterText, Box selectedBox, bool groupHeaderMatches = false)
|
||||
{
|
||||
if (selectedBox != null)
|
||||
{
|
||||
Visible = CanConnectTo(selectedBox);
|
||||
if (!Visible)
|
||||
{
|
||||
_highlights?.Clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_isStartsWithMatch = _isFullMatch = false;
|
||||
if (filterText == null)
|
||||
if (string.IsNullOrEmpty(filterText))
|
||||
{
|
||||
// Clear filter
|
||||
_highlights?.Clear();
|
||||
@@ -184,7 +243,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
|
||||
Data = data;
|
||||
}
|
||||
else
|
||||
else if (!groupHeaderMatches)
|
||||
{
|
||||
// Hide
|
||||
_highlights?.Clear();
|
||||
|
||||
Reference in New Issue
Block a user