From fa67d0581e113c511e59ba6a0314cc9c08ae4936 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Sun, 9 Jun 2024 13:45:53 +0200 Subject: [PATCH 01/29] - Added optional description panel to visject CM - Enbaled description panel for visual scripting - Archetype description now gets drawn in description panel --- .../Editor/Surface/ContextMenu/VisjectCM.cs | 44 ++++++++++++++++++- .../Surface/ContextMenu/VisjectCMItem.cs | 7 +++ .../Surface/VisjectSurface.ContextMenu.cs | 1 + Source/Editor/Surface/VisjectSurface.cs | 5 +++ Source/Editor/Surface/VisualScriptSurface.cs | 3 ++ 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index ae4cef3dc..005c164fd 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -51,6 +51,10 @@ namespace FlaxEditor.Surface.ContextMenu private Elements.Box _selectedBox; private NodeArchetype _parameterGetNodeArchetype; private NodeArchetype _parameterSetNodeArchetype; + private bool _useDescriptionPanel; + private string _currentDescriptionText; + private Panel _descriptionPanel; + private Label _descriptionLabel; /// /// The selected item @@ -82,6 +86,11 @@ namespace FlaxEditor.Surface.ContextMenu /// public bool CanSetParameters; + /// + /// True if the surface should make use of a description panel drawn at the bottom of the context menu + /// + public bool UseDescriptionPanel; + /// /// The groups archetypes. Cannot be null. /// @@ -127,9 +136,11 @@ namespace FlaxEditor.Surface.ContextMenu _parameterGetNodeArchetype = info.ParameterGetNodeArchetype ?? Archetypes.Parameters.Nodes[0]; if (info.CanSetParameters) _parameterSetNodeArchetype = info.ParameterSetNodeArchetype ?? Archetypes.Parameters.Nodes[3]; + _useDescriptionPanel = info.UseDescriptionPanel; + float descriptionHeight = 75; // Context menu dimensions - Size = new Float2(300, 400); + Size = new Float2(300, 400 + (_useDescriptionPanel ? descriptionHeight : 0)); var headerPanel = new Panel(ScrollBars.None) { @@ -187,7 +198,7 @@ namespace FlaxEditor.Surface.ContextMenu // Create first panel (for scrollbar) var panel1 = new Panel(ScrollBars.Vertical) { - Bounds = new Rectangle(0, _searchBox.Bottom + 1, Width, Height - _searchBox.Bottom - 2), + Bounds = new Rectangle(0, _searchBox.Bottom + 1, Width, Height - _searchBox.Bottom - (_useDescriptionPanel ? descriptionHeight : 0) - 2), Parent = this }; @@ -202,6 +213,27 @@ namespace FlaxEditor.Surface.ContextMenu }; _groupsPanel = panel2; + // Create description panel if enabled + if (_useDescriptionPanel) + { + var descriptionPanel = new Panel(ScrollBars.None) + { + Parent = this, + Bounds = new Rectangle(0, Height - descriptionHeight, Width, descriptionHeight), + BackgroundColor = Style.Current.BackgroundNormal, + }; + _descriptionPanel = descriptionPanel; + + var descriptionLabel = new Label(8,8,Width-16,Height-16) + { + Parent = _descriptionPanel, + HorizontalAlignment = TextAlignment.Near, + VerticalAlignment = TextAlignment.Near, + Wrapping = TextWrapping.WrapWords, + }; + _descriptionLabel = descriptionLabel; + } + // Init groups var nodes = new List(); foreach (var groupArchetype in info.Groups) @@ -549,6 +581,14 @@ namespace FlaxEditor.Surface.ContextMenu _groups[i].Open(animate); } + public void SetDescriptionText(string text) + { + if(!_useDescriptionPanel) + return; + _currentDescriptionText = text; + _descriptionLabel.Text = _currentDescriptionText; + } + /// /// Resets the view. /// diff --git a/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs b/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs index 9d582c491..ede6775e7 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs @@ -338,6 +338,13 @@ namespace FlaxEditor.Surface.ContextMenu return base.OnMouseUp(location, button); } + /// + public override void OnMouseEnter(Float2 location) + { + base.OnMouseEnter(location); + Group.ContextMenu.SetDescriptionText(_archetype.Description); + } + /// public override void OnMouseLeave() { diff --git a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs index 7f284420d..54f4e14e6 100644 --- a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs +++ b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs @@ -237,6 +237,7 @@ namespace FlaxEditor.Surface return new VisjectCM(new VisjectCM.InitInfo { CanSetParameters = CanSetParameters, + UseDescriptionPanel = UseContextMenuDescriptionPanel, Groups = NodeArchetypes, CanSpawnNode = CanUseNodeType, ParametersGetter = () => Parameters, diff --git a/Source/Editor/Surface/VisjectSurface.cs b/Source/Editor/Surface/VisjectSurface.cs index 78277dbe2..b3869f304 100644 --- a/Source/Editor/Surface/VisjectSurface.cs +++ b/Source/Editor/Surface/VisjectSurface.cs @@ -535,6 +535,11 @@ namespace FlaxEditor.Surface /// public virtual bool CanSetParameters => false; + /// + /// True of the context menu should make use of a description panel drawn at the bottom of the menu + /// + public virtual bool UseContextMenuDescriptionPanel => false; + /// /// Gets a value indicating whether surface supports/allows live previewing graph modifications due to value sliders and color pickers. True by default but disabled for shader surfaces that generate and compile shader source at flight. /// diff --git a/Source/Editor/Surface/VisualScriptSurface.cs b/Source/Editor/Surface/VisualScriptSurface.cs index ee0a3c6d6..f32bd2ea0 100644 --- a/Source/Editor/Surface/VisualScriptSurface.cs +++ b/Source/Editor/Surface/VisualScriptSurface.cs @@ -174,6 +174,9 @@ namespace FlaxEditor.Surface /// public override bool CanSetParameters => true; + /// + public override bool UseContextMenuDescriptionPanel => true; + /// public override bool CanUseNodeType(GroupArchetype groupArchetype, NodeArchetype nodeArchetype) { From bd06ed9c148c62374826f02b62aeedca445c09bd Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Sun, 9 Jun 2024 23:42:48 +0200 Subject: [PATCH 02/29] - Archetypes now fetch signature and description independently - Added larger label for signature to description panel --- Source/Editor/Surface/Archetypes/Particles.cs | 2 +- .../Editor/Surface/ContextMenu/VisjectCM.cs | 23 +++++-- .../Surface/ContextMenu/VisjectCMItem.cs | 4 +- Source/Editor/Surface/NodeArchetype.cs | 6 ++ Source/Editor/Surface/SurfaceNode.cs | 2 +- Source/Editor/Surface/SurfaceUtils.cs | 63 +++++++++++-------- Source/Editor/Surface/VisualScriptSurface.cs | 13 ++-- 7 files changed, 75 insertions(+), 38 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/Particles.cs b/Source/Editor/Surface/Archetypes/Particles.cs index 081f53e30..9166cb0d9 100644 --- a/Source/Editor/Surface/Archetypes/Particles.cs +++ b/Source/Editor/Surface/Archetypes/Particles.cs @@ -122,7 +122,7 @@ namespace FlaxEditor.Surface.Archetypes { Name = module.Title, Tag = module.TypeID, - TooltipText = module.Description, + TooltipText = $"{module.Signature}\n{module.Description}", }); } cm.ItemClicked += item => AddModule((ushort)item.Tag); diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 005c164fd..182d18b5d 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -52,8 +52,8 @@ namespace FlaxEditor.Surface.ContextMenu private NodeArchetype _parameterGetNodeArchetype; private NodeArchetype _parameterSetNodeArchetype; private bool _useDescriptionPanel; - private string _currentDescriptionText; private Panel _descriptionPanel; + private Label _descriptionSignatureLabel; private Label _descriptionLabel; /// @@ -224,7 +224,20 @@ namespace FlaxEditor.Surface.ContextMenu }; _descriptionPanel = descriptionPanel; - var descriptionLabel = new Label(8,8,Width-16,Height-16) + var signatureFontReference = new FontReference(Style.Current.FontLarge.Asset, 11); + var signatureLabel = new Label(8, 8, Width - 16, Height - 16) + { + Parent = _descriptionPanel, + HorizontalAlignment = TextAlignment.Near, + VerticalAlignment = TextAlignment.Near, + Wrapping = TextWrapping.WrapWords, + Font = signatureFontReference, + Bold = true, + Italic = true, + }; + _descriptionSignatureLabel = signatureLabel; + + var descriptionLabel = new Label(8, 40, Width - 16, Height - 16) { Parent = _descriptionPanel, HorizontalAlignment = TextAlignment.Near, @@ -581,12 +594,12 @@ namespace FlaxEditor.Surface.ContextMenu _groups[i].Open(animate); } - public void SetDescriptionText(string text) + public void SetDescriptionText(string header, string text) { if(!_useDescriptionPanel) return; - _currentDescriptionText = text; - _descriptionLabel.Text = _currentDescriptionText; + _descriptionSignatureLabel.Text = header; + _descriptionLabel.Text = text; } /// diff --git a/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs b/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs index ede6775e7..8d9fceba7 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs @@ -62,7 +62,7 @@ namespace FlaxEditor.Surface.ContextMenu Group = group; _groupArchetype = groupArchetype; _archetype = archetype; - TooltipText = _archetype.Description; + TooltipText = $"{_archetype.Signature}\n{_archetype.Description}"; } /// @@ -342,7 +342,7 @@ namespace FlaxEditor.Surface.ContextMenu public override void OnMouseEnter(Float2 location) { base.OnMouseEnter(location); - Group.ContextMenu.SetDescriptionText(_archetype.Description); + Group.ContextMenu.SetDescriptionText(_archetype.Signature, _archetype.Description); } /// diff --git a/Source/Editor/Surface/NodeArchetype.cs b/Source/Editor/Surface/NodeArchetype.cs index d0e3f2291..efcec6b62 100644 --- a/Source/Editor/Surface/NodeArchetype.cs +++ b/Source/Editor/Surface/NodeArchetype.cs @@ -134,6 +134,11 @@ namespace FlaxEditor.Surface /// public string SubTitle; + /// + /// Node signature for tooltip and description purposes + /// + public string Signature; + /// /// Short node description. /// @@ -210,6 +215,7 @@ namespace FlaxEditor.Surface Flags = Flags, Title = Title, SubTitle = SubTitle, + Signature = Signature, Description = Description, AlternativeTitles = (string[])AlternativeTitles?.Clone(), Tag = Tag, diff --git a/Source/Editor/Surface/SurfaceNode.cs b/Source/Editor/Surface/SurfaceNode.cs index 0eb739d72..07dc4f5e9 100644 --- a/Source/Editor/Surface/SurfaceNode.cs +++ b/Source/Editor/Surface/SurfaceNode.cs @@ -124,7 +124,7 @@ namespace FlaxEditor.Surface Archetype = nodeArch; GroupArchetype = groupArch; AutoFocus = false; - TooltipText = nodeArch.Description; + TooltipText = TooltipText = $"{nodeArch.Signature}\n{nodeArch.Description}"; CullChildren = false; BackgroundColor = Style.Current.BackgroundNormal; diff --git a/Source/Editor/Surface/SurfaceUtils.cs b/Source/Editor/Surface/SurfaceUtils.cs index 9bec6c179..936aa52eb 100644 --- a/Source/Editor/Surface/SurfaceUtils.cs +++ b/Source/Editor/Surface/SurfaceUtils.cs @@ -440,12 +440,24 @@ namespace FlaxEditor.Surface return sb.ToString(); } - internal static string GetVisualScriptMemberInfoDescription(ScriptMemberInfo member) + internal static string GetVisualScriptMemberInfoSignature(ScriptMemberInfo member, bool appendPropertyInfo = true) { var name = member.Name; var declaringType = member.DeclaringType; var valueType = member.ValueType; + // Getter/setter method of the property - we can return early here + bool isGetterOrSetter = name.StartsWith("get_") || name.StartsWith("set_"); + if (member.IsMethod && isGetterOrSetter) + { + var flags = member.IsStatic ? BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly : BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; + var property = declaringType.GetMembers(name.Substring(4), MemberTypes.Property, flags); + if (property != null && property.Length != 0) + { + return GetVisualScriptMemberInfoDescription(property[0]); + } + } + var sb = new StringBuilder(); if (member.IsStatic) sb.Append("static "); @@ -456,34 +468,22 @@ namespace FlaxEditor.Surface sb.Append(declaringType.Name); sb.Append('.'); sb.Append(name); - if (member.IsMethod) + + // Is a method and not a property + if (member.IsMethod && !isGetterOrSetter) { - // Getter/setter method of the property - if (name.StartsWith("get_") || name.StartsWith("set_")) + sb.Append('('); + var parameters = member.GetParameters(); + for (int i = 0; i < parameters.Length; i++) { - var flags = member.IsStatic ? BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly : BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; - var property = declaringType.GetMembers(name.Substring(4), MemberTypes.Property, flags); - if (property != null && property.Length != 0) - { - return GetVisualScriptMemberInfoDescription(property[0]); - } - } - // Method - else - { - sb.Append('('); - var parameters = member.GetParameters(); - for (int i = 0; i < parameters.Length; i++) - { - if (i != 0) - sb.Append(", "); - ref var param = ref parameters[i]; - param.ToString(sb); - } - sb.Append(')'); + if (i != 0) + sb.Append(", "); + ref var param = ref parameters[i]; + param.ToString(sb); } + sb.Append(')'); } - else if (member.IsProperty) + else if (member.IsProperty && appendPropertyInfo) { sb.Append(' '); sb.Append('{'); @@ -495,6 +495,19 @@ namespace FlaxEditor.Surface sb.Append('}'); } + return sb.ToString(); + } + + internal static string GetVisualScriptMemberShortDescription(ScriptMemberInfo member) + { + return Editor.Instance.CodeDocs.GetTooltip(member); + } + + internal static string GetVisualScriptMemberInfoDescription(ScriptMemberInfo member) + { + var signature = GetVisualScriptMemberInfoSignature(member); + var sb = new StringBuilder(signature); + // Tooltip var tooltip = Editor.Instance.CodeDocs.GetTooltip(member); if (!string.IsNullOrEmpty(tooltip)) diff --git a/Source/Editor/Surface/VisualScriptSurface.cs b/Source/Editor/Surface/VisualScriptSurface.cs index f32bd2ea0..39a705ff9 100644 --- a/Source/Editor/Surface/VisualScriptSurface.cs +++ b/Source/Editor/Surface/VisualScriptSurface.cs @@ -370,7 +370,8 @@ namespace FlaxEditor.Surface node.DefaultValues[2] = parameters.Length; node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = SurfaceUtils.GetMethodDisplayName((string)node.DefaultValues[1]); - node.Description = SurfaceUtils.GetVisualScriptMemberInfoDescription(member); + node.Signature = SurfaceUtils.GetVisualScriptMemberInfoSignature(member); + node.Description = SurfaceUtils.GetVisualScriptMemberShortDescription(member); node.SubTitle = string.Format(" (in {0})", scriptTypeName); node.Tag = member; @@ -418,7 +419,8 @@ namespace FlaxEditor.Surface node.DefaultValues[3] = member.IsStatic; node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = "Get " + name; - node.Description = SurfaceUtils.GetVisualScriptMemberInfoDescription(member); + node.Signature = SurfaceUtils.GetVisualScriptMemberInfoSignature(member); + node.Description = SurfaceUtils.GetVisualScriptMemberShortDescription(member); node.SubTitle = string.Format(" (in {0})", scriptTypeName); // Create group archetype @@ -452,7 +454,8 @@ namespace FlaxEditor.Surface node.DefaultValues[3] = member.IsStatic; node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = "Set " + name; - node.Description = SurfaceUtils.GetVisualScriptMemberInfoDescription(member); + node.Signature = SurfaceUtils.GetVisualScriptMemberInfoSignature(member); + node.Description = SurfaceUtils.GetVisualScriptMemberShortDescription(member); node.SubTitle = string.Format(" (in {0})", scriptTypeName); // Create group archetype @@ -510,7 +513,8 @@ namespace FlaxEditor.Surface bindNode.DefaultValues[1] = name; bindNode.Flags &= ~NodeFlags.NoSpawnViaGUI; bindNode.Title = "Bind " + name; - bindNode.Description = SurfaceUtils.GetVisualScriptMemberInfoDescription(member); + bindNode.Signature = SurfaceUtils.GetVisualScriptMemberInfoSignature(member); + bindNode.Description = SurfaceUtils.GetVisualScriptMemberShortDescription(member); bindNode.SubTitle = string.Format(" (in {0})", scriptTypeName); ((IList)group.Archetypes).Add(bindNode); @@ -520,6 +524,7 @@ namespace FlaxEditor.Surface unbindNode.DefaultValues[1] = name; unbindNode.Flags &= ~NodeFlags.NoSpawnViaGUI; unbindNode.Title = "Unbind " + name; + unbindNode.Signature = bindNode.Signature; unbindNode.Description = bindNode.Description; unbindNode.SubTitle = bindNode.SubTitle; ((IList)group.Archetypes).Add(unbindNode); From ed8c7bc33846083e504aae0698373d2a80ac749a Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Sun, 9 Jun 2024 23:52:34 +0200 Subject: [PATCH 03/29] - Format change --- Source/Editor/Surface/ContextMenu/VisjectCM.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 182d18b5d..2b922297c 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -225,7 +225,7 @@ namespace FlaxEditor.Surface.ContextMenu _descriptionPanel = descriptionPanel; var signatureFontReference = new FontReference(Style.Current.FontLarge.Asset, 11); - var signatureLabel = new Label(8, 8, Width - 16, Height - 16) + var signatureLabel = new Label(8, 12, Width - 16, Height - 16) { Parent = _descriptionPanel, HorizontalAlignment = TextAlignment.Near, From da6883489ebb87399725f4e61a279964d3a2cadc Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Mon, 10 Jun 2024 12:03:34 +0200 Subject: [PATCH 04/29] - Added description panel resizing --- .../Editor/Surface/ContextMenu/VisjectCM.cs | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 2b922297c..aaac3c9d3 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -138,9 +138,8 @@ namespace FlaxEditor.Surface.ContextMenu _parameterSetNodeArchetype = info.ParameterSetNodeArchetype ?? Archetypes.Parameters.Nodes[3]; _useDescriptionPanel = info.UseDescriptionPanel; - float descriptionHeight = 75; // Context menu dimensions - Size = new Float2(300, 400 + (_useDescriptionPanel ? descriptionHeight : 0)); + Size = new Float2(300, 400); var headerPanel = new Panel(ScrollBars.None) { @@ -152,7 +151,7 @@ namespace FlaxEditor.Surface.ContextMenu }; // Title bar - var titleFontReference = new FontReference(Style.Current.FontLarge.Asset, 10); + var titleFontReference = new FontReference(Style.Current.FontMedium.Asset, 11); var titleLabel = new Label { Width = Width * 0.5f - 8f, @@ -198,7 +197,7 @@ namespace FlaxEditor.Surface.ContextMenu // Create first panel (for scrollbar) var panel1 = new Panel(ScrollBars.Vertical) { - Bounds = new Rectangle(0, _searchBox.Bottom + 1, Width, Height - _searchBox.Bottom - (_useDescriptionPanel ? descriptionHeight : 0) - 2), + Bounds = new Rectangle(0, _searchBox.Bottom + 1, Width, Height - _searchBox.Bottom - 2), Parent = this }; @@ -219,13 +218,13 @@ namespace FlaxEditor.Surface.ContextMenu var descriptionPanel = new Panel(ScrollBars.None) { Parent = this, - Bounds = new Rectangle(0, Height - descriptionHeight, Width, descriptionHeight), + Bounds = new Rectangle(0, Height, Width, 0), BackgroundColor = Style.Current.BackgroundNormal, }; _descriptionPanel = descriptionPanel; - var signatureFontReference = new FontReference(Style.Current.FontLarge.Asset, 11); - var signatureLabel = new Label(8, 12, Width - 16, Height - 16) + var signatureFontReference = new FontReference(Style.Current.FontMedium.Asset, 10); + var signatureLabel = new Label(8, 12, Width - 16, 0) { Parent = _descriptionPanel, HorizontalAlignment = TextAlignment.Near, @@ -234,16 +233,20 @@ namespace FlaxEditor.Surface.ContextMenu Font = signatureFontReference, Bold = true, Italic = true, + AutoHeight = true, }; + signatureLabel.SetAnchorPreset(AnchorPresets.TopLeft, true); _descriptionSignatureLabel = signatureLabel; - var descriptionLabel = new Label(8, 40, Width - 16, Height - 16) + var descriptionLabel = new Label(8, 0, Width - 16, 0) { Parent = _descriptionPanel, HorizontalAlignment = TextAlignment.Near, VerticalAlignment = TextAlignment.Near, Wrapping = TextWrapping.WrapWords, + AutoHeight = true, }; + descriptionLabel.SetAnchorPreset(AnchorPresets.TopLeft, true); _descriptionLabel = descriptionLabel; } @@ -598,8 +601,17 @@ namespace FlaxEditor.Surface.ContextMenu { if(!_useDescriptionPanel) return; + _descriptionSignatureLabel.Text = header; + var panelHeight = _descriptionSignatureLabel.Height; + + _descriptionLabel.Y = _descriptionSignatureLabel.Bounds.Bottom + 8f; _descriptionLabel.Text = text; + + panelHeight += _descriptionLabel.Height + 8f + 24f; + _descriptionPanel.Height = panelHeight; + Size = new Float2(300, 400 + _descriptionPanel.Height); + UpdateWindowSize(); } /// From 1da00264a057df8fc4fb5d17c62a766697734627 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Mon, 10 Jun 2024 18:45:03 +0200 Subject: [PATCH 05/29] - Description panel now updates when navigating items with keyboard - First test of drawing images in description panel (showing class type) - Layout and style changes to work with images and make evertything a bit tighter --- Source/Editor/Surface/AnimGraphSurface.cs | 2 + .../Editor/Surface/ContextMenu/VisjectCM.cs | 99 ++++++++++++++----- .../Surface/ContextMenu/VisjectCMItem.cs | 10 +- .../Surface/VisjectSurface.ContextMenu.cs | 1 + 4 files changed, 86 insertions(+), 26 deletions(-) diff --git a/Source/Editor/Surface/AnimGraphSurface.cs b/Source/Editor/Surface/AnimGraphSurface.cs index 4e8b6f11e..ea0d9d32f 100644 --- a/Source/Editor/Surface/AnimGraphSurface.cs +++ b/Source/Editor/Surface/AnimGraphSurface.cs @@ -197,6 +197,7 @@ namespace FlaxEditor.Surface { Groups = StateMachineGroupArchetypes, CanSpawnNode = (_, _) => true, + Style = Style, }); _cmStateMachineMenu.ShowExpanded = true; } @@ -214,6 +215,7 @@ namespace FlaxEditor.Surface CanSpawnNode = CanUseNodeType, ParametersGetter = null, CustomNodesGroup = GetCustomNodes(), + Style = Style, }); _cmStateMachineTransitionMenu.AddGroup(StateMachineTransitionGroupArchetype, false); } diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index aaac3c9d3..ce2b5d12b 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -51,15 +51,29 @@ namespace FlaxEditor.Surface.ContextMenu private Elements.Box _selectedBox; private NodeArchetype _parameterGetNodeArchetype; private NodeArchetype _parameterSetNodeArchetype; - private bool _useDescriptionPanel; - private Panel _descriptionPanel; - private Label _descriptionSignatureLabel; - private Label _descriptionLabel; + + // Description panel elements + private readonly bool _useDescriptionPanel; + private readonly Panel _descriptionPanel; + private readonly Image _descriptionClassImage; + private readonly Label _descriptionSignatureLabel; + private readonly Label _descriptionLabel; + + + private VisjectCMItem _selectedItem; /// /// The selected item /// - public VisjectCMItem SelectedItem; + public VisjectCMItem SelectedItem + { + get => _selectedItem; + set + { + _selectedItem = value; + _selectedItem?.OnSelect(); + } + } /// /// Event fired when any item in this popup menu gets clicked. @@ -120,6 +134,11 @@ namespace FlaxEditor.Surface.ContextMenu /// The parameter setter node archetype to spawn when adding the parameter getter. Can be null. /// public NodeArchetype ParameterSetNodeArchetype; + + /// + /// The surface style to use to draw images in the description panel + /// + public SurfaceStyle Style; } /// @@ -151,7 +170,7 @@ namespace FlaxEditor.Surface.ContextMenu }; // Title bar - var titleFontReference = new FontReference(Style.Current.FontMedium.Asset, 11); + var titleFontReference = new FontReference(Style.Current.FontLarge.Asset, 10); var titleLabel = new Label { Width = Width * 0.5f - 8f, @@ -200,7 +219,6 @@ namespace FlaxEditor.Surface.ContextMenu Bounds = new Rectangle(0, _searchBox.Bottom + 1, Width, Height - _searchBox.Bottom - 2), Parent = this }; - _panel1 = panel1; // Create second panel (for groups arrangement) @@ -215,16 +233,25 @@ namespace FlaxEditor.Surface.ContextMenu // Create description panel if enabled if (_useDescriptionPanel) { - var descriptionPanel = new Panel(ScrollBars.None) + _descriptionPanel = new Panel(ScrollBars.None) { Parent = this, Bounds = new Rectangle(0, Height, Width, 0), BackgroundColor = Style.Current.BackgroundNormal, }; - _descriptionPanel = descriptionPanel; - var signatureFontReference = new FontReference(Style.Current.FontMedium.Asset, 10); - var signatureLabel = new Label(8, 12, Width - 16, 0) + var spriteHandle = info.Style.Icons.BoxClose; + _descriptionClassImage = new Image(8, 12, 20, 20) + { + Parent = _descriptionPanel, + Brush = new SpriteBrush(spriteHandle), + Color = Color.Aqua, + MouseOverColor = Color.Aqua, + AutoFocus = false, + }; + + var signatureFontReference = new FontReference(Style.Current.FontMedium.Asset, 9f); + _descriptionSignatureLabel = new Label(32, 8, Width - 40, 0) { Parent = _descriptionPanel, HorizontalAlignment = TextAlignment.Near, @@ -232,22 +259,20 @@ namespace FlaxEditor.Surface.ContextMenu Wrapping = TextWrapping.WrapWords, Font = signatureFontReference, Bold = true, - Italic = true, AutoHeight = true, }; - signatureLabel.SetAnchorPreset(AnchorPresets.TopLeft, true); - _descriptionSignatureLabel = signatureLabel; - - var descriptionLabel = new Label(8, 0, Width - 16, 0) + _descriptionSignatureLabel.SetAnchorPreset(AnchorPresets.TopLeft, true); + + _descriptionLabel = new Label(32, 0, Width - 40, 0) { Parent = _descriptionPanel, HorizontalAlignment = TextAlignment.Near, VerticalAlignment = TextAlignment.Near, Wrapping = TextWrapping.WrapWords, + Font = signatureFontReference, AutoHeight = true, }; - descriptionLabel.SetAnchorPreset(AnchorPresets.TopLeft, true); - _descriptionLabel = descriptionLabel; + _descriptionLabel.SetAnchorPreset(AnchorPresets.TopLeft, true); } // Init groups @@ -597,20 +622,44 @@ namespace FlaxEditor.Surface.ContextMenu _groups[i].Open(animate); } - public void SetDescriptionText(string header, string text) + /// + /// Updates the description panel and shows information about the set archetype + /// + /// The node archetype + public void SetDescriptionPanelArchetype(NodeArchetype archetype) { if(!_useDescriptionPanel) return; + + if (archetype == null) + { + HideDescriptionPanel(); + return; + } - _descriptionSignatureLabel.Text = header; - var panelHeight = _descriptionSignatureLabel.Height; + Profiler.BeginEvent("VisjectCM.SetDescriptionPanelArchetype"); + + _descriptionSignatureLabel.Text = archetype.Signature; + float panelHeight = _descriptionSignatureLabel.Height; - _descriptionLabel.Y = _descriptionSignatureLabel.Bounds.Bottom + 8f; - _descriptionLabel.Text = text; + _descriptionLabel.Y = _descriptionSignatureLabel.Bounds.Bottom + 6f; + _descriptionLabel.Text = archetype.Description; - panelHeight += _descriptionLabel.Height + 8f + 24f; + panelHeight += _descriptionLabel.Height + 6f + 18f; + _descriptionPanel.Height = panelHeight; - Size = new Float2(300, 400 + _descriptionPanel.Height); + Height = 400 + Mathf.RoundToInt(_descriptionPanel.Height); + UpdateWindowSize(); + + Profiler.EndEvent(); + } + + /// + /// Hides the description panel and resets the context menu to its original size + /// + public void HideDescriptionPanel() + { + Height = 400; UpdateWindowSize(); } diff --git a/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs b/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs index 8d9fceba7..c0fba5586 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs @@ -315,6 +315,14 @@ namespace FlaxEditor.Surface.ContextMenu } } + /// + /// Callback when selected by the visject CM + /// + public void OnSelect() + { + Group.ContextMenu.SetDescriptionPanelArchetype(_archetype); + } + /// public override bool OnMouseDown(Float2 location, MouseButton button) { @@ -342,7 +350,7 @@ namespace FlaxEditor.Surface.ContextMenu public override void OnMouseEnter(Float2 location) { base.OnMouseEnter(location); - Group.ContextMenu.SetDescriptionText(_archetype.Signature, _archetype.Description); + Group.ContextMenu.SetDescriptionPanelArchetype(_archetype); } /// diff --git a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs index 54f4e14e6..604394769 100644 --- a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs +++ b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs @@ -243,6 +243,7 @@ namespace FlaxEditor.Surface ParametersGetter = () => Parameters, CustomNodesGroup = GetCustomNodes(), ParameterGetNodeArchetype = GetParameterGetterNodeArchetype(out _), + Style = Style, }); } From 99c10e5ed3c6037c751e4d2227941900c3978062 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Mon, 10 Jun 2024 23:14:24 +0200 Subject: [PATCH 06/29] - Now correctly fetching signature and description for properties - Minor code cleanup --- .../Editor/Surface/ContextMenu/VisjectCM.cs | 19 ++++++++++++++--- Source/Editor/Surface/SurfaceUtils.cs | 21 ++++++++++++++++--- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index ce2b5d12b..2844d16b0 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -5,6 +5,7 @@ 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; @@ -638,15 +639,27 @@ namespace FlaxEditor.Surface.ContextMenu } Profiler.BeginEvent("VisjectCM.SetDescriptionPanelArchetype"); - - _descriptionSignatureLabel.Text = archetype.Signature; + + if (archetype.Tag is ScriptMemberInfo memberInfo) + { + var name = memberInfo.Name; + if (memberInfo.IsMethod && memberInfo.Name.StartsWith("get_") || memberInfo.Name.StartsWith("set_")) + { + name = memberInfo.Name.Substring(4); + } + + _descriptionSignatureLabel.Text = memberInfo.DeclaringType + "." + name; + } + else + _descriptionSignatureLabel.Text = archetype.Signature; + float panelHeight = _descriptionSignatureLabel.Height; _descriptionLabel.Y = _descriptionSignatureLabel.Bounds.Bottom + 6f; _descriptionLabel.Text = archetype.Description; panelHeight += _descriptionLabel.Height + 6f + 18f; - + _descriptionPanel.Height = panelHeight; Height = 400 + Mathf.RoundToInt(_descriptionPanel.Height); UpdateWindowSize(); diff --git a/Source/Editor/Surface/SurfaceUtils.cs b/Source/Editor/Surface/SurfaceUtils.cs index 936aa52eb..8e14787b6 100644 --- a/Source/Editor/Surface/SurfaceUtils.cs +++ b/Source/Editor/Surface/SurfaceUtils.cs @@ -440,7 +440,7 @@ namespace FlaxEditor.Surface return sb.ToString(); } - internal static string GetVisualScriptMemberInfoSignature(ScriptMemberInfo member, bool appendPropertyInfo = true) + internal static string GetVisualScriptMemberInfoSignature(ScriptMemberInfo member) { var name = member.Name; var declaringType = member.DeclaringType; @@ -454,7 +454,7 @@ namespace FlaxEditor.Surface var property = declaringType.GetMembers(name.Substring(4), MemberTypes.Property, flags); if (property != null && property.Length != 0) { - return GetVisualScriptMemberInfoDescription(property[0]); + return GetVisualScriptMemberInfoSignature(property[0]); } } @@ -483,7 +483,7 @@ namespace FlaxEditor.Surface } sb.Append(')'); } - else if (member.IsProperty && appendPropertyInfo) + else if (member.IsProperty) { sb.Append(' '); sb.Append('{'); @@ -500,6 +500,21 @@ namespace FlaxEditor.Surface internal static string GetVisualScriptMemberShortDescription(ScriptMemberInfo member) { + var name = member.Name; + var declaringType = member.DeclaringType; + + // Getter/setter method of the property - we can return early here + bool isGetterOrSetter = name.StartsWith("get_") || name.StartsWith("set_"); + if (member.IsMethod && isGetterOrSetter) + { + var flags = member.IsStatic ? BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly : BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; + var property = declaringType.GetMembers(name.Substring(4), MemberTypes.Property, flags); + if (property != null && property.Length != 0) + { + return GetVisualScriptMemberShortDescription(property[0]); + } + } + return Editor.Instance.CodeDocs.GetTooltip(member); } From 5059cef0654fdcee63477828399506a28ac03445 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Mon, 10 Jun 2024 23:24:34 +0200 Subject: [PATCH 07/29] - Description panel declaring type icon now updates its color --- Source/Editor/Surface/ContextMenu/VisjectCM.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 2844d16b0..00afa803d 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -59,6 +59,7 @@ namespace FlaxEditor.Surface.ContextMenu private readonly Image _descriptionClassImage; private readonly Label _descriptionSignatureLabel; private readonly Label _descriptionLabel; + private readonly SurfaceStyle _surfaceStyle; private VisjectCMItem _selectedItem; @@ -157,6 +158,7 @@ namespace FlaxEditor.Surface.ContextMenu if (info.CanSetParameters) _parameterSetNodeArchetype = info.ParameterSetNodeArchetype ?? Archetypes.Parameters.Nodes[3]; _useDescriptionPanel = info.UseDescriptionPanel; + _surfaceStyle = info.Style; // Context menu dimensions Size = new Float2(300, 400); @@ -639,7 +641,8 @@ namespace FlaxEditor.Surface.ContextMenu } Profiler.BeginEvent("VisjectCM.SetDescriptionPanelArchetype"); - + + ScriptType declaringType; if (archetype.Tag is ScriptMemberInfo memberInfo) { var name = memberInfo.Name; @@ -647,12 +650,20 @@ namespace FlaxEditor.Surface.ContextMenu { name = memberInfo.Name.Substring(4); } - + + declaringType = memberInfo.DeclaringType; _descriptionSignatureLabel.Text = memberInfo.DeclaringType + "." + name; } else + { _descriptionSignatureLabel.Text = archetype.Signature; + declaringType = archetype.DefaultType; + } + _surfaceStyle.GetConnectionColor(declaringType, archetype.ConnectionsHints, out var typeColor); + _descriptionClassImage.Color = typeColor; + _descriptionClassImage.MouseOverColor = typeColor; + float panelHeight = _descriptionSignatureLabel.Height; _descriptionLabel.Y = _descriptionSignatureLabel.Bounds.Bottom + 6f; From df404507b59170a8115a37e26f2ae2f40e1143fb Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Wed, 12 Jun 2024 19:20:09 +0200 Subject: [PATCH 08/29] - Now showing inputs and outputs in a very buggy and dirty way --- .../Editor/Surface/ContextMenu/VisjectCM.cs | 98 ++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 00afa803d..0a85e7bdf 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -60,6 +60,8 @@ namespace FlaxEditor.Surface.ContextMenu private readonly Label _descriptionSignatureLabel; private readonly Label _descriptionLabel; private readonly SurfaceStyle _surfaceStyle; + private readonly VerticalPanel _descriptionInputPanel; + private readonly VerticalPanel _descriptionOutputPanel; private VisjectCMItem _selectedItem; @@ -276,6 +278,22 @@ namespace FlaxEditor.Surface.ContextMenu AutoHeight = true, }; _descriptionLabel.SetAnchorPreset(AnchorPresets.TopLeft, true); + + _descriptionInputPanel = new VerticalPanel() + { + Parent = _descriptionPanel, + Width = Width * 0.5f, + AnchorPreset = AnchorPresets.TopLeft, + AutoSize = true, + }; + + _descriptionOutputPanel = new VerticalPanel() + { + Parent = _descriptionPanel, + X = Width * 0.5f, + Width = Width * 0.5f, + AutoSize = true, + }; } // Init groups @@ -643,6 +661,10 @@ namespace FlaxEditor.Surface.ContextMenu Profiler.BeginEvent("VisjectCM.SetDescriptionPanelArchetype"); ScriptType declaringType; + + _descriptionInputPanel.RemoveChildren(); + _descriptionOutputPanel.RemoveChildren(); + if (archetype.Tag is ScriptMemberInfo memberInfo) { var name = memberInfo.Name; @@ -652,12 +674,80 @@ namespace FlaxEditor.Surface.ContextMenu } declaringType = memberInfo.DeclaringType; - _descriptionSignatureLabel.Text = memberInfo.DeclaringType + "." + name; + _descriptionSignatureLabel.Text = memberInfo.DeclaringType + "." + name; + + if(!memberInfo.IsStatic) + _descriptionInputPanel.AddChild(new Label(0,0,100, 16) + { + Text = $">Instance ({memberInfo.DeclaringType.Name})", + HorizontalAlignment = TextAlignment.Near, + VerticalAlignment = TextAlignment.Near, + Wrapping = TextWrapping.NoWrap, + }).SetAnchorPreset(AnchorPresets.TopLeft, true); + + if (memberInfo.ValueType != ScriptType.Null || memberInfo.ValueType != ScriptType.Void) + { + _descriptionOutputPanel.AddChild(new Label(0,0,100, 16) + { + Text = $">Return ({memberInfo.ValueType.Name})", + HorizontalAlignment = TextAlignment.Near, + VerticalAlignment = TextAlignment.Near, + Wrapping = TextWrapping.NoWrap, + }).SetAnchorPreset(AnchorPresets.TopLeft, true); + } + + for(int i = 0; i < memberInfo.ParametersCount; i++) + { + var param = memberInfo.GetParameters()[i]; + if (param.IsOut) + { + _descriptionOutputPanel.AddChild(new Label(0,0,100, 16) + { + Text = $"{param.Name} ({param.Type.Name})", + HorizontalAlignment = TextAlignment.Near, + VerticalAlignment = TextAlignment.Near, + Wrapping = TextWrapping.NoWrap, + }).SetAnchorPreset(AnchorPresets.TopLeft, true); + + continue; + } + _descriptionInputPanel.AddChild(new Label(0,0,100, 16) + { + Text = $"{param.Name} ({param.Type.Name})", + HorizontalAlignment = TextAlignment.Near, + VerticalAlignment = TextAlignment.Near, + Wrapping = TextWrapping.NoWrap, + }).SetAnchorPreset(AnchorPresets.TopLeft, true); + } } else { _descriptionSignatureLabel.Text = archetype.Signature; declaringType = archetype.DefaultType; + + foreach (var element in archetype.Elements) + { + if (element.Type == NodeElementType.Input) + { + _descriptionInputPanel.AddChild(new Label(0,0,100, 16) + { + Text = element.Text, + HorizontalAlignment = TextAlignment.Near, + VerticalAlignment = TextAlignment.Near, + Wrapping = TextWrapping.NoWrap, + }).SetAnchorPreset(AnchorPresets.TopLeft, true); + } + else if (element.Type == NodeElementType.Output) + { + _descriptionOutputPanel.AddChild(new Label(0,0,100, 16) + { + Text = element.Text, + HorizontalAlignment = TextAlignment.Near, + VerticalAlignment = TextAlignment.Near, + Wrapping = TextWrapping.NoWrap, + }).SetAnchorPreset(AnchorPresets.TopLeft, true); + } + } } _surfaceStyle.GetConnectionColor(declaringType, archetype.ConnectionsHints, out var typeColor); @@ -671,10 +761,16 @@ namespace FlaxEditor.Surface.ContextMenu panelHeight += _descriptionLabel.Height + 6f + 18f; + _descriptionInputPanel.Y = panelHeight; + _descriptionOutputPanel.Y = panelHeight; + + panelHeight += Mathf.Max(_descriptionInputPanel.Height, _descriptionOutputPanel.Height); _descriptionPanel.Height = panelHeight; Height = 400 + Mathf.RoundToInt(_descriptionPanel.Height); UpdateWindowSize(); + PerformLayout(); + Profiler.EndEvent(); } From 1be136bd2e087cf16604b7446c388458cac3ace0 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Wed, 12 Jun 2024 21:07:35 +0200 Subject: [PATCH 09/29] - Now drawing icon type for inputs/outputs for archetypes with their attached memberinfo --- .../Editor/Surface/ContextMenu/VisjectCM.cs | 48 ++++++++++++++++--- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 0a85e7bdf..b2b7507d5 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -661,10 +661,12 @@ namespace FlaxEditor.Surface.ContextMenu Profiler.BeginEvent("VisjectCM.SetDescriptionPanelArchetype"); ScriptType declaringType; + Color typeColor; _descriptionInputPanel.RemoveChildren(); _descriptionOutputPanel.RemoveChildren(); + var spriteHandle = _surfaceStyle.Icons.BoxOpen; if (archetype.Tag is ScriptMemberInfo memberInfo) { var name = memberInfo.Name; @@ -675,8 +677,17 @@ namespace FlaxEditor.Surface.ContextMenu declaringType = memberInfo.DeclaringType; _descriptionSignatureLabel.Text = memberInfo.DeclaringType + "." + name; - - if(!memberInfo.IsStatic) + + if (!memberInfo.IsStatic) + { + _surfaceStyle.GetConnectionColor(declaringType, archetype.ConnectionsHints, out typeColor); + _descriptionInputPanel.AddChild(new Image(2, 0, 12, 12) + { + Brush = new SpriteBrush(spriteHandle), + Color = typeColor, + MouseOverColor = typeColor, + AutoFocus = false, + }).SetAnchorPreset(AnchorPresets.TopLeft, true); _descriptionInputPanel.AddChild(new Label(0,0,100, 16) { Text = $">Instance ({memberInfo.DeclaringType.Name})", @@ -684,9 +695,18 @@ namespace FlaxEditor.Surface.ContextMenu VerticalAlignment = TextAlignment.Near, Wrapping = TextWrapping.NoWrap, }).SetAnchorPreset(AnchorPresets.TopLeft, true); + } - if (memberInfo.ValueType != ScriptType.Null || memberInfo.ValueType != ScriptType.Void) + if (memberInfo.ValueType != ScriptType.Null && memberInfo.ValueType != ScriptType.Void) { + _surfaceStyle.GetConnectionColor(memberInfo.ValueType, archetype.ConnectionsHints, out typeColor); + _descriptionOutputPanel.AddChild(new Image(2, 0, 12, 12) + { + Brush = new SpriteBrush(spriteHandle), + Color = typeColor, + MouseOverColor = typeColor, + AutoFocus = false, + }).SetAnchorPreset(AnchorPresets.TopLeft, true); _descriptionOutputPanel.AddChild(new Label(0,0,100, 16) { Text = $">Return ({memberInfo.ValueType.Name})", @@ -699,9 +719,17 @@ namespace FlaxEditor.Surface.ContextMenu for(int i = 0; i < memberInfo.ParametersCount; i++) { var param = memberInfo.GetParameters()[i]; + _surfaceStyle.GetConnectionColor(param.Type, archetype.ConnectionsHints, out typeColor); if (param.IsOut) { - _descriptionOutputPanel.AddChild(new Label(0,0,100, 16) + _descriptionOutputPanel.AddChild(new Image(2, 0, 12, 12) + { + Brush = new SpriteBrush(spriteHandle), + Color = typeColor, + MouseOverColor = typeColor, + AutoFocus = false, + }).SetAnchorPreset(AnchorPresets.TopLeft, true); + _descriptionOutputPanel.AddChild(new Label(12,0,100, 16) { Text = $"{param.Name} ({param.Type.Name})", HorizontalAlignment = TextAlignment.Near, @@ -711,7 +739,15 @@ namespace FlaxEditor.Surface.ContextMenu continue; } - _descriptionInputPanel.AddChild(new Label(0,0,100, 16) + + _descriptionInputPanel.AddChild(new Image(2, 0, 12, 12) + { + Brush = new SpriteBrush(spriteHandle), + Color = typeColor, + MouseOverColor = typeColor, + AutoFocus = false, + }).SetAnchorPreset(AnchorPresets.TopLeft, true); + _descriptionInputPanel.AddChild(new Label(12,0,100, 16) { Text = $"{param.Name} ({param.Type.Name})", HorizontalAlignment = TextAlignment.Near, @@ -750,7 +786,7 @@ namespace FlaxEditor.Surface.ContextMenu } } - _surfaceStyle.GetConnectionColor(declaringType, archetype.ConnectionsHints, out var typeColor); + _surfaceStyle.GetConnectionColor(declaringType, archetype.ConnectionsHints, out typeColor); _descriptionClassImage.Color = typeColor; _descriptionClassImage.MouseOverColor = typeColor; From 36bdd6cbd07c24b78cf89df299575aa377c76554 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Thu, 13 Jun 2024 19:04:46 +0200 Subject: [PATCH 10/29] - Refactored some code handling the input/output elements - Added member information to all cached nodes to be able to fetch their informations --- .../Editor/Surface/ContextMenu/VisjectCM.cs | 144 +++++++++--------- Source/Editor/Surface/VisualScriptSurface.cs | 4 + 2 files changed, 76 insertions(+), 72 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index b2b7507d5..e386fa668 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -667,6 +667,7 @@ namespace FlaxEditor.Surface.ContextMenu _descriptionOutputPanel.RemoveChildren(); var spriteHandle = _surfaceStyle.Icons.BoxOpen; + if (archetype.Tag is ScriptMemberInfo memberInfo) { var name = memberInfo.Name; @@ -681,39 +682,13 @@ namespace FlaxEditor.Surface.ContextMenu if (!memberInfo.IsStatic) { _surfaceStyle.GetConnectionColor(declaringType, archetype.ConnectionsHints, out typeColor); - _descriptionInputPanel.AddChild(new Image(2, 0, 12, 12) - { - Brush = new SpriteBrush(spriteHandle), - Color = typeColor, - MouseOverColor = typeColor, - AutoFocus = false, - }).SetAnchorPreset(AnchorPresets.TopLeft, true); - _descriptionInputPanel.AddChild(new Label(0,0,100, 16) - { - Text = $">Instance ({memberInfo.DeclaringType.Name})", - HorizontalAlignment = TextAlignment.Near, - VerticalAlignment = TextAlignment.Near, - Wrapping = TextWrapping.NoWrap, - }).SetAnchorPreset(AnchorPresets.TopLeft, true); + AddInputElement(spriteHandle, typeColor, $">Instance ({memberInfo.DeclaringType.Name})"); } if (memberInfo.ValueType != ScriptType.Null && memberInfo.ValueType != ScriptType.Void) { _surfaceStyle.GetConnectionColor(memberInfo.ValueType, archetype.ConnectionsHints, out typeColor); - _descriptionOutputPanel.AddChild(new Image(2, 0, 12, 12) - { - Brush = new SpriteBrush(spriteHandle), - Color = typeColor, - MouseOverColor = typeColor, - AutoFocus = false, - }).SetAnchorPreset(AnchorPresets.TopLeft, true); - _descriptionOutputPanel.AddChild(new Label(0,0,100, 16) - { - Text = $">Return ({memberInfo.ValueType.Name})", - HorizontalAlignment = TextAlignment.Near, - VerticalAlignment = TextAlignment.Near, - Wrapping = TextWrapping.NoWrap, - }).SetAnchorPreset(AnchorPresets.TopLeft, true); + AddOutputElement(spriteHandle, typeColor, $">Return ({memberInfo.ValueType.Name})"); } for(int i = 0; i < memberInfo.ParametersCount; i++) @@ -722,38 +697,11 @@ namespace FlaxEditor.Surface.ContextMenu _surfaceStyle.GetConnectionColor(param.Type, archetype.ConnectionsHints, out typeColor); if (param.IsOut) { - _descriptionOutputPanel.AddChild(new Image(2, 0, 12, 12) - { - Brush = new SpriteBrush(spriteHandle), - Color = typeColor, - MouseOverColor = typeColor, - AutoFocus = false, - }).SetAnchorPreset(AnchorPresets.TopLeft, true); - _descriptionOutputPanel.AddChild(new Label(12,0,100, 16) - { - Text = $"{param.Name} ({param.Type.Name})", - HorizontalAlignment = TextAlignment.Near, - VerticalAlignment = TextAlignment.Near, - Wrapping = TextWrapping.NoWrap, - }).SetAnchorPreset(AnchorPresets.TopLeft, true); - + AddOutputElement(spriteHandle, typeColor, $"{param.Name} ({param.Type.Name})"); continue; } - - _descriptionInputPanel.AddChild(new Image(2, 0, 12, 12) - { - Brush = new SpriteBrush(spriteHandle), - Color = typeColor, - MouseOverColor = typeColor, - AutoFocus = false, - }).SetAnchorPreset(AnchorPresets.TopLeft, true); - _descriptionInputPanel.AddChild(new Label(12,0,100, 16) - { - Text = $"{param.Name} ({param.Type.Name})", - HorizontalAlignment = TextAlignment.Near, - VerticalAlignment = TextAlignment.Near, - Wrapping = TextWrapping.NoWrap, - }).SetAnchorPreset(AnchorPresets.TopLeft, true); + + AddInputElement(spriteHandle, typeColor, $"{param.Name} ({param.Type.Name})"); } } else @@ -761,27 +709,18 @@ namespace FlaxEditor.Surface.ContextMenu _descriptionSignatureLabel.Text = archetype.Signature; declaringType = archetype.DefaultType; + Debug.Log(archetype.Elements); foreach (var element in archetype.Elements) { if (element.Type == NodeElementType.Input) { - _descriptionInputPanel.AddChild(new Label(0,0,100, 16) - { - Text = element.Text, - HorizontalAlignment = TextAlignment.Near, - VerticalAlignment = TextAlignment.Near, - Wrapping = TextWrapping.NoWrap, - }).SetAnchorPreset(AnchorPresets.TopLeft, true); + _surfaceStyle.GetConnectionColor(element.ConnectionsType, archetype.ConnectionsHints, out typeColor); + AddInputElement(spriteHandle, typeColor, element.Text); } else if (element.Type == NodeElementType.Output) { - _descriptionOutputPanel.AddChild(new Label(0,0,100, 16) - { - Text = element.Text, - HorizontalAlignment = TextAlignment.Near, - VerticalAlignment = TextAlignment.Near, - Wrapping = TextWrapping.NoWrap, - }).SetAnchorPreset(AnchorPresets.TopLeft, true); + _surfaceStyle.GetConnectionColor(element.ConnectionsType, archetype.ConnectionsHints, out typeColor); + AddOutputElement(spriteHandle, typeColor, element.Text); } } } @@ -810,6 +749,67 @@ namespace FlaxEditor.Surface.ContextMenu Profiler.EndEvent(); } + private void AddInputElement(SpriteHandle sprite, Color typeColor, string text) + { + var elementPanel = new Panel() + { + Width = Width * 0.5f, + Height = 16, + Parent = _descriptionInputPanel, + AnchorPreset = AnchorPresets.TopLeft + }; + + elementPanel.AddChild(new Image(2, 0, 12, 12) + { + Brush = new SpriteBrush(sprite), + Color = typeColor, + MouseOverColor = typeColor, + AutoFocus = false, + }).SetAnchorPreset(AnchorPresets.TopLeft, true); + + var elementText = new Label(16, 0, Width * 0.5f - 32, 16) + { + Text = text, + HorizontalAlignment = TextAlignment.Near, + VerticalAlignment = TextAlignment.Near, + Wrapping = TextWrapping.WrapWords, + AutoHeight = true, + }; + elementText.SetAnchorPreset(AnchorPresets.TopLeft, true); + elementPanel.AddChild(elementText); + elementPanel.Height = elementText.Height; + } + + private void AddOutputElement(SpriteHandle sprite, Color typeColor, string text) + { + var elementPanel = new Panel() + { + Width = Width * 0.5f, + Height = 16, + Parent = _descriptionOutputPanel, + AnchorPreset = AnchorPresets.TopLeft + }; + + elementPanel.AddChild(new Image(2, 0, 12, 12) + { + Brush = new SpriteBrush(sprite), + Color = typeColor, + MouseOverColor = typeColor, + AutoFocus = false, + }).SetAnchorPreset(AnchorPresets.TopLeft, true); + + var elementText = new Label(16, 0, Width * 0.5f - 32, 16) + { + Text = text, + HorizontalAlignment = TextAlignment.Near, + VerticalAlignment = TextAlignment.Near, + Wrapping = TextWrapping.NoWrap, + }; + elementText.SetAnchorPreset(AnchorPresets.TopLeft, true); + elementPanel.AddChild(elementText); + elementPanel.Height = elementText.Height; + } + /// /// Hides the description panel and resets the context menu to its original size /// diff --git a/Source/Editor/Surface/VisualScriptSurface.cs b/Source/Editor/Surface/VisualScriptSurface.cs index 39a705ff9..7ee3a381b 100644 --- a/Source/Editor/Surface/VisualScriptSurface.cs +++ b/Source/Editor/Surface/VisualScriptSurface.cs @@ -422,6 +422,7 @@ namespace FlaxEditor.Surface node.Signature = SurfaceUtils.GetVisualScriptMemberInfoSignature(member); node.Description = SurfaceUtils.GetVisualScriptMemberShortDescription(member); node.SubTitle = string.Format(" (in {0})", scriptTypeName); + node.Tag = member; // Create group archetype var groupKey = new KeyValuePair(scriptTypeName, 16); @@ -457,6 +458,7 @@ namespace FlaxEditor.Surface node.Signature = SurfaceUtils.GetVisualScriptMemberInfoSignature(member); node.Description = SurfaceUtils.GetVisualScriptMemberShortDescription(member); node.SubTitle = string.Format(" (in {0})", scriptTypeName); + node.Tag = member; // Create group archetype var groupKey = new KeyValuePair(scriptTypeName, 16); @@ -516,6 +518,7 @@ namespace FlaxEditor.Surface bindNode.Signature = SurfaceUtils.GetVisualScriptMemberInfoSignature(member); bindNode.Description = SurfaceUtils.GetVisualScriptMemberShortDescription(member); bindNode.SubTitle = string.Format(" (in {0})", scriptTypeName); + bindNode.Tag = member; ((IList)group.Archetypes).Add(bindNode); // Add Unbind event node @@ -527,6 +530,7 @@ namespace FlaxEditor.Surface unbindNode.Signature = bindNode.Signature; unbindNode.Description = bindNode.Description; unbindNode.SubTitle = bindNode.SubTitle; + unbindNode.Tag = member; ((IList)group.Archetypes).Add(unbindNode); #if DEBUG_EVENTS_SEARCHING From 67f3f89bf76b2eb1d91d0b70e3c4c65fb73717fa Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Thu, 13 Jun 2024 22:03:41 +0200 Subject: [PATCH 11/29] - Override node inputs/outputs now also get shown - Added special treatment for enum, pack and unpack nodes in order to also show their inputs/outputs --- .../Editor/Surface/ContextMenu/VisjectCM.cs | 69 ++++++++++++++++--- Source/Editor/Surface/VisualScriptSurface.cs | 1 + 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index e386fa668..15e1448b0 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -2,7 +2,9 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Reflection; using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.Input; using FlaxEditor.Scripting; @@ -688,7 +690,10 @@ namespace FlaxEditor.Surface.ContextMenu if (memberInfo.ValueType != ScriptType.Null && memberInfo.ValueType != ScriptType.Void) { _surfaceStyle.GetConnectionColor(memberInfo.ValueType, archetype.ConnectionsHints, out typeColor); - AddOutputElement(spriteHandle, typeColor, $">Return ({memberInfo.ValueType.Name})"); + if (memberInfo.IsField && archetype.Title.StartsWith("Set ")) + AddInputElement(spriteHandle, typeColor, $"({memberInfo.ValueType.Name})"); + else + AddOutputElement(spriteHandle, typeColor, $">Return ({memberInfo.ValueType.Name})"); } for(int i = 0; i < memberInfo.ParametersCount; i++) @@ -708,19 +713,63 @@ namespace FlaxEditor.Surface.ContextMenu { _descriptionSignatureLabel.Text = archetype.Signature; declaringType = archetype.DefaultType; - - Debug.Log(archetype.Elements); - foreach (var element in archetype.Elements) + + // Special handling for Pack nodes + if (archetype.TypeID == 26) { - if (element.Type == NodeElementType.Input) + var outputType = TypeUtils.GetType((string)archetype.DefaultValues[0]); + _surfaceStyle.GetConnectionColor(outputType, archetype.ConnectionsHints, out typeColor); + AddOutputElement(spriteHandle, typeColor, $"{outputType.Name}"); + + var fields = outputType.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); + var fieldsLength = fields.Length; + for (var i = 0; i < fieldsLength; i++) { - _surfaceStyle.GetConnectionColor(element.ConnectionsType, archetype.ConnectionsHints, out typeColor); - AddInputElement(spriteHandle, typeColor, element.Text); + var field = fields[i]; + _surfaceStyle.GetConnectionColor(field.ValueType, archetype.ConnectionsHints, out typeColor); + AddInputElement(spriteHandle, typeColor, $"{field.Name} ({field.ValueType.Name})"); } - else if (element.Type == NodeElementType.Output) + } + else if (archetype.TypeID == 36) + { + var inputType = TypeUtils.GetType((string)archetype.DefaultValues[0]); + _surfaceStyle.GetConnectionColor(inputType, archetype.ConnectionsHints, out typeColor); + AddInputElement(spriteHandle, typeColor, $"{inputType.Name}"); + + var fields = inputType.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); + var fieldsLength = fields.Length; + for (var i = 0; i < fieldsLength; i++) { - _surfaceStyle.GetConnectionColor(element.ConnectionsType, archetype.ConnectionsHints, out typeColor); - AddOutputElement(spriteHandle, typeColor, element.Text); + var field = fields[i]; + _surfaceStyle.GetConnectionColor(field.ValueType, archetype.ConnectionsHints, out typeColor); + AddOutputElement(spriteHandle, typeColor, $"{field.Name} ({field.ValueType.Name})"); + } + } + else + { + foreach (var element in archetype.Elements) + { + if (element.Type == NodeElementType.Input) + { + _surfaceStyle.GetConnectionColor(element.ConnectionsType, archetype.ConnectionsHints, out typeColor); + AddInputElement(spriteHandle, typeColor, $"{element.Text} ({element.Type.ToString()})"); + } + else if (element.Type == NodeElementType.Output) + { + // TODO: better check for enums + switch (archetype.TypeID) + { + case 11: + var t = new ScriptType(archetype.DefaultValues[0].GetType()); + _surfaceStyle.GetConnectionColor(t, archetype.ConnectionsHints, out typeColor); + AddOutputElement(spriteHandle, typeColor, $"{t.Name}"); + break; + default: + _surfaceStyle.GetConnectionColor(element.ConnectionsType, archetype.ConnectionsHints, out typeColor); + AddOutputElement(spriteHandle, typeColor, $"{element.Text} ({element.Type.ToString()})"); + break; + } + } } } } diff --git a/Source/Editor/Surface/VisualScriptSurface.cs b/Source/Editor/Surface/VisualScriptSurface.cs index 7ee3a381b..f7fafeef8 100644 --- a/Source/Editor/Surface/VisualScriptSurface.cs +++ b/Source/Editor/Surface/VisualScriptSurface.cs @@ -242,6 +242,7 @@ namespace FlaxEditor.Surface node.DefaultValues[0] = name; node.DefaultValues[1] = parameters.Length; node.Title = "Override " + name; + node.Tag = member; nodes.Add(node); } } From 804e652b6d0441b7a5914062ac24ae436a4ab49e Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Fri, 14 Jun 2024 20:39:39 +0200 Subject: [PATCH 12/29] - Now using the connectionhints when no connectionstype is available - Some special treatment for Array and Dictionary Constants, kinda dirty --- .../Editor/Surface/ContextMenu/VisjectCM.cs | 46 +++++++++++++++---- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 15e1448b0..80fb4ecb6 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -8,6 +8,7 @@ using System.Reflection; using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.Input; using FlaxEditor.Scripting; +using FlaxEditor.Surface.Archetypes; using FlaxEngine; using FlaxEngine.GUI; using FlaxEngine.Utilities; @@ -702,7 +703,7 @@ namespace FlaxEditor.Surface.ContextMenu _surfaceStyle.GetConnectionColor(param.Type, archetype.ConnectionsHints, out typeColor); if (param.IsOut) { - AddOutputElement(spriteHandle, typeColor, $"{param.Name} ({param.Type.Name})"); + AddOutputElement(spriteHandle, typeColor, $">{param.Name} ({param.Type.Name})"); continue; } @@ -751,23 +752,48 @@ namespace FlaxEditor.Surface.ContextMenu { if (element.Type == NodeElementType.Input) { - _surfaceStyle.GetConnectionColor(element.ConnectionsType, archetype.ConnectionsHints, out typeColor); - AddInputElement(spriteHandle, typeColor, $"{element.Text} ({element.Type.ToString()})"); + var connectionsType = element.ConnectionsType; + _surfaceStyle.GetConnectionColor(connectionsType, archetype.ConnectionsHints, out typeColor); + + if (connectionsType == null) + { + if(archetype == Archetypes.Constants.Nodes[12]) + AddInputElement(spriteHandle, typeColor, $"-{element.Text} ({ConnectionsHint.Array.ToString()})"); + else if (archetype == Archetypes.Constants.Nodes[13]) + AddInputElement(spriteHandle, typeColor, $"-{element.Text} ({ConnectionsHint.Dictionary.ToString()})"); + else + AddInputElement(spriteHandle, typeColor, $"-{element.Text} ({archetype.ConnectionsHints.ToString()})"); + continue; + } + + AddInputElement(spriteHandle, typeColor, $"{element.Text} ({element.ConnectionsType.Name})"); } else if (element.Type == NodeElementType.Output) { // TODO: better check for enums - switch (archetype.TypeID) + if (archetype == Archetypes.Constants.Nodes[10]) { - case 11: var t = new ScriptType(archetype.DefaultValues[0].GetType()); _surfaceStyle.GetConnectionColor(t, archetype.ConnectionsHints, out typeColor); AddOutputElement(spriteHandle, typeColor, $"{t.Name}"); - break; - default: - _surfaceStyle.GetConnectionColor(element.ConnectionsType, archetype.ConnectionsHints, out typeColor); - AddOutputElement(spriteHandle, typeColor, $"{element.Text} ({element.Type.ToString()})"); - break; + } + else + { + var connectionsType = element.ConnectionsType; + _surfaceStyle.GetConnectionColor(connectionsType, archetype.ConnectionsHints, out typeColor); + + if (connectionsType == null) + { + if(archetype == Archetypes.Constants.Nodes[12]) + AddOutputElement(spriteHandle, typeColor, $"-{element.Text} ({ConnectionsHint.Array.ToString()})"); + else if (archetype == Archetypes.Constants.Nodes[13]) + AddOutputElement(spriteHandle, typeColor, $"-{element.Text} ({ConnectionsHint.Dictionary.ToString()})"); + else + AddOutputElement(spriteHandle, typeColor, $"-{element.Text} ({archetype.ConnectionsHints.ToString()})"); + continue; + } + + AddOutputElement(spriteHandle, typeColor, $"-{element.Text} ({connectionsType.Name})"); } } } From 46cc4c72e79240397a1dffcbd0909f98e531071e Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Sat, 15 Jun 2024 19:47:48 +0200 Subject: [PATCH 13/29] - Refactored and cleaned up a bunch of redundant code --- .../Editor/Surface/ContextMenu/VisjectCM.cs | 133 ++++-------------- 1 file changed, 29 insertions(+), 104 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 80fb4ecb6..a7737b4de 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -664,12 +664,11 @@ namespace FlaxEditor.Surface.ContextMenu Profiler.BeginEvent("VisjectCM.SetDescriptionPanelArchetype"); ScriptType declaringType; - Color typeColor; + string elementName, elementTypeName; _descriptionInputPanel.RemoveChildren(); _descriptionOutputPanel.RemoveChildren(); - var spriteHandle = _surfaceStyle.Icons.BoxOpen; if (archetype.Tag is ScriptMemberInfo memberInfo) { @@ -683,31 +682,26 @@ namespace FlaxEditor.Surface.ContextMenu _descriptionSignatureLabel.Text = memberInfo.DeclaringType + "." + name; if (!memberInfo.IsStatic) - { - _surfaceStyle.GetConnectionColor(declaringType, archetype.ConnectionsHints, out typeColor); - AddInputElement(spriteHandle, typeColor, $">Instance ({memberInfo.DeclaringType.Name})"); - } + AddInputOutputElement(archetype, declaringType, false, $">Instance ({memberInfo.DeclaringType.Name})"); if (memberInfo.ValueType != ScriptType.Null && memberInfo.ValueType != ScriptType.Void) { - _surfaceStyle.GetConnectionColor(memberInfo.ValueType, archetype.ConnectionsHints, out typeColor); if (memberInfo.IsField && archetype.Title.StartsWith("Set ")) - AddInputElement(spriteHandle, typeColor, $"({memberInfo.ValueType.Name})"); + AddInputOutputElement(archetype, memberInfo.ValueType, false, $"({memberInfo.ValueType.Name})"); else - AddOutputElement(spriteHandle, typeColor, $">Return ({memberInfo.ValueType.Name})"); + AddInputOutputElement(archetype, memberInfo.ValueType, true, $"Return ({memberInfo.ValueType.Name})"); } for(int i = 0; i < memberInfo.ParametersCount; i++) { var param = memberInfo.GetParameters()[i]; - _surfaceStyle.GetConnectionColor(param.Type, archetype.ConnectionsHints, out typeColor); if (param.IsOut) { - AddOutputElement(spriteHandle, typeColor, $">{param.Name} ({param.Type.Name})"); + AddInputOutputElement(archetype, param.Type, true, $">{param.Name} ({param.Type.Name})"); continue; } - AddInputElement(spriteHandle, typeColor, $"{param.Name} ({param.Type.Name})"); + AddInputOutputElement(archetype, param.Type, false, $">{param.Name} ({param.Type.Name})"); } } else @@ -716,93 +710,52 @@ namespace FlaxEditor.Surface.ContextMenu declaringType = archetype.DefaultType; // Special handling for Pack nodes - if (archetype.TypeID == 26) + if (archetype == Packing.Nodes[6] || archetype == Packing.Nodes[13]) { - var outputType = TypeUtils.GetType((string)archetype.DefaultValues[0]); - _surfaceStyle.GetConnectionColor(outputType, archetype.ConnectionsHints, out typeColor); - AddOutputElement(spriteHandle, typeColor, $"{outputType.Name}"); + bool isOutput = archetype == Packing.Nodes[6]; + var type = TypeUtils.GetType((string)archetype.DefaultValues[0]); + AddInputOutputElement(archetype, type, isOutput, $"{type.Name}"); - var fields = outputType.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); + var fields = type.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); var fieldsLength = fields.Length; for (var i = 0; i < fieldsLength; i++) { var field = fields[i]; - _surfaceStyle.GetConnectionColor(field.ValueType, archetype.ConnectionsHints, out typeColor); - AddInputElement(spriteHandle, typeColor, $"{field.Name} ({field.ValueType.Name})"); + AddInputOutputElement(archetype, field.ValueType, !isOutput, $"{field.Name} ({field.ValueType.Name})"); } } - else if (archetype.TypeID == 36) + else if (archetype == Archetypes.Constants.Nodes[10]) { - var inputType = TypeUtils.GetType((string)archetype.DefaultValues[0]); - _surfaceStyle.GetConnectionColor(inputType, archetype.ConnectionsHints, out typeColor); - AddInputElement(spriteHandle, typeColor, $"{inputType.Name}"); - - var fields = inputType.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); - var fieldsLength = fields.Length; - for (var i = 0; i < fieldsLength; i++) - { - var field = fields[i]; - _surfaceStyle.GetConnectionColor(field.ValueType, archetype.ConnectionsHints, out typeColor); - AddOutputElement(spriteHandle, typeColor, $"{field.Name} ({field.ValueType.Name})"); - } + var t = new ScriptType(archetype.DefaultValues[0].GetType()); + AddInputOutputElement(archetype, t, true, $"ENUM {t.Name}"); } else { foreach (var element in archetype.Elements) { - if (element.Type == NodeElementType.Input) + if (element.Type is NodeElementType.Input or NodeElementType.Output) { - var connectionsType = element.ConnectionsType; - _surfaceStyle.GetConnectionColor(connectionsType, archetype.ConnectionsHints, out typeColor); - - if (connectionsType == null) + bool isOutput = element.Type == NodeElementType.Output; + if (element.ConnectionsType == null) { if(archetype == Archetypes.Constants.Nodes[12]) - AddInputElement(spriteHandle, typeColor, $"-{element.Text} ({ConnectionsHint.Array.ToString()})"); + AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({ConnectionsHint.Array.ToString()})"); else if (archetype == Archetypes.Constants.Nodes[13]) - AddInputElement(spriteHandle, typeColor, $"-{element.Text} ({ConnectionsHint.Dictionary.ToString()})"); + AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({ConnectionsHint.Dictionary.ToString()})"); else - AddInputElement(spriteHandle, typeColor, $"-{element.Text} ({archetype.ConnectionsHints.ToString()})"); + AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({archetype.ConnectionsHints.ToString()})"); continue; } - AddInputElement(spriteHandle, typeColor, $"{element.Text} ({element.ConnectionsType.Name})"); - } - else if (element.Type == NodeElementType.Output) - { - // TODO: better check for enums - if (archetype == Archetypes.Constants.Nodes[10]) - { - var t = new ScriptType(archetype.DefaultValues[0].GetType()); - _surfaceStyle.GetConnectionColor(t, archetype.ConnectionsHints, out typeColor); - AddOutputElement(spriteHandle, typeColor, $"{t.Name}"); - } - else - { - var connectionsType = element.ConnectionsType; - _surfaceStyle.GetConnectionColor(connectionsType, archetype.ConnectionsHints, out typeColor); - - if (connectionsType == null) - { - if(archetype == Archetypes.Constants.Nodes[12]) - AddOutputElement(spriteHandle, typeColor, $"-{element.Text} ({ConnectionsHint.Array.ToString()})"); - else if (archetype == Archetypes.Constants.Nodes[13]) - AddOutputElement(spriteHandle, typeColor, $"-{element.Text} ({ConnectionsHint.Dictionary.ToString()})"); - else - AddOutputElement(spriteHandle, typeColor, $"-{element.Text} ({archetype.ConnectionsHints.ToString()})"); - continue; - } - - AddOutputElement(spriteHandle, typeColor, $"-{element.Text} ({connectionsType.Name})"); - } + AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({element.ConnectionsType.Name})"); } } } } - _surfaceStyle.GetConnectionColor(declaringType, archetype.ConnectionsHints, out typeColor); - _descriptionClassImage.Color = typeColor; - _descriptionClassImage.MouseOverColor = typeColor; + _surfaceStyle.GetConnectionColor(declaringType, archetype.ConnectionsHints, out var declaringTypeColor); + _descriptionClassImage.Color = declaringTypeColor; + _descriptionClassImage.MouseOverColor = declaringTypeColor; float panelHeight = _descriptionSignatureLabel.Height; @@ -824,16 +777,18 @@ namespace FlaxEditor.Surface.ContextMenu Profiler.EndEvent(); } - private void AddInputElement(SpriteHandle sprite, Color typeColor, string text) + private void AddInputOutputElement(NodeArchetype nodeArchetype, ScriptType type, bool isOutput, string text) { var elementPanel = new Panel() { + Parent = isOutput ? _descriptionOutputPanel : _descriptionInputPanel, Width = Width * 0.5f, Height = 16, - Parent = _descriptionInputPanel, AnchorPreset = AnchorPresets.TopLeft }; + var sprite = _surfaceStyle.Icons.BoxOpen; + _surfaceStyle.GetConnectionColor(type, nodeArchetype.ConnectionsHints, out var typeColor); elementPanel.AddChild(new Image(2, 0, 12, 12) { Brush = new SpriteBrush(sprite), @@ -855,36 +810,6 @@ namespace FlaxEditor.Surface.ContextMenu elementPanel.Height = elementText.Height; } - private void AddOutputElement(SpriteHandle sprite, Color typeColor, string text) - { - var elementPanel = new Panel() - { - Width = Width * 0.5f, - Height = 16, - Parent = _descriptionOutputPanel, - AnchorPreset = AnchorPresets.TopLeft - }; - - elementPanel.AddChild(new Image(2, 0, 12, 12) - { - Brush = new SpriteBrush(sprite), - Color = typeColor, - MouseOverColor = typeColor, - AutoFocus = false, - }).SetAnchorPreset(AnchorPresets.TopLeft, true); - - var elementText = new Label(16, 0, Width * 0.5f - 32, 16) - { - Text = text, - HorizontalAlignment = TextAlignment.Near, - VerticalAlignment = TextAlignment.Near, - Wrapping = TextWrapping.NoWrap, - }; - elementText.SetAnchorPreset(AnchorPresets.TopLeft, true); - elementPanel.AddChild(elementText); - elementPanel.Height = elementText.Height; - } - /// /// Hides the description panel and resets the context menu to its original size /// From 0fd8de80295225043f75a82b2fa9a1b692841920 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Sat, 15 Jun 2024 22:13:05 +0200 Subject: [PATCH 14/29] - Added custom func to fetch information for nodes that need special treatment like Array, Enum or Un/Pack nodes - More refactoring and cleanup --- Source/Editor/Surface/Archetypes/Constants.cs | 24 +++++++++ Source/Editor/Surface/Archetypes/Packing.cs | 32 ++++++++++++ .../Editor/Surface/ContextMenu/VisjectCM.cs | 50 ++++++++----------- Source/Editor/Surface/NodeArchetype.cs | 13 ++++- 4 files changed, 88 insertions(+), 31 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/Constants.cs b/Source/Editor/Surface/Archetypes/Constants.cs index b94bc34cb..8cce34332 100644 --- a/Source/Editor/Surface/Archetypes/Constants.cs +++ b/Source/Editor/Surface/Archetypes/Constants.cs @@ -7,6 +7,8 @@ using Real = System.Single; #endif using System; +using System.Collections; +using System.Collections.Generic; using System.Linq; using FlaxEditor.CustomEditors.Editors; using FlaxEditor.GUI; @@ -182,6 +184,13 @@ namespace FlaxEditor.Surface.Archetypes base.OnDestroy(); } + + internal static void GetInputOutputDescription(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs) + { + var type = new ScriptType(nodeArch.DefaultValues[0].GetType()); + inputs = null; + outputs = [(type.Name, type)]; + } } private class ArrayNode : SurfaceNode @@ -321,6 +330,12 @@ namespace FlaxEditor.Surface.Archetypes array.SetValue(value, box.ID - 1); SetValue(0, array); } + + internal static void GetInputOutputDescription(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs) + { + inputs = null; + outputs = [("", new ScriptType(typeof(Array)))]; + } } private class DictionaryNode : SurfaceNode @@ -449,6 +464,12 @@ namespace FlaxEditor.Surface.Archetypes array.SetValue(value, box.ID - 1); SetValue(0, array); } + + internal static void GetInputOutputDescription(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs) + { + inputs = null; + outputs = [("", new ScriptType(typeof(Dictionary)))]; + } } /// @@ -743,6 +764,7 @@ namespace FlaxEditor.Surface.Archetypes Title = "Enum", Create = (id, context, arch, groupArch) => new EnumNode(id, context, arch, groupArch), Description = "Enum constant value.", + GetInputOutputDescription = EnumNode.GetInputOutputDescription, Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph | NodeFlags.NoSpawnViaGUI, Size = new Float2(180, 20), DefaultValues = new object[] @@ -779,6 +801,7 @@ namespace FlaxEditor.Surface.Archetypes Title = "Array", Create = (id, context, arch, groupArch) => new ArrayNode(id, context, arch, groupArch), Description = "Constant array value.", + GetInputOutputDescription = ArrayNode.GetInputOutputDescription, Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph, Size = new Float2(150, 20), DefaultValues = new object[] { new int[] { 0, 1, 2 } }, @@ -790,6 +813,7 @@ namespace FlaxEditor.Surface.Archetypes Title = "Dictionary", Create = (id, context, arch, groupArch) => new DictionaryNode(id, context, arch, groupArch), Description = "Creates an empty dictionary.", + GetInputOutputDescription = DictionaryNode.GetInputOutputDescription, Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph, Size = new Float2(150, 40), DefaultValues = new object[] { typeof(int).FullName, typeof(string).FullName }, diff --git a/Source/Editor/Surface/Archetypes/Packing.cs b/Source/Editor/Surface/Archetypes/Packing.cs index 40244c2ca..5e84d615a 100644 --- a/Source/Editor/Surface/Archetypes/Packing.cs +++ b/Source/Editor/Surface/Archetypes/Packing.cs @@ -245,6 +245,21 @@ namespace FlaxEditor.Surface.Archetypes } return false; } + + internal static void GetInputOutputDescription(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs) + { + var type = TypeUtils.GetType((string)nodeArch.DefaultValues[0]); + outputs = [(type.Name, type)]; + + var fields = type.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); + var fieldsLength = fields.Length; + inputs = new (string, ScriptType)[fieldsLength]; + for (var i = 0; i < fieldsLength; i++) + { + var field = fields[i]; + inputs[i] = (field.Name, field.ValueType); + } + } } private sealed class UnpackStructureNode : StructureNode @@ -283,6 +298,21 @@ namespace FlaxEditor.Surface.Archetypes } return false; } + + internal static void GetInputOutputDescription(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs) + { + var type = TypeUtils.GetType((string)nodeArch.DefaultValues[0]); + inputs = [(type.Name, type)]; + + var fields = type.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); + var fieldsLength = fields.Length; + outputs = new (string, ScriptType)[fieldsLength]; + for (var i = 0; i < fieldsLength; i++) + { + var field = fields[i]; + outputs[i] = (field.Name, field.ValueType); + } + } } /// @@ -411,6 +441,7 @@ namespace FlaxEditor.Surface.Archetypes Create = (id, context, arch, groupArch) => new PackStructureNode(id, context, arch, groupArch), IsInputCompatible = PackStructureNode.IsInputCompatible, IsOutputCompatible = PackStructureNode.IsOutputCompatible, + GetInputOutputDescription = PackStructureNode.GetInputOutputDescription, Description = "Makes the structure data to from the components.", Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph | NodeFlags.NoSpawnViaGUI, Size = new Float2(180, 20), @@ -523,6 +554,7 @@ namespace FlaxEditor.Surface.Archetypes Create = (id, context, arch, groupArch) => new UnpackStructureNode(id, context, arch, groupArch), IsInputCompatible = UnpackStructureNode.IsInputCompatible, IsOutputCompatible = UnpackStructureNode.IsOutputCompatible, + GetInputOutputDescription = UnpackStructureNode.GetInputOutputDescription, Description = "Breaks the structure data to allow extracting components from it.", Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph | NodeFlags.NoSpawnViaGUI, Size = new Float2(180, 20), diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index a7737b4de..c2518519a 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -663,13 +663,10 @@ namespace FlaxEditor.Surface.ContextMenu Profiler.BeginEvent("VisjectCM.SetDescriptionPanelArchetype"); - ScriptType declaringType; - string elementName, elementTypeName; - _descriptionInputPanel.RemoveChildren(); _descriptionOutputPanel.RemoveChildren(); - + ScriptType declaringType; if (archetype.Tag is ScriptMemberInfo memberInfo) { var name = memberInfo.Name; @@ -710,24 +707,25 @@ namespace FlaxEditor.Surface.ContextMenu declaringType = archetype.DefaultType; // Special handling for Pack nodes - if (archetype == Packing.Nodes[6] || archetype == Packing.Nodes[13]) + if (archetype.GetInputOutputDescription != null) { - bool isOutput = archetype == Packing.Nodes[6]; - var type = TypeUtils.GetType((string)archetype.DefaultValues[0]); - AddInputOutputElement(archetype, type, isOutput, $"{type.Name}"); - - var fields = type.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); - var fieldsLength = fields.Length; - for (var i = 0; i < fieldsLength; i++) + archetype.GetInputOutputDescription.Invoke(archetype, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs); + + if (inputs != null) { - var field = fields[i]; - AddInputOutputElement(archetype, field.ValueType, !isOutput, $"{field.Name} ({field.ValueType.Name})"); + for (int i = 0; i < inputs.Length; i++) + { + AddInputOutputElement(archetype, inputs[i].Item2, false, $"{inputs[i].Item1} ({inputs[i].Item2.Name})"); + } + } + + if (outputs != null) + { + for (int i = 0; i < outputs.Length; i++) + { + AddInputOutputElement(archetype, outputs[i].Item2, true, $"{outputs[i].Item1} ({outputs[i].Item2.Name})"); + } } - } - else if (archetype == Archetypes.Constants.Nodes[10]) - { - var t = new ScriptType(archetype.DefaultValues[0].GetType()); - AddInputOutputElement(archetype, t, true, $"ENUM {t.Name}"); } else { @@ -737,17 +735,9 @@ namespace FlaxEditor.Surface.ContextMenu { bool isOutput = element.Type == NodeElementType.Output; if (element.ConnectionsType == null) - { - if(archetype == Archetypes.Constants.Nodes[12]) - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({ConnectionsHint.Array.ToString()})"); - else if (archetype == Archetypes.Constants.Nodes[13]) - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({ConnectionsHint.Dictionary.ToString()})"); - else - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({archetype.ConnectionsHints.ToString()})"); - continue; - } - - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({element.ConnectionsType.Name})"); + AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({archetype.ConnectionsHints.ToString()})"); + else + AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({element.ConnectionsType.Name})"); } } } diff --git a/Source/Editor/Surface/NodeArchetype.cs b/Source/Editor/Surface/NodeArchetype.cs index efcec6b62..63d731b72 100644 --- a/Source/Editor/Surface/NodeArchetype.cs +++ b/Source/Editor/Surface/NodeArchetype.cs @@ -90,10 +90,15 @@ namespace FlaxEditor.Surface public delegate SurfaceNode CreateCustomNodeFunc(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch); /// - /// Checks if the given type is compatible with the given node archetype. Used for custom nodes + /// Checks if the given type is compatible with the given node archetype. Used for custom nodes. /// public delegate bool IsCompatible(NodeArchetype nodeArch, ScriptType portType, ConnectionsHint hint, VisjectSurfaceContext context); + /// + /// Gets description of inputs and outputs of the archetype. Used for special cases for the description panel. + /// + public delegate void GetElementsDescriptionFunc(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs); + /// /// Unique node type ID within a single group. /// @@ -144,6 +149,11 @@ namespace FlaxEditor.Surface /// public string Description; + /// + /// Custom function to get descriptions of input and output elements. Used for description panel (optional). + /// + public GetElementsDescriptionFunc GetInputOutputDescription; + /// /// Alternative node titles. /// @@ -217,6 +227,7 @@ namespace FlaxEditor.Surface SubTitle = SubTitle, Signature = Signature, Description = Description, + GetInputOutputDescription = GetInputOutputDescription, AlternativeTitles = (string[])AlternativeTitles?.Clone(), Tag = Tag, SortScore = SortScore, From 53006ac9adc51656d8943c442c3e3de34ba01a9f Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Sun, 16 Jun 2024 12:12:26 +0200 Subject: [PATCH 15/29] - Moved description panel code - Description panel now gets hidden when hiding the context menu - Cleanup when hiding description panel --- .../Editor/Surface/ContextMenu/VisjectCM.cs | 329 +++++++++--------- 1 file changed, 166 insertions(+), 163 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index c2518519a..14160a304 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -646,169 +646,6 @@ namespace FlaxEditor.Surface.ContextMenu _groups[i].Open(animate); } - /// - /// Updates the description panel and shows information about the set archetype - /// - /// The node archetype - public void SetDescriptionPanelArchetype(NodeArchetype archetype) - { - if(!_useDescriptionPanel) - return; - - if (archetype == null) - { - HideDescriptionPanel(); - return; - } - - Profiler.BeginEvent("VisjectCM.SetDescriptionPanelArchetype"); - - _descriptionInputPanel.RemoveChildren(); - _descriptionOutputPanel.RemoveChildren(); - - ScriptType declaringType; - if (archetype.Tag is ScriptMemberInfo memberInfo) - { - var name = memberInfo.Name; - if (memberInfo.IsMethod && memberInfo.Name.StartsWith("get_") || memberInfo.Name.StartsWith("set_")) - { - name = memberInfo.Name.Substring(4); - } - - declaringType = memberInfo.DeclaringType; - _descriptionSignatureLabel.Text = memberInfo.DeclaringType + "." + name; - - if (!memberInfo.IsStatic) - AddInputOutputElement(archetype, declaringType, false, $">Instance ({memberInfo.DeclaringType.Name})"); - - if (memberInfo.ValueType != ScriptType.Null && memberInfo.ValueType != ScriptType.Void) - { - if (memberInfo.IsField && archetype.Title.StartsWith("Set ")) - AddInputOutputElement(archetype, memberInfo.ValueType, false, $"({memberInfo.ValueType.Name})"); - else - AddInputOutputElement(archetype, memberInfo.ValueType, true, $"Return ({memberInfo.ValueType.Name})"); - } - - for(int i = 0; i < memberInfo.ParametersCount; i++) - { - var param = memberInfo.GetParameters()[i]; - if (param.IsOut) - { - AddInputOutputElement(archetype, param.Type, true, $">{param.Name} ({param.Type.Name})"); - continue; - } - - AddInputOutputElement(archetype, param.Type, false, $">{param.Name} ({param.Type.Name})"); - } - } - else - { - _descriptionSignatureLabel.Text = archetype.Signature; - declaringType = archetype.DefaultType; - - // Special handling for Pack nodes - if (archetype.GetInputOutputDescription != null) - { - archetype.GetInputOutputDescription.Invoke(archetype, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs); - - if (inputs != null) - { - for (int i = 0; i < inputs.Length; i++) - { - AddInputOutputElement(archetype, inputs[i].Item2, false, $"{inputs[i].Item1} ({inputs[i].Item2.Name})"); - } - } - - if (outputs != null) - { - for (int i = 0; i < outputs.Length; i++) - { - AddInputOutputElement(archetype, outputs[i].Item2, true, $"{outputs[i].Item1} ({outputs[i].Item2.Name})"); - } - } - } - else - { - foreach (var element in archetype.Elements) - { - if (element.Type is NodeElementType.Input or NodeElementType.Output) - { - bool isOutput = element.Type == NodeElementType.Output; - if (element.ConnectionsType == null) - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({archetype.ConnectionsHints.ToString()})"); - else - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({element.ConnectionsType.Name})"); - } - } - } - } - - _surfaceStyle.GetConnectionColor(declaringType, archetype.ConnectionsHints, out var declaringTypeColor); - _descriptionClassImage.Color = declaringTypeColor; - _descriptionClassImage.MouseOverColor = declaringTypeColor; - - float panelHeight = _descriptionSignatureLabel.Height; - - _descriptionLabel.Y = _descriptionSignatureLabel.Bounds.Bottom + 6f; - _descriptionLabel.Text = archetype.Description; - - panelHeight += _descriptionLabel.Height + 6f + 18f; - - _descriptionInputPanel.Y = panelHeight; - _descriptionOutputPanel.Y = panelHeight; - - panelHeight += Mathf.Max(_descriptionInputPanel.Height, _descriptionOutputPanel.Height); - _descriptionPanel.Height = panelHeight; - Height = 400 + Mathf.RoundToInt(_descriptionPanel.Height); - UpdateWindowSize(); - - PerformLayout(); - - Profiler.EndEvent(); - } - - private void AddInputOutputElement(NodeArchetype nodeArchetype, ScriptType type, bool isOutput, string text) - { - var elementPanel = new Panel() - { - Parent = isOutput ? _descriptionOutputPanel : _descriptionInputPanel, - Width = Width * 0.5f, - Height = 16, - AnchorPreset = AnchorPresets.TopLeft - }; - - var sprite = _surfaceStyle.Icons.BoxOpen; - _surfaceStyle.GetConnectionColor(type, nodeArchetype.ConnectionsHints, out var typeColor); - elementPanel.AddChild(new Image(2, 0, 12, 12) - { - Brush = new SpriteBrush(sprite), - Color = typeColor, - MouseOverColor = typeColor, - AutoFocus = false, - }).SetAnchorPreset(AnchorPresets.TopLeft, true); - - var elementText = new Label(16, 0, Width * 0.5f - 32, 16) - { - Text = text, - HorizontalAlignment = TextAlignment.Near, - VerticalAlignment = TextAlignment.Near, - Wrapping = TextWrapping.WrapWords, - AutoHeight = true, - }; - elementText.SetAnchorPreset(AnchorPresets.TopLeft, true); - elementPanel.AddChild(elementText); - elementPanel.Height = elementText.Height; - } - - /// - /// Hides the description panel and resets the context menu to its original size - /// - public void HideDescriptionPanel() - { - Height = 400; - UpdateWindowSize(); - } - /// /// Resets the view. /// @@ -953,9 +790,175 @@ namespace FlaxEditor.Surface.ContextMenu { Focus(null); + if(_useDescriptionPanel) + HideDescriptionPanel(); + base.Hide(); } + /// + /// Updates the description panel and shows information about the set archetype + /// + /// The node archetype + public void SetDescriptionPanelArchetype(NodeArchetype archetype) + { + if(!_useDescriptionPanel) + return; + + if (archetype == null) + { + HideDescriptionPanel(); + return; + } + + Profiler.BeginEvent("VisjectCM.SetDescriptionPanelArchetype"); + + _descriptionInputPanel.RemoveChildren(); + _descriptionOutputPanel.RemoveChildren(); + + ScriptType declaringType; + if (archetype.Tag is ScriptMemberInfo memberInfo) + { + var name = memberInfo.Name; + if (memberInfo.IsMethod && memberInfo.Name.StartsWith("get_") || memberInfo.Name.StartsWith("set_")) + { + name = memberInfo.Name.Substring(4); + } + + declaringType = memberInfo.DeclaringType; + _descriptionSignatureLabel.Text = memberInfo.DeclaringType + "." + name; + + if (!memberInfo.IsStatic) + AddInputOutputElement(archetype, declaringType, false, $">Instance ({memberInfo.DeclaringType.Name})"); + + if (memberInfo.ValueType != ScriptType.Null && memberInfo.ValueType != ScriptType.Void) + { + if (memberInfo.IsField && archetype.Title.StartsWith("Set ")) + AddInputOutputElement(archetype, memberInfo.ValueType, false, $"({memberInfo.ValueType.Name})"); + else + AddInputOutputElement(archetype, memberInfo.ValueType, true, $"Return ({memberInfo.ValueType.Name})"); + } + + for(int i = 0; i < memberInfo.ParametersCount; i++) + { + var param = memberInfo.GetParameters()[i]; + if (param.IsOut) + { + AddInputOutputElement(archetype, param.Type, true, $">{param.Name} ({param.Type.Name})"); + continue; + } + + AddInputOutputElement(archetype, param.Type, false, $">{param.Name} ({param.Type.Name})"); + } + } + else + { + _descriptionSignatureLabel.Text = string.IsNullOrEmpty(archetype.Signature) ? archetype.Title : archetype.Signature; + declaringType = archetype.DefaultType; + + // Special handling for Pack nodes + if (archetype.GetInputOutputDescription != null) + { + archetype.GetInputOutputDescription.Invoke(archetype, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs); + + if (inputs != null) + { + for (int i = 0; i < inputs.Length; i++) + { + AddInputOutputElement(archetype, inputs[i].Item2, false, $"{inputs[i].Item1} ({inputs[i].Item2.Name})"); + } + } + + if (outputs != null) + { + for (int i = 0; i < outputs.Length; i++) + { + AddInputOutputElement(archetype, outputs[i].Item2, true, $"{outputs[i].Item1} ({outputs[i].Item2.Name})"); + } + } + } + else + { + foreach (var element in archetype.Elements) + { + if (element.Type is NodeElementType.Input or NodeElementType.Output) + { + bool isOutput = element.Type == NodeElementType.Output; + if (element.ConnectionsType == null) + AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({archetype.ConnectionsHints.ToString()})"); + else + AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({element.ConnectionsType.Name})"); + } + } + } + } + + _surfaceStyle.GetConnectionColor(declaringType, archetype.ConnectionsHints, out var declaringTypeColor); + _descriptionClassImage.Color = declaringTypeColor; + _descriptionClassImage.MouseOverColor = declaringTypeColor; + + float panelHeight = _descriptionSignatureLabel.Height; + + _descriptionLabel.Y = _descriptionSignatureLabel.Bounds.Bottom + 6f; + _descriptionLabel.Text = archetype.Description; + + panelHeight += _descriptionLabel.Height + 6f + 18f; + + _descriptionInputPanel.Y = panelHeight; + _descriptionOutputPanel.Y = panelHeight; + + panelHeight += Mathf.Max(_descriptionInputPanel.Height, _descriptionOutputPanel.Height); + _descriptionPanel.Height = panelHeight; + Height = 400 + Mathf.RoundToInt(_descriptionPanel.Height); + UpdateWindowSize(); + + Profiler.EndEvent(); + } + + private void AddInputOutputElement(NodeArchetype nodeArchetype, ScriptType type, bool isOutput, string text) + { + var elementPanel = new Panel() + { + Parent = isOutput ? _descriptionOutputPanel : _descriptionInputPanel, + Width = Width * 0.5f, + Height = 16, + AnchorPreset = AnchorPresets.TopLeft + }; + + var sprite = _surfaceStyle.Icons.BoxOpen; + _surfaceStyle.GetConnectionColor(type, nodeArchetype.ConnectionsHints, out var typeColor); + elementPanel.AddChild(new Image(2, 0, 12, 12) + { + Brush = new SpriteBrush(sprite), + Color = typeColor, + MouseOverColor = typeColor, + AutoFocus = false, + }).SetAnchorPreset(AnchorPresets.TopLeft, true); + + var elementText = new Label(16, 0, Width * 0.5f - 32, 16) + { + Text = text, + HorizontalAlignment = TextAlignment.Near, + VerticalAlignment = TextAlignment.Near, + Wrapping = TextWrapping.WrapWords, + AutoHeight = true, + }; + elementText.SetAnchorPreset(AnchorPresets.TopLeft, true); + elementPanel.AddChild(elementText); + elementPanel.Height = elementText.Height; + } + + /// + /// Hides the description panel and resets the context menu to its original size + /// + public void HideDescriptionPanel() + { + _descriptionInputPanel.RemoveChildren(); + _descriptionOutputPanel.RemoveChildren(); + Height = 400; + UpdateWindowSize(); + } + /// public override bool OnKeyDown(KeyboardKeys key) { From b0953e94948f5ad0691c14f65be0235111fb0c03 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Sun, 16 Jun 2024 12:18:03 +0200 Subject: [PATCH 16/29] - Minor refactoring and cleanup --- Source/Editor/Surface/ContextMenu/VisjectCM.cs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 14160a304..9f512b7ac 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -842,13 +842,7 @@ namespace FlaxEditor.Surface.ContextMenu for(int i = 0; i < memberInfo.ParametersCount; i++) { var param = memberInfo.GetParameters()[i]; - if (param.IsOut) - { - AddInputOutputElement(archetype, param.Type, true, $">{param.Name} ({param.Type.Name})"); - continue; - } - - AddInputOutputElement(archetype, param.Type, false, $">{param.Name} ({param.Type.Name})"); + AddInputOutputElement(archetype, param.Type, param.IsOut, $">{param.Name} ({param.Type.Name})"); } } else @@ -856,7 +850,6 @@ namespace FlaxEditor.Surface.ContextMenu _descriptionSignatureLabel.Text = string.IsNullOrEmpty(archetype.Signature) ? archetype.Title : archetype.Signature; declaringType = archetype.DefaultType; - // Special handling for Pack nodes if (archetype.GetInputOutputDescription != null) { archetype.GetInputOutputDescription.Invoke(archetype, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs); @@ -866,7 +859,7 @@ namespace FlaxEditor.Surface.ContextMenu for (int i = 0; i < inputs.Length; i++) { AddInputOutputElement(archetype, inputs[i].Item2, false, $"{inputs[i].Item1} ({inputs[i].Item2.Name})"); - } + } } if (outputs != null) @@ -874,7 +867,7 @@ namespace FlaxEditor.Surface.ContextMenu for (int i = 0; i < outputs.Length; i++) { AddInputOutputElement(archetype, outputs[i].Item2, true, $"{outputs[i].Item1} ({outputs[i].Item2.Name})"); - } + } } } else @@ -951,7 +944,7 @@ namespace FlaxEditor.Surface.ContextMenu /// /// Hides the description panel and resets the context menu to its original size /// - public void HideDescriptionPanel() + private void HideDescriptionPanel() { _descriptionInputPanel.RemoveChildren(); _descriptionOutputPanel.RemoveChildren(); From 62778fc1e96d26afbe833c09a557de5042c8a874 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Sun, 16 Jun 2024 12:37:46 +0200 Subject: [PATCH 17/29] - Increasing width of CM slightly when using description panel - Some padding and size changes - A tiny bit of cleanup --- .../Editor/Surface/ContextMenu/VisjectCM.cs | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 9f512b7ac..8f90e80cd 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -66,7 +66,6 @@ namespace FlaxEditor.Surface.ContextMenu private readonly VerticalPanel _descriptionInputPanel; private readonly VerticalPanel _descriptionOutputPanel; - private VisjectCMItem _selectedItem; /// @@ -75,7 +74,7 @@ namespace FlaxEditor.Surface.ContextMenu public VisjectCMItem SelectedItem { get => _selectedItem; - set + private set { _selectedItem = value; _selectedItem?.OnSelect(); @@ -166,7 +165,7 @@ namespace FlaxEditor.Surface.ContextMenu _surfaceStyle = info.Style; // Context menu dimensions - Size = new Float2(300, 400); + Size = new Float2(_useDescriptionPanel ? 350 : 300, 400); var headerPanel = new Panel(ScrollBars.None) { @@ -253,11 +252,8 @@ namespace FlaxEditor.Surface.ContextMenu { Parent = _descriptionPanel, Brush = new SpriteBrush(spriteHandle), - Color = Color.Aqua, - MouseOverColor = Color.Aqua, - AutoFocus = false, }; - + var signatureFontReference = new FontReference(Style.Current.FontMedium.Asset, 9f); _descriptionSignatureLabel = new Label(32, 8, Width - 40, 0) { @@ -285,16 +281,16 @@ namespace FlaxEditor.Surface.ContextMenu _descriptionInputPanel = new VerticalPanel() { Parent = _descriptionPanel, - Width = Width * 0.5f, - AnchorPreset = AnchorPresets.TopLeft, + X = 8, + Width = Width * 0.5f - 16, AutoSize = true, }; - + _descriptionOutputPanel = new VerticalPanel() { Parent = _descriptionPanel, - X = Width * 0.5f, - Width = Width * 0.5f, + X = Width * 0.5f + 8, + Width = Width * 0.5f - 16, AutoSize = true, }; } @@ -829,7 +825,7 @@ namespace FlaxEditor.Surface.ContextMenu _descriptionSignatureLabel.Text = memberInfo.DeclaringType + "." + name; if (!memberInfo.IsStatic) - AddInputOutputElement(archetype, declaringType, false, $">Instance ({memberInfo.DeclaringType.Name})"); + AddInputOutputElement(archetype, declaringType, false, $"Instance ({memberInfo.DeclaringType.Name})"); if (memberInfo.ValueType != ScriptType.Null && memberInfo.ValueType != ScriptType.Void) { @@ -842,7 +838,7 @@ namespace FlaxEditor.Surface.ContextMenu for(int i = 0; i < memberInfo.ParametersCount; i++) { var param = memberInfo.GetParameters()[i]; - AddInputOutputElement(archetype, param.Type, param.IsOut, $">{param.Name} ({param.Type.Name})"); + AddInputOutputElement(archetype, param.Type, param.IsOut, $"{param.Name} ({param.Type.Name})"); } } else @@ -878,9 +874,9 @@ namespace FlaxEditor.Surface.ContextMenu { bool isOutput = element.Type == NodeElementType.Output; if (element.ConnectionsType == null) - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({archetype.ConnectionsHints.ToString()})"); + AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"{element.Text} ({archetype.ConnectionsHints.ToString()})"); else - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({element.ConnectionsType.Name})"); + AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"{element.Text} ({element.ConnectionsType.Name})"); } } } From 4abe8587f30a4d8a7e39b02d2aa2966bb7bf0194 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Sun, 16 Jun 2024 13:37:03 +0200 Subject: [PATCH 18/29] - Fixed some tooltip regressions - Defined signatures where necessary --- Source/Editor/Surface/ContextMenu/VisjectCMItem.cs | 12 +++++++++++- Source/Editor/Surface/SurfaceNode.cs | 12 +++++++++++- Source/Editor/Surface/SurfaceUtils.cs | 10 ++++------ .../Surface/VisjectSurfaceContext.Serialization.cs | 1 + Source/Editor/Surface/VisualScriptSurface.cs | 6 +++++- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs b/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs index c0fba5586..370025360 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using FlaxEditor.Scripting; using FlaxEditor.Surface.Elements; using FlaxEditor.Utilities; @@ -62,7 +63,7 @@ namespace FlaxEditor.Surface.ContextMenu Group = group; _groupArchetype = groupArchetype; _archetype = archetype; - TooltipText = $"{_archetype.Signature}\n{_archetype.Description}"; + TooltipText = GetTooltip(); } /// @@ -323,6 +324,15 @@ namespace FlaxEditor.Surface.ContextMenu Group.ContextMenu.SetDescriptionPanelArchetype(_archetype); } + private string GetTooltip() + { + StringBuilder sb = new StringBuilder(); + if (!string.IsNullOrEmpty(_archetype.Signature)) + sb.Append(_archetype.Signature + "\n"); + sb.Append(_archetype.Description); + return sb.ToString(); + } + /// public override bool OnMouseDown(Float2 location, MouseButton button) { diff --git a/Source/Editor/Surface/SurfaceNode.cs b/Source/Editor/Surface/SurfaceNode.cs index 07dc4f5e9..1dbb8424b 100644 --- a/Source/Editor/Surface/SurfaceNode.cs +++ b/Source/Editor/Surface/SurfaceNode.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Text; using FlaxEditor.Scripting; using FlaxEditor.Surface.Elements; using FlaxEditor.Surface.Undo; @@ -124,7 +125,7 @@ namespace FlaxEditor.Surface Archetype = nodeArch; GroupArchetype = groupArch; AutoFocus = false; - TooltipText = TooltipText = $"{nodeArch.Signature}\n{nodeArch.Description}"; + TooltipText = GetTooltip(); CullChildren = false; BackgroundColor = Style.Current.BackgroundNormal; @@ -851,6 +852,15 @@ namespace FlaxEditor.Surface } } + private string GetTooltip() + { + StringBuilder sb = new StringBuilder(); + if (!string.IsNullOrEmpty(Archetype.Signature)) + sb.Append(Archetype.Signature + "\n"); + sb.Append(Archetype.Description); + return sb.ToString(); + } + /// protected override bool ShowTooltip => base.ShowTooltip && _headerRect.Contains(ref _mousePosition) && !Surface.IsLeftMouseButtonDown && !Surface.IsRightMouseButtonDown && !Surface.IsPrimaryMenuOpened; diff --git a/Source/Editor/Surface/SurfaceUtils.cs b/Source/Editor/Surface/SurfaceUtils.cs index 8e14787b6..6bc834b0a 100644 --- a/Source/Editor/Surface/SurfaceUtils.cs +++ b/Source/Editor/Surface/SurfaceUtils.cs @@ -447,8 +447,7 @@ namespace FlaxEditor.Surface var valueType = member.ValueType; // Getter/setter method of the property - we can return early here - bool isGetterOrSetter = name.StartsWith("get_") || name.StartsWith("set_"); - if (member.IsMethod && isGetterOrSetter) + if (member.IsMethod && (name.StartsWith("get_") || name.StartsWith("set_"))) { var flags = member.IsStatic ? BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly : BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; var property = declaringType.GetMembers(name.Substring(4), MemberTypes.Property, flags); @@ -470,7 +469,7 @@ namespace FlaxEditor.Surface sb.Append(name); // Is a method and not a property - if (member.IsMethod && !isGetterOrSetter) + if (member.IsMethod) { sb.Append('('); var parameters = member.GetParameters(); @@ -504,8 +503,7 @@ namespace FlaxEditor.Surface var declaringType = member.DeclaringType; // Getter/setter method of the property - we can return early here - bool isGetterOrSetter = name.StartsWith("get_") || name.StartsWith("set_"); - if (member.IsMethod && isGetterOrSetter) + if (member.IsMethod && (name.StartsWith("get_") || name.StartsWith("set_"))) { var flags = member.IsStatic ? BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly : BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; var property = declaringType.GetMembers(name.Substring(4), MemberTypes.Property, flags); @@ -524,7 +522,7 @@ namespace FlaxEditor.Surface var sb = new StringBuilder(signature); // Tooltip - var tooltip = Editor.Instance.CodeDocs.GetTooltip(member); + var tooltip = GetVisualScriptMemberShortDescription(member); if (!string.IsNullOrEmpty(tooltip)) sb.Append("\n").Append(tooltip); diff --git a/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs b/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs index 09147efac..97122f872 100644 --- a/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs +++ b/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs @@ -51,6 +51,7 @@ namespace FlaxEditor.Surface { TypeID = originalNodeId, Title = "Missing Node :(", + Signature = ":(", Description = ":(", Flags = NodeFlags.AllGraphs, Size = new Float2(200, 70), diff --git a/Source/Editor/Surface/VisualScriptSurface.cs b/Source/Editor/Surface/VisualScriptSurface.cs index f7fafeef8..e17453b0a 100644 --- a/Source/Editor/Surface/VisualScriptSurface.cs +++ b/Source/Editor/Surface/VisualScriptSurface.cs @@ -238,7 +238,8 @@ namespace FlaxEditor.Surface var node = (NodeArchetype)Archetypes.Function.Nodes[2].Clone(); node.Flags &= ~NodeFlags.NoSpawnViaGUI; - node.Description = Editor.Instance.CodeDocs.GetTooltip(member); + node.Signature = SurfaceUtils.GetVisualScriptMemberInfoSignature(member); + node.Description = SurfaceUtils.GetVisualScriptMemberShortDescription(member); node.DefaultValues[0] = name; node.DefaultValues[1] = parameters.Length; node.Title = "Override " + name; @@ -280,6 +281,7 @@ namespace FlaxEditor.Surface node.DefaultValues[0] = Activator.CreateInstance(scriptType.Type); node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = scriptTypeName; + node.Signature = scriptTypeName; node.Description = Editor.Instance.CodeDocs.GetTooltip(scriptType); // Create group archetype @@ -330,6 +332,7 @@ namespace FlaxEditor.Surface node.DefaultValues[0] = scriptTypeTypeName; node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = "Pack " + scriptTypeName; + node.Signature = "Pack " + scriptTypeName; node.Description = tooltip; ((IList)group.Archetypes).Add(node); @@ -338,6 +341,7 @@ namespace FlaxEditor.Surface node.DefaultValues[0] = scriptTypeTypeName; node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = "Unpack " + scriptTypeName; + node.Signature = "Unpack " + scriptTypeName; node.Description = tooltip; ((IList)group.Archetypes).Add(node); } From d74b7fb304df94f3a4aa31730d26babc2e2a4d50 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Tue, 18 Jun 2024 18:40:28 +0200 Subject: [PATCH 19/29] - Set description panel min height to reduce window jittering (workaround) --- Source/Editor/Surface/ContextMenu/VisjectCM.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 8f90e80cd..23ff43364 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -897,8 +897,11 @@ namespace FlaxEditor.Surface.ContextMenu _descriptionOutputPanel.Y = panelHeight; panelHeight += Mathf.Max(_descriptionInputPanel.Height, _descriptionOutputPanel.Height); - _descriptionPanel.Height = panelHeight; - Height = 400 + Mathf.RoundToInt(_descriptionPanel.Height); + + // Forcing the description panel to at least have a height of 120 to not make the window size change too much in order to reduce jittering + // TODO: Remove the Mathf.Max and just set the height to panelHeight once the window jitter issue is fixed - Nils + _descriptionPanel.Height = Mathf.Max(120f, panelHeight); + Height = 400 + _descriptionPanel.Height; UpdateWindowSize(); Profiler.EndEvent(); From 3fd4bb622fd0861cb222a05f0ac4e1c84396af18 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Tue, 18 Jun 2024 18:51:49 +0200 Subject: [PATCH 20/29] - Added editor option to toggle description panel for visual scripting --- Source/Editor/Options/InterfaceOptions.cs | 7 +++++++ Source/Editor/Surface/ContextMenu/VisjectCM.cs | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Options/InterfaceOptions.cs b/Source/Editor/Options/InterfaceOptions.cs index 360d1a7ed..286ec720d 100644 --- a/Source/Editor/Options/InterfaceOptions.cs +++ b/Source/Editor/Options/InterfaceOptions.cs @@ -368,6 +368,13 @@ namespace FlaxEditor.Options [EditorDisplay("Visject"), EditorOrder(550)] public float ConnectionCurvature { get; set; } = 1.0f; + /// + /// Gets or sets the visject connection curvature. + /// + [DefaultValue(true)] + [EditorDisplay("Visject"), EditorOrder(550)] + public bool VisualScriptingDescriptionPanel { get; set; } = true; + private static FontAsset DefaultFont => FlaxEngine.Content.LoadAsyncInternal(EditorAssets.PrimaryFont); private static FontAsset ConsoleFont => FlaxEngine.Content.LoadAsyncInternal(EditorAssets.InconsolataRegularFont); diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 23ff43364..b25b4c6e0 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -58,6 +58,7 @@ namespace FlaxEditor.Surface.ContextMenu // Description panel elements private readonly bool _useDescriptionPanel; + private bool _descriptionPanelVisible; private readonly Panel _descriptionPanel; private readonly Image _descriptionClassImage; private readonly Label _descriptionSignatureLabel; @@ -801,7 +802,7 @@ namespace FlaxEditor.Surface.ContextMenu if(!_useDescriptionPanel) return; - if (archetype == null) + if (archetype == null || !Editor.Instance.Options.Options.Interface.VisualScriptingDescriptionPanel) { HideDescriptionPanel(); return; @@ -903,6 +904,7 @@ namespace FlaxEditor.Surface.ContextMenu _descriptionPanel.Height = Mathf.Max(120f, panelHeight); Height = 400 + _descriptionPanel.Height; UpdateWindowSize(); + _descriptionPanelVisible = true; Profiler.EndEvent(); } @@ -945,10 +947,14 @@ namespace FlaxEditor.Surface.ContextMenu /// private void HideDescriptionPanel() { + if(!_descriptionPanelVisible) + return; + _descriptionInputPanel.RemoveChildren(); _descriptionOutputPanel.RemoveChildren(); Height = 400; UpdateWindowSize(); + _descriptionPanelVisible = false; } /// From 37a3c4dbb508fd5ccf7dc8a48c397d193c2ff6d4 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Tue, 18 Jun 2024 19:01:53 +0200 Subject: [PATCH 21/29] - Added separator line between description and inputs/outputs --- Source/Editor/Surface/ContextMenu/VisjectCM.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index b25b4c6e0..2ebdc1c3b 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -60,6 +60,7 @@ namespace FlaxEditor.Surface.ContextMenu private readonly bool _useDescriptionPanel; private bool _descriptionPanelVisible; private readonly Panel _descriptionPanel; + private readonly Panel _descriptionPanelSeparator; private readonly Image _descriptionClassImage; private readonly Label _descriptionSignatureLabel; private readonly Label _descriptionLabel; @@ -279,6 +280,13 @@ namespace FlaxEditor.Surface.ContextMenu }; _descriptionLabel.SetAnchorPreset(AnchorPresets.TopLeft, true); + _descriptionPanelSeparator = new Panel(ScrollBars.None) + { + Parent = _descriptionPanel, + Bounds = new Rectangle(8, Height, Width - 16, 2), + BackgroundColor = Style.Current.BackgroundHighlighted, + }; + _descriptionInputPanel = new VerticalPanel() { Parent = _descriptionPanel, @@ -892,16 +900,18 @@ namespace FlaxEditor.Surface.ContextMenu _descriptionLabel.Y = _descriptionSignatureLabel.Bounds.Bottom + 6f; _descriptionLabel.Text = archetype.Description; - panelHeight += _descriptionLabel.Height + 6f + 18f; + _descriptionPanelSeparator.Y = _descriptionLabel.Bounds.Bottom + 8f; + + panelHeight += _descriptionLabel.Height + 32f; _descriptionInputPanel.Y = panelHeight; _descriptionOutputPanel.Y = panelHeight; panelHeight += Mathf.Max(_descriptionInputPanel.Height, _descriptionOutputPanel.Height); - // Forcing the description panel to at least have a height of 120 to not make the window size change too much in order to reduce jittering + // Forcing the description panel to at least have a minimum height to not make the window size change too much in order to reduce jittering // TODO: Remove the Mathf.Max and just set the height to panelHeight once the window jitter issue is fixed - Nils - _descriptionPanel.Height = Mathf.Max(120f, panelHeight); + _descriptionPanel.Height = Mathf.Max(135f, panelHeight); Height = 400 + _descriptionPanel.Height; UpdateWindowSize(); _descriptionPanelVisible = true; From a808ac5dc8b6aea975121c37140c665ce3365e9f Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Tue, 18 Jun 2024 19:44:07 +0200 Subject: [PATCH 22/29] - Added descriptions to Bitwise OR, XOR - Added description to Boolean XOR, NOR, NAND and updated AND, OR - Minor tooltip text fix --- Source/Editor/Surface/Archetypes/Bitwise.cs | 4 ++-- Source/Editor/Surface/Archetypes/Boolean.cs | 10 +++++----- Source/Editor/Surface/Archetypes/Particles.cs | 2 +- Source/Editor/Surface/ContextMenu/VisjectCMItem.cs | 6 +++--- Source/Editor/Surface/SurfaceNode.cs | 6 +++--- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/Bitwise.cs b/Source/Editor/Surface/Archetypes/Bitwise.cs index 5b96627f0..92616bcbc 100644 --- a/Source/Editor/Surface/Archetypes/Bitwise.cs +++ b/Source/Editor/Surface/Archetypes/Bitwise.cs @@ -59,8 +59,8 @@ namespace FlaxEditor.Surface.Archetypes { Op1(1, "Bitwise NOT", "Negates the value using bitwise operation", new[] { "!", "~" }), Op2(2, "Bitwise AND", "Performs a bitwise conjunction on two values", new[] { "&" }), - Op2(3, "Bitwise OR", "", new[] { "|" }), - Op2(4, "Bitwise XOR", "", new[] { "^" }), + Op2(3, "Bitwise OR", "Performs a bitwise disjunction on two values", new[] { "|" }), + Op2(4, "Bitwise XOR", "Performs a bitwise exclusive disjunction on two values", new[] { "^" }), }; } } diff --git a/Source/Editor/Surface/Archetypes/Boolean.cs b/Source/Editor/Surface/Archetypes/Boolean.cs index 268d7a360..73db196d6 100644 --- a/Source/Editor/Surface/Archetypes/Boolean.cs +++ b/Source/Editor/Surface/Archetypes/Boolean.cs @@ -58,11 +58,11 @@ namespace FlaxEditor.Surface.Archetypes public static NodeArchetype[] Nodes = { Op1(1, "Boolean NOT", "Negates the boolean value", new[] { "!", "~" }), - Op2(2, "Boolean AND", "Performs a logical conjunction on two values", new[] { "&&" }), - Op2(3, "Boolean OR", "Returns true if either (or both) of its operands is true", new[] { "||" }), - Op2(4, "Boolean XOR", "", new[] { "^" }), - Op2(5, "Boolean NOR", ""), - Op2(6, "Boolean NAND", ""), + Op2(2, "Boolean AND", "Performs a logical conjunction on two values. Returns true if both of its operands are true", new[] { "&&" }), + Op2(3, "Boolean OR", "Performs a logical disjunction on two values. Returns true if either (or both) of its operands is true", new[] { "||" }), + Op2(4, "Boolean XOR", "Performs a logical exclusive disjunction on two values. Returns true if both of its operands are different", new[] { "^" }), + Op2(5, "Boolean NOR", "Performs a logical disjunction on two values and negates it. Returns true if both of its operands are false"), + Op2(6, "Boolean NAND", "Performs a logical conjunction on two values and negates it. Returns true if either (or both) of its operands are false"), }; } } diff --git a/Source/Editor/Surface/Archetypes/Particles.cs b/Source/Editor/Surface/Archetypes/Particles.cs index 9166cb0d9..03df9a0a9 100644 --- a/Source/Editor/Surface/Archetypes/Particles.cs +++ b/Source/Editor/Surface/Archetypes/Particles.cs @@ -122,7 +122,7 @@ namespace FlaxEditor.Surface.Archetypes { Name = module.Title, Tag = module.TypeID, - TooltipText = $"{module.Signature}\n{module.Description}", + TooltipText = $"{(string.IsNullOrEmpty(module.Signature) ? module.Title : module.Signature)}\n{module.Description}", }); } cm.ItemClicked += item => AddModule((ushort)item.Tag); diff --git a/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs b/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs index 370025360..1d7b9fa8b 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs @@ -327,9 +327,9 @@ namespace FlaxEditor.Surface.ContextMenu private string GetTooltip() { StringBuilder sb = new StringBuilder(); - if (!string.IsNullOrEmpty(_archetype.Signature)) - sb.Append(_archetype.Signature + "\n"); - sb.Append(_archetype.Description); + sb.Append(string.IsNullOrEmpty(_archetype.Signature) ? _archetype.Title : _archetype.Signature); + if (!string.IsNullOrEmpty(_archetype.Description)) + sb.Append("\n" + _archetype.Description); return sb.ToString(); } diff --git a/Source/Editor/Surface/SurfaceNode.cs b/Source/Editor/Surface/SurfaceNode.cs index 1dbb8424b..10f079579 100644 --- a/Source/Editor/Surface/SurfaceNode.cs +++ b/Source/Editor/Surface/SurfaceNode.cs @@ -855,9 +855,9 @@ namespace FlaxEditor.Surface private string GetTooltip() { StringBuilder sb = new StringBuilder(); - if (!string.IsNullOrEmpty(Archetype.Signature)) - sb.Append(Archetype.Signature + "\n"); - sb.Append(Archetype.Description); + sb.Append(string.IsNullOrEmpty(Archetype.Signature) ? Archetype.Title : Archetype.Signature); + if (!string.IsNullOrEmpty(Archetype.Description)) + sb.Append("\n" + Archetype.Description); return sb.ToString(); } From cb1324fc2ddb582b35567f5879c5a5fbce263af8 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Wed, 19 Jun 2024 20:56:25 +0200 Subject: [PATCH 23/29] - Now removing tags from tooltips - Capitalizing the first character of inputs/outpus - Removing & chars from input/output types to make it easier to read - Moving description signature down to make items without a description look less ugly --- .../Modules/SourceCodeEditing/CodeDocsModule.cs | 4 +++- Source/Editor/Surface/ContextMenu/VisjectCM.cs | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Source/Editor/Modules/SourceCodeEditing/CodeDocsModule.cs b/Source/Editor/Modules/SourceCodeEditing/CodeDocsModule.cs index 610368a82..a26fe9924 100644 --- a/Source/Editor/Modules/SourceCodeEditing/CodeDocsModule.cs +++ b/Source/Editor/Modules/SourceCodeEditing/CodeDocsModule.cs @@ -316,7 +316,9 @@ namespace FlaxEditor.Modules.SourceCodeEditing var memberReader = xmlReader.ReadSubtree(); if (memberReader.ReadToDescendant("summary")) { - result[rawName] = memberReader.ReadInnerXml().Replace('\n', ' ').Trim(); + // Remove and replace them with the captured group (the content of the cref). Additionally, getting rid of prefixes + const string crefPattern = @""; + result[rawName] = Regex.Replace(memberReader.ReadInnerXml(), crefPattern, "$1").Replace('\n', ' ').Trim(); } } } diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 2ebdc1c3b..b30e726dd 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using System.Text.RegularExpressions; using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.Input; using FlaxEditor.Scripting; @@ -897,8 +898,17 @@ namespace FlaxEditor.Surface.ContextMenu float panelHeight = _descriptionSignatureLabel.Height; - _descriptionLabel.Y = _descriptionSignatureLabel.Bounds.Bottom + 6f; - _descriptionLabel.Text = archetype.Description; + if (string.IsNullOrEmpty(archetype.Description)) + { + _descriptionSignatureLabel.Y = 15; + _descriptionLabel.Text = ""; + } + else + { + _descriptionSignatureLabel.Y = 8; + _descriptionLabel.Y = _descriptionSignatureLabel.Bounds.Bottom + 6f; + _descriptionLabel.Text = Regex.Replace(archetype.Description, @"\s{2,}", "\n"); + } _descriptionPanelSeparator.Y = _descriptionLabel.Bounds.Bottom + 8f; @@ -938,7 +948,8 @@ namespace FlaxEditor.Surface.ContextMenu MouseOverColor = typeColor, AutoFocus = false, }).SetAnchorPreset(AnchorPresets.TopLeft, true); - + + text = (char.ToUpper(text[0]) + text.Substring(1)).Replace("&", ""); var elementText = new Label(16, 0, Width * 0.5f - 32, 16) { Text = text, From d7a0c699904c76005de3c328a77bc0db561e1b65 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Thu, 20 Jun 2024 00:18:11 +0200 Subject: [PATCH 24/29] - Some cleanup and tooltips --- Source/Editor/Options/InterfaceOptions.cs | 2 +- Source/Editor/Surface/AnimGraphSurface.cs | 2 - Source/Editor/Surface/Archetypes/Constants.cs | 4 +- Source/Editor/Surface/Archetypes/Packing.cs | 49 ++++++++++------- .../Editor/Surface/ContextMenu/VisjectCM.cs | 54 +++++++++---------- Source/Editor/Surface/NodeArchetype.cs | 2 +- Source/Editor/Surface/SurfaceUtils.cs | 3 +- .../VisjectSurfaceContext.Serialization.cs | 2 +- 8 files changed, 61 insertions(+), 57 deletions(-) diff --git a/Source/Editor/Options/InterfaceOptions.cs b/Source/Editor/Options/InterfaceOptions.cs index 286ec720d..d62dc8510 100644 --- a/Source/Editor/Options/InterfaceOptions.cs +++ b/Source/Editor/Options/InterfaceOptions.cs @@ -372,7 +372,7 @@ namespace FlaxEditor.Options /// Gets or sets the visject connection curvature. /// [DefaultValue(true)] - [EditorDisplay("Visject"), EditorOrder(550)] + [EditorDisplay("Visject"), EditorOrder(550), Tooltip("Shows/hides the description panel in the visual scripting context menu.")] public bool VisualScriptingDescriptionPanel { get; set; } = true; private static FontAsset DefaultFont => FlaxEngine.Content.LoadAsyncInternal(EditorAssets.PrimaryFont); diff --git a/Source/Editor/Surface/AnimGraphSurface.cs b/Source/Editor/Surface/AnimGraphSurface.cs index ea0d9d32f..4e8b6f11e 100644 --- a/Source/Editor/Surface/AnimGraphSurface.cs +++ b/Source/Editor/Surface/AnimGraphSurface.cs @@ -197,7 +197,6 @@ namespace FlaxEditor.Surface { Groups = StateMachineGroupArchetypes, CanSpawnNode = (_, _) => true, - Style = Style, }); _cmStateMachineMenu.ShowExpanded = true; } @@ -215,7 +214,6 @@ namespace FlaxEditor.Surface CanSpawnNode = CanUseNodeType, ParametersGetter = null, CustomNodesGroup = GetCustomNodes(), - Style = Style, }); _cmStateMachineTransitionMenu.AddGroup(StateMachineTransitionGroupArchetype, false); } diff --git a/Source/Editor/Surface/Archetypes/Constants.cs b/Source/Editor/Surface/Archetypes/Constants.cs index 8cce34332..59b554e6b 100644 --- a/Source/Editor/Surface/Archetypes/Constants.cs +++ b/Source/Editor/Surface/Archetypes/Constants.cs @@ -7,8 +7,6 @@ using Real = System.Single; #endif using System; -using System.Collections; -using System.Collections.Generic; using System.Linq; using FlaxEditor.CustomEditors.Editors; using FlaxEditor.GUI; @@ -468,7 +466,7 @@ namespace FlaxEditor.Surface.Archetypes internal static void GetInputOutputDescription(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs) { inputs = null; - outputs = [("", new ScriptType(typeof(Dictionary)))]; + outputs = [("", new ScriptType(typeof(System.Collections.Generic.Dictionary)))]; } } diff --git a/Source/Editor/Surface/Archetypes/Packing.cs b/Source/Editor/Surface/Archetypes/Packing.cs index 5e84d615a..88ed6a64d 100644 --- a/Source/Editor/Surface/Archetypes/Packing.cs +++ b/Source/Editor/Surface/Archetypes/Packing.cs @@ -248,17 +248,24 @@ namespace FlaxEditor.Surface.Archetypes internal static void GetInputOutputDescription(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs) { - var type = TypeUtils.GetType((string)nodeArch.DefaultValues[0]); - outputs = [(type.Name, type)]; - - var fields = type.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); - var fieldsLength = fields.Length; - inputs = new (string, ScriptType)[fieldsLength]; - for (var i = 0; i < fieldsLength; i++) + var typeName = (string)nodeArch.DefaultValues[0]; + var type = TypeUtils.GetType(typeName); + if (type) { - var field = fields[i]; - inputs[i] = (field.Name, field.ValueType); + var fields = type.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); + var fieldsLength = fields.Length; + inputs = new (string, ScriptType)[fieldsLength]; + for (var i = 0; i < fieldsLength; i++) + { + var field = fields[i]; + inputs[i] = (field.Name, field.ValueType); + } + + outputs = [(type.Name, type)]; } + + inputs = null; + outputs = null; } } @@ -301,17 +308,23 @@ namespace FlaxEditor.Surface.Archetypes internal static void GetInputOutputDescription(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs) { - var type = TypeUtils.GetType((string)nodeArch.DefaultValues[0]); - inputs = [(type.Name, type)]; - - var fields = type.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); - var fieldsLength = fields.Length; - outputs = new (string, ScriptType)[fieldsLength]; - for (var i = 0; i < fieldsLength; i++) + var typeName = (string)nodeArch.DefaultValues[0]; + var type = TypeUtils.GetType(typeName); + if (type) { - var field = fields[i]; - outputs[i] = (field.Name, field.ValueType); + inputs = [(type.Name, type)]; + + var fields = type.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); + var fieldsLength = fields.Length; + outputs = new (string, ScriptType)[fieldsLength]; + for (var i = 0; i < fieldsLength; i++) + { + var field = fields[i]; + outputs[i] = (field.Name, field.ValueType); + } } + inputs = null; + outputs = null; } } diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index b30e726dd..d6dd852b4 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -2,14 +2,11 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Reflection; using System.Text.RegularExpressions; using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.Input; using FlaxEditor.Scripting; -using FlaxEditor.Surface.Archetypes; using FlaxEngine; using FlaxEngine.GUI; using FlaxEngine.Utilities; @@ -62,13 +59,12 @@ namespace FlaxEditor.Surface.ContextMenu private bool _descriptionPanelVisible; private readonly Panel _descriptionPanel; private readonly Panel _descriptionPanelSeparator; - private readonly Image _descriptionClassImage; + private readonly Image _descriptionDeclaringClassImage; private readonly Label _descriptionSignatureLabel; private readonly Label _descriptionLabel; - private readonly SurfaceStyle _surfaceStyle; private readonly VerticalPanel _descriptionInputPanel; private readonly VerticalPanel _descriptionOutputPanel; - + private readonly SurfaceStyle _surfaceStyle; private VisjectCMItem _selectedItem; /// @@ -251,7 +247,7 @@ namespace FlaxEditor.Surface.ContextMenu }; var spriteHandle = info.Style.Icons.BoxClose; - _descriptionClassImage = new Image(8, 12, 20, 20) + _descriptionDeclaringClassImage = new Image(8, 12, 20, 20) { Parent = _descriptionPanel, Brush = new SpriteBrush(spriteHandle), @@ -816,12 +812,12 @@ namespace FlaxEditor.Surface.ContextMenu HideDescriptionPanel(); return; } - + Profiler.BeginEvent("VisjectCM.SetDescriptionPanelArchetype"); - + _descriptionInputPanel.RemoveChildren(); _descriptionOutputPanel.RemoveChildren(); - + ScriptType declaringType; if (archetype.Tag is ScriptMemberInfo memberInfo) { @@ -844,7 +840,7 @@ namespace FlaxEditor.Surface.ContextMenu else AddInputOutputElement(archetype, memberInfo.ValueType, true, $"Return ({memberInfo.ValueType.Name})"); } - + for(int i = 0; i < memberInfo.ParametersCount; i++) { var param = memberInfo.GetParameters()[i]; @@ -858,13 +854,13 @@ namespace FlaxEditor.Surface.ContextMenu if (archetype.GetInputOutputDescription != null) { - archetype.GetInputOutputDescription.Invoke(archetype, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs); + archetype.GetInputOutputDescription.Invoke(archetype, out (string Name, ScriptType Type)[] inputs, out (string Name, ScriptType Type)[] outputs); if (inputs != null) { for (int i = 0; i < inputs.Length; i++) { - AddInputOutputElement(archetype, inputs[i].Item2, false, $"{inputs[i].Item1} ({inputs[i].Item2.Name})"); + AddInputOutputElement(archetype, inputs[i].Type, false, $"{inputs[i].Name} ({inputs[i].Type.Name})"); } } @@ -872,7 +868,7 @@ namespace FlaxEditor.Surface.ContextMenu { for (int i = 0; i < outputs.Length; i++) { - AddInputOutputElement(archetype, outputs[i].Item2, true, $"{outputs[i].Item1} ({outputs[i].Item2.Name})"); + AddInputOutputElement(archetype, outputs[i].Type, true, $"{outputs[i].Name} ({outputs[i].Type.Name})"); } } } @@ -880,22 +876,22 @@ namespace FlaxEditor.Surface.ContextMenu { foreach (var element in archetype.Elements) { - if (element.Type is NodeElementType.Input or NodeElementType.Output) - { - bool isOutput = element.Type == NodeElementType.Output; - if (element.ConnectionsType == null) - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"{element.Text} ({archetype.ConnectionsHints.ToString()})"); - else - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"{element.Text} ({element.ConnectionsType.Name})"); - } + if (element.Type is not (NodeElementType.Input or NodeElementType.Output)) + continue; + + bool isOutput = element.Type == NodeElementType.Output; + if (element.ConnectionsType == null) + AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"{element.Text} ({archetype.ConnectionsHints.ToString()})"); + else + AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"{element.Text} ({element.ConnectionsType.Name})"); } } } _surfaceStyle.GetConnectionColor(declaringType, archetype.ConnectionsHints, out var declaringTypeColor); - _descriptionClassImage.Color = declaringTypeColor; - _descriptionClassImage.MouseOverColor = declaringTypeColor; - + _descriptionDeclaringClassImage.Color = declaringTypeColor; + _descriptionDeclaringClassImage.MouseOverColor = declaringTypeColor; + float panelHeight = _descriptionSignatureLabel.Height; if (string.IsNullOrEmpty(archetype.Description)) @@ -911,21 +907,21 @@ namespace FlaxEditor.Surface.ContextMenu } _descriptionPanelSeparator.Y = _descriptionLabel.Bounds.Bottom + 8f; - + panelHeight += _descriptionLabel.Height + 32f; _descriptionInputPanel.Y = panelHeight; _descriptionOutputPanel.Y = panelHeight; panelHeight += Mathf.Max(_descriptionInputPanel.Height, _descriptionOutputPanel.Height); - + // Forcing the description panel to at least have a minimum height to not make the window size change too much in order to reduce jittering // TODO: Remove the Mathf.Max and just set the height to panelHeight once the window jitter issue is fixed - Nils _descriptionPanel.Height = Mathf.Max(135f, panelHeight); Height = 400 + _descriptionPanel.Height; UpdateWindowSize(); _descriptionPanelVisible = true; - + Profiler.EndEvent(); } @@ -962,7 +958,7 @@ namespace FlaxEditor.Surface.ContextMenu elementPanel.AddChild(elementText); elementPanel.Height = elementText.Height; } - + /// /// Hides the description panel and resets the context menu to its original size /// diff --git a/Source/Editor/Surface/NodeArchetype.cs b/Source/Editor/Surface/NodeArchetype.cs index 63d731b72..609b7b5f7 100644 --- a/Source/Editor/Surface/NodeArchetype.cs +++ b/Source/Editor/Surface/NodeArchetype.cs @@ -97,7 +97,7 @@ namespace FlaxEditor.Surface /// /// Gets description of inputs and outputs of the archetype. Used for special cases for the description panel. /// - public delegate void GetElementsDescriptionFunc(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs); + public delegate void GetElementsDescriptionFunc(NodeArchetype nodeArch, out (string Name, ScriptType Type)[] inputs, out (string Name, ScriptType Type)[] outputs); /// /// Unique node type ID within a single group. diff --git a/Source/Editor/Surface/SurfaceUtils.cs b/Source/Editor/Surface/SurfaceUtils.cs index 6bc834b0a..ad77aa510 100644 --- a/Source/Editor/Surface/SurfaceUtils.cs +++ b/Source/Editor/Surface/SurfaceUtils.cs @@ -468,7 +468,6 @@ namespace FlaxEditor.Surface sb.Append('.'); sb.Append(name); - // Is a method and not a property if (member.IsMethod) { sb.Append('('); @@ -512,7 +511,7 @@ namespace FlaxEditor.Surface return GetVisualScriptMemberShortDescription(property[0]); } } - + return Editor.Instance.CodeDocs.GetTooltip(member); } diff --git a/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs b/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs index 97122f872..7ddbc72db 100644 --- a/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs +++ b/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs @@ -51,7 +51,7 @@ namespace FlaxEditor.Surface { TypeID = originalNodeId, Title = "Missing Node :(", - Signature = ":(", + Signature = "Missing Node :(", Description = ":(", Flags = NodeFlags.AllGraphs, Size = new Float2(200, 70), From db17d8d0ced79d82aaa6108e62b6267d5693fa32 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Fri, 21 Jun 2024 20:26:24 +0200 Subject: [PATCH 25/29] - Comments, cleanup and a bit of refactoring --- .../Editor/Surface/ContextMenu/VisjectCM.cs | 65 ++++++++++--------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index d6dd852b4..2d22b2e3f 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -41,6 +41,9 @@ namespace FlaxEditor.Surface.ContextMenu /// TThe list of surface parameters or null if failed (readonly). public delegate List ParameterGetterDelegate(); + private const float DefaultWidth = 300; + private const float DefaultHeight = 400; + private readonly List _groups = new List(16); private CheckBox _contextSensitiveToggle; private bool _contextSensitiveSearchEnabled = true; @@ -164,7 +167,7 @@ namespace FlaxEditor.Surface.ContextMenu _surfaceStyle = info.Style; // Context menu dimensions - Size = new Float2(_useDescriptionPanel ? 350 : 300, 400); + Size = new Float2(_useDescriptionPanel ? DefaultWidth + 50f : DefaultWidth, DefaultHeight); var headerPanel = new Panel(ScrollBars.None) { @@ -236,7 +239,7 @@ namespace FlaxEditor.Surface.ContextMenu }; _groupsPanel = panel2; - // Create description panel if enabled + // Create description panel elements only when description panel is about to be used if (_useDescriptionPanel) { _descriptionPanel = new Panel(ScrollBars.None) @@ -246,21 +249,20 @@ namespace FlaxEditor.Surface.ContextMenu BackgroundColor = Style.Current.BackgroundNormal, }; - var spriteHandle = info.Style.Icons.BoxClose; _descriptionDeclaringClassImage = new Image(8, 12, 20, 20) { Parent = _descriptionPanel, - Brush = new SpriteBrush(spriteHandle), + Brush = new SpriteBrush(info.Style.Icons.BoxClose), }; - var signatureFontReference = new FontReference(Style.Current.FontMedium.Asset, 9f); + var descriptionFontReference = new FontReference(Style.Current.FontMedium.Asset, 9f); _descriptionSignatureLabel = new Label(32, 8, Width - 40, 0) { Parent = _descriptionPanel, HorizontalAlignment = TextAlignment.Near, VerticalAlignment = TextAlignment.Near, Wrapping = TextWrapping.WrapWords, - Font = signatureFontReference, + Font = descriptionFontReference, Bold = true, AutoHeight = true, }; @@ -272,7 +274,7 @@ namespace FlaxEditor.Surface.ContextMenu HorizontalAlignment = TextAlignment.Near, VerticalAlignment = TextAlignment.Near, Wrapping = TextWrapping.WrapWords, - Font = signatureFontReference, + Font = descriptionFontReference, AutoHeight = true, }; _descriptionLabel.SetAnchorPreset(AnchorPresets.TopLeft, true); @@ -818,6 +820,7 @@ namespace FlaxEditor.Surface.ContextMenu _descriptionInputPanel.RemoveChildren(); _descriptionOutputPanel.RemoveChildren(); + // Fetch description and information from the memberInfo - mainly from nodes that got fetched asynchronously by the visual scripting editor ScriptType declaringType; if (archetype.Tag is ScriptMemberInfo memberInfo) { @@ -830,11 +833,14 @@ namespace FlaxEditor.Surface.ContextMenu declaringType = memberInfo.DeclaringType; _descriptionSignatureLabel.Text = memberInfo.DeclaringType + "." + name; + // We have to add the Instance information manually for members that aren't static if (!memberInfo.IsStatic) AddInputOutputElement(archetype, declaringType, false, $"Instance ({memberInfo.DeclaringType.Name})"); + // We also have to manually add the Return information as well. if (memberInfo.ValueType != ScriptType.Null && memberInfo.ValueType != ScriptType.Void) { + // When a field has a setter we don't want it to show the input as a return output. if (memberInfo.IsField && archetype.Title.StartsWith("Set ")) AddInputOutputElement(archetype, memberInfo.ValueType, false, $"({memberInfo.ValueType.Name})"); else @@ -849,27 +855,24 @@ namespace FlaxEditor.Surface.ContextMenu } else { + // Try to fetch as many informations as possible from the predefined hardcoded nodes _descriptionSignatureLabel.Text = string.IsNullOrEmpty(archetype.Signature) ? archetype.Title : archetype.Signature; declaringType = archetype.DefaultType; + // Some nodes are more delicate. Like Arrays or Dictionaries. In this case we let them fetch the inputs/outputs for us. + // Otherwise, it is not possible to show a proper return type on some nodes. if (archetype.GetInputOutputDescription != null) { - archetype.GetInputOutputDescription.Invoke(archetype, out (string Name, ScriptType Type)[] inputs, out (string Name, ScriptType Type)[] outputs); + archetype.GetInputOutputDescription.Invoke(archetype, out var inputs, out var outputs); - if (inputs != null) + foreach (var input in inputs ?? []) { - for (int i = 0; i < inputs.Length; i++) - { - AddInputOutputElement(archetype, inputs[i].Type, false, $"{inputs[i].Name} ({inputs[i].Type.Name})"); - } + AddInputOutputElement(archetype, input.Type, false, $"{input.Name} ({input.Type.Name})"); } - if (outputs != null) + foreach (var output in outputs ?? []) { - for (int i = 0; i < outputs.Length; i++) - { - AddInputOutputElement(archetype, outputs[i].Type, true, $"{outputs[i].Name} ({outputs[i].Type.Name})"); - } + AddInputOutputElement(archetype, output.Type, true, $"{output.Name} ({output.Type.Name})"); } } else @@ -879,21 +882,21 @@ namespace FlaxEditor.Surface.ContextMenu if (element.Type is not (NodeElementType.Input or NodeElementType.Output)) continue; - bool isOutput = element.Type == NodeElementType.Output; - if (element.ConnectionsType == null) - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"{element.Text} ({archetype.ConnectionsHints.ToString()})"); - else - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"{element.Text} ({element.ConnectionsType.Name})"); + var typeText = element.ConnectionsType ? element.ConnectionsType.Name : archetype.ConnectionsHints.ToString(); + AddInputOutputElement(archetype, element.ConnectionsType, element.Type == NodeElementType.Output, $"{element.Text} ({typeText})"); } } } + // Set declaring type icon color _surfaceStyle.GetConnectionColor(declaringType, archetype.ConnectionsHints, out var declaringTypeColor); _descriptionDeclaringClassImage.Color = declaringTypeColor; _descriptionDeclaringClassImage.MouseOverColor = declaringTypeColor; + // Calculate the description panel height. (I am doing this manually since working with autoSize on horizontal/vertical panels didn't work, especially with nesting - Nils) float panelHeight = _descriptionSignatureLabel.Height; + // If thee is no description we move the signature label down a bit to align it with the icon. Just a cosmetic check if (string.IsNullOrEmpty(archetype.Description)) { _descriptionSignatureLabel.Y = 15; @@ -903,22 +906,21 @@ namespace FlaxEditor.Surface.ContextMenu { _descriptionSignatureLabel.Y = 8; _descriptionLabel.Y = _descriptionSignatureLabel.Bounds.Bottom + 6f; + // Replacing multiple whitespaces with a linebreak for better readability. (Mainly doing this because the ToolTip fetching system replaces linebreaks with whitespaces - Nils) _descriptionLabel.Text = Regex.Replace(archetype.Description, @"\s{2,}", "\n"); } + // Some padding and moving elements around _descriptionPanelSeparator.Y = _descriptionLabel.Bounds.Bottom + 8f; - panelHeight += _descriptionLabel.Height + 32f; - _descriptionInputPanel.Y = panelHeight; _descriptionOutputPanel.Y = panelHeight; - panelHeight += Mathf.Max(_descriptionInputPanel.Height, _descriptionOutputPanel.Height); // Forcing the description panel to at least have a minimum height to not make the window size change too much in order to reduce jittering // TODO: Remove the Mathf.Max and just set the height to panelHeight once the window jitter issue is fixed - Nils _descriptionPanel.Height = Mathf.Max(135f, panelHeight); - Height = 400 + _descriptionPanel.Height; + Height = DefaultHeight + _descriptionPanel.Height; UpdateWindowSize(); _descriptionPanelVisible = true; @@ -927,6 +929,7 @@ namespace FlaxEditor.Surface.ContextMenu private void AddInputOutputElement(NodeArchetype nodeArchetype, ScriptType type, bool isOutput, string text) { + // Using a panel instead of a vertical panel because auto sizing is unreliable - so we are doing this manually here as well var elementPanel = new Panel() { Parent = isOutput ? _descriptionOutputPanel : _descriptionInputPanel, @@ -934,17 +937,17 @@ namespace FlaxEditor.Surface.ContextMenu Height = 16, AnchorPreset = AnchorPresets.TopLeft }; - - var sprite = _surfaceStyle.Icons.BoxOpen; + _surfaceStyle.GetConnectionColor(type, nodeArchetype.ConnectionsHints, out var typeColor); elementPanel.AddChild(new Image(2, 0, 12, 12) { - Brush = new SpriteBrush(sprite), + Brush = new SpriteBrush(_surfaceStyle.Icons.BoxOpen), Color = typeColor, MouseOverColor = typeColor, AutoFocus = false, }).SetAnchorPreset(AnchorPresets.TopLeft, true); + // Forcing the first letter to be capital and removing the '&' char from pointer-references text = (char.ToUpper(text[0]) + text.Substring(1)).Replace("&", ""); var elementText = new Label(16, 0, Width * 0.5f - 32, 16) { @@ -969,7 +972,7 @@ namespace FlaxEditor.Surface.ContextMenu _descriptionInputPanel.RemoveChildren(); _descriptionOutputPanel.RemoveChildren(); - Height = 400; + Height = DefaultHeight; UpdateWindowSize(); _descriptionPanelVisible = false; } From a8bd59c07f662b3c4a73c9268a261fb7cc3b98dd Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Fri, 21 Jun 2024 20:40:39 +0200 Subject: [PATCH 26/29] - Fixed regression where pack/unpack nodes didn't return any inputs/outputs --- Source/Editor/Surface/Archetypes/Packing.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/Editor/Surface/Archetypes/Packing.cs b/Source/Editor/Surface/Archetypes/Packing.cs index 88ed6a64d..99899e033 100644 --- a/Source/Editor/Surface/Archetypes/Packing.cs +++ b/Source/Editor/Surface/Archetypes/Packing.cs @@ -262,6 +262,7 @@ namespace FlaxEditor.Surface.Archetypes } outputs = [(type.Name, type)]; + return; } inputs = null; @@ -322,7 +323,9 @@ namespace FlaxEditor.Surface.Archetypes var field = fields[i]; outputs[i] = (field.Name, field.ValueType); } + return; } + inputs = null; outputs = null; } From ef5d4013d3143ba1264474a4e3b1fe5f60c50c80 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Fri, 21 Jun 2024 20:45:22 +0200 Subject: [PATCH 27/29] - Increased min description panel height a tiny bit to make 4 input/output elements fit without causing jittering / flickering --- Source/Editor/Surface/ContextMenu/VisjectCM.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 2d22b2e3f..691bef2dd 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -919,7 +919,7 @@ namespace FlaxEditor.Surface.ContextMenu // Forcing the description panel to at least have a minimum height to not make the window size change too much in order to reduce jittering // TODO: Remove the Mathf.Max and just set the height to panelHeight once the window jitter issue is fixed - Nils - _descriptionPanel.Height = Mathf.Max(135f, panelHeight); + _descriptionPanel.Height = Mathf.Max(140f, panelHeight); Height = DefaultHeight + _descriptionPanel.Height; UpdateWindowSize(); _descriptionPanelVisible = true; From 240ddbcde3411fccb4dc6f43d8a669b8c46c4bb8 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Fri, 21 Jun 2024 20:52:14 +0200 Subject: [PATCH 28/29] - Minor cleanup --- Source/Editor/Surface/ContextMenu/VisjectCMItem.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs b/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs index 1d7b9fa8b..792579b67 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCMItem.cs @@ -359,8 +359,9 @@ namespace FlaxEditor.Surface.ContextMenu /// public override void OnMouseEnter(Float2 location) { - base.OnMouseEnter(location); Group.ContextMenu.SetDescriptionPanelArchetype(_archetype); + + base.OnMouseEnter(location); } /// From 1a953c99bcbe11dcfac7d8eac821bf958202f9c1 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 5 Aug 2024 19:01:56 +0200 Subject: [PATCH 29/29] Format code --- Source/Editor/Surface/ContextMenu/VisjectCM.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 691bef2dd..526c24fae 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -794,7 +794,7 @@ namespace FlaxEditor.Surface.ContextMenu { Focus(null); - if(_useDescriptionPanel) + if (_useDescriptionPanel) HideDescriptionPanel(); base.Hide(); @@ -806,7 +806,7 @@ namespace FlaxEditor.Surface.ContextMenu /// The node archetype public void SetDescriptionPanelArchetype(NodeArchetype archetype) { - if(!_useDescriptionPanel) + if (!_useDescriptionPanel) return; if (archetype == null || !Editor.Instance.Options.Options.Interface.VisualScriptingDescriptionPanel) @@ -847,7 +847,7 @@ namespace FlaxEditor.Surface.ContextMenu AddInputOutputElement(archetype, memberInfo.ValueType, true, $"Return ({memberInfo.ValueType.Name})"); } - for(int i = 0; i < memberInfo.ParametersCount; i++) + for (int i = 0; i < memberInfo.ParametersCount; i++) { var param = memberInfo.GetParameters()[i]; AddInputOutputElement(archetype, param.Type, param.IsOut, $"{param.Name} ({param.Type.Name})"); @@ -882,7 +882,7 @@ namespace FlaxEditor.Surface.ContextMenu if (element.Type is not (NodeElementType.Input or NodeElementType.Output)) continue; - var typeText = element.ConnectionsType ? element.ConnectionsType.Name : archetype.ConnectionsHints.ToString(); + var typeText = element.ConnectionsType ? element.ConnectionsType.Name : archetype.ConnectionsHints.ToString(); AddInputOutputElement(archetype, element.ConnectionsType, element.Type == NodeElementType.Output, $"{element.Text} ({typeText})"); } } @@ -967,7 +967,7 @@ namespace FlaxEditor.Surface.ContextMenu /// private void HideDescriptionPanel() { - if(!_descriptionPanelVisible) + if (!_descriptionPanelVisible) return; _descriptionInputPanel.RemoveChildren();